diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index 668d090f5..85fd91db1 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using StreamJsonRpc; +using StreamJsonRpc.Protocol; using System.Collections.Concurrent; using System.Data; using System.Diagnostics; @@ -1104,7 +1105,7 @@ await Rpc.SessionFs.SetProviderAsync( cancellationToken); } - private void ConfigureSessionFsHandlers(CopilotSession session, Func? createSessionFsHandler) + private void ConfigureSessionFsHandlers(CopilotSession session, Func? createSessionFsHandler) { if (_options.SessionFs is null) { @@ -1836,6 +1837,7 @@ private static LogLevel MapLevel(TraceEventType eventType) AllowOutOfOrderMetadataProperties = true, NumberHandling = JsonNumberHandling.AllowReadingFromString, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] + [JsonSerializable(typeof(CommonErrorData))] [JsonSerializable(typeof(CreateSessionRequest))] [JsonSerializable(typeof(CreateSessionResponse))] [JsonSerializable(typeof(CustomAgentConfig))] diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index 0c9880de6..8de5b2fd4 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -30,13 +30,13 @@ public sealed class PingResult [JsonPropertyName("message")] public string Message { get; set; } = string.Empty; - /// Server timestamp in milliseconds. - [JsonPropertyName("timestamp")] - public long Timestamp { get; set; } - /// Server protocol version number. [JsonPropertyName("protocolVersion")] public long ProtocolVersion { get; set; } + + /// Server timestamp in milliseconds. + [JsonPropertyName("timestamp")] + public long Timestamp { get; set; } } /// RPC data type for Ping operations. @@ -47,69 +47,77 @@ internal sealed class PingRequest public string? Message { get; set; } } -/// Feature flags indicating what the model supports. -public sealed class ModelCapabilitiesSupports +/// Billing information. +public sealed class ModelBilling { - /// Whether this model supports vision/image input. - [JsonPropertyName("vision")] - public bool? Vision { get; set; } - - /// Whether this model supports reasoning effort configuration. - [JsonPropertyName("reasoningEffort")] - public bool? ReasoningEffort { get; set; } + /// Billing cost multiplier relative to the base rate. + [JsonPropertyName("multiplier")] + public double Multiplier { get; set; } } /// Vision-specific limits. public sealed class ModelCapabilitiesLimitsVision { - /// MIME types the model accepts. - [JsonPropertyName("supported_media_types")] - public IList SupportedMediaTypes { get => field ??= []; set; } + /// Maximum image size in bytes. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("max_prompt_image_size")] + public long MaxPromptImageSize { get; set; } /// Maximum number of images per prompt. [Range((double)1, (double)long.MaxValue)] [JsonPropertyName("max_prompt_images")] public long MaxPromptImages { get; set; } - /// Maximum image size in bytes. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("max_prompt_image_size")] - public long MaxPromptImageSize { get; set; } + /// MIME types the model accepts. + [JsonPropertyName("supported_media_types")] + public IList SupportedMediaTypes { get => field ??= []; set; } } /// Token limits for prompts, outputs, and context window. public sealed class ModelCapabilitiesLimits { - /// Maximum number of prompt/input tokens. + /// Maximum total context window size in tokens. [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("max_prompt_tokens")] - public long? MaxPromptTokens { get; set; } + [JsonPropertyName("max_context_window_tokens")] + public long? MaxContextWindowTokens { get; set; } /// Maximum number of output/completion tokens. [Range((double)0, (double)long.MaxValue)] [JsonPropertyName("max_output_tokens")] public long? MaxOutputTokens { get; set; } - /// Maximum total context window size in tokens. + /// Maximum number of prompt/input tokens. [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("max_context_window_tokens")] - public long? MaxContextWindowTokens { get; set; } + [JsonPropertyName("max_prompt_tokens")] + public long? MaxPromptTokens { get; set; } /// Vision-specific limits. [JsonPropertyName("vision")] public ModelCapabilitiesLimitsVision? Vision { get; set; } } +/// Feature flags indicating what the model supports. +public sealed class ModelCapabilitiesSupports +{ + /// Whether this model supports reasoning effort configuration. + [JsonPropertyName("reasoningEffort")] + public bool? ReasoningEffort { get; set; } + + /// Whether this model supports vision/image input. + [JsonPropertyName("vision")] + public bool? Vision { get; set; } +} + /// Model capabilities and limits. public sealed class ModelCapabilities { - /// Feature flags indicating what the model supports. - [JsonPropertyName("supports")] - public ModelCapabilitiesSupports? Supports { get; set; } - /// Token limits for prompts, outputs, and context window. [JsonPropertyName("limits")] public ModelCapabilitiesLimits? Limits { get; set; } + + /// Feature flags indicating what the model supports. + [JsonPropertyName("supports")] + public ModelCapabilitiesSupports? Supports { get; set; } } /// Policy state (if applicable). @@ -124,17 +132,21 @@ public sealed class ModelPolicy public string Terms { get; set; } = string.Empty; } -/// Billing information. -public sealed class ModelBilling -{ - /// Billing cost multiplier relative to the base rate. - [JsonPropertyName("multiplier")] - public double Multiplier { get; set; } -} - /// RPC data type for Model operations. public sealed class Model { + /// Billing information. + [JsonPropertyName("billing")] + public ModelBilling? Billing { get; set; } + + /// Model capabilities and limits. + [JsonPropertyName("capabilities")] + public ModelCapabilities Capabilities { get => field ??= new(); set; } + + /// Default reasoning effort level (only present if model supports reasoning effort). + [JsonPropertyName("defaultReasoningEffort")] + public string? DefaultReasoningEffort { get; set; } + /// Model identifier (e.g., "claude-sonnet-4.5"). [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; @@ -143,25 +155,13 @@ public sealed class Model [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Model capabilities and limits. - [JsonPropertyName("capabilities")] - public ModelCapabilities Capabilities { get => field ??= new(); set; } - /// Policy state (if applicable). [JsonPropertyName("policy")] public ModelPolicy? Policy { get; set; } - /// Billing information. - [JsonPropertyName("billing")] - public ModelBilling? Billing { get; set; } - /// Supported reasoning effort levels (only present if model supports reasoning effort). [JsonPropertyName("supportedReasoningEfforts")] public IList? SupportedReasoningEfforts { get; set; } - - /// Default reasoning effort level (only present if model supports reasoning effort). - [JsonPropertyName("defaultReasoningEffort")] - public string? DefaultReasoningEffort { get; set; } } /// RPC data type for ModelList operations. @@ -175,6 +175,14 @@ public sealed class ModelList /// RPC data type for Tool operations. public sealed class Tool { + /// Description of what the tool does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Optional instructions for how to use this tool effectively. + [JsonPropertyName("instructions")] + public string? Instructions { get; set; } + /// Tool identifier (e.g., "bash", "grep", "str_replace_editor"). [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; @@ -183,17 +191,9 @@ public sealed class Tool [JsonPropertyName("namespacedName")] public string? NamespacedName { get; set; } - /// Description of what the tool does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - /// JSON Schema for the tool's input parameters. [JsonPropertyName("parameters")] public IDictionary? Parameters { get; set; } - - /// Optional instructions for how to use this tool effectively. - [JsonPropertyName("instructions")] - public string? Instructions { get; set; } } /// RPC data type for ToolList operations. @@ -219,27 +219,35 @@ public sealed class AccountQuotaSnapshot [JsonPropertyName("entitlementRequests")] public long EntitlementRequests { get; set; } - /// Number of requests used so far this period. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("usedRequests")] - public long UsedRequests { get; set; } - - /// Percentage of entitlement remaining. - [JsonPropertyName("remainingPercentage")] - public double RemainingPercentage { get; set; } + /// Whether the user has an unlimited usage entitlement. + [JsonPropertyName("isUnlimitedEntitlement")] + public bool IsUnlimitedEntitlement { get; set; } /// Number of overage requests made this period. - [Range((double)0, (double)long.MaxValue)] + [Range(0, double.MaxValue)] [JsonPropertyName("overage")] - public long Overage { get; set; } + public double Overage { get; set; } - /// Whether pay-per-request usage is allowed when quota is exhausted. + /// Whether overage is allowed when quota is exhausted. [JsonPropertyName("overageAllowedWithExhaustedQuota")] public bool OverageAllowedWithExhaustedQuota { get; set; } - /// Date when the quota resets (ISO 8601). + /// Percentage of entitlement remaining. + [JsonPropertyName("remainingPercentage")] + public double RemainingPercentage { get; set; } + + /// Date when the quota resets (ISO 8601 string). [JsonPropertyName("resetDate")] - public DateTimeOffset? ResetDate { get; set; } + public string? ResetDate { get; set; } + + /// Whether usage is still permitted after quota exhaustion. + [JsonPropertyName("usageAllowedWithExhaustedQuota")] + public bool UsageAllowedWithExhaustedQuota { get; set; } + + /// Number of requests used so far this period. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("usedRequests")] + public long UsedRequests { get; set; } } /// RPC data type for AccountGetQuota operations. @@ -253,22 +261,22 @@ public sealed class AccountGetQuotaResult /// RPC data type for DiscoveredMcpServer operations. public sealed class DiscoveredMcpServer { + /// Whether the server is enabled (not in the disabled list). + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + /// Server name (config key). [RegularExpression("^[0-9a-zA-Z_.@-]+(\\/[0-9a-zA-Z_.@-]+)*$")] [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio). - [JsonPropertyName("type")] - public DiscoveredMcpServerType? Type { get; set; } - /// Configuration source. [JsonPropertyName("source")] public DiscoveredMcpServerSource Source { get; set; } - /// Whether the server is enabled (not in the disabled list). - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio). + [JsonPropertyName("type")] + public DiscoveredMcpServerType? Type { get; set; } } /// RPC data type for McpDiscover operations. @@ -298,27 +306,27 @@ public sealed class McpConfigList /// RPC data type for McpConfigAdd operations. internal sealed class McpConfigAddRequest { + /// MCP server configuration (local/stdio or remote/http). + [JsonPropertyName("config")] + public object Config { get; set; } = null!; + /// Unique name for the MCP server. [RegularExpression("^[0-9a-zA-Z_.@-]+(\\/[0-9a-zA-Z_.@-]+)*$")] [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - - /// MCP server configuration (local/stdio or remote/http). - [JsonPropertyName("config")] - public object Config { get; set; } = null!; } /// RPC data type for McpConfigUpdate operations. internal sealed class McpConfigUpdateRequest { + /// MCP server configuration (local/stdio or remote/http). + [JsonPropertyName("config")] + public object Config { get; set; } = null!; + /// Name of the MCP server to update. [RegularExpression("^[0-9a-zA-Z_.@-]+(\\/[0-9a-zA-Z_.@-]+)*$")] [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - - /// MCP server configuration (local/stdio or remote/http). - [JsonPropertyName("config")] - public object Config { get; set; } = null!; } /// RPC data type for McpConfigRemove operations. @@ -333,26 +341,18 @@ internal sealed class McpConfigRemoveRequest /// RPC data type for ServerSkill operations. public sealed class ServerSkill { - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - /// Description of what the skill does. [JsonPropertyName("description")] public string Description { get; set; } = string.Empty; - /// Source location type (e.g., project, personal-copilot, plugin, builtin). - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; - - /// Whether the skill can be invoked by the user as a slash command. - [JsonPropertyName("userInvocable")] - public bool UserInvocable { get; set; } - /// Whether the skill is currently enabled (based on global config). [JsonPropertyName("enabled")] public bool Enabled { get; set; } + /// Unique identifier for the skill. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + /// Absolute path to the skill file. [JsonPropertyName("path")] public string? Path { get; set; } @@ -360,6 +360,14 @@ public sealed class ServerSkill /// The project path this skill belongs to (only for project/inherited skills). [JsonPropertyName("projectPath")] public string? ProjectPath { get; set; } + + /// Source location type (e.g., project, personal-copilot, plugin, builtin). + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; + + /// Whether the skill can be invoked by the user as a slash command. + [JsonPropertyName("userInvocable")] + public bool UserInvocable { get; set; } } /// RPC data type for ServerSkillList operations. @@ -401,6 +409,10 @@ public sealed class SessionFsSetProviderResult /// RPC data type for SessionFsSetProvider operations. internal sealed class SessionFsSetProviderRequest { + /// Path conventions used by this filesystem. + [JsonPropertyName("conventions")] + public SessionFsSetProviderConventions Conventions { get; set; } + /// Initial working directory for sessions. [JsonPropertyName("initialCwd")] public string InitialCwd { get; set; } = string.Empty; @@ -408,10 +420,6 @@ internal sealed class SessionFsSetProviderRequest /// Path within each session's SessionFs where the runtime stores files for that session. [JsonPropertyName("sessionStatePath")] public string SessionStatePath { get; set; } = string.Empty; - - /// Path conventions used by this filesystem. - [JsonPropertyName("conventions")] - public SessionFsSetProviderConventions Conventions { get; set; } } /// RPC data type for SessionsFork operations. @@ -447,21 +455,21 @@ public sealed class LogResult /// RPC data type for Log operations. internal sealed class LogRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - - /// Human-readable message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// When true, the message is transient and not persisted to the session event log on disk. + [JsonPropertyName("ephemeral")] + public bool? Ephemeral { get; set; } /// Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". [JsonPropertyName("level")] public SessionLogLevel? Level { get; set; } - /// When true, the message is transient and not persisted to the session event log on disk. - [JsonPropertyName("ephemeral")] - public bool? Ephemeral { get; set; } + /// Human-readable message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; /// Optional URL the user can open in their browser for more details. [Url] @@ -494,77 +502,77 @@ public sealed class ModelSwitchToResult public string? ModelId { get; set; } } -/// Feature flags indicating what the model supports. -public sealed class ModelCapabilitiesOverrideSupports -{ - /// Gets or sets the vision value. - [JsonPropertyName("vision")] - public bool? Vision { get; set; } - - /// Gets or sets the reasoningEffort value. - [JsonPropertyName("reasoningEffort")] - public bool? ReasoningEffort { get; set; } -} - /// RPC data type for ModelCapabilitiesOverrideLimitsVision operations. public sealed class ModelCapabilitiesOverrideLimitsVision { - /// MIME types the model accepts. - [JsonPropertyName("supported_media_types")] - public IList? SupportedMediaTypes { get; set; } + /// Maximum image size in bytes. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("max_prompt_image_size")] + public long? MaxPromptImageSize { get; set; } /// Maximum number of images per prompt. [Range((double)1, (double)long.MaxValue)] [JsonPropertyName("max_prompt_images")] public long? MaxPromptImages { get; set; } - /// Maximum image size in bytes. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("max_prompt_image_size")] - public long? MaxPromptImageSize { get; set; } + /// MIME types the model accepts. + [JsonPropertyName("supported_media_types")] + public IList? SupportedMediaTypes { get; set; } } /// Token limits for prompts, outputs, and context window. public sealed class ModelCapabilitiesOverrideLimits { - /// Gets or sets the max_prompt_tokens value. + /// Maximum total context window size in tokens. [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("max_prompt_tokens")] - public long? MaxPromptTokens { get; set; } + [JsonPropertyName("max_context_window_tokens")] + public long? MaxContextWindowTokens { get; set; } /// Gets or sets the max_output_tokens value. [Range((double)0, (double)long.MaxValue)] [JsonPropertyName("max_output_tokens")] public long? MaxOutputTokens { get; set; } - /// Maximum total context window size in tokens. + /// Gets or sets the max_prompt_tokens value. [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("max_context_window_tokens")] - public long? MaxContextWindowTokens { get; set; } + [JsonPropertyName("max_prompt_tokens")] + public long? MaxPromptTokens { get; set; } /// Gets or sets the vision value. [JsonPropertyName("vision")] public ModelCapabilitiesOverrideLimitsVision? Vision { get; set; } } +/// Feature flags indicating what the model supports. +public sealed class ModelCapabilitiesOverrideSupports +{ + /// Gets or sets the reasoningEffort value. + [JsonPropertyName("reasoningEffort")] + public bool? ReasoningEffort { get; set; } + + /// Gets or sets the vision value. + [JsonPropertyName("vision")] + public bool? Vision { get; set; } +} + /// Override individual model capabilities resolved by the runtime. public sealed class ModelCapabilitiesOverride { - /// Feature flags indicating what the model supports. - [JsonPropertyName("supports")] - public ModelCapabilitiesOverrideSupports? Supports { get; set; } - /// Token limits for prompts, outputs, and context window. [JsonPropertyName("limits")] public ModelCapabilitiesOverrideLimits? Limits { get; set; } + + /// Feature flags indicating what the model supports. + [JsonPropertyName("supports")] + public ModelCapabilitiesOverrideSupports? Supports { get; set; } } /// RPC data type for ModelSwitchTo operations. internal sealed class ModelSwitchToRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Override individual model capabilities resolved by the runtime. + [JsonPropertyName("modelCapabilities")] + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } /// Model identifier to switch to. [JsonPropertyName("modelId")] @@ -574,9 +582,9 @@ internal sealed class ModelSwitchToRequest [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } - /// Override individual model capabilities resolved by the runtime. - [JsonPropertyName("modelCapabilities")] - public ModelCapabilitiesOverride? ModelCapabilities { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionModeGet operations. @@ -590,13 +598,13 @@ internal sealed class SessionModeGetRequest /// RPC data type for ModeSet operations. internal sealed class ModeSetRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// The agent mode. Valid values: "interactive", "plan", "autopilot". [JsonPropertyName("mode")] public SessionMode Mode { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for NameGet operations. @@ -618,29 +626,29 @@ internal sealed class SessionNameGetRequest /// RPC data type for NameSet operations. internal sealed class NameSetRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// New session name (1–100 characters, trimmed of leading/trailing whitespace). [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MinLength(1)] [MaxLength(100)] [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for PlanRead operations. public sealed class PlanReadResult { - /// Whether the plan file exists in the workspace. - [JsonPropertyName("exists")] - public bool Exists { get; set; } - /// The content of the plan file, or null if it does not exist. [JsonPropertyName("content")] public string? Content { get; set; } + /// Whether the plan file exists in the workspace. + [JsonPropertyName("exists")] + public bool Exists { get; set; } + /// Absolute file path of the plan file, or null if workspace is not enabled. [JsonPropertyName("path")] public string? Path { get; set; } @@ -657,13 +665,13 @@ internal sealed class SessionPlanReadRequest /// RPC data type for PlanUpdate operations. internal sealed class PlanUpdateRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// The new content for the plan file. [JsonPropertyName("content")] public string Content { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionPlanDelete operations. @@ -677,9 +685,17 @@ internal sealed class SessionPlanDeleteRequest /// RPC data type for WorkspacesGetWorkspaceResultWorkspace operations. public sealed class WorkspacesGetWorkspaceResultWorkspace { - /// Gets or sets the id value. - [JsonPropertyName("id")] - public Guid Id { get; set; } + /// Gets or sets the branch value. + [JsonPropertyName("branch")] + public string? Branch { get; set; } + + /// Gets or sets the chronicle_sync_dismissed value. + [JsonPropertyName("chronicle_sync_dismissed")] + public bool? ChronicleSyncDismissed { get; set; } + + /// Gets or sets the created_at value. + [JsonPropertyName("created_at")] + public DateTimeOffset? CreatedAt { get; set; } /// Gets or sets the cwd value. [JsonPropertyName("cwd")] @@ -689,62 +705,54 @@ public sealed class WorkspacesGetWorkspaceResultWorkspace [JsonPropertyName("git_root")] public string? GitRoot { get; set; } - /// Gets or sets the repository value. - [JsonPropertyName("repository")] - public string? Repository { get; set; } - /// Gets or sets the host_type value. [JsonPropertyName("host_type")] public WorkspacesGetWorkspaceResultWorkspaceHostType? HostType { get; set; } - /// Gets or sets the branch value. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Gets or sets the summary value. - [JsonPropertyName("summary")] - public string? Summary { get; set; } - - /// Gets or sets the name value. - [JsonPropertyName("name")] - public string? Name { get; set; } - - /// Gets or sets the summary_count value. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("summary_count")] - public long? SummaryCount { get; set; } + /// Gets or sets the id value. + [JsonPropertyName("id")] + public Guid Id { get; set; } - /// Gets or sets the created_at value. - [JsonPropertyName("created_at")] - public DateTimeOffset? CreatedAt { get; set; } + /// Gets or sets the mc_last_event_id value. + [JsonPropertyName("mc_last_event_id")] + public string? McLastEventId { get; set; } - /// Gets or sets the updated_at value. - [JsonPropertyName("updated_at")] - public DateTimeOffset? UpdatedAt { get; set; } + /// Gets or sets the mc_session_id value. + [JsonPropertyName("mc_session_id")] + public string? McSessionId { get; set; } /// Gets or sets the mc_task_id value. [JsonPropertyName("mc_task_id")] public string? McTaskId { get; set; } - /// Gets or sets the mc_session_id value. - [JsonPropertyName("mc_session_id")] - public string? McSessionId { get; set; } + /// Gets or sets the name value. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Gets or sets the mc_last_event_id value. - [JsonPropertyName("mc_last_event_id")] - public string? McLastEventId { get; set; } + /// Gets or sets the remote_steerable value. + [JsonPropertyName("remote_steerable")] + public bool? RemoteSteerable { get; set; } + + /// Gets or sets the repository value. + [JsonPropertyName("repository")] + public string? Repository { get; set; } /// Gets or sets the session_sync_level value. [JsonPropertyName("session_sync_level")] public WorkspacesGetWorkspaceResultWorkspaceSessionSyncLevel? SessionSyncLevel { get; set; } - /// Gets or sets the pr_create_sync_dismissed value. - [JsonPropertyName("pr_create_sync_dismissed")] - public bool? PrCreateSyncDismissed { get; set; } + /// Gets or sets the summary value. + [JsonPropertyName("summary")] + public string? Summary { get; set; } - /// Gets or sets the chronicle_sync_dismissed value. - [JsonPropertyName("chronicle_sync_dismissed")] - public bool? ChronicleSyncDismissed { get; set; } + /// Gets or sets the summary_count value. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("summary_count")] + public long? SummaryCount { get; set; } + + /// Gets or sets the updated_at value. + [JsonPropertyName("updated_at")] + public DateTimeOffset? UpdatedAt { get; set; } } /// RPC data type for WorkspacesGetWorkspace operations. @@ -790,34 +798,46 @@ public sealed class WorkspacesReadFileResult /// RPC data type for WorkspacesReadFile operations. internal sealed class WorkspacesReadFileRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Relative path within the workspace files directory. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for WorkspacesCreateFile operations. internal sealed class WorkspacesCreateFileRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// File content to write as a UTF-8 string. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; /// Relative path within the workspace files directory. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; - /// File content to write as a UTF-8 string. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for InstructionsSources operations. public sealed class InstructionsSources { + /// Glob pattern from frontmatter — when set, this instruction applies only to matching files. + [JsonPropertyName("applyTo")] + public string? ApplyTo { get; set; } + + /// Raw content of the instruction file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Short description (body after frontmatter) for use in instruction tables. + [JsonPropertyName("description")] + public string? Description { get; set; } + /// Unique identifier for this source (used for toggling). [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; @@ -826,29 +846,17 @@ public sealed class InstructionsSources [JsonPropertyName("label")] public string Label { get; set; } = string.Empty; + /// Where this source lives — used for UI grouping. + [JsonPropertyName("location")] + public InstructionsSourcesLocation Location { get; set; } + /// File path relative to repo or absolute for home. [JsonPropertyName("sourcePath")] public string SourcePath { get; set; } = string.Empty; - /// Raw content of the instruction file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; - /// Category of instruction source — used for merge logic. [JsonPropertyName("type")] public InstructionsSourcesType Type { get; set; } - - /// Where this source lives — used for UI grouping. - [JsonPropertyName("location")] - public InstructionsSourcesLocation Location { get; set; } - - /// Glob pattern from frontmatter — when set, this instruction applies only to matching files. - [JsonPropertyName("applyTo")] - public string? ApplyTo { get; set; } - - /// Short description (body after frontmatter) for use in instruction tables. - [JsonPropertyName("description")] - public string? Description { get; set; } } /// RPC data type for InstructionsGetSources operations. @@ -880,29 +888,29 @@ public sealed class FleetStartResult [Experimental(Diagnostics.Experimental)] internal sealed class FleetStartRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Optional user prompt to combine with fleet instructions. [JsonPropertyName("prompt")] public string? Prompt { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for AgentInfo operations. public sealed class AgentInfo { - /// Unique identifier of the custom agent. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Description of the agent's purpose. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; /// Human-readable display name. [JsonPropertyName("displayName")] public string DisplayName { get; set; } = string.Empty; - /// Description of the agent's purpose. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Unique identifier of the custom agent. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } /// RPC data type for AgentList operations. @@ -954,13 +962,13 @@ public sealed class AgentSelectResult [Experimental(Diagnostics.Experimental)] internal sealed class AgentSelectRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Name of the custom agent to select. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionAgentDeselect operations. @@ -993,13 +1001,21 @@ internal sealed class SessionAgentReloadRequest /// RPC data type for Skill operations. public sealed class Skill { + /// Description of what the skill does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Whether the skill is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + /// Unique identifier for the skill. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Description of what the skill does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Absolute path to the skill file. + [JsonPropertyName("path")] + public string? Path { get; set; } /// Source location type (e.g., project, personal, plugin). [JsonPropertyName("source")] @@ -1008,14 +1024,6 @@ public sealed class Skill /// Whether the skill can be invoked by the user as a slash command. [JsonPropertyName("userInvocable")] public bool UserInvocable { get; set; } - - /// Whether the skill is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Absolute path to the skill file. - [JsonPropertyName("path")] - public string? Path { get; set; } } /// RPC data type for SkillList operations. @@ -1040,26 +1048,26 @@ internal sealed class SessionSkillsListRequest [Experimental(Diagnostics.Experimental)] internal sealed class SkillsEnableRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Name of the skill to enable. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SkillsDisable operations. [Experimental(Diagnostics.Experimental)] internal sealed class SkillsDisableRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Name of the skill to disable. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionSkillsReload operations. @@ -1074,22 +1082,22 @@ internal sealed class SessionSkillsReloadRequest /// RPC data type for McpServer operations. public sealed class McpServer { + /// Error message if the server failed to connect. + [JsonPropertyName("error")] + public string? Error { get; set; } + /// Server name (config key). [RegularExpression("^[0-9a-zA-Z_.@-]+(\\/[0-9a-zA-Z_.@-]+)*$")] [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured. - [JsonPropertyName("status")] - public McpServerStatus Status { get; set; } - /// Configuration source: user, workspace, plugin, or builtin. [JsonPropertyName("source")] public McpServerSource? Source { get; set; } - /// Error message if the server failed to connect. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured. + [JsonPropertyName("status")] + public McpServerStatus Status { get; set; } } /// RPC data type for McpServerList operations. @@ -1114,28 +1122,28 @@ internal sealed class SessionMcpListRequest [Experimental(Diagnostics.Experimental)] internal sealed class McpEnableRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Name of the MCP server to enable. [RegularExpression("^[0-9a-zA-Z_.@-]+(\\/[0-9a-zA-Z_.@-]+)*$")] [JsonPropertyName("serverName")] public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for McpDisable operations. [Experimental(Diagnostics.Experimental)] internal sealed class McpDisableRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Name of the MCP server to disable. [RegularExpression("^[0-9a-zA-Z_.@-]+(\\/[0-9a-zA-Z_.@-]+)*$")] [JsonPropertyName("serverName")] public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionMcpReload operations. @@ -1150,21 +1158,21 @@ internal sealed class SessionMcpReloadRequest /// RPC data type for Plugin operations. public sealed class Plugin { - /// Plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether the plugin is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } /// Marketplace the plugin came from. [JsonPropertyName("marketplace")] public string Marketplace { get; set; } = string.Empty; + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + /// Installed version. [JsonPropertyName("version")] public string? Version { get; set; } - - /// Whether the plugin is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } } /// RPC data type for PluginList operations. @@ -1196,6 +1204,10 @@ public sealed class Extension [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; + /// Process ID if the extension is running. + [JsonPropertyName("pid")] + public long? Pid { get; set; } + /// Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/). [JsonPropertyName("source")] public ExtensionSource Source { get; set; } @@ -1203,10 +1215,6 @@ public sealed class Extension /// Current status: running, disabled, failed, or starting. [JsonPropertyName("status")] public ExtensionStatus Status { get; set; } - - /// Process ID if the extension is running. - [JsonPropertyName("pid")] - public long? Pid { get; set; } } /// RPC data type for ExtensionList operations. @@ -1231,26 +1239,26 @@ internal sealed class SessionExtensionsListRequest [Experimental(Diagnostics.Experimental)] internal sealed class ExtensionsEnableRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Source-qualified extension ID to enable. [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for ExtensionsDisable operations. [Experimental(Diagnostics.Experimental)] internal sealed class ExtensionsDisableRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Source-qualified extension ID to disable. [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionExtensionsReload operations. @@ -1273,9 +1281,9 @@ public sealed class HandleToolCallResult /// RPC data type for ToolsHandlePendingToolCall operations. internal sealed class ToolsHandlePendingToolCallRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Error message if the tool call failed. + [JsonPropertyName("error")] + public string? Error { get; set; } /// Request ID of the pending tool call. [JsonPropertyName("requestId")] @@ -1285,9 +1293,9 @@ internal sealed class ToolsHandlePendingToolCallRequest [JsonPropertyName("result")] public object? Result { get; set; } - /// Error message if the tool call failed. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for CommandsHandlePendingCommand operations. @@ -1301,17 +1309,17 @@ public sealed class CommandsHandlePendingCommandResult /// RPC data type for CommandsHandlePendingCommand operations. internal sealed class CommandsHandlePendingCommandRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Error message if the command handler failed. + [JsonPropertyName("error")] + public string? Error { get; set; } /// Request ID from the command invocation event. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; - /// Error message if the command handler failed. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// The elicitation response (accept with form values, decline, or cancel). @@ -1329,10 +1337,6 @@ public sealed class UIElicitationResponse /// JSON Schema describing the form fields to present to the user. public sealed class UIElicitationSchema { - /// Schema type indicator (always 'object'). - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; - /// Form field definitions, keyed by field name. [JsonPropertyName("properties")] public IDictionary Properties { get => field ??= new Dictionary(); set; } @@ -1340,15 +1344,15 @@ public sealed class UIElicitationSchema /// List of required field names. [JsonPropertyName("required")] public IList? Required { get; set; } + + /// Schema type indicator (always 'object'). + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; } /// RPC data type for UIElicitation operations. internal sealed class UIElicitationRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Message describing what information is needed from the user. [JsonPropertyName("message")] public string Message { get; set; } = string.Empty; @@ -1356,6 +1360,10 @@ internal sealed class UIElicitationRequest /// JSON Schema describing the form fields to present to the user. [JsonPropertyName("requestedSchema")] public UIElicitationSchema RequestedSchema { get => field ??= new(); set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for UIElicitation operations. @@ -1369,10 +1377,6 @@ public sealed class UIElicitationResult /// RPC data type for UIHandlePendingElicitation operations. internal sealed class UIHandlePendingElicitationRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// The unique request ID from the elicitation.requested event. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; @@ -1380,6 +1384,10 @@ internal sealed class UIHandlePendingElicitationRequest /// The elicitation response (accept with form values, decline, or cancel). [JsonPropertyName("result")] public UIElicitationResponse Result { get => field ??= new(); set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for PermissionRequest operations. @@ -1390,20 +1398,113 @@ public sealed class PermissionRequestResult public bool Success { get; set; } } +/// Polymorphic base type discriminated by kind. +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(PermissionDecisionApproved), "approved")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByRules), "denied-by-rules")] +[JsonDerivedType(typeof(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser), "denied-no-approval-rule-and-could-not-request-from-user")] +[JsonDerivedType(typeof(PermissionDecisionDeniedInteractivelyByUser), "denied-interactively-by-user")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByContentExclusionPolicy), "denied-by-content-exclusion-policy")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByPermissionRequestHook), "denied-by-permission-request-hook")] +public partial class PermissionDecision +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} + + +/// The approved variant of . +public partial class PermissionDecisionApproved : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "approved"; +} + +/// The denied-by-rules variant of . +public partial class PermissionDecisionDeniedByRules : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "denied-by-rules"; + + /// Rules that denied the request. + [JsonPropertyName("rules")] + public required object[] Rules { get; set; } +} + +/// The denied-no-approval-rule-and-could-not-request-from-user variant of . +public partial class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "denied-no-approval-rule-and-could-not-request-from-user"; +} + +/// The denied-interactively-by-user variant of . +public partial class PermissionDecisionDeniedInteractivelyByUser : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "denied-interactively-by-user"; + + /// Optional feedback from the user explaining the denial. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("feedback")] + public string? Feedback { get; set; } +} + +/// The denied-by-content-exclusion-policy variant of . +public partial class PermissionDecisionDeniedByContentExclusionPolicy : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "denied-by-content-exclusion-policy"; + + /// Human-readable explanation of why the path was excluded. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// File path that triggered the exclusion. + [JsonPropertyName("path")] + public required string Path { get; set; } +} + +/// The denied-by-permission-request-hook variant of . +public partial class PermissionDecisionDeniedByPermissionRequestHook : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "denied-by-permission-request-hook"; + + /// Whether to interrupt the current agent turn. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("interrupt")] + public bool? Interrupt { get; set; } + + /// Optional message from the hook explaining the denial. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } +} + /// RPC data type for PermissionDecision operations. internal sealed class PermissionDecisionRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Request ID of the pending permission request. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; /// Gets or sets the result value. [JsonPropertyName("result")] - public object Result { get; set; } = null!; + public PermissionDecision Result { get => field ??= new(); set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for ShellExec operations. @@ -1417,10 +1518,6 @@ public sealed class ShellExecResult /// RPC data type for ShellExec operations. internal sealed class ShellExecRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Shell command to execute. [JsonPropertyName("command")] public string Command { get; set; } = string.Empty; @@ -1429,6 +1526,10 @@ internal sealed class ShellExecRequest [JsonPropertyName("cwd")] public string? Cwd { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + /// Timeout in milliseconds (default: 30000). [Range((double)0, (double)long.MaxValue)] [JsonConverter(typeof(MillisecondsTimeSpanConverter))] @@ -1447,14 +1548,14 @@ public sealed class ShellKillResult /// RPC data type for ShellKill operations. internal sealed class ShellKillRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Process identifier returned by shell.exec. [JsonPropertyName("processId")] public string ProcessId { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + /// Signal to send (default: SIGTERM). [JsonPropertyName("signal")] public ShellKillSignal? Signal { get; set; } @@ -1463,10 +1564,10 @@ internal sealed class ShellKillRequest /// Post-compaction context window usage breakdown. public sealed class HistoryCompactContextWindow { - /// Maximum token count for the model's context window. + /// Token count from non-system messages (user, assistant, tool). [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("tokenLimit")] - public long TokenLimit { get; set; } + [JsonPropertyName("conversationTokens")] + public long? ConversationTokens { get; set; } /// Current total tokens in the context window (system + conversation + tool definitions). [Range((double)0, (double)long.MaxValue)] @@ -1483,10 +1584,10 @@ public sealed class HistoryCompactContextWindow [JsonPropertyName("systemTokens")] public long? SystemTokens { get; set; } - /// Token count from non-system messages (user, assistant, tool). + /// Maximum token count for the model's context window. [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("conversationTokens")] - public long? ConversationTokens { get; set; } + [JsonPropertyName("tokenLimit")] + public long TokenLimit { get; set; } /// Token count from tool definitions. [Range((double)0, (double)long.MaxValue)] @@ -1498,6 +1599,15 @@ public sealed class HistoryCompactContextWindow [Experimental(Diagnostics.Experimental)] public sealed class HistoryCompactResult { + /// Post-compaction context window usage breakdown. + [JsonPropertyName("contextWindow")] + public HistoryCompactContextWindow? ContextWindow { get; set; } + + /// Number of messages removed during compaction. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("messagesRemoved")] + public long MessagesRemoved { get; set; } + /// Whether compaction completed successfully. [JsonPropertyName("success")] public bool Success { get; set; } @@ -1506,15 +1616,6 @@ public sealed class HistoryCompactResult [Range((double)0, (double)long.MaxValue)] [JsonPropertyName("tokensRemoved")] public long TokensRemoved { get; set; } - - /// Number of messages removed during compaction. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("messagesRemoved")] - public long MessagesRemoved { get; set; } - - /// Post-compaction context window usage breakdown. - [JsonPropertyName("contextWindow")] - public HistoryCompactContextWindow? ContextWindow { get; set; } } /// RPC data type for SessionHistoryCompact operations. @@ -1540,18 +1641,22 @@ public sealed class HistoryTruncateResult [Experimental(Diagnostics.Experimental)] internal sealed class HistoryTruncateRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Event ID to truncate to. This event and all events after it are removed from the session. [JsonPropertyName("eventId")] public string EventId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// Aggregated code change metrics. public sealed class UsageMetricsCodeChanges { + /// Number of distinct files modified. + [JsonPropertyName("filesModifiedCount")] + public long FilesModifiedCount { get; set; } + /// Total lines of code added. [JsonPropertyName("linesAdded")] public long LinesAdded { get; set; } @@ -1559,37 +1664,23 @@ public sealed class UsageMetricsCodeChanges /// Total lines of code removed. [JsonPropertyName("linesRemoved")] public long LinesRemoved { get; set; } - - /// Number of distinct files modified. - [JsonPropertyName("filesModifiedCount")] - public long FilesModifiedCount { get; set; } } /// Request count and cost metrics for this model. public sealed class UsageMetricsModelMetricRequests { - /// Number of API requests made with this model. - [JsonPropertyName("count")] - public long Count { get; set; } - /// User-initiated premium request cost (with multiplier applied). [JsonPropertyName("cost")] public double Cost { get; set; } + + /// Number of API requests made with this model. + [JsonPropertyName("count")] + public long Count { get; set; } } /// Token usage metrics for this model. public sealed class UsageMetricsModelMetricUsage { - /// Total input tokens consumed. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("inputTokens")] - public long InputTokens { get; set; } - - /// Total output tokens produced. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("outputTokens")] - public long OutputTokens { get; set; } - /// Total tokens read from prompt cache. [Range((double)0, (double)long.MaxValue)] [JsonPropertyName("cacheReadTokens")] @@ -1600,6 +1691,16 @@ public sealed class UsageMetricsModelMetricUsage [JsonPropertyName("cacheWriteTokens")] public long CacheWriteTokens { get; set; } + /// Total input tokens consumed. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("inputTokens")] + public long InputTokens { get; set; } + + /// Total output tokens produced. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("outputTokens")] + public long OutputTokens { get; set; } + /// Total output tokens used for reasoning. [Range((double)0, (double)long.MaxValue)] [JsonPropertyName("reasoningTokens")] @@ -1622,46 +1723,46 @@ public sealed class UsageMetricsModelMetric [Experimental(Diagnostics.Experimental)] public sealed class UsageGetMetricsResult { - /// Total user-initiated premium request cost across all models (may be fractional due to multipliers). - [JsonPropertyName("totalPremiumRequestCost")] - public double TotalPremiumRequestCost { get; set; } - - /// Raw count of user-initiated API requests. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("totalUserRequests")] - public long TotalUserRequests { get; set; } - - /// Total time spent in model API calls (milliseconds). - [Range(0, double.MaxValue)] - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("totalApiDurationMs")] - public TimeSpan TotalApiDurationMs { get; set; } - - /// Session start timestamp (epoch milliseconds). - [JsonPropertyName("sessionStartTime")] - public long SessionStartTime { get; set; } - /// Aggregated code change metrics. [JsonPropertyName("codeChanges")] public UsageMetricsCodeChanges CodeChanges { get => field ??= new(); set; } + /// Currently active model identifier. + [JsonPropertyName("currentModel")] + public string? CurrentModel { get; set; } + + /// Input tokens from the most recent main-agent API call. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("lastCallInputTokens")] + public long LastCallInputTokens { get; set; } + + /// Output tokens from the most recent main-agent API call. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("lastCallOutputTokens")] + public long LastCallOutputTokens { get; set; } + /// Per-model token and request metrics, keyed by model identifier. [JsonPropertyName("modelMetrics")] public IDictionary ModelMetrics { get => field ??= new Dictionary(); set; } - /// Currently active model identifier. - [JsonPropertyName("currentModel")] - public string? CurrentModel { get; set; } + /// Session start timestamp (epoch milliseconds). + [JsonPropertyName("sessionStartTime")] + public long SessionStartTime { get; set; } - /// Input tokens from the most recent main-agent API call. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("lastCallInputTokens")] - public long LastCallInputTokens { get; set; } + /// Total time spent in model API calls (milliseconds). + [Range(0, double.MaxValue)] + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonPropertyName("totalApiDurationMs")] + public TimeSpan TotalApiDurationMs { get; set; } - /// Output tokens from the most recent main-agent API call. + /// Total user-initiated premium request cost across all models (may be fractional due to multipliers). + [JsonPropertyName("totalPremiumRequestCost")] + public double TotalPremiumRequestCost { get; set; } + + /// Raw count of user-initiated API requests. [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("lastCallOutputTokens")] - public long LastCallOutputTokens { get; set; } + [JsonPropertyName("totalUserRequests")] + public long TotalUserRequests { get; set; } } /// RPC data type for SessionUsageGetMetrics operations. @@ -1673,37 +1774,45 @@ internal sealed class SessionUsageGetMetricsRequest public string SessionId { get; set; } = string.Empty; } +/// Describes a filesystem error. +public sealed class SessionFsError +{ + /// Error classification. + [JsonPropertyName("code")] + public SessionFsErrorCode Code { get; set; } + + /// Free-form detail about the error, for logging/diagnostics. + [JsonPropertyName("message")] + public string? Message { get; set; } +} + /// RPC data type for SessionFsReadFile operations. public sealed class SessionFsReadFileResult { /// File content as UTF-8 string. [JsonPropertyName("content")] public string Content { get; set; } = string.Empty; + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } /// RPC data type for SessionFsReadFile operations. public sealed class SessionFsReadFileRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Path using SessionFs conventions. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; -} -/// RPC data type for SessionFsWriteFile operations. -public sealed class SessionFsWriteFileRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; +} - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - +/// RPC data type for SessionFsWriteFile operations. +public sealed class SessionFsWriteFileRequest +{ /// Content to write. [JsonPropertyName("content")] public string Content { get; set; } = string.Empty; @@ -1712,19 +1821,19 @@ public sealed class SessionFsWriteFileRequest [Range((double)0, (double)long.MaxValue)] [JsonPropertyName("mode")] public long? Mode { get; set; } -} - -/// RPC data type for SessionFsAppendFile operations. -public sealed class SessionFsAppendFileRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; /// Path using SessionFs conventions. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// RPC data type for SessionFsAppendFile operations. +public sealed class SessionFsAppendFileRequest +{ /// Content to append. [JsonPropertyName("content")] public string Content { get; set; } = string.Empty; @@ -1733,6 +1842,14 @@ public sealed class SessionFsAppendFileRequest [Range((double)0, (double)long.MaxValue)] [JsonPropertyName("mode")] public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionFsExists operations. @@ -1746,58 +1863,63 @@ public sealed class SessionFsExistsResult /// RPC data type for SessionFsExists operations. public sealed class SessionFsExistsRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Path using SessionFs conventions. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionFsStat operations. public sealed class SessionFsStatResult { - /// Whether the path is a file. - [JsonPropertyName("isFile")] - public bool IsFile { get; set; } + /// ISO 8601 timestamp of creation. + [JsonPropertyName("birthtime")] + public DateTimeOffset Birthtime { get; set; } + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } /// Whether the path is a directory. [JsonPropertyName("isDirectory")] public bool IsDirectory { get; set; } - /// File size in bytes. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("size")] - public long Size { get; set; } + /// Whether the path is a file. + [JsonPropertyName("isFile")] + public bool IsFile { get; set; } /// ISO 8601 timestamp of last modification. [JsonPropertyName("mtime")] public DateTimeOffset Mtime { get; set; } - /// ISO 8601 timestamp of creation. - [JsonPropertyName("birthtime")] - public DateTimeOffset Birthtime { get; set; } + /// File size in bytes. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("size")] + public long Size { get; set; } } /// RPC data type for SessionFsStat operations. public sealed class SessionFsStatRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Path using SessionFs conventions. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionFsMkdir operations. public sealed class SessionFsMkdirRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional POSIX-style mode for newly created directories. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("mode")] + public long? Mode { get; set; } /// Path using SessionFs conventions. [JsonPropertyName("path")] @@ -1807,10 +1929,9 @@ public sealed class SessionFsMkdirRequest [JsonPropertyName("recursive")] public bool? Recursive { get; set; } - /// Optional POSIX-style mode for newly created directories. - [Range((double)0, (double)long.MaxValue)] - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionFsReaddir operations. @@ -1819,18 +1940,22 @@ public sealed class SessionFsReaddirResult /// Entry names in the directory. [JsonPropertyName("entries")] public IList Entries { get => field ??= []; set; } + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } /// RPC data type for SessionFsReaddir operations. public sealed class SessionFsReaddirRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Path using SessionFs conventions. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionFsReaddirWithTypesEntry operations. @@ -1851,26 +1976,30 @@ public sealed class SessionFsReaddirWithTypesResult /// Directory entries with type information. [JsonPropertyName("entries")] public IList Entries { get => field ??= []; set; } + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } /// RPC data type for SessionFsReaddirWithTypes operations. public sealed class SessionFsReaddirWithTypesRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - /// Path using SessionFs conventions. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionFsRm operations. public sealed class SessionFsRmRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Ignore errors if the path does not exist. + [JsonPropertyName("force")] + public bool? Force { get; set; } /// Path using SessionFs conventions. [JsonPropertyName("path")] @@ -1880,14 +2009,18 @@ public sealed class SessionFsRmRequest [JsonPropertyName("recursive")] public bool? Recursive { get; set; } - /// Ignore errors if the path does not exist. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// RPC data type for SessionFsRename operations. public sealed class SessionFsRenameRequest { + /// Destination path using SessionFs conventions. + [JsonPropertyName("dest")] + public string Dest { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; @@ -1895,12 +2028,27 @@ public sealed class SessionFsRenameRequest /// Source path using SessionFs conventions. [JsonPropertyName("src")] public string Src { get; set; } = string.Empty; +} - /// Destination path using SessionFs conventions. - [JsonPropertyName("dest")] - public string Dest { get; set; } = string.Empty; +/// Configuration source. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum DiscoveredMcpServerSource +{ + /// The user variant. + [JsonStringEnumMemberName("user")] + User, + /// The workspace variant. + [JsonStringEnumMemberName("workspace")] + Workspace, + /// The plugin variant. + [JsonStringEnumMemberName("plugin")] + Plugin, + /// The builtin variant. + [JsonStringEnumMemberName("builtin")] + Builtin, } + /// Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio). [JsonConverter(typeof(JsonStringEnumConverter))] public enum DiscoveredMcpServerType @@ -1920,25 +2068,6 @@ public enum DiscoveredMcpServerType } -/// Configuration source. -[JsonConverter(typeof(JsonStringEnumConverter))] -public enum DiscoveredMcpServerSource -{ - /// The user variant. - [JsonStringEnumMemberName("user")] - User, - /// The workspace variant. - [JsonStringEnumMemberName("workspace")] - Workspace, - /// The plugin variant. - [JsonStringEnumMemberName("plugin")] - Plugin, - /// The builtin variant. - [JsonStringEnumMemberName("builtin")] - Builtin, -} - - /// Path conventions used by this filesystem. [JsonConverter(typeof(JsonStringEnumConverter))] public enum SessionFsSetProviderConventions @@ -2013,6 +2142,22 @@ public enum WorkspacesGetWorkspaceResultWorkspaceSessionSyncLevel } +/// Where this source lives — used for UI grouping. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum InstructionsSourcesLocation +{ + /// The user variant. + [JsonStringEnumMemberName("user")] + User, + /// The repository variant. + [JsonStringEnumMemberName("repository")] + Repository, + /// The working-directory variant. + [JsonStringEnumMemberName("working-directory")] + WorkingDirectory, +} + + /// Category of instruction source — used for merge logic. [JsonConverter(typeof(JsonStringEnumConverter))] public enum InstructionsSourcesType @@ -2038,19 +2183,22 @@ public enum InstructionsSourcesType } -/// Where this source lives — used for UI grouping. -[JsonConverter(typeof(JsonStringEnumConverter))] -public enum InstructionsSourcesLocation +/// Configuration source: user, workspace, plugin, or builtin. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum McpServerSource { /// The user variant. [JsonStringEnumMemberName("user")] User, - /// The repository variant. - [JsonStringEnumMemberName("repository")] - Repository, - /// The working-directory variant. - [JsonStringEnumMemberName("working-directory")] - WorkingDirectory, + /// The workspace variant. + [JsonStringEnumMemberName("workspace")] + Workspace, + /// The plugin variant. + [JsonStringEnumMemberName("plugin")] + Plugin, + /// The builtin variant. + [JsonStringEnumMemberName("builtin")] + Builtin, } @@ -2079,25 +2227,6 @@ public enum McpServerStatus } -/// Configuration source: user, workspace, plugin, or builtin. -[JsonConverter(typeof(JsonStringEnumConverter))] -public enum McpServerSource -{ - /// The user variant. - [JsonStringEnumMemberName("user")] - User, - /// The workspace variant. - [JsonStringEnumMemberName("workspace")] - Workspace, - /// The plugin variant. - [JsonStringEnumMemberName("plugin")] - Plugin, - /// The builtin variant. - [JsonStringEnumMemberName("builtin")] - Builtin, -} - - /// Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/). [JsonConverter(typeof(JsonStringEnumConverter))] public enum ExtensionSource @@ -2162,6 +2291,19 @@ public enum ShellKillSignal } +/// Error classification. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum SessionFsErrorCode +{ + /// The ENOENT variant. + [JsonStringEnumMemberName("ENOENT")] + ENOENT, + /// The UNKNOWN variant. + [JsonStringEnumMemberName("UNKNOWN")] + UNKNOWN, +} + + /// Entry type. [JsonConverter(typeof(JsonStringEnumConverter))] public enum SessionFsReaddirWithTypesEntryType @@ -2979,7 +3121,7 @@ internal PermissionsApi(JsonRpc rpc, string sessionId) } /// Calls "session.permissions.handlePendingPermissionRequest". - public async Task HandlePendingPermissionRequestAsync(string requestId, object result, CancellationToken cancellationToken = default) + public async Task HandlePendingPermissionRequestAsync(string requestId, PermissionDecision result, CancellationToken cancellationToken = default) { var request = new PermissionDecisionRequest { SessionId = _sessionId, RequestId = requestId, Result = result }; return await CopilotClient.InvokeRpcAsync(_rpc, "session.permissions.handlePendingPermissionRequest", [request], cancellationToken); @@ -3068,23 +3210,23 @@ public interface ISessionFsHandler /// Handles "sessionFs.readFile". Task ReadFileAsync(SessionFsReadFileRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.writeFile". - Task WriteFileAsync(SessionFsWriteFileRequest request, CancellationToken cancellationToken = default); + Task WriteFileAsync(SessionFsWriteFileRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.appendFile". - Task AppendFileAsync(SessionFsAppendFileRequest request, CancellationToken cancellationToken = default); + Task AppendFileAsync(SessionFsAppendFileRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.exists". Task ExistsAsync(SessionFsExistsRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.stat". Task StatAsync(SessionFsStatRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.mkdir". - Task MkdirAsync(SessionFsMkdirRequest request, CancellationToken cancellationToken = default); + Task MkdirAsync(SessionFsMkdirRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.readdir". Task ReaddirAsync(SessionFsReaddirRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.readdirWithTypes". Task ReaddirWithTypesAsync(SessionFsReaddirWithTypesRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.rm". - Task RmAsync(SessionFsRmRequest request, CancellationToken cancellationToken = default); + Task RmAsync(SessionFsRmRequest request, CancellationToken cancellationToken = default); /// Handles "sessionFs.rename". - Task RenameAsync(SessionFsRenameRequest request, CancellationToken cancellationToken = default); + Task RenameAsync(SessionFsRenameRequest request, CancellationToken cancellationToken = default); } /// Provides all client session API handler groups for a session. @@ -3114,21 +3256,21 @@ public static void RegisterClientSessionApiHandlers(JsonRpc rpc, Func)(async (request, cancellationToken) => + var registerSessionFsWriteFileMethod = (Func>)(async (request, cancellationToken) => { var handler = getHandlers(request.SessionId).SessionFs; if (handler is null) throw new InvalidOperationException($"No sessionFs handler registered for session: {request.SessionId}"); - await handler.WriteFileAsync(request, cancellationToken); + return await handler.WriteFileAsync(request, cancellationToken); }); rpc.AddLocalRpcMethod(registerSessionFsWriteFileMethod.Method, registerSessionFsWriteFileMethod.Target!, new JsonRpcMethodAttribute("sessionFs.writeFile") { UseSingleObjectParameterDeserialization = true }); - var registerSessionFsAppendFileMethod = (Func)(async (request, cancellationToken) => + var registerSessionFsAppendFileMethod = (Func>)(async (request, cancellationToken) => { var handler = getHandlers(request.SessionId).SessionFs; if (handler is null) throw new InvalidOperationException($"No sessionFs handler registered for session: {request.SessionId}"); - await handler.AppendFileAsync(request, cancellationToken); + return await handler.AppendFileAsync(request, cancellationToken); }); rpc.AddLocalRpcMethod(registerSessionFsAppendFileMethod.Method, registerSessionFsAppendFileMethod.Target!, new JsonRpcMethodAttribute("sessionFs.appendFile") { @@ -3154,11 +3296,11 @@ public static void RegisterClientSessionApiHandlers(JsonRpc rpc, Func)(async (request, cancellationToken) => + var registerSessionFsMkdirMethod = (Func>)(async (request, cancellationToken) => { var handler = getHandlers(request.SessionId).SessionFs; if (handler is null) throw new InvalidOperationException($"No sessionFs handler registered for session: {request.SessionId}"); - await handler.MkdirAsync(request, cancellationToken); + return await handler.MkdirAsync(request, cancellationToken); }); rpc.AddLocalRpcMethod(registerSessionFsMkdirMethod.Method, registerSessionFsMkdirMethod.Target!, new JsonRpcMethodAttribute("sessionFs.mkdir") { @@ -3184,21 +3326,21 @@ public static void RegisterClientSessionApiHandlers(JsonRpc rpc, Func)(async (request, cancellationToken) => + var registerSessionFsRmMethod = (Func>)(async (request, cancellationToken) => { var handler = getHandlers(request.SessionId).SessionFs; if (handler is null) throw new InvalidOperationException($"No sessionFs handler registered for session: {request.SessionId}"); - await handler.RmAsync(request, cancellationToken); + return await handler.RmAsync(request, cancellationToken); }); rpc.AddLocalRpcMethod(registerSessionFsRmMethod.Method, registerSessionFsRmMethod.Target!, new JsonRpcMethodAttribute("sessionFs.rm") { UseSingleObjectParameterDeserialization = true }); - var registerSessionFsRenameMethod = (Func)(async (request, cancellationToken) => + var registerSessionFsRenameMethod = (Func>)(async (request, cancellationToken) => { var handler = getHandlers(request.SessionId).SessionFs; if (handler is null) throw new InvalidOperationException($"No sessionFs handler registered for session: {request.SessionId}"); - await handler.RenameAsync(request, cancellationToken); + return await handler.RenameAsync(request, cancellationToken); }); rpc.AddLocalRpcMethod(registerSessionFsRenameMethod.Method, registerSessionFsRenameMethod.Target!, new JsonRpcMethodAttribute("sessionFs.rename") { @@ -3265,6 +3407,7 @@ public static void RegisterClientSessionApiHandlers(JsonRpc rpc, FuncSession initialization metadata including context and configuration. public partial class SessionStartData { - /// Unique identifier for the session. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } - - /// Schema version number for the session event format. - [JsonPropertyName("version")] - public required double Version { get; set; } + /// Whether the session was already in use by another client at start time. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("alreadyInUse")] + public bool? AlreadyInUse { get; set; } - /// Identifier of the software producing the events (e.g., "copilot-agent"). - [JsonPropertyName("producer")] - public required string Producer { get; set; } + /// Working directory and git context at session start. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("context")] + public WorkingDirectoryContext? Context { get; set; } /// Version string of the Copilot application. [JsonPropertyName("copilotVersion")] public required string CopilotVersion { get; set; } - /// ISO 8601 timestamp when the session was created. - [JsonPropertyName("startTime")] - public required DateTimeOffset StartTime { get; set; } - - /// Model selected at session creation time, if any. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("selectedModel")] - public string? SelectedModel { get; set; } + /// Identifier of the software producing the events (e.g., "copilot-agent"). + [JsonPropertyName("producer")] + public required string Producer { get; set; } /// Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } - /// Working directory and git context at session start. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("context")] - public WorkingDirectoryContext? Context { get; set; } - - /// Whether the session was already in use by another client at start time. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("alreadyInUse")] - public bool? AlreadyInUse { get; set; } - /// Whether this session supports remote steering via Mission Control. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("remoteSteerable")] public bool? RemoteSteerable { get; set; } + + /// Model selected at session creation time, if any. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("selectedModel")] + public string? SelectedModel { get; set; } + + /// Unique identifier for the session. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } + + /// ISO 8601 timestamp when the session was created. + [JsonPropertyName("startTime")] + public required DateTimeOffset StartTime { get; set; } + + /// Schema version number for the session event format. + [JsonPropertyName("version")] + public required double Version { get; set; } } /// Session resume metadata including current context and event count. public partial class SessionResumeData { - /// ISO 8601 timestamp when the session was resumed. - [JsonPropertyName("resumeTime")] - public required DateTimeOffset ResumeTime { get; set; } + /// Whether the session was already in use by another client at resume time. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("alreadyInUse")] + public bool? AlreadyInUse { get; set; } + + /// Updated working directory and git context at resume time. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("context")] + public WorkingDirectoryContext? Context { get; set; } /// Total number of persisted events in the session at the time of resume. [JsonPropertyName("eventCount")] public required double EventCount { get; set; } - /// Model currently selected at resume time. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("selectedModel")] - public string? SelectedModel { get; set; } - /// Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } - /// Updated working directory and git context at resume time. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("context")] - public WorkingDirectoryContext? Context { get; set; } - - /// Whether the session was already in use by another client at resume time. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("alreadyInUse")] - public bool? AlreadyInUse { get; set; } - /// Whether this session supports remote steering via Mission Control. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("remoteSteerable")] public bool? RemoteSteerable { get; set; } + + /// ISO 8601 timestamp when the session was resumed. + [JsonPropertyName("resumeTime")] + public required DateTimeOffset ResumeTime { get; set; } + + /// Model currently selected at resume time. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("selectedModel")] + public string? SelectedModel { get; set; } } /// Notifies Mission Control that the session's remote steering capability has changed. @@ -1193,6 +1193,11 @@ public partial class SessionErrorData [JsonPropertyName("message")] public required string Message { get; set; } + /// GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerCallId")] + public string? ProviderCallId { get; set; } + /// Error stack trace, when available. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("stack")] @@ -1203,11 +1208,6 @@ public partial class SessionErrorData [JsonPropertyName("statusCode")] public long? StatusCode { get; set; } - /// GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("providerCallId")] - public string? ProviderCallId { get; set; } - /// Optional URL associated with this error that the user can open in a browser. [Url] [StringSyntax(StringSyntaxAttribute.Uri)] @@ -1255,10 +1255,6 @@ public partial class SessionInfoData /// Warning message for timeline display with categorization. public partial class SessionWarningData { - /// Category of warning (e.g., "subscription", "policy", "mcp"). - [JsonPropertyName("warningType")] - public required string WarningType { get; set; } - /// Human-readable warning message for display in the timeline. [JsonPropertyName("message")] public required string Message { get; set; } @@ -1269,20 +1265,24 @@ public partial class SessionWarningData [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("url")] public string? Url { get; set; } + + /// Category of warning (e.g., "subscription", "policy", "mcp"). + [JsonPropertyName("warningType")] + public required string WarningType { get; set; } } /// Model change details including previous and new model identifiers. public partial class SessionModelChangeData { + /// Newly selected model identifier. + [JsonPropertyName("newModel")] + public required string NewModel { get; set; } + /// Model that was previously selected, if any. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("previousModel")] public string? PreviousModel { get; set; } - /// Newly selected model identifier. - [JsonPropertyName("newModel")] - public required string NewModel { get; set; } - /// Reasoning effort level before the model change, if applicable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("previousReasoningEffort")] @@ -1297,13 +1297,13 @@ public partial class SessionModelChangeData /// Agent mode change details including previous and new modes. public partial class SessionModeChangedData { - /// Agent mode before the change (e.g., "interactive", "plan", "autopilot"). - [JsonPropertyName("previousMode")] - public required string PreviousMode { get; set; } - /// Agent mode after the change (e.g., "interactive", "plan", "autopilot"). [JsonPropertyName("newMode")] public required string NewMode { get; set; } + + /// Agent mode before the change (e.g., "interactive", "plan", "autopilot"). + [JsonPropertyName("previousMode")] + public required string PreviousMode { get; set; } } /// Plan file operation details indicating what changed. @@ -1317,131 +1317,111 @@ public partial class SessionPlanChangedData /// Workspace file change details including path and operation type. public partial class SessionWorkspaceFileChangedData { - /// Relative path within the session workspace files directory. - [JsonPropertyName("path")] - public required string Path { get; set; } - /// Whether the file was newly created or updated. [JsonPropertyName("operation")] public required WorkspaceFileChangedOperation Operation { get; set; } + + /// Relative path within the session workspace files directory. + [JsonPropertyName("path")] + public required string Path { get; set; } } /// Session handoff metadata including source, context, and repository information. public partial class SessionHandoffData { + /// Additional context information for the handoff. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("context")] + public string? Context { get; set; } + /// ISO 8601 timestamp when the handoff occurred. [JsonPropertyName("handoffTime")] public required DateTimeOffset HandoffTime { get; set; } - /// Origin type of the session being handed off. - [JsonPropertyName("sourceType")] - public required HandoffSourceType SourceType { get; set; } + /// GitHub host URL for the source session (e.g., https://github.com or https://tenant.ghe.com). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("host")] + public string? Host { get; set; } + + /// Session ID of the remote session being handed off. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("remoteSessionId")] + public string? RemoteSessionId { get; set; } /// Repository context for the handed-off session. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("repository")] public HandoffRepository? Repository { get; set; } - /// Additional context information for the handoff. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("context")] - public string? Context { get; set; } + /// Origin type of the session being handed off. + [JsonPropertyName("sourceType")] + public required HandoffSourceType SourceType { get; set; } /// Summary of the work done in the source session. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("summary")] public string? Summary { get; set; } - - /// Session ID of the remote session being handed off. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("remoteSessionId")] - public string? RemoteSessionId { get; set; } - - /// GitHub host URL for the source session (e.g., https://github.com or https://tenant.ghe.com). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("host")] - public string? Host { get; set; } } /// Conversation truncation statistics including token counts and removed content metrics. public partial class SessionTruncationData { - /// Maximum token count for the model's context window. - [JsonPropertyName("tokenLimit")] - public required double TokenLimit { get; set; } + /// Number of messages removed by truncation. + [JsonPropertyName("messagesRemovedDuringTruncation")] + public required double MessagesRemovedDuringTruncation { get; set; } - /// Total tokens in conversation messages before truncation. - [JsonPropertyName("preTruncationTokensInMessages")] - public required double PreTruncationTokensInMessages { get; set; } + /// Identifier of the component that performed truncation (e.g., "BasicTruncator"). + [JsonPropertyName("performedBy")] + public required string PerformedBy { get; set; } - /// Number of conversation messages before truncation. - [JsonPropertyName("preTruncationMessagesLength")] - public required double PreTruncationMessagesLength { get; set; } + /// Number of conversation messages after truncation. + [JsonPropertyName("postTruncationMessagesLength")] + public required double PostTruncationMessagesLength { get; set; } /// Total tokens in conversation messages after truncation. [JsonPropertyName("postTruncationTokensInMessages")] public required double PostTruncationTokensInMessages { get; set; } - /// Number of conversation messages after truncation. - [JsonPropertyName("postTruncationMessagesLength")] - public required double PostTruncationMessagesLength { get; set; } + /// Number of conversation messages before truncation. + [JsonPropertyName("preTruncationMessagesLength")] + public required double PreTruncationMessagesLength { get; set; } + + /// Total tokens in conversation messages before truncation. + [JsonPropertyName("preTruncationTokensInMessages")] + public required double PreTruncationTokensInMessages { get; set; } + + /// Maximum token count for the model's context window. + [JsonPropertyName("tokenLimit")] + public required double TokenLimit { get; set; } /// Number of tokens removed by truncation. [JsonPropertyName("tokensRemovedDuringTruncation")] public required double TokensRemovedDuringTruncation { get; set; } - - /// Number of messages removed by truncation. - [JsonPropertyName("messagesRemovedDuringTruncation")] - public required double MessagesRemovedDuringTruncation { get; set; } - - /// Identifier of the component that performed truncation (e.g., "BasicTruncator"). - [JsonPropertyName("performedBy")] - public required string PerformedBy { get; set; } } /// Session rewind details including target event and count of removed events. public partial class SessionSnapshotRewindData { - /// Event ID that was rewound to; this event and all after it were removed. - [JsonPropertyName("upToEventId")] - public required string UpToEventId { get; set; } - /// Number of events that were removed by the rewind. [JsonPropertyName("eventsRemoved")] public required double EventsRemoved { get; set; } + + /// Event ID that was rewound to; this event and all after it were removed. + [JsonPropertyName("upToEventId")] + public required string UpToEventId { get; set; } } /// Session termination metrics including usage statistics, code changes, and shutdown reason. public partial class SessionShutdownData { - /// Whether the session ended normally ("routine") or due to a crash/fatal error ("error"). - [JsonPropertyName("shutdownType")] - public required ShutdownType ShutdownType { get; set; } - - /// Error description when shutdownType is "error". - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("errorReason")] - public string? ErrorReason { get; set; } - - /// Total number of premium API requests used during the session. - [JsonPropertyName("totalPremiumRequests")] - public required double TotalPremiumRequests { get; set; } - - /// Cumulative time spent in API calls during the session, in milliseconds. - [JsonPropertyName("totalApiDurationMs")] - public required double TotalApiDurationMs { get; set; } - - /// Unix timestamp (milliseconds) when the session started. - [JsonPropertyName("sessionStartTime")] - public required double SessionStartTime { get; set; } - /// Aggregate code change metrics for the session. [JsonPropertyName("codeChanges")] public required ShutdownCodeChanges CodeChanges { get; set; } - /// Per-model usage breakdown, keyed by model identifier. - [JsonPropertyName("modelMetrics")] - public required IDictionary ModelMetrics { get; set; } + /// Non-system message token count at shutdown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("conversationTokens")] + public double? ConversationTokens { get; set; } /// Model that was selected at the time of shutdown. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1453,25 +1433,55 @@ public partial class SessionShutdownData [JsonPropertyName("currentTokens")] public double? CurrentTokens { get; set; } + /// Error description when shutdownType is "error". + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("errorReason")] + public string? ErrorReason { get; set; } + + /// Per-model usage breakdown, keyed by model identifier. + [JsonPropertyName("modelMetrics")] + public required IDictionary ModelMetrics { get; set; } + + /// Unix timestamp (milliseconds) when the session started. + [JsonPropertyName("sessionStartTime")] + public required double SessionStartTime { get; set; } + + /// Whether the session ended normally ("routine") or due to a crash/fatal error ("error"). + [JsonPropertyName("shutdownType")] + public required ShutdownType ShutdownType { get; set; } + /// System message token count at shutdown. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("systemTokens")] public double? SystemTokens { get; set; } - /// Non-system message token count at shutdown. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("conversationTokens")] - public double? ConversationTokens { get; set; } - /// Tool definitions token count at shutdown. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolDefinitionsTokens")] public double? ToolDefinitionsTokens { get; set; } + + /// Cumulative time spent in API calls during the session, in milliseconds. + [JsonPropertyName("totalApiDurationMs")] + public required double TotalApiDurationMs { get; set; } + + /// Total number of premium API requests used during the session. + [JsonPropertyName("totalPremiumRequests")] + public required double TotalPremiumRequests { get; set; } } /// Working directory and git context at session start. public partial class SessionContextChangedData { + /// Base commit of current git branch at session start time. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("baseCommit")] + public string? BaseCommit { get; set; } + + /// Current git branch name. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("branch")] + public string? Branch { get; set; } + /// Current working directory path. [JsonPropertyName("cwd")] public required string Cwd { get; set; } @@ -1481,43 +1491,44 @@ public partial class SessionContextChangedData [JsonPropertyName("gitRoot")] public string? GitRoot { get; set; } - /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). + /// Head commit of current git branch at session start time. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("repository")] - public string? Repository { get; set; } + [JsonPropertyName("headCommit")] + public string? HeadCommit { get; set; } /// Hosting platform type of the repository (github or ado). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("hostType")] public WorkingDirectoryContextHostType? HostType { get; set; } - /// Current git branch name. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Head commit of current git branch at session start time. + /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("headCommit")] - public string? HeadCommit { get; set; } + [JsonPropertyName("repository")] + public string? Repository { get; set; } - /// Base commit of current git branch at session start time. + /// Raw host string from the git remote URL (e.g. "github.com", "mycompany.ghe.com", "dev.azure.com"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("baseCommit")] - public string? BaseCommit { get; set; } + [JsonPropertyName("repositoryHost")] + public string? RepositoryHost { get; set; } } /// Current context window usage statistics including token and message counts. public partial class SessionUsageInfoData { - /// Maximum token count for the model's context window. - [JsonPropertyName("tokenLimit")] - public required double TokenLimit { get; set; } + /// Token count from non-system messages (user, assistant, tool). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("conversationTokens")] + public double? ConversationTokens { get; set; } /// Current number of tokens in the context window. [JsonPropertyName("currentTokens")] public required double CurrentTokens { get; set; } + /// Whether this is the first usage_info event emitted in this session. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("isInitial")] + public bool? IsInitial { get; set; } + /// Current number of messages in the conversation. [JsonPropertyName("messagesLength")] public required double MessagesLength { get; set; } @@ -1527,35 +1538,29 @@ public partial class SessionUsageInfoData [JsonPropertyName("systemTokens")] public double? SystemTokens { get; set; } - /// Token count from non-system messages (user, assistant, tool). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("conversationTokens")] - public double? ConversationTokens { get; set; } + /// Maximum token count for the model's context window. + [JsonPropertyName("tokenLimit")] + public required double TokenLimit { get; set; } /// Token count from tool definitions. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolDefinitionsTokens")] public double? ToolDefinitionsTokens { get; set; } - - /// Whether this is the first usage_info event emitted in this session. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("isInitial")] - public bool? IsInitial { get; set; } } /// Context window breakdown at the start of LLM-powered conversation compaction. public partial class SessionCompactionStartData { - /// Token count from system message(s) at compaction start. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("systemTokens")] - public double? SystemTokens { get; set; } - /// Token count from non-system messages (user, assistant, tool) at compaction start. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("conversationTokens")] public double? ConversationTokens { get; set; } + /// Token count from system message(s) at compaction start. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("systemTokens")] + public double? SystemTokens { get; set; } + /// Token count from tool definitions at compaction start. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolDefinitionsTokens")] @@ -1565,19 +1570,35 @@ public partial class SessionCompactionStartData /// Conversation compaction results including success status, metrics, and optional error details. public partial class SessionCompactionCompleteData { - /// Whether compaction completed successfully. - [JsonPropertyName("success")] - public required bool Success { get; set; } + /// Checkpoint snapshot number created for recovery. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("checkpointNumber")] + public double? CheckpointNumber { get; set; } + + /// File path where the checkpoint was stored. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("checkpointPath")] + public string? CheckpointPath { get; set; } + + /// Token usage breakdown for the compaction LLM call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("compactionTokensUsed")] + public CompactionCompleteCompactionTokensUsed? CompactionTokensUsed { get; set; } + + /// Token count from non-system messages (user, assistant, tool) after compaction. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("conversationTokens")] + public double? ConversationTokens { get; set; } /// Error message if compaction failed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("error")] public string? Error { get; set; } - /// Total tokens in conversation before compaction. + /// Number of messages removed during compaction. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("preCompactionTokens")] - public double? PreCompactionTokens { get; set; } + [JsonPropertyName("messagesRemoved")] + public double? MessagesRemoved { get; set; } /// Total tokens in conversation after compaction. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1589,50 +1610,34 @@ public partial class SessionCompactionCompleteData [JsonPropertyName("preCompactionMessagesLength")] public double? PreCompactionMessagesLength { get; set; } - /// Number of messages removed during compaction. + /// Total tokens in conversation before compaction. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("messagesRemoved")] - public double? MessagesRemoved { get; set; } + [JsonPropertyName("preCompactionTokens")] + public double? PreCompactionTokens { get; set; } - /// Number of tokens removed during compaction. + /// GitHub request tracing ID (x-github-request-id header) for the compaction LLM call. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("tokensRemoved")] - public double? TokensRemoved { get; set; } + [JsonPropertyName("requestId")] + public string? RequestId { get; set; } + + /// Whether compaction completed successfully. + [JsonPropertyName("success")] + public required bool Success { get; set; } /// LLM-generated summary of the compacted conversation history. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("summaryContent")] public string? SummaryContent { get; set; } - /// Checkpoint snapshot number created for recovery. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("checkpointNumber")] - public double? CheckpointNumber { get; set; } - - /// File path where the checkpoint was stored. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("checkpointPath")] - public string? CheckpointPath { get; set; } - - /// Token usage breakdown for the compaction LLM call. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("compactionTokensUsed")] - public CompactionCompleteCompactionTokensUsed? CompactionTokensUsed { get; set; } - - /// GitHub request tracing ID (x-github-request-id header) for the compaction LLM call. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("requestId")] - public string? RequestId { get; set; } - /// Token count from system message(s) after compaction. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("systemTokens")] public double? SystemTokens { get; set; } - /// Token count from non-system messages (user, assistant, tool) after compaction. + /// Number of tokens removed during compaction. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("conversationTokens")] - public double? ConversationTokens { get; set; } + [JsonPropertyName("tokensRemoved")] + public double? TokensRemoved { get; set; } /// Token count from tool definitions after compaction. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1643,38 +1648,38 @@ public partial class SessionCompactionCompleteData /// Task completion notification with summary from the agent. public partial class SessionTaskCompleteData { - /// Summary of the completed task, provided by the agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("summary")] - public string? Summary { get; set; } - /// Whether the tool call succeeded. False when validation failed (e.g., invalid arguments). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("success")] public bool? Success { get; set; } + + /// Summary of the completed task, provided by the agent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("summary")] + public string? Summary { get; set; } } /// Event payload for . public partial class UserMessageData { - /// The user's message text as displayed in the timeline. - [JsonPropertyName("content")] - public required string Content { get; set; } - - /// Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching. + /// The agent mode that was active when this message was sent. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("transformedContent")] - public string? TransformedContent { get; set; } + [JsonPropertyName("agentMode")] + public UserMessageAgentMode? AgentMode { get; set; } /// Files, selections, or GitHub references attached to the message. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("attachments")] public UserMessageAttachment[]? Attachments { get; set; } - /// Normalized document MIME types that were sent natively instead of through tagged_files XML. + /// The user's message text as displayed in the timeline. + [JsonPropertyName("content")] + public required string Content { get; set; } + + /// CAPI interaction ID for correlating this user message with its turn. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("supportedNativeDocumentMimeTypes")] - public string[]? SupportedNativeDocumentMimeTypes { get; set; } + [JsonPropertyName("interactionId")] + public string? InteractionId { get; set; } /// Path-backed native document attachments that stayed on the tagged_files path flow because native upload would exceed the request size limit. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1686,15 +1691,15 @@ public partial class UserMessageData [JsonPropertyName("source")] public string? Source { get; set; } - /// The agent mode that was active when this message was sent. + /// Normalized document MIME types that were sent natively instead of through tagged_files XML. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("agentMode")] - public UserMessageAgentMode? AgentMode { get; set; } + [JsonPropertyName("supportedNativeDocumentMimeTypes")] + public string[]? SupportedNativeDocumentMimeTypes { get; set; } - /// CAPI interaction ID for correlating this user message with its turn. + /// Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("interactionId")] - public string? InteractionId { get; set; } + [JsonPropertyName("transformedContent")] + public string? TransformedContent { get; set; } } /// Empty payload; the event signals that the pending message queue has changed. @@ -1705,14 +1710,14 @@ public partial class PendingMessagesModifiedData /// Turn initialization metadata including identifier and interaction tracking. public partial class AssistantTurnStartData { - /// Identifier for this turn within the agentic loop, typically a stringified turn number. - [JsonPropertyName("turnId")] - public required string TurnId { get; set; } - /// CAPI interaction ID for correlating this turn with upstream telemetry. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("interactionId")] public string? InteractionId { get; set; } + + /// Identifier for this turn within the agentic loop, typically a stringified turn number. + [JsonPropertyName("turnId")] + public required string TurnId { get; set; } } /// Agent intent description for current activity or plan. @@ -1726,25 +1731,25 @@ public partial class AssistantIntentData /// Assistant reasoning content for timeline display with complete thinking text. public partial class AssistantReasoningData { - /// Unique identifier for this reasoning block. - [JsonPropertyName("reasoningId")] - public required string ReasoningId { get; set; } - /// The complete extended thinking text from the model. [JsonPropertyName("content")] public required string Content { get; set; } + + /// Unique identifier for this reasoning block. + [JsonPropertyName("reasoningId")] + public required string ReasoningId { get; set; } } /// Streaming reasoning delta for incremental extended thinking updates. public partial class AssistantReasoningDeltaData { - /// Reasoning block ID this delta belongs to, matching the corresponding assistant.reasoning event. - [JsonPropertyName("reasoningId")] - public required string ReasoningId { get; set; } - /// Incremental text chunk to append to the reasoning content. [JsonPropertyName("deltaContent")] public required string DeltaContent { get; set; } + + /// Reasoning block ID this delta belongs to, matching the corresponding assistant.reasoning event. + [JsonPropertyName("reasoningId")] + public required string ReasoningId { get; set; } } /// Streaming response progress with cumulative byte count. @@ -1758,72 +1763,72 @@ public partial class AssistantStreamingDeltaData /// Assistant response containing text content, optional tool requests, and interaction metadata. public partial class AssistantMessageData { - /// Unique identifier for this assistant message. - [JsonPropertyName("messageId")] - public required string MessageId { get; set; } - /// The assistant's text response content. [JsonPropertyName("content")] public required string Content { get; set; } - /// Tool invocations requested by the assistant in this message. + /// Encrypted reasoning content from OpenAI models. Session-bound and stripped on resume. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolRequests")] - public AssistantMessageToolRequest[]? ToolRequests { get; set; } + [JsonPropertyName("encryptedContent")] + public string? EncryptedContent { get; set; } - /// Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. + /// CAPI interaction ID for correlating this message with upstream telemetry. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reasoningOpaque")] - public string? ReasoningOpaque { get; set; } + [JsonPropertyName("interactionId")] + public string? InteractionId { get; set; } - /// Readable reasoning text from the model's extended thinking. + /// Unique identifier for this assistant message. + [JsonPropertyName("messageId")] + public required string MessageId { get; set; } + + /// Actual output token count from the API response (completion_tokens), used for accurate token accounting. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reasoningText")] - public string? ReasoningText { get; set; } + [JsonPropertyName("outputTokens")] + public double? OutputTokens { get; set; } - /// Encrypted reasoning content from OpenAI models. Session-bound and stripped on resume. + /// Tool call ID of the parent tool invocation when this event originates from a sub-agent. + [Obsolete("This member is deprecated and will be removed in a future version.")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("encryptedContent")] - public string? EncryptedContent { get; set; } + [JsonPropertyName("parentToolCallId")] + public string? ParentToolCallId { get; set; } /// Generation phase for phased-output models (e.g., thinking vs. response phases). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("phase")] public string? Phase { get; set; } - /// Actual output token count from the API response (completion_tokens), used for accurate token accounting. + /// Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputTokens")] - public double? OutputTokens { get; set; } + [JsonPropertyName("reasoningOpaque")] + public string? ReasoningOpaque { get; set; } - /// CAPI interaction ID for correlating this message with upstream telemetry. + /// Readable reasoning text from the model's extended thinking. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("interactionId")] - public string? InteractionId { get; set; } + [JsonPropertyName("reasoningText")] + public string? ReasoningText { get; set; } /// GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("requestId")] public string? RequestId { get; set; } - /// Tool call ID of the parent tool invocation when this event originates from a sub-agent. - [Obsolete("This member is deprecated and will be removed in a future version.")] + /// Tool invocations requested by the assistant in this message. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("parentToolCallId")] - public string? ParentToolCallId { get; set; } + [JsonPropertyName("toolRequests")] + public AssistantMessageToolRequest[]? ToolRequests { get; set; } } /// Streaming assistant message delta for incremental response updates. public partial class AssistantMessageDeltaData { - /// Message ID this delta belongs to, matching the corresponding assistant.message event. - [JsonPropertyName("messageId")] - public required string MessageId { get; set; } - /// Incremental text chunk to append to the message content. [JsonPropertyName("deltaContent")] public required string DeltaContent { get; set; } + /// Message ID this delta belongs to, matching the corresponding assistant.message event. + [JsonPropertyName("messageId")] + public required string MessageId { get; set; } + /// Tool call ID of the parent tool invocation when this event originates from a sub-agent. [Obsolete("This member is deprecated and will be removed in a future version.")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1842,19 +1847,10 @@ public partial class AssistantTurnEndData /// LLM API call usage metrics including tokens, costs, quotas, and billing information. public partial class AssistantUsageData { - /// Model identifier used for this API call. - [JsonPropertyName("model")] - public required string Model { get; set; } - - /// Number of input tokens consumed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("inputTokens")] - public double? InputTokens { get; set; } - - /// Number of output tokens produced. + /// Completion ID from the model provider (e.g., chatcmpl-abc123). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputTokens")] - public double? OutputTokens { get; set; } + [JsonPropertyName("apiCallId")] + public string? ApiCallId { get; set; } /// Number of tokens read from prompt cache. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1866,10 +1862,10 @@ public partial class AssistantUsageData [JsonPropertyName("cacheWriteTokens")] public double? CacheWriteTokens { get; set; } - /// Number of output tokens used for reasoning (e.g., chain-of-thought). + /// Per-request cost and usage data from the CAPI copilot_usage response field. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reasoningTokens")] - public double? ReasoningTokens { get; set; } + [JsonPropertyName("copilotUsage")] + public AssistantUsageCopilotUsage? CopilotUsage { get; set; } /// Model multiplier cost for billing purposes. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1881,30 +1877,29 @@ public partial class AssistantUsageData [JsonPropertyName("duration")] public double? Duration { get; set; } - /// Time to first token in milliseconds. Only available for streaming requests. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ttftMs")] - public double? TtftMs { get; set; } - - /// Average inter-token latency in milliseconds. Only available for streaming requests. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("interTokenLatencyMs")] - public double? InterTokenLatencyMs { get; set; } - /// What initiated this API call (e.g., "sub-agent", "mcp-sampling"); absent for user-initiated calls. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("initiator")] public string? Initiator { get; set; } - /// Completion ID from the model provider (e.g., chatcmpl-abc123). + /// Number of input tokens consumed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("inputTokens")] + public double? InputTokens { get; set; } + + /// Average inter-token latency in milliseconds. Only available for streaming requests. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("apiCallId")] - public string? ApiCallId { get; set; } + [JsonPropertyName("interTokenLatencyMs")] + public double? InterTokenLatencyMs { get; set; } - /// GitHub request tracing ID (x-github-request-id header) for server-side log correlation. + /// Model identifier used for this API call. + [JsonPropertyName("model")] + public required string Model { get; set; } + + /// Number of output tokens produced. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("providerCallId")] - public string? ProviderCallId { get; set; } + [JsonPropertyName("outputTokens")] + public double? OutputTokens { get; set; } /// Parent tool call ID when this usage originates from a sub-agent. [Obsolete("This member is deprecated and will be removed in a future version.")] @@ -1912,20 +1907,30 @@ public partial class AssistantUsageData [JsonPropertyName("parentToolCallId")] public string? ParentToolCallId { get; set; } - /// Per-quota resource usage snapshots, keyed by quota identifier. + /// GitHub request tracing ID (x-github-request-id header) for server-side log correlation. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("quotaSnapshots")] - public IDictionary? QuotaSnapshots { get; set; } + [JsonPropertyName("providerCallId")] + public string? ProviderCallId { get; set; } - /// Per-request cost and usage data from the CAPI copilot_usage response field. + /// Per-quota resource usage snapshots, keyed by quota identifier. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUsage")] - public AssistantUsageCopilotUsage? CopilotUsage { get; set; } + [JsonPropertyName("quotaSnapshots")] + public IDictionary? QuotaSnapshots { get; set; } /// Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } + + /// Number of output tokens used for reasoning (e.g., chain-of-thought). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningTokens")] + public double? ReasoningTokens { get; set; } + + /// Time to first token in milliseconds. Only available for streaming requests. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ttftMs")] + public double? TtftMs { get; set; } } /// Turn abort information including the reason for termination. @@ -1939,31 +1944,23 @@ public partial class AbortData /// User-initiated tool invocation request with tool name and arguments. public partial class ToolUserRequestedData { - /// Unique identifier for this tool call. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } - - /// Name of the tool the user wants to invoke. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } - /// Arguments for the tool invocation. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("arguments")] public object? Arguments { get; set; } -} -/// Tool execution startup details including MCP server information when applicable. -public partial class ToolExecutionStartData -{ /// Unique identifier for this tool call. [JsonPropertyName("toolCallId")] public required string ToolCallId { get; set; } - /// Name of the tool being executed. + /// Name of the tool the user wants to invoke. [JsonPropertyName("toolName")] public required string ToolName { get; set; } +} +/// Tool execution startup details including MCP server information when applicable. +public partial class ToolExecutionStartData +{ /// Arguments passed to the tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("arguments")] @@ -1984,47 +1981,47 @@ public partial class ToolExecutionStartData [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("parentToolCallId")] public string? ParentToolCallId { get; set; } + + /// Unique identifier for this tool call. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } + + /// Name of the tool being executed. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } /// Streaming tool execution output for incremental result display. public partial class ToolExecutionPartialResultData { - /// Tool call ID this partial result belongs to. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } - /// Incremental output chunk from the running tool. [JsonPropertyName("partialOutput")] public required string PartialOutput { get; set; } + + /// Tool call ID this partial result belongs to. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } } /// Tool execution progress notification with status message. public partial class ToolExecutionProgressData { - /// Tool call ID this progress notification belongs to. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } - /// Human-readable progress status message (e.g., from an MCP server). [JsonPropertyName("progressMessage")] public required string ProgressMessage { get; set; } + + /// Tool call ID this progress notification belongs to. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } } /// Tool execution completion results including success status, detailed output, and error information. public partial class ToolExecutionCompleteData { - /// Unique identifier for the completed tool call. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } - - /// Whether the tool execution completed successfully. - [JsonPropertyName("success")] - public required bool Success { get; set; } - - /// Model identifier that generated this tool call. + /// Error details when the tool execution failed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } + [JsonPropertyName("error")] + public ToolExecutionCompleteError? Error { get; set; } /// CAPI interaction ID for correlating this tool execution with upstream telemetry. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -2036,31 +2033,53 @@ public partial class ToolExecutionCompleteData [JsonPropertyName("isUserRequested")] public bool? IsUserRequested { get; set; } + /// Model identifier that generated this tool call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Tool call ID of the parent tool invocation when this event originates from a sub-agent. + [Obsolete("This member is deprecated and will be removed in a future version.")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("parentToolCallId")] + public string? ParentToolCallId { get; set; } + /// Tool execution result on success. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("result")] public ToolExecutionCompleteResult? Result { get; set; } - /// Error details when the tool execution failed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public ToolExecutionCompleteError? Error { get; set; } + /// Whether the tool execution completed successfully. + [JsonPropertyName("success")] + public required bool Success { get; set; } + + /// Unique identifier for the completed tool call. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } /// Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolTelemetry")] public IDictionary? ToolTelemetry { get; set; } - - /// Tool call ID of the parent tool invocation when this event originates from a sub-agent. - [Obsolete("This member is deprecated and will be removed in a future version.")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("parentToolCallId")] - public string? ParentToolCallId { get; set; } } /// Skill invocation details including content, allowed tools, and plugin metadata. public partial class SkillInvokedData { + /// Tool names that should be auto-approved when this skill is active. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("allowedTools")] + public string[]? AllowedTools { get; set; } + + /// Full content of the skill file, injected into the conversation for the model. + [JsonPropertyName("content")] + public required string Content { get; set; } + + /// Description of the skill from its SKILL.md frontmatter. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + /// Name of the invoked skill. [JsonPropertyName("name")] public required string Name { get; set; } @@ -2069,15 +2088,6 @@ public partial class SkillInvokedData [JsonPropertyName("path")] public required string Path { get; set; } - /// Full content of the skill file, injected into the conversation for the model. - [JsonPropertyName("content")] - public required string Content { get; set; } - - /// Tool names that should be auto-approved when this skill is active. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("allowedTools")] - public string[]? AllowedTools { get; set; } - /// Name of the plugin this skill originated from, when applicable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("pluginName")] @@ -2087,83 +2097,79 @@ public partial class SkillInvokedData [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("pluginVersion")] public string? PluginVersion { get; set; } - - /// Description of the skill from its SKILL.md frontmatter. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } } /// Sub-agent startup details including parent tool call and agent information. public partial class SubagentStartedData { - /// Tool call ID of the parent tool invocation that spawned this sub-agent. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } - - /// Internal name of the sub-agent. - [JsonPropertyName("agentName")] - public required string AgentName { get; set; } + /// Description of what the sub-agent does. + [JsonPropertyName("agentDescription")] + public required string AgentDescription { get; set; } /// Human-readable display name of the sub-agent. [JsonPropertyName("agentDisplayName")] public required string AgentDisplayName { get; set; } - /// Description of what the sub-agent does. - [JsonPropertyName("agentDescription")] - public required string AgentDescription { get; set; } + /// Internal name of the sub-agent. + [JsonPropertyName("agentName")] + public required string AgentName { get; set; } + + /// Tool call ID of the parent tool invocation that spawned this sub-agent. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } } /// Sub-agent completion details for successful execution. public partial class SubagentCompletedData { - /// Tool call ID of the parent tool invocation that spawned this sub-agent. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } + /// Human-readable display name of the sub-agent. + [JsonPropertyName("agentDisplayName")] + public required string AgentDisplayName { get; set; } /// Internal name of the sub-agent. [JsonPropertyName("agentName")] public required string AgentName { get; set; } - /// Human-readable display name of the sub-agent. - [JsonPropertyName("agentDisplayName")] - public required string AgentDisplayName { get; set; } + /// Wall-clock duration of the sub-agent execution in milliseconds. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("durationMs")] + public double? DurationMs { get; set; } /// Model used by the sub-agent. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("model")] public string? Model { get; set; } - /// Total number of tool calls made by the sub-agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("totalToolCalls")] - public double? TotalToolCalls { get; set; } + /// Tool call ID of the parent tool invocation that spawned this sub-agent. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } /// Total tokens (input + output) consumed by the sub-agent. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("totalTokens")] public double? TotalTokens { get; set; } - /// Wall-clock duration of the sub-agent execution in milliseconds. + /// Total number of tool calls made by the sub-agent. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("durationMs")] - public double? DurationMs { get; set; } + [JsonPropertyName("totalToolCalls")] + public double? TotalToolCalls { get; set; } } /// Sub-agent failure details including error message and agent information. public partial class SubagentFailedData { - /// Tool call ID of the parent tool invocation that spawned this sub-agent. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } + /// Human-readable display name of the sub-agent. + [JsonPropertyName("agentDisplayName")] + public required string AgentDisplayName { get; set; } /// Internal name of the sub-agent. [JsonPropertyName("agentName")] public required string AgentName { get; set; } - /// Human-readable display name of the sub-agent. - [JsonPropertyName("agentDisplayName")] - public required string AgentDisplayName { get; set; } + /// Wall-clock duration of the sub-agent execution in milliseconds. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("durationMs")] + public double? DurationMs { get; set; } /// Error message describing why the sub-agent failed. [JsonPropertyName("error")] @@ -2174,33 +2180,32 @@ public partial class SubagentFailedData [JsonPropertyName("model")] public string? Model { get; set; } - /// Total number of tool calls made before the sub-agent failed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("totalToolCalls")] - public double? TotalToolCalls { get; set; } + /// Tool call ID of the parent tool invocation that spawned this sub-agent. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } /// Total tokens (input + output) consumed before the sub-agent failed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("totalTokens")] public double? TotalTokens { get; set; } - /// Wall-clock duration of the sub-agent execution in milliseconds. + /// Total number of tool calls made before the sub-agent failed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("durationMs")] - public double? DurationMs { get; set; } + [JsonPropertyName("totalToolCalls")] + public double? TotalToolCalls { get; set; } } /// Custom agent selection details including name and available tools. public partial class SubagentSelectedData { - /// Internal name of the selected custom agent. - [JsonPropertyName("agentName")] - public required string AgentName { get; set; } - /// Human-readable display name of the selected custom agent. [JsonPropertyName("agentDisplayName")] public required string AgentDisplayName { get; set; } + /// Internal name of the selected custom agent. + [JsonPropertyName("agentName")] + public required string AgentName { get; set; } + /// List of tool names available to this agent, or null for all tools. [JsonPropertyName("tools")] public string[]? Tools { get; set; } @@ -2231,6 +2236,11 @@ public partial class HookStartData /// Hook invocation completion details including output, success status, and error information. public partial class HookEndData { + /// Error details when the hook failed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("error")] + public HookEndError? Error { get; set; } + /// Identifier matching the corresponding hook.start event. [JsonPropertyName("hookInvocationId")] public required string HookInvocationId { get; set; } @@ -2247,11 +2257,6 @@ public partial class HookEndData /// Whether the hook completed successfully. [JsonPropertyName("success")] public required bool Success { get; set; } - - /// Error details when the hook failed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public HookEndError? Error { get; set; } } /// System/developer instruction content with role and optional template metadata. @@ -2261,19 +2266,19 @@ public partial class SystemMessageData [JsonPropertyName("content")] public required string Content { get; set; } - /// Message role: "system" for system prompts, "developer" for developer-injected instructions. - [JsonPropertyName("role")] - public required SystemMessageRole Role { get; set; } + /// Metadata about the prompt template and its construction. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("metadata")] + public SystemMessageMetadata? Metadata { get; set; } /// Optional name identifier for the message source. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("name")] public string? Name { get; set; } - /// Metadata about the prompt template and its construction. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("metadata")] - public SystemMessageMetadata? Metadata { get; set; } + /// Message role: "system" for system prompts, "developer" for developer-injected instructions. + [JsonPropertyName("role")] + public required SystemMessageRole Role { get; set; } } /// System-generated notification for runtime events like background task completion. @@ -2291,14 +2296,14 @@ public partial class SystemNotificationData /// Permission request notification requiring client approval with request details. public partial class PermissionRequestedData { - /// Unique identifier for this permission request; used to respond via session.respondToPermission(). - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - /// Details of the permission being requested. [JsonPropertyName("permissionRequest")] public required PermissionRequest PermissionRequest { get; set; } + /// Unique identifier for this permission request; used to respond via session.respondToPermission(). + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } + /// When true, this permission was already resolved by a permissionRequest hook and requires no client action. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("resolvedByHook")] @@ -2320,23 +2325,23 @@ public partial class PermissionCompletedData /// User input request notification with question and optional predefined choices. public partial class UserInputRequestedData { - /// Unique identifier for this input request; used to respond via session.respondToUserInput(). - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - - /// The question or prompt to present to the user. - [JsonPropertyName("question")] - public required string Question { get; set; } + /// Whether the user can provide a free-form text response in addition to predefined choices. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("allowFreeform")] + public bool? AllowFreeform { get; set; } /// Predefined choices for the user to select from, if applicable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("choices")] public string[]? Choices { get; set; } - /// Whether the user can provide a free-form text response in addition to predefined choices. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("allowFreeform")] - public bool? AllowFreeform { get; set; } + /// The question or prompt to present to the user. + [JsonPropertyName("question")] + public required string Question { get; set; } + + /// Unique identifier for this input request; used to respond via session.respondToUserInput(). + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } /// The LLM-assigned tool call ID that triggered this request; used by remote UIs to correlate responses. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -2347,15 +2352,15 @@ public partial class UserInputRequestedData /// User input request completion with the user's response. public partial class UserInputCompletedData { - /// Request ID of the resolved user input request; clients should dismiss any UI for this request. - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - /// The user's answer to the input request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("answer")] public string? Answer { get; set; } + /// Request ID of the resolved user input request; clients should dismiss any UI for this request. + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } + /// Whether the answer was typed as free-form text rather than selected from choices. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("wasFreeform")] @@ -2365,15 +2370,6 @@ public partial class UserInputCompletedData /// Elicitation request; may be form-based (structured input) or URL-based (browser redirect). public partial class ElicitationRequestedData { - /// Unique identifier for this elicitation request; used to respond via session.respondToElicitation(). - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - - /// Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id for remote UIs. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } - /// The source that initiated the request (MCP server name, or absent for agent-initiated). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("elicitationSource")] @@ -2393,6 +2389,15 @@ public partial class ElicitationRequestedData [JsonPropertyName("requestedSchema")] public ElicitationRequestedSchema? RequestedSchema { get; set; } + /// Unique identifier for this elicitation request; used to respond via session.respondToElicitation(). + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } + + /// Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id for remote UIs. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } + /// URL to open in the user's browser (url mode only). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("url")] @@ -2402,10 +2407,6 @@ public partial class ElicitationRequestedData /// Elicitation request completion with the user's response. public partial class ElicitationCompletedData { - /// Request ID of the resolved elicitation request; clients should dismiss any UI for this request. - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - /// The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("action")] @@ -2415,11 +2416,19 @@ public partial class ElicitationCompletedData [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("content")] public IDictionary? Content { get; set; } + + /// Request ID of the resolved elicitation request; clients should dismiss any UI for this request. + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } } /// Sampling request from an MCP server; contains the server name and a requestId for correlation. public partial class SamplingRequestedData { + /// The JSON-RPC request ID from the MCP protocol. + [JsonPropertyName("mcpRequestId")] + public required object McpRequestId { get; set; } + /// Unique identifier for this sampling request; used to respond via session.respondToSampling(). [JsonPropertyName("requestId")] public required string RequestId { get; set; } @@ -2427,10 +2436,6 @@ public partial class SamplingRequestedData /// Name of the MCP server that initiated the sampling request. [JsonPropertyName("serverName")] public required string ServerName { get; set; } - - /// The JSON-RPC request ID from the MCP protocol. - [JsonPropertyName("mcpRequestId")] - public required object McpRequestId { get; set; } } /// Sampling request completion notification signaling UI dismissal. @@ -2473,6 +2478,11 @@ public partial class McpOauthCompletedData /// External tool invocation request for client-side tool execution. public partial class ExternalToolRequestedData { + /// Arguments to pass to the external tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("arguments")] + public object? Arguments { get; set; } + /// Unique identifier for this request; used to respond via session.respondToExternalTool(). [JsonPropertyName("requestId")] public required string RequestId { get; set; } @@ -2489,11 +2499,6 @@ public partial class ExternalToolRequestedData [JsonPropertyName("toolName")] public required string ToolName { get; set; } - /// Arguments to pass to the external tool. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("arguments")] - public object? Arguments { get; set; } - /// W3C Trace Context traceparent header for the execute_tool span. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("traceparent")] @@ -2516,21 +2521,21 @@ public partial class ExternalToolCompletedData /// Queued slash command dispatch request for client execution. public partial class CommandQueuedData { - /// Unique identifier for this request; used to respond via session.respondToQueuedCommand(). - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - /// The slash command text to be executed (e.g., /help, /clear). [JsonPropertyName("command")] public required string Command { get; set; } + + /// Unique identifier for this request; used to respond via session.respondToQueuedCommand(). + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } } /// Registered command dispatch request routed to the owning client. public partial class CommandExecuteData { - /// Unique identifier; used to respond via session.commands.handlePendingCommand(). - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } + /// Raw argument string after the command name. + [JsonPropertyName("args")] + public required string Args { get; set; } /// The full command text (e.g., /deploy production). [JsonPropertyName("command")] @@ -2540,9 +2545,9 @@ public partial class CommandExecuteData [JsonPropertyName("commandName")] public required string CommandName { get; set; } - /// Raw argument string after the command name. - [JsonPropertyName("args")] - public required string Args { get; set; } + /// Unique identifier; used to respond via session.commands.handlePendingCommand(). + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } } /// Queued command completion notification signaling UI dismissal. @@ -2573,44 +2578,35 @@ public partial class CapabilitiesChangedData /// Plan approval request with plan content and available user actions. public partial class ExitPlanModeRequestedData { - /// Unique identifier for this request; used to respond via session.respondToExitPlanMode(). - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - - /// Summary of the plan that was created. - [JsonPropertyName("summary")] - public required string Summary { get; set; } + /// Available actions the user can take (e.g., approve, edit, reject). + [JsonPropertyName("actions")] + public required string[] Actions { get; set; } /// Full content of the plan file. [JsonPropertyName("planContent")] public required string PlanContent { get; set; } - /// Available actions the user can take (e.g., approve, edit, reject). - [JsonPropertyName("actions")] - public required string[] Actions { get; set; } - /// The recommended action for the user to take. [JsonPropertyName("recommendedAction")] public required string RecommendedAction { get; set; } + + /// Unique identifier for this request; used to respond via session.respondToExitPlanMode(). + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } + + /// Summary of the plan that was created. + [JsonPropertyName("summary")] + public required string Summary { get; set; } } /// Plan mode exit completion with the user's approval decision and optional feedback. public partial class ExitPlanModeCompletedData { - /// Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request. - [JsonPropertyName("requestId")] - public required string RequestId { get; set; } - /// Whether the plan was approved by the user. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("approved")] public bool? Approved { get; set; } - /// Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only'). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("selectedAction")] - public string? SelectedAction { get; set; } - /// Whether edits should be auto-approved without confirmation. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("autoApproveEdits")] @@ -2620,6 +2616,15 @@ public partial class ExitPlanModeCompletedData [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("feedback")] public string? Feedback { get; set; } + + /// Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request. + [JsonPropertyName("requestId")] + public required string RequestId { get; set; } + + /// Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only'). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("selectedAction")] + public string? SelectedAction { get; set; } } /// Event payload for . @@ -2650,13 +2655,13 @@ public partial class SessionCustomAgentsUpdatedData [JsonPropertyName("agents")] public required CustomAgentsUpdatedAgent[] Agents { get; set; } - /// Non-fatal warnings from agent loading. - [JsonPropertyName("warnings")] - public required string[] Warnings { get; set; } - /// Fatal errors from agent loading. [JsonPropertyName("errors")] public required string[] Errors { get; set; } + + /// Non-fatal warnings from agent loading. + [JsonPropertyName("warnings")] + public required string[] Warnings { get; set; } } /// Event payload for . @@ -2691,6 +2696,16 @@ public partial class SessionExtensionsLoadedData /// Nested data type for WorkingDirectoryContext. public partial class WorkingDirectoryContext { + /// Base commit of current git branch at session start time. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("baseCommit")] + public string? BaseCommit { get; set; } + + /// Current git branch name. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("branch")] + public string? Branch { get; set; } + /// Current working directory path. [JsonPropertyName("cwd")] public required string Cwd { get; set; } @@ -2700,54 +2715,53 @@ public partial class WorkingDirectoryContext [JsonPropertyName("gitRoot")] public string? GitRoot { get; set; } - /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). + /// Head commit of current git branch at session start time. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("repository")] - public string? Repository { get; set; } + [JsonPropertyName("headCommit")] + public string? HeadCommit { get; set; } /// Hosting platform type of the repository (github or ado). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("hostType")] public WorkingDirectoryContextHostType? HostType { get; set; } - /// Current git branch name. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Head commit of current git branch at session start time. + /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("headCommit")] - public string? HeadCommit { get; set; } + [JsonPropertyName("repository")] + public string? Repository { get; set; } - /// Base commit of current git branch at session start time. + /// Raw host string from the git remote URL (e.g. "github.com", "mycompany.ghe.com", "dev.azure.com"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("baseCommit")] - public string? BaseCommit { get; set; } + [JsonPropertyName("repositoryHost")] + public string? RepositoryHost { get; set; } } /// Repository context for the handed-off session. /// Nested data type for HandoffRepository. public partial class HandoffRepository { - /// Repository owner (user or organization). - [JsonPropertyName("owner")] - public required string Owner { get; set; } + /// Git branch name, if applicable. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("branch")] + public string? Branch { get; set; } /// Repository name. [JsonPropertyName("name")] public required string Name { get; set; } - /// Git branch name, if applicable. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("branch")] - public string? Branch { get; set; } + /// Repository owner (user or organization). + [JsonPropertyName("owner")] + public required string Owner { get; set; } } /// Aggregate code change metrics for the session. /// Nested data type for ShutdownCodeChanges. public partial class ShutdownCodeChanges { + /// List of file paths that were modified during the session. + [JsonPropertyName("filesModified")] + public required string[] FilesModified { get; set; } + /// Total number of lines added during the session. [JsonPropertyName("linesAdded")] public required double LinesAdded { get; set; } @@ -2755,16 +2769,67 @@ public partial class ShutdownCodeChanges /// Total number of lines removed during the session. [JsonPropertyName("linesRemoved")] public required double LinesRemoved { get; set; } +} - /// List of file paths that were modified during the session. - [JsonPropertyName("filesModified")] - public required string[] FilesModified { get; set; } +/// Request count and cost metrics. +/// Nested data type for ShutdownModelMetricRequests. +public partial class ShutdownModelMetricRequests +{ + /// Cumulative cost multiplier for requests to this model. + [JsonPropertyName("cost")] + public required double Cost { get; set; } + + /// Total number of API requests made to this model. + [JsonPropertyName("count")] + public required double Count { get; set; } +} + +/// Token usage breakdown. +/// Nested data type for ShutdownModelMetricUsage. +public partial class ShutdownModelMetricUsage +{ + /// Total tokens read from prompt cache across all requests. + [JsonPropertyName("cacheReadTokens")] + public required double CacheReadTokens { get; set; } + + /// Total tokens written to prompt cache across all requests. + [JsonPropertyName("cacheWriteTokens")] + public required double CacheWriteTokens { get; set; } + + /// Total input tokens consumed across all requests to this model. + [JsonPropertyName("inputTokens")] + public required double InputTokens { get; set; } + + /// Total output tokens produced across all requests to this model. + [JsonPropertyName("outputTokens")] + public required double OutputTokens { get; set; } + + /// Total reasoning tokens produced across all requests to this model. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningTokens")] + public double? ReasoningTokens { get; set; } +} + +/// Nested data type for ShutdownModelMetric. +public partial class ShutdownModelMetric +{ + /// Request count and cost metrics. + [JsonPropertyName("requests")] + public required ShutdownModelMetricRequests Requests { get; set; } + + /// Token usage breakdown. + [JsonPropertyName("usage")] + public required ShutdownModelMetricUsage Usage { get; set; } } /// Token usage breakdown for the compaction LLM call. /// Nested data type for CompactionCompleteCompactionTokensUsed. public partial class CompactionCompleteCompactionTokensUsed { + /// Cached input tokens reused in the compaction LLM call. + [JsonPropertyName("cachedInput")] + public required double CachedInput { get; set; } + /// Input tokens consumed by the compaction LLM call. [JsonPropertyName("input")] public required double Input { get; set; } @@ -2772,23 +2837,19 @@ public partial class CompactionCompleteCompactionTokensUsed /// Output tokens produced by the compaction LLM call. [JsonPropertyName("output")] public required double Output { get; set; } - - /// Cached input tokens reused in the compaction LLM call. - [JsonPropertyName("cachedInput")] - public required double CachedInput { get; set; } } /// Optional line range to scope the attachment to a specific section of the file. /// Nested data type for UserMessageAttachmentFileLineRange. public partial class UserMessageAttachmentFileLineRange { - /// Start line number (1-based). - [JsonPropertyName("start")] - public required double Start { get; set; } - /// End line number (1-based, inclusive). [JsonPropertyName("end")] public required double End { get; set; } + + /// Start line number (1-based). + [JsonPropertyName("start")] + public required double Start { get; set; } } /// File attachment. @@ -2799,10 +2860,6 @@ public partial class UserMessageAttachmentFile : UserMessageAttachment [JsonIgnore] public override string Type => "file"; - /// Absolute file path. - [JsonPropertyName("path")] - public required string Path { get; set; } - /// User-facing display name for the attachment. [JsonPropertyName("displayName")] public required string DisplayName { get; set; } @@ -2811,6 +2868,10 @@ public partial class UserMessageAttachmentFile : UserMessageAttachment [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("lineRange")] public UserMessageAttachmentFileLineRange? LineRange { get; set; } + + /// Absolute file path. + [JsonPropertyName("path")] + public required string Path { get; set; } } /// Directory attachment. @@ -2821,52 +2882,52 @@ public partial class UserMessageAttachmentDirectory : UserMessageAttachment [JsonIgnore] public override string Type => "directory"; - /// Absolute directory path. - [JsonPropertyName("path")] - public required string Path { get; set; } - /// User-facing display name for the attachment. [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } -} - -/// Start position of the selection. -/// Nested data type for UserMessageAttachmentSelectionDetailsStart. -public partial class UserMessageAttachmentSelectionDetailsStart -{ - /// Start line number (0-based). - [JsonPropertyName("line")] - public required double Line { get; set; } + public required string DisplayName { get; set; } - /// Start character offset within the line (0-based). - [JsonPropertyName("character")] - public required double Character { get; set; } + /// Absolute directory path. + [JsonPropertyName("path")] + public required string Path { get; set; } } /// End position of the selection. /// Nested data type for UserMessageAttachmentSelectionDetailsEnd. public partial class UserMessageAttachmentSelectionDetailsEnd { + /// End character offset within the line (0-based). + [JsonPropertyName("character")] + public required double Character { get; set; } + /// End line number (0-based). [JsonPropertyName("line")] public required double Line { get; set; } +} - /// End character offset within the line (0-based). +/// Start position of the selection. +/// Nested data type for UserMessageAttachmentSelectionDetailsStart. +public partial class UserMessageAttachmentSelectionDetailsStart +{ + /// Start character offset within the line (0-based). [JsonPropertyName("character")] public required double Character { get; set; } + + /// Start line number (0-based). + [JsonPropertyName("line")] + public required double Line { get; set; } } /// Position range of the selection within the file. /// Nested data type for UserMessageAttachmentSelectionDetails. public partial class UserMessageAttachmentSelectionDetails { - /// Start position of the selection. - [JsonPropertyName("start")] - public required UserMessageAttachmentSelectionDetailsStart Start { get; set; } - /// End position of the selection. [JsonPropertyName("end")] public required UserMessageAttachmentSelectionDetailsEnd End { get; set; } + + /// Start position of the selection. + [JsonPropertyName("start")] + public required UserMessageAttachmentSelectionDetailsStart Start { get; set; } } /// Code selection attachment from an editor. @@ -2877,21 +2938,21 @@ public partial class UserMessageAttachmentSelection : UserMessageAttachment [JsonIgnore] public override string Type => "selection"; - /// Absolute path to the file containing the selection. - [JsonPropertyName("filePath")] - public required string FilePath { get; set; } - /// User-facing display name for the selection. [JsonPropertyName("displayName")] public required string DisplayName { get; set; } - /// The selected text content. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Absolute path to the file containing the selection. + [JsonPropertyName("filePath")] + public required string FilePath { get; set; } /// Position range of the selection within the file. [JsonPropertyName("selection")] public required UserMessageAttachmentSelectionDetails Selection { get; set; } + + /// The selected text content. + [JsonPropertyName("text")] + public required string Text { get; set; } } /// GitHub issue, pull request, or discussion reference. @@ -2906,10 +2967,6 @@ public partial class UserMessageAttachmentGithubReference : UserMessageAttachmen [JsonPropertyName("number")] public required double Number { get; set; } - /// Title of the referenced item. - [JsonPropertyName("title")] - public required string Title { get; set; } - /// Type of GitHub reference. [JsonPropertyName("referenceType")] public required UserMessageAttachmentGithubReferenceType ReferenceType { get; set; } @@ -2918,6 +2975,10 @@ public partial class UserMessageAttachmentGithubReference : UserMessageAttachmen [JsonPropertyName("state")] public required string State { get; set; } + /// Title of the referenced item. + [JsonPropertyName("title")] + public required string Title { get; set; } + /// URL to the referenced item on GitHub. [JsonPropertyName("url")] public required string Url { get; set; } @@ -2936,14 +2997,14 @@ public partial class UserMessageAttachmentBlob : UserMessageAttachment [JsonPropertyName("data")] public required string Data { get; set; } - /// MIME type of the inline data. - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } - /// User-facing display name for the attachment. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("displayName")] public string? DisplayName { get; set; } + + /// MIME type of the inline data. + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } } /// A user message attachment — a file, directory, code selection, blob, or GitHub reference. @@ -2968,38 +3029,38 @@ public partial class UserMessageAttachment /// Nested data type for AssistantMessageToolRequest. public partial class AssistantMessageToolRequest { - /// Unique identifier for this tool call. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } - - /// Name of the tool being invoked. - [JsonPropertyName("name")] - public required string Name { get; set; } - /// Arguments to pass to the tool, format depends on the tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("arguments")] public object? Arguments { get; set; } - /// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("type")] - public AssistantMessageToolRequestType? Type { get; set; } - - /// Human-readable display title for the tool. + /// Resolved intention summary describing what this specific call does. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolTitle")] - public string? ToolTitle { get; set; } + [JsonPropertyName("intentionSummary")] + public string? IntentionSummary { get; set; } /// Name of the MCP server hosting this tool, when the tool is an MCP tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("mcpServerName")] public string? McpServerName { get; set; } - /// Resolved intention summary describing what this specific call does. + /// Name of the tool being invoked. + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// Unique identifier for this tool call. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } + + /// Human-readable display title for the tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("intentionSummary")] - public string? IntentionSummary { get; set; } + [JsonPropertyName("toolTitle")] + public string? ToolTitle { get; set; } + + /// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("type")] + public AssistantMessageToolRequestType? Type { get; set; } } /// Token usage detail for a single billing category. @@ -3036,6 +3097,57 @@ public partial class AssistantUsageCopilotUsage public required double TotalNanoAiu { get; set; } } +/// Nested data type for AssistantUsageQuotaSnapshot. +public partial class AssistantUsageQuotaSnapshot +{ + /// Total requests allowed by the entitlement. + [JsonPropertyName("entitlementRequests")] + public required double EntitlementRequests { get; set; } + + /// Whether the user has an unlimited usage entitlement. + [JsonPropertyName("isUnlimitedEntitlement")] + public required bool IsUnlimitedEntitlement { get; set; } + + /// Number of requests over the entitlement limit. + [JsonPropertyName("overage")] + public required double Overage { get; set; } + + /// Whether overage is allowed when quota is exhausted. + [JsonPropertyName("overageAllowedWithExhaustedQuota")] + public required bool OverageAllowedWithExhaustedQuota { get; set; } + + /// Percentage of quota remaining (0.0 to 1.0). + [JsonPropertyName("remainingPercentage")] + public required double RemainingPercentage { get; set; } + + /// Date when the quota resets. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resetDate")] + public DateTimeOffset? ResetDate { get; set; } + + /// Whether usage is still permitted after quota exhaustion. + [JsonPropertyName("usageAllowedWithExhaustedQuota")] + public required bool UsageAllowedWithExhaustedQuota { get; set; } + + /// Number of requests already consumed. + [JsonPropertyName("usedRequests")] + public required double UsedRequests { get; set; } +} + +/// Error details when the tool execution failed. +/// Nested data type for ToolExecutionCompleteError. +public partial class ToolExecutionCompleteError +{ + /// Machine-readable error code. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("code")] + public string? Code { get; set; } + + /// Human-readable error message. + [JsonPropertyName("message")] + public required string Message { get; set; } +} + /// Plain text content block. /// The text variant of . public partial class ToolExecutionCompleteContentText : ToolExecutionCompleteContent @@ -3057,19 +3169,19 @@ public partial class ToolExecutionCompleteContentTerminal : ToolExecutionComplet [JsonIgnore] public override string Type => "terminal"; - /// Terminal/shell output text. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Working directory where the command was executed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } /// Process exit code, if the command has completed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("exitCode")] public double? ExitCode { get; set; } - /// Working directory where the command was executed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Terminal/shell output text. + [JsonPropertyName("text")] + public required string Text { get; set; } } /// Image content block with base64-encoded data. @@ -3112,10 +3224,6 @@ public partial class ToolExecutionCompleteContentAudio : ToolExecutionCompleteCo /// Nested data type for ToolExecutionCompleteContentResourceLinkIcon. public partial class ToolExecutionCompleteContentResourceLinkIcon { - /// URL or path to the icon image. - [JsonPropertyName("src")] - public required string Src { get; set; } - /// MIME type of the icon image. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("mimeType")] @@ -3126,6 +3234,10 @@ public partial class ToolExecutionCompleteContentResourceLinkIcon [JsonPropertyName("sizes")] public string[]? Sizes { get; set; } + /// URL or path to the icon image. + [JsonPropertyName("src")] + public required string Src { get; set; } + /// Theme variant this icon is intended for. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("theme")] @@ -3140,15 +3252,30 @@ public partial class ToolExecutionCompleteContentResourceLink : ToolExecutionCom [JsonIgnore] public override string Type => "resource_link"; + /// Human-readable description of the resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + /// Icons associated with this resource. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("icons")] public ToolExecutionCompleteContentResourceLinkIcon[]? Icons { get; set; } + /// MIME type of the resource content. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + /// Resource name identifier. [JsonPropertyName("name")] public required string Name { get; set; } + /// Size of the resource in bytes. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("size")] + public double? Size { get; set; } + /// Human-readable display title for the resource. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("title")] @@ -3157,21 +3284,6 @@ public partial class ToolExecutionCompleteContentResourceLink : ToolExecutionCom /// URI identifying the resource. [JsonPropertyName("uri")] public required string Uri { get; set; } - - /// Human-readable description of the resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// MIME type of the resource content. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } - - /// Size of the resource in bytes. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("size")] - public double? Size { get; set; } } /// Embedded resource content block with inline text or binary data. @@ -3214,29 +3326,15 @@ public partial class ToolExecutionCompleteResult [JsonPropertyName("content")] public required string Content { get; set; } - /// Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("detailedContent")] - public string? DetailedContent { get; set; } - /// Structured content blocks (text, images, audio, resources) returned by the tool in their native format. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("contents")] public ToolExecutionCompleteContent[]? Contents { get; set; } -} - -/// Error details when the tool execution failed. -/// Nested data type for ToolExecutionCompleteError. -public partial class ToolExecutionCompleteError -{ - /// Human-readable error message. - [JsonPropertyName("message")] - public required string Message { get; set; } - /// Machine-readable error code. + /// Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("code")] - public string? Code { get; set; } + [JsonPropertyName("detailedContent")] + public string? DetailedContent { get; set; } } /// Error details when the hook failed. @@ -3283,10 +3381,6 @@ public partial class SystemNotificationAgentCompleted : SystemNotification [JsonPropertyName("agentType")] public required string AgentType { get; set; } - /// Whether the agent completed successfully or failed. - [JsonPropertyName("status")] - public required SystemNotificationAgentCompletedStatus Status { get; set; } - /// Human-readable description of the agent task. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("description")] @@ -3296,6 +3390,10 @@ public partial class SystemNotificationAgentCompleted : SystemNotification [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("prompt")] public string? Prompt { get; set; } + + /// Whether the agent completed successfully or failed. + [JsonPropertyName("status")] + public required SystemNotificationAgentCompletedStatus Status { get; set; } } /// The agent_idle variant of . @@ -3319,6 +3417,30 @@ public partial class SystemNotificationAgentIdle : SystemNotification public string? Description { get; set; } } +/// The new_inbox_message variant of . +public partial class SystemNotificationNewInboxMessage : SystemNotification +{ + /// + [JsonIgnore] + public override string Type => "new_inbox_message"; + + /// Unique identifier of the inbox entry. + [JsonPropertyName("entryId")] + public required string EntryId { get; set; } + + /// Human-readable name of the sender. + [JsonPropertyName("senderName")] + public required string SenderName { get; set; } + + /// Category of the sender (e.g., ambient-agent, plugin, hook). + [JsonPropertyName("senderType")] + public required string SenderType { get; set; } + + /// Short summary shown before the agent decides whether to read the inbox. + [JsonPropertyName("summary")] + public required string Summary { get; set; } +} + /// The shell_completed variant of . public partial class SystemNotificationShellCompleted : SystemNotification { @@ -3326,19 +3448,19 @@ public partial class SystemNotificationShellCompleted : SystemNotification [JsonIgnore] public override string Type => "shell_completed"; - /// Unique identifier of the shell session. - [JsonPropertyName("shellId")] - public required string ShellId { get; set; } + /// Human-readable description of the command. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } /// Exit code of the shell command, if available. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("exitCode")] public double? ExitCode { get; set; } - /// Human-readable description of the command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Unique identifier of the shell session. + [JsonPropertyName("shellId")] + public required string ShellId { get; set; } } /// The shell_detached_completed variant of . @@ -3348,14 +3470,14 @@ public partial class SystemNotificationShellDetachedCompleted : SystemNotificati [JsonIgnore] public override string Type => "shell_detached_completed"; - /// Unique identifier of the detached shell session. - [JsonPropertyName("shellId")] - public required string ShellId { get; set; } - /// Human-readable description of the command. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("description")] public string? Description { get; set; } + + /// Unique identifier of the detached shell session. + [JsonPropertyName("shellId")] + public required string ShellId { get; set; } } /// Structured metadata identifying what triggered this notification. @@ -3365,6 +3487,7 @@ public partial class SystemNotificationShellDetachedCompleted : SystemNotificati UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] [JsonDerivedType(typeof(SystemNotificationAgentCompleted), "agent_completed")] [JsonDerivedType(typeof(SystemNotificationAgentIdle), "agent_idle")] +[JsonDerivedType(typeof(SystemNotificationNewInboxMessage), "new_inbox_message")] [JsonDerivedType(typeof(SystemNotificationShellCompleted), "shell_completed")] [JsonDerivedType(typeof(SystemNotificationShellDetachedCompleted), "shell_detached_completed")] public partial class SystemNotification @@ -3403,22 +3526,25 @@ public partial class PermissionRequestShell : PermissionRequest [JsonIgnore] public override string Kind => "shell"; - /// Tool call ID that triggered this permission request. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + /// Whether the UI can offer session-wide approval for this command pattern. + [JsonPropertyName("canOfferSessionApproval")] + public required bool CanOfferSessionApproval { get; set; } + + /// Parsed command identifiers found in the command text. + [JsonPropertyName("commands")] + public required PermissionRequestShellCommand[] Commands { get; set; } /// The complete shell command text to be executed. [JsonPropertyName("fullCommandText")] public required string FullCommandText { get; set; } + /// Whether the command includes a file write redirection (e.g., > or >>). + [JsonPropertyName("hasWriteFileRedirection")] + public required bool HasWriteFileRedirection { get; set; } + /// Human-readable description of what the command intends to do. [JsonPropertyName("intention")] - public required string Intention { get; set; } - - /// Parsed command identifiers found in the command text. - [JsonPropertyName("commands")] - public required PermissionRequestShellCommand[] Commands { get; set; } + public required string Intention { get; set; } /// File paths that may be read or written by the command. [JsonPropertyName("possiblePaths")] @@ -3428,13 +3554,10 @@ public partial class PermissionRequestShell : PermissionRequest [JsonPropertyName("possibleUrls")] public required PermissionRequestShellPossibleUrl[] PossibleUrls { get; set; } - /// Whether the command includes a file write redirection (e.g., > or >>). - [JsonPropertyName("hasWriteFileRedirection")] - public required bool HasWriteFileRedirection { get; set; } - - /// Whether the UI can offer session-wide approval for this command pattern. - [JsonPropertyName("canOfferSessionApproval")] - public required bool CanOfferSessionApproval { get; set; } + /// Tool call ID that triggered this permission request. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } /// Optional warning message about risks of running this command. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -3450,31 +3573,31 @@ public partial class PermissionRequestWrite : PermissionRequest [JsonIgnore] public override string Kind => "write"; - /// Tool call ID that triggered this permission request. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + /// Whether the UI can offer session-wide approval for file write operations. + [JsonPropertyName("canOfferSessionApproval")] + public required bool CanOfferSessionApproval { get; set; } - /// Human-readable description of the intended file change. - [JsonPropertyName("intention")] - public required string Intention { get; set; } + /// Unified diff showing the proposed changes. + [JsonPropertyName("diff")] + public required string Diff { get; set; } /// Path of the file being written to. [JsonPropertyName("fileName")] public required string FileName { get; set; } - /// Unified diff showing the proposed changes. - [JsonPropertyName("diff")] - public required string Diff { get; set; } + /// Human-readable description of the intended file change. + [JsonPropertyName("intention")] + public required string Intention { get; set; } /// Complete new file contents for newly created files. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("newFileContents")] public string? NewFileContents { get; set; } - /// Whether the UI can offer session-wide approval for file write operations. - [JsonPropertyName("canOfferSessionApproval")] - public required bool CanOfferSessionApproval { get; set; } + /// Tool call ID that triggered this permission request. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } /// File or directory read permission request. @@ -3485,11 +3608,6 @@ public partial class PermissionRequestRead : PermissionRequest [JsonIgnore] public override string Kind => "read"; - /// Tool call ID that triggered this permission request. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } - /// Human-readable description of why the file is being read. [JsonPropertyName("intention")] public required string Intention { get; set; } @@ -3497,6 +3615,11 @@ public partial class PermissionRequestRead : PermissionRequest /// Path of the file or directory being read. [JsonPropertyName("path")] public required string Path { get; set; } + + /// Tool call ID that triggered this permission request. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } /// MCP tool invocation permission request. @@ -3507,15 +3630,24 @@ public partial class PermissionRequestMcp : PermissionRequest [JsonIgnore] public override string Kind => "mcp"; - /// Tool call ID that triggered this permission request. + /// Arguments to pass to the MCP tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + [JsonPropertyName("args")] + public object? Args { get; set; } + + /// Whether this MCP tool is read-only (no side effects). + [JsonPropertyName("readOnly")] + public required bool ReadOnly { get; set; } /// Name of the MCP server providing the tool. [JsonPropertyName("serverName")] public required string ServerName { get; set; } + /// Tool call ID that triggered this permission request. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } + /// Internal name of the MCP tool. [JsonPropertyName("toolName")] public required string ToolName { get; set; } @@ -3523,15 +3655,6 @@ public partial class PermissionRequestMcp : PermissionRequest /// Human-readable title of the MCP tool. [JsonPropertyName("toolTitle")] public required string ToolTitle { get; set; } - - /// Arguments to pass to the MCP tool. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("args")] - public object? Args { get; set; } - - /// Whether this MCP tool is read-only (no side effects). - [JsonPropertyName("readOnly")] - public required bool ReadOnly { get; set; } } /// URL access permission request. @@ -3542,15 +3665,15 @@ public partial class PermissionRequestUrl : PermissionRequest [JsonIgnore] public override string Kind => "url"; + /// Human-readable description of why the URL is being accessed. + [JsonPropertyName("intention")] + public required string Intention { get; set; } + /// Tool call ID that triggered this permission request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolCallId")] public string? ToolCallId { get; set; } - /// Human-readable description of why the URL is being accessed. - [JsonPropertyName("intention")] - public required string Intention { get; set; } - /// URL to be fetched. [JsonPropertyName("url")] public required string Url { get; set; } @@ -3564,25 +3687,11 @@ public partial class PermissionRequestMemory : PermissionRequest [JsonIgnore] public override string Kind => "memory"; - /// Tool call ID that triggered this permission request. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } - /// Whether this is a store or vote memory operation. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("action")] public PermissionRequestMemoryAction? Action { get; set; } - /// Topic or subject of the memory (store only). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("subject")] - public string? Subject { get; set; } - - /// The fact being stored or voted on. - [JsonPropertyName("fact")] - public required string Fact { get; set; } - /// Source references for the stored fact (store only). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("citations")] @@ -3593,10 +3702,24 @@ public partial class PermissionRequestMemory : PermissionRequest [JsonPropertyName("direction")] public PermissionRequestMemoryDirection? Direction { get; set; } + /// The fact being stored or voted on. + [JsonPropertyName("fact")] + public required string Fact { get; set; } + /// Reason for the vote (vote only). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reason")] public string? Reason { get; set; } + + /// Topic or subject of the memory (store only). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("subject")] + public string? Subject { get; set; } + + /// Tool call ID that triggered this permission request. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } /// Custom tool invocation permission request. @@ -3607,23 +3730,23 @@ public partial class PermissionRequestCustomTool : PermissionRequest [JsonIgnore] public override string Kind => "custom-tool"; + /// Arguments to pass to the custom tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("args")] + public object? Args { get; set; } + /// Tool call ID that triggered this permission request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolCallId")] public string? ToolCallId { get; set; } - /// Name of the custom tool. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } - /// Description of what the custom tool does. [JsonPropertyName("toolDescription")] public required string ToolDescription { get; set; } - /// Arguments to pass to the custom tool. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("args")] - public object? Args { get; set; } + /// Name of the custom tool. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } /// Hook confirmation permission request. @@ -3634,24 +3757,24 @@ public partial class PermissionRequestHook : PermissionRequest [JsonIgnore] public override string Kind => "hook"; - /// Tool call ID that triggered this permission request. + /// Optional message from the hook explaining why confirmation is needed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } - - /// Name of the tool the hook is gating. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } + [JsonPropertyName("hookMessage")] + public string? HookMessage { get; set; } /// Arguments of the tool call being gated. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolArgs")] public object? ToolArgs { get; set; } - /// Optional message from the hook explaining why confirmation is needed. + /// Tool call ID that triggered this permission request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("hookMessage")] - public string? HookMessage { get; set; } + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } + + /// Name of the tool the hook is gating. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } /// Details of the permission being requested. @@ -3688,10 +3811,6 @@ public partial class PermissionCompletedResult /// Nested data type for ElicitationRequestedSchema. public partial class ElicitationRequestedSchema { - /// Schema type indicator (always 'object'). - [JsonPropertyName("type")] - public required string Type { get; set; } - /// Form field definitions, keyed by field name. [JsonPropertyName("properties")] public required IDictionary Properties { get; set; } @@ -3700,6 +3819,10 @@ public partial class ElicitationRequestedSchema [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("required")] public string[]? Required { get; set; } + + /// Schema type indicator (always 'object'). + [JsonPropertyName("type")] + public required string Type { get; set; } } /// Static OAuth client configuration, if the server specifies one. @@ -3719,14 +3842,14 @@ public partial class McpOauthRequiredStaticClientConfig /// Nested data type for CommandsChangedCommand. public partial class CommandsChangedCommand { - /// Gets or sets the name value. - [JsonPropertyName("name")] - public required string Name { get; set; } - /// Gets or sets the description value. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("description")] public string? Description { get; set; } + + /// Gets or sets the name value. + [JsonPropertyName("name")] + public required string Name { get; set; } } /// UI capability changes. @@ -3742,51 +3865,56 @@ public partial class CapabilitiesChangedUI /// Nested data type for SkillsLoadedSkill. public partial class SkillsLoadedSkill { - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public required string Name { get; set; } - /// Description of what the skill does. [JsonPropertyName("description")] public required string Description { get; set; } - /// Source location type of the skill (e.g., project, personal, plugin). - [JsonPropertyName("source")] - public required string Source { get; set; } - - /// Whether the skill can be invoked by the user as a slash command. - [JsonPropertyName("userInvocable")] - public required bool UserInvocable { get; set; } - /// Whether the skill is currently enabled. [JsonPropertyName("enabled")] public required bool Enabled { get; set; } + /// Unique identifier for the skill. + [JsonPropertyName("name")] + public required string Name { get; set; } + /// Absolute path to the skill file, if available. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("path")] public string? Path { get; set; } + + /// Source location type of the skill (e.g., project, personal, plugin). + [JsonPropertyName("source")] + public required string Source { get; set; } + + /// Whether the skill can be invoked by the user as a slash command. + [JsonPropertyName("userInvocable")] + public required bool UserInvocable { get; set; } } /// Nested data type for CustomAgentsUpdatedAgent. public partial class CustomAgentsUpdatedAgent { + /// Description of what the agent does. + [JsonPropertyName("description")] + public required string Description { get; set; } + + /// Human-readable display name. + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } + /// Unique identifier for the agent. [JsonPropertyName("id")] public required string Id { get; set; } + /// Model override for this agent, if set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("model")] + public string? Model { get; set; } + /// Internal name of the agent. [JsonPropertyName("name")] public required string Name { get; set; } - /// Human-readable display name. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } - - /// Description of what the agent does. - [JsonPropertyName("description")] - public required string Description { get; set; } - /// Source location: user, project, inherited, remote, or plugin. [JsonPropertyName("source")] public required string Source { get; set; } @@ -3798,33 +3926,28 @@ public partial class CustomAgentsUpdatedAgent /// Whether the agent can be selected by the user. [JsonPropertyName("userInvocable")] public required bool UserInvocable { get; set; } - - /// Model override for this agent, if set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } } /// Nested data type for McpServersLoadedServer. public partial class McpServersLoadedServer { + /// Error message if the server failed to connect. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("error")] + public string? Error { get; set; } + /// Server name (config key). [JsonPropertyName("name")] public required string Name { get; set; } - /// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured. - [JsonPropertyName("status")] - public required McpServersLoadedServerStatus Status { get; set; } - /// Configuration source: user, workspace, plugin, or builtin. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("source")] public string? Source { get; set; } - /// Error message if the server failed to connect. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured. + [JsonPropertyName("status")] + public required McpServersLoadedServerStatus Status { get; set; } } /// Nested data type for ExtensionsLoadedExtension. @@ -3910,21 +4033,6 @@ public enum ShutdownType Error, } -/// Type of GitHub reference. -[JsonConverter(typeof(JsonStringEnumConverter))] -public enum UserMessageAttachmentGithubReferenceType -{ - /// The issue variant. - [JsonStringEnumMemberName("issue")] - Issue, - /// The pr variant. - [JsonStringEnumMemberName("pr")] - Pr, - /// The discussion variant. - [JsonStringEnumMemberName("discussion")] - Discussion, -} - /// The agent mode that was active when this message was sent. [JsonConverter(typeof(JsonStringEnumConverter))] public enum UserMessageAgentMode @@ -3943,6 +4051,21 @@ public enum UserMessageAgentMode Shell, } +/// Type of GitHub reference. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum UserMessageAttachmentGithubReferenceType +{ + /// The issue variant. + [JsonStringEnumMemberName("issue")] + Issue, + /// The pr variant. + [JsonStringEnumMemberName("pr")] + Pr, + /// The discussion variant. + [JsonStringEnumMemberName("discussion")] + Discussion, +} + /// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. [JsonConverter(typeof(JsonStringEnumConverter))] public enum AssistantMessageToolRequestType @@ -4172,6 +4295,7 @@ public enum ExtensionsLoadedExtensionStatus [JsonSerializable(typeof(AssistantUsageCopilotUsageTokenDetail))] [JsonSerializable(typeof(AssistantUsageData))] [JsonSerializable(typeof(AssistantUsageEvent))] +[JsonSerializable(typeof(AssistantUsageQuotaSnapshot))] [JsonSerializable(typeof(CapabilitiesChangedData))] [JsonSerializable(typeof(CapabilitiesChangedEvent))] [JsonSerializable(typeof(CapabilitiesChangedUI))] @@ -4292,6 +4416,9 @@ public enum ExtensionsLoadedExtensionStatus [JsonSerializable(typeof(SessionWorkspaceFileChangedData))] [JsonSerializable(typeof(SessionWorkspaceFileChangedEvent))] [JsonSerializable(typeof(ShutdownCodeChanges))] +[JsonSerializable(typeof(ShutdownModelMetric))] +[JsonSerializable(typeof(ShutdownModelMetricRequests))] +[JsonSerializable(typeof(ShutdownModelMetricUsage))] [JsonSerializable(typeof(SkillInvokedData))] [JsonSerializable(typeof(SkillInvokedEvent))] [JsonSerializable(typeof(SkillsLoadedSkill))] @@ -4313,6 +4440,7 @@ public enum ExtensionsLoadedExtensionStatus [JsonSerializable(typeof(SystemNotificationAgentIdle))] [JsonSerializable(typeof(SystemNotificationData))] [JsonSerializable(typeof(SystemNotificationEvent))] +[JsonSerializable(typeof(SystemNotificationNewInboxMessage))] [JsonSerializable(typeof(SystemNotificationShellCompleted))] [JsonSerializable(typeof(SystemNotificationShellDetachedCompleted))] [JsonSerializable(typeof(ToolExecutionCompleteContent))] diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs index 20d6525b8..455cecdba 100644 --- a/dotnet/src/Session.cs +++ b/dotnet/src/Session.cs @@ -607,15 +607,15 @@ private async Task ExecutePermissionAndRespondAsync(string requestId, Permission { return; } - await Rpc.Permissions.HandlePendingPermissionRequestAsync(requestId, result); + await Rpc.Permissions.HandlePendingPermissionRequestAsync(requestId, new PermissionDecision { Kind = result.Kind.Value }); } catch (Exception) { try { - await Rpc.Permissions.HandlePendingPermissionRequestAsync(requestId, new PermissionRequestResult + await Rpc.Permissions.HandlePendingPermissionRequestAsync(requestId, new PermissionDecision { - Kind = PermissionRequestResultKind.DeniedCouldNotRequestFromUser + Kind = PermissionRequestResultKind.DeniedCouldNotRequestFromUser.Value }); } catch (IOException) diff --git a/dotnet/src/SessionFsProvider.cs b/dotnet/src/SessionFsProvider.cs new file mode 100644 index 000000000..6007dd081 --- /dev/null +++ b/dotnet/src/SessionFsProvider.cs @@ -0,0 +1,216 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +using GitHub.Copilot.SDK.Rpc; + +namespace GitHub.Copilot.SDK; + +/// +/// Base class for session filesystem providers. Subclasses override the +/// virtual methods and use normal C# patterns (return values, throw exceptions). +/// The base class catches exceptions and converts them to +/// results expected by the runtime. +/// +public abstract class SessionFsProvider : ISessionFsHandler +{ + /// Reads the full content of a file. Throw if the file does not exist. + /// SessionFs-relative path. + /// Cancellation token. + /// The file content as a UTF-8 string. + protected abstract Task ReadFileAsync(string path, CancellationToken cancellationToken); + + /// Writes content to a file, creating it (and parent directories) if needed. + /// SessionFs-relative path. + /// Content to write. + /// Optional POSIX-style permission mode. Null means use OS default. + /// Cancellation token. + protected abstract Task WriteFileAsync(string path, string content, int? mode, CancellationToken cancellationToken); + + /// Appends content to a file, creating it (and parent directories) if needed. + /// SessionFs-relative path. + /// Content to append. + /// Optional POSIX-style permission mode. Null means use OS default. + /// Cancellation token. + protected abstract Task AppendFileAsync(string path, string content, int? mode, CancellationToken cancellationToken); + + /// Checks whether a path exists. + /// SessionFs-relative path. + /// Cancellation token. + /// true if the path exists, false otherwise. + protected abstract Task ExistsAsync(string path, CancellationToken cancellationToken); + + /// Gets metadata about a file or directory. Throw if the path does not exist. + /// SessionFs-relative path. + /// Cancellation token. + protected abstract Task StatAsync(string path, CancellationToken cancellationToken); + + /// Creates a directory (and optionally parents). Does not fail if it already exists. + /// SessionFs-relative path. + /// Whether to create parent directories. + /// Optional POSIX-style permission mode (e.g., 0x1FF for 0777). Null means use OS default. + /// Cancellation token. + protected abstract Task MkdirAsync(string path, bool recursive, int? mode, CancellationToken cancellationToken); + + /// Lists entry names in a directory. Throw if the directory does not exist. + /// SessionFs-relative path. + /// Cancellation token. + protected abstract Task> ReaddirAsync(string path, CancellationToken cancellationToken); + + /// Lists entries with type info in a directory. Throw if the directory does not exist. + /// SessionFs-relative path. + /// Cancellation token. + protected abstract Task> ReaddirWithTypesAsync(string path, CancellationToken cancellationToken); + + /// Removes a file or directory. Throw if the path does not exist (unless is true). + /// SessionFs-relative path. + /// Whether to remove directory contents recursively. + /// If true, do not throw when the path does not exist. + /// Cancellation token. + protected abstract Task RmAsync(string path, bool recursive, bool force, CancellationToken cancellationToken); + + /// Renames/moves a file or directory. + /// Source path. + /// Destination path. + /// Cancellation token. + protected abstract Task RenameAsync(string src, string dest, CancellationToken cancellationToken); + + // ---- ISessionFsHandler implementation (private, handles error mapping) ---- + + async Task ISessionFsHandler.ReadFileAsync(SessionFsReadFileRequest request, CancellationToken cancellationToken) + { + try + { + var content = await ReadFileAsync(request.Path, cancellationToken).ConfigureAwait(false); + return new SessionFsReadFileResult { Content = content }; + } + catch (Exception ex) + { + return new SessionFsReadFileResult { Error = ToSessionFsError(ex) }; + } + } + + async Task ISessionFsHandler.WriteFileAsync(SessionFsWriteFileRequest request, CancellationToken cancellationToken) + { + try + { + await WriteFileAsync(request.Path, request.Content, (int?)request.Mode, cancellationToken).ConfigureAwait(false); + return null; + } + catch (Exception ex) + { + return ToSessionFsError(ex); + } + } + + async Task ISessionFsHandler.AppendFileAsync(SessionFsAppendFileRequest request, CancellationToken cancellationToken) + { + try + { + await AppendFileAsync(request.Path, request.Content, (int?)request.Mode, cancellationToken).ConfigureAwait(false); + return null; + } + catch (Exception ex) + { + return ToSessionFsError(ex); + } + } + + async Task ISessionFsHandler.ExistsAsync(SessionFsExistsRequest request, CancellationToken cancellationToken) + { + try + { + var exists = await ExistsAsync(request.Path, cancellationToken).ConfigureAwait(false); + return new SessionFsExistsResult { Exists = exists }; + } + catch + { + return new SessionFsExistsResult { Exists = false }; + } + } + + async Task ISessionFsHandler.StatAsync(SessionFsStatRequest request, CancellationToken cancellationToken) + { + try + { + return await StatAsync(request.Path, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + return new SessionFsStatResult { Error = ToSessionFsError(ex) }; + } + } + + async Task ISessionFsHandler.MkdirAsync(SessionFsMkdirRequest request, CancellationToken cancellationToken) + { + try + { + await MkdirAsync(request.Path, request.Recursive ?? false, (int?)request.Mode, cancellationToken).ConfigureAwait(false); + return null; + } + catch (Exception ex) + { + return ToSessionFsError(ex); + } + } + + async Task ISessionFsHandler.ReaddirAsync(SessionFsReaddirRequest request, CancellationToken cancellationToken) + { + try + { + var entries = await ReaddirAsync(request.Path, cancellationToken).ConfigureAwait(false); + return new SessionFsReaddirResult { Entries = entries }; + } + catch (Exception ex) + { + return new SessionFsReaddirResult { Error = ToSessionFsError(ex) }; + } + } + + async Task ISessionFsHandler.ReaddirWithTypesAsync(SessionFsReaddirWithTypesRequest request, CancellationToken cancellationToken) + { + try + { + var entries = await ReaddirWithTypesAsync(request.Path, cancellationToken).ConfigureAwait(false); + return new SessionFsReaddirWithTypesResult { Entries = entries }; + } + catch (Exception ex) + { + return new SessionFsReaddirWithTypesResult { Error = ToSessionFsError(ex) }; + } + } + + async Task ISessionFsHandler.RmAsync(SessionFsRmRequest request, CancellationToken cancellationToken) + { + try + { + await RmAsync(request.Path, request.Recursive ?? false, request.Force ?? false, cancellationToken).ConfigureAwait(false); + return null; + } + catch (Exception ex) + { + return ToSessionFsError(ex); + } + } + + async Task ISessionFsHandler.RenameAsync(SessionFsRenameRequest request, CancellationToken cancellationToken) + { + try + { + await RenameAsync(request.Src, request.Dest, cancellationToken).ConfigureAwait(false); + return null; + } + catch (Exception ex) + { + return ToSessionFsError(ex); + } + } + + private static SessionFsError ToSessionFsError(Exception ex) + { + var code = ex is FileNotFoundException or DirectoryNotFoundException + ? SessionFsErrorCode.ENOENT + : SessionFsErrorCode.UNKNOWN; + return new SessionFsError { Code = code, Message = ex.Message }; + } +} diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index fd42d0c27..fe952c8c4 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -1909,7 +1909,7 @@ protected SessionConfig(SessionConfig? other) /// Supplies a handler for session filesystem operations. /// This is used only when is configured. /// - public Func? CreateSessionFsHandler { get; set; } + public Func? CreateSessionFsHandler { get; set; } /// /// Creates a shallow clone of this instance. @@ -2148,7 +2148,7 @@ protected ResumeSessionConfig(ResumeSessionConfig? other) /// Supplies a handler for session filesystem operations. /// This is used only when is configured. /// - public Func? CreateSessionFsHandler { get; set; } + public Func? CreateSessionFsHandler { get; set; } /// /// Creates a shallow clone of this instance. diff --git a/dotnet/test/CompactionTests.cs b/dotnet/test/CompactionTests.cs index c1cbc42df..f70bf5ecb 100644 --- a/dotnet/test/CompactionTests.cs +++ b/dotnet/test/CompactionTests.cs @@ -11,7 +11,7 @@ namespace GitHub.Copilot.SDK.Test; public class CompactionTests(E2ETestFixture fixture, ITestOutputHelper output) : E2ETestBase(fixture, "compaction", output) { - [Fact] + [Fact(Skip = "Compaction tests are skipped due to flakiness — re-enable once stabilized")] public async Task Should_Trigger_Compaction_With_Low_Threshold_And_Emit_Events() { // Create session with very low compaction thresholds to trigger compaction quickly @@ -81,7 +81,7 @@ await session.SendAndWaitAsync(new MessageOptions Assert.Contains("dragon", answer.Data.Content.ToLower()); } - [Fact] + [Fact(Skip = "Compaction tests are skipped due to flakiness — re-enable once stabilized")] public async Task Should_Not_Emit_Compaction_Events_When_Infinite_Sessions_Disabled() { var session = await CreateSessionAsync(new SessionConfig diff --git a/dotnet/test/Harness/E2ETestBase.cs b/dotnet/test/Harness/E2ETestBase.cs index d1756ea61..46162b50f 100644 --- a/dotnet/test/Harness/E2ETestBase.cs +++ b/dotnet/test/Harness/E2ETestBase.cs @@ -5,6 +5,7 @@ using System.Data; using System.Reflection; using GitHub.Copilot.SDK.Test.Harness; +using Microsoft.Extensions.Logging; using Xunit; using Xunit.Abstractions; @@ -24,6 +25,26 @@ protected E2ETestBase(E2ETestFixture fixture, string snapshotCategory, ITestOutp _fixture = fixture; _snapshotCategory = snapshotCategory; _testName = GetTestName(output); + Logger = new XunitLogger(output); + + // Wire logger into the shared context so all clients created via Ctx.CreateClient get it. + Ctx.Logger = Logger; + } + + /// Logger that forwards warnings and above to xunit test output. + protected ILogger Logger { get; } + + /// Bridges to xunit's . + private sealed class XunitLogger(ITestOutputHelper output) : ILogger + { + public IDisposable? BeginScope(TState state) where TState : notnull => null; + public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Warning; + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + { + if (!IsEnabled(logLevel)) return; + try { output.WriteLine($"[{logLevel}] {formatter(state, exception)}"); } + catch (InvalidOperationException) { /* test already finished */ } + } } private static string GetTestName(ITestOutputHelper output) diff --git a/dotnet/test/Harness/E2ETestContext.cs b/dotnet/test/Harness/E2ETestContext.cs index 47c8b2c4d..7b47ab0b7 100644 --- a/dotnet/test/Harness/E2ETestContext.cs +++ b/dotnet/test/Harness/E2ETestContext.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using System.Text.RegularExpressions; +using Microsoft.Extensions.Logging; namespace GitHub.Copilot.SDK.Test.Harness; @@ -13,6 +14,9 @@ public sealed class E2ETestContext : IAsyncDisposable public string WorkDir { get; } public string ProxyUrl { get; } + /// Optional logger injected by tests; applied to all clients created via . + public ILogger? Logger { get; set; } + private readonly CapiProxy _proxy; private readonly string _repoRoot; @@ -99,6 +103,7 @@ public CopilotClient CreateClient(bool useStdio = true, CopilotClientOptions? op options.Cwd ??= WorkDir; options.Environment ??= GetEnvironment(); options.UseStdio = useStdio; + options.Logger ??= Logger; if (string.IsNullOrEmpty(options.CliUrl)) { diff --git a/dotnet/test/SessionEventSerializationTests.cs b/dotnet/test/SessionEventSerializationTests.cs index 476867a4d..93e5ae935 100644 --- a/dotnet/test/SessionEventSerializationTests.cs +++ b/dotnet/test/SessionEventSerializationTests.cs @@ -93,22 +93,19 @@ public class SessionEventSerializationTests LinesRemoved = 0, FilesModified = ["README.md"], }, - ModelMetrics = new Dictionary + ModelMetrics = new Dictionary { - ["gpt-5.4"] = ParseJsonElement(""" + ["gpt-5.4"] = new ShutdownModelMetric + { + Requests = new ShutdownModelMetricRequests { Count = 1, Cost = 1 }, + Usage = new ShutdownModelMetricUsage { - "requests": { - "count": 1, - "cost": 1 - }, - "usage": { - "inputTokens": 10, - "outputTokens": 5, - "cacheReadTokens": 0, - "cacheWriteTokens": 0 - } - } - """), + InputTokens = 10, + OutputTokens = 5, + CacheReadTokens = 0, + CacheWriteTokens = 0, + }, + }, }, CurrentModel = "gpt-5.4", }, diff --git a/dotnet/test/SessionFsTests.cs b/dotnet/test/SessionFsTests.cs index 8c55b1120..1d0e6d2e5 100644 --- a/dotnet/test/SessionFsTests.cs +++ b/dotnet/test/SessionFsTests.cs @@ -56,7 +56,7 @@ public async Task Should_Load_Session_Data_From_Fs_Provider_On_Resume() try { await using var client = CreateSessionFsClient(providerRoot); - Func createSessionFsHandler = s => new TestSessionFsHandler(s.SessionId, providerRoot); + Func createSessionFsHandler = s => new TestSessionFsHandler(s.SessionId, providerRoot); var session1 = await client.CreateSessionAsync(new SessionConfig { @@ -95,7 +95,7 @@ public async Task Should_Reject_SetProvider_When_Sessions_Already_Exist() try { await using var client1 = CreateSessionFsClient(providerRoot, useStdio: false); - var createSessionFsHandler = (Func)(s => new TestSessionFsHandler(s.SessionId, providerRoot)); + var createSessionFsHandler = (Func)(s => new TestSessionFsHandler(s.SessionId, providerRoot)); _ = await client1.CreateSessionAsync(new SessionConfig { @@ -227,6 +227,70 @@ await WaitForConditionAsync(async () => } } + [Fact] + public async Task Should_Write_Workspace_Metadata_Via_SessionFs() + { + var providerRoot = CreateProviderRoot(); + try + { + await using var client = CreateSessionFsClient(providerRoot); + var session = await client.CreateSessionAsync(new SessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + CreateSessionFsHandler = s => new TestSessionFsHandler(s.SessionId, providerRoot), + }); + + var msg = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 7 * 8?" }); + Assert.Contains("56", msg?.Data.Content ?? string.Empty); + + // WorkspaceManager should have created workspace.yaml via sessionFs + var workspaceYamlPath = GetStoredPath(providerRoot, session.SessionId, "/session-state/workspace.yaml"); + await WaitForConditionAsync(() => File.Exists(workspaceYamlPath)); + var yaml = await ReadAllTextSharedAsync(workspaceYamlPath); + Assert.Contains("id:", yaml); + + // Checkpoint index should also exist + var indexPath = GetStoredPath(providerRoot, session.SessionId, "/session-state/checkpoints/index.md"); + await WaitForConditionAsync(() => File.Exists(indexPath)); + + await session.DisposeAsync(); + } + finally + { + await TryDeleteDirectoryAsync(providerRoot); + } + } + + [Fact] + public async Task Should_Persist_Plan_Md_Via_SessionFs() + { + var providerRoot = CreateProviderRoot(); + try + { + await using var client = CreateSessionFsClient(providerRoot); + var session = await client.CreateSessionAsync(new SessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + CreateSessionFsHandler = s => new TestSessionFsHandler(s.SessionId, providerRoot), + }); + + // Write a plan via the session RPC + await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2 + 3?" }); + await session.Rpc.Plan.UpdateAsync("# Test Plan\n\nThis is a test."); + + var planPath = GetStoredPath(providerRoot, session.SessionId, "/session-state/plan.md"); + await WaitForConditionAsync(() => File.Exists(planPath)); + var content = await ReadAllTextSharedAsync(planPath); + Assert.Contains("# Test Plan", content); + + await session.DisposeAsync(); + } + finally + { + await TryDeleteDirectoryAsync(providerRoot); + } + } + private CopilotClient CreateSessionFsClient(string providerRoot, bool useStdio = true) { Directory.CreateDirectory(providerRoot); @@ -367,40 +431,36 @@ private static string NormalizeRelativePathSegment(string segment, string paramN return normalized; } - private sealed class TestSessionFsHandler(string sessionId, string rootDir) : ISessionFsHandler + private sealed class TestSessionFsHandler(string sessionId, string rootDir) : SessionFsProvider { - public async Task ReadFileAsync(SessionFsReadFileRequest request, CancellationToken cancellationToken = default) + protected override async Task ReadFileAsync(string path, CancellationToken cancellationToken) { - var content = await File.ReadAllTextAsync(ResolvePath(request.Path), cancellationToken); - return new SessionFsReadFileResult { Content = content }; + return await File.ReadAllTextAsync(ResolvePath(path), cancellationToken); } - public async Task WriteFileAsync(SessionFsWriteFileRequest request, CancellationToken cancellationToken = default) + protected override async Task WriteFileAsync(string path, string content, int? mode, CancellationToken cancellationToken) { - var fullPath = ResolvePath(request.Path); + var fullPath = ResolvePath(path); Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!); - await File.WriteAllTextAsync(fullPath, request.Content, cancellationToken); + await File.WriteAllTextAsync(fullPath, content, cancellationToken); } - public async Task AppendFileAsync(SessionFsAppendFileRequest request, CancellationToken cancellationToken = default) + protected override async Task AppendFileAsync(string path, string content, int? mode, CancellationToken cancellationToken) { - var fullPath = ResolvePath(request.Path); + var fullPath = ResolvePath(path); Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!); - await File.AppendAllTextAsync(fullPath, request.Content, cancellationToken); + await File.AppendAllTextAsync(fullPath, content, cancellationToken); } - public Task ExistsAsync(SessionFsExistsRequest request, CancellationToken cancellationToken = default) + protected override Task ExistsAsync(string path, CancellationToken cancellationToken) { - var fullPath = ResolvePath(request.Path); - return Task.FromResult(new SessionFsExistsResult - { - Exists = File.Exists(fullPath) || Directory.Exists(fullPath), - }); + var fullPath = ResolvePath(path); + return Task.FromResult(File.Exists(fullPath) || Directory.Exists(fullPath)); } - public Task StatAsync(SessionFsStatRequest request, CancellationToken cancellationToken = default) + protected override Task StatAsync(string path, CancellationToken cancellationToken) { - var fullPath = ResolvePath(request.Path); + var fullPath = ResolvePath(path); if (File.Exists(fullPath)) { var info = new FileInfo(fullPath); @@ -417,7 +477,7 @@ public Task StatAsync(SessionFsStatRequest request, Cancell var dirInfo = new DirectoryInfo(fullPath); if (!dirInfo.Exists) { - throw new FileNotFoundException($"Path does not exist: {request.Path}"); + throw new DirectoryNotFoundException($"Path does not exist: {path}"); } return Task.FromResult(new SessionFsStatResult @@ -430,41 +490,39 @@ public Task StatAsync(SessionFsStatRequest request, Cancell }); } - public Task MkdirAsync(SessionFsMkdirRequest request, CancellationToken cancellationToken = default) + protected override Task MkdirAsync(string path, bool recursive, int? mode, CancellationToken cancellationToken) { - Directory.CreateDirectory(ResolvePath(request.Path)); + Directory.CreateDirectory(ResolvePath(path)); return Task.CompletedTask; } - public Task ReaddirAsync(SessionFsReaddirRequest request, CancellationToken cancellationToken = default) + protected override Task> ReaddirAsync(string path, CancellationToken cancellationToken) { - var entries = Directory - .EnumerateFileSystemEntries(ResolvePath(request.Path)) + IList entries = Directory + .EnumerateFileSystemEntries(ResolvePath(path)) .Select(Path.GetFileName) .Where(name => name is not null) .Cast() .ToList(); - - return Task.FromResult(new SessionFsReaddirResult { Entries = entries }); + return Task.FromResult(entries); } - public Task ReaddirWithTypesAsync(SessionFsReaddirWithTypesRequest request, CancellationToken cancellationToken = default) + protected override Task> ReaddirWithTypesAsync(string path, CancellationToken cancellationToken) { - var entries = Directory - .EnumerateFileSystemEntries(ResolvePath(request.Path)) - .Select(path => new SessionFsReaddirWithTypesEntry + IList entries = Directory + .EnumerateFileSystemEntries(ResolvePath(path)) + .Select(p => new SessionFsReaddirWithTypesEntry { - Name = Path.GetFileName(path), - Type = Directory.Exists(path) ? SessionFsReaddirWithTypesEntryType.Directory : SessionFsReaddirWithTypesEntryType.File, + Name = Path.GetFileName(p), + Type = Directory.Exists(p) ? SessionFsReaddirWithTypesEntryType.Directory : SessionFsReaddirWithTypesEntryType.File, }) .ToList(); - - return Task.FromResult(new SessionFsReaddirWithTypesResult { Entries = entries }); + return Task.FromResult(entries); } - public Task RmAsync(SessionFsRmRequest request, CancellationToken cancellationToken = default) + protected override Task RmAsync(string path, bool recursive, bool force, CancellationToken cancellationToken) { - var fullPath = ResolvePath(request.Path); + var fullPath = ResolvePath(path); if (File.Exists(fullPath)) { @@ -474,31 +532,31 @@ public Task RmAsync(SessionFsRmRequest request, CancellationToken cancellationTo if (Directory.Exists(fullPath)) { - Directory.Delete(fullPath, request.Recursive ?? false); + Directory.Delete(fullPath, recursive); return Task.CompletedTask; } - if (request.Force == true) + if (force) { return Task.CompletedTask; } - throw new FileNotFoundException($"Path does not exist: {request.Path}"); + throw new FileNotFoundException($"Path does not exist: {path}"); } - public Task RenameAsync(SessionFsRenameRequest request, CancellationToken cancellationToken = default) + protected override Task RenameAsync(string src, string dest, CancellationToken cancellationToken) { - var src = ResolvePath(request.Src); - var dest = ResolvePath(request.Dest); - Directory.CreateDirectory(Path.GetDirectoryName(dest)!); + var srcPath = ResolvePath(src); + var destPath = ResolvePath(dest); + Directory.CreateDirectory(Path.GetDirectoryName(destPath)!); - if (Directory.Exists(src)) + if (Directory.Exists(srcPath)) { - Directory.Move(src, dest); + Directory.Move(srcPath, destPath); } else { - File.Move(src, dest, overwrite: true); + File.Move(srcPath, destPath, overwrite: true); } return Task.CompletedTask; diff --git a/go/client.go b/go/client.go index 37e572dc8..feb31eeb8 100644 --- a/go/client.go +++ b/go/client.go @@ -675,7 +675,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses c.sessionsMux.Unlock() return nil, fmt.Errorf("CreateSessionFsHandler is required in session config when SessionFs is enabled in client options") } - session.clientSessionApis.SessionFs = config.CreateSessionFsHandler(session) + session.clientSessionApis.SessionFs = newSessionFsAdapter(config.CreateSessionFsHandler(session)) } result, err := c.client.Request("session.create", req) @@ -833,7 +833,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, c.sessionsMux.Unlock() return nil, fmt.Errorf("CreateSessionFsHandler is required in session config when SessionFs is enabled in client options") } - session.clientSessionApis.SessionFs = config.CreateSessionFsHandler(session) + session.clientSessionApis.SessionFs = newSessionFsAdapter(config.CreateSessionFsHandler(session)) } result, err := c.client.Request("session.resume", req) diff --git a/go/generated_session_events.go b/go/generated_session_events.go index 95ace9123..d0bbde414 100644 --- a/go/generated_session_events.go +++ b/go/generated_session_events.go @@ -620,1282 +620,1186 @@ const ( SessionEventTypeSessionExtensionsLoaded SessionEventType = "session.extensions_loaded" ) -// Session initialization metadata including context and configuration -type SessionStartData struct { - // Unique identifier for the session - SessionID string `json:"sessionId"` - // Schema version number for the session event format - Version float64 `json:"version"` - // Identifier of the software producing the events (e.g., "copilot-agent") - Producer string `json:"producer"` - // Version string of the Copilot application - CopilotVersion string `json:"copilotVersion"` - // ISO 8601 timestamp when the session was created - StartTime time.Time `json:"startTime"` - // Model selected at session creation time, if any - SelectedModel *string `json:"selectedModel,omitempty"` - // Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") - ReasoningEffort *string `json:"reasoningEffort,omitempty"` - // Working directory and git context at session start - Context *WorkingDirectoryContext `json:"context,omitempty"` - // Whether the session was already in use by another client at start time - AlreadyInUse *bool `json:"alreadyInUse,omitempty"` - // Whether this session supports remote steering via Mission Control - RemoteSteerable *bool `json:"remoteSteerable,omitempty"` +// Agent intent description for current activity or plan +type AssistantIntentData struct { + // Short description of what the agent is currently doing or planning to do + Intent string `json:"intent"` } -func (*SessionStartData) sessionEventData() {} +func (*AssistantIntentData) sessionEventData() {} -// Session resume metadata including current context and event count -type SessionResumeData struct { - // ISO 8601 timestamp when the session was resumed - ResumeTime time.Time `json:"resumeTime"` - // Total number of persisted events in the session at the time of resume - EventCount float64 `json:"eventCount"` - // Model currently selected at resume time - SelectedModel *string `json:"selectedModel,omitempty"` - // Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") - ReasoningEffort *string `json:"reasoningEffort,omitempty"` - // Updated working directory and git context at resume time - Context *WorkingDirectoryContext `json:"context,omitempty"` - // Whether the session was already in use by another client at resume time - AlreadyInUse *bool `json:"alreadyInUse,omitempty"` - // Whether this session supports remote steering via Mission Control - RemoteSteerable *bool `json:"remoteSteerable,omitempty"` +// Agent mode change details including previous and new modes +type SessionModeChangedData struct { + // Agent mode after the change (e.g., "interactive", "plan", "autopilot") + NewMode string `json:"newMode"` + // Agent mode before the change (e.g., "interactive", "plan", "autopilot") + PreviousMode string `json:"previousMode"` } -func (*SessionResumeData) sessionEventData() {} +func (*SessionModeChangedData) sessionEventData() {} -// Notifies Mission Control that the session's remote steering capability has changed -type SessionRemoteSteerableChangedData struct { - // Whether this session now supports remote steering via Mission Control - RemoteSteerable bool `json:"remoteSteerable"` +// Assistant reasoning content for timeline display with complete thinking text +type AssistantReasoningData struct { + // The complete extended thinking text from the model + Content string `json:"content"` + // Unique identifier for this reasoning block + ReasoningID string `json:"reasoningId"` } -func (*SessionRemoteSteerableChangedData) sessionEventData() {} +func (*AssistantReasoningData) sessionEventData() {} -// Error details for timeline display including message and optional diagnostic information -type SessionErrorData struct { - // Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") - ErrorType string `json:"errorType"` - // Human-readable error message - Message string `json:"message"` - // Error stack trace, when available - Stack *string `json:"stack,omitempty"` - // HTTP status code from the upstream request, if applicable - StatusCode *int64 `json:"statusCode,omitempty"` +// Assistant response containing text content, optional tool requests, and interaction metadata +type AssistantMessageData struct { + // The assistant's text response content + Content string `json:"content"` + // Encrypted reasoning content from OpenAI models. Session-bound and stripped on resume. + EncryptedContent *string `json:"encryptedContent,omitempty"` + // CAPI interaction ID for correlating this message with upstream telemetry + InteractionID *string `json:"interactionId,omitempty"` + // Unique identifier for this assistant message + MessageID string `json:"messageId"` + // Actual output token count from the API response (completion_tokens), used for accurate token accounting + OutputTokens *float64 `json:"outputTokens,omitempty"` + // Tool call ID of the parent tool invocation when this event originates from a sub-agent + // Deprecated: ParentToolCallID is deprecated. + ParentToolCallID *string `json:"parentToolCallId,omitempty"` + // Generation phase for phased-output models (e.g., thinking vs. response phases) + Phase *string `json:"phase,omitempty"` + // Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. + ReasoningOpaque *string `json:"reasoningOpaque,omitempty"` + // Readable reasoning text from the model's extended thinking + ReasoningText *string `json:"reasoningText,omitempty"` // GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs - ProviderCallID *string `json:"providerCallId,omitempty"` - // Optional URL associated with this error that the user can open in a browser - URL *string `json:"url,omitempty"` -} - -func (*SessionErrorData) sessionEventData() {} - -// Payload indicating the session is idle with no background agents in flight -type SessionIdleData struct { - // True when the preceding agentic loop was cancelled via abort signal - Aborted *bool `json:"aborted,omitempty"` + RequestID *string `json:"requestId,omitempty"` + // Tool invocations requested by the assistant in this message + ToolRequests []AssistantMessageToolRequest `json:"toolRequests,omitempty"` } -func (*SessionIdleData) sessionEventData() {} +func (*AssistantMessageData) sessionEventData() {} -// Session title change payload containing the new display title -type SessionTitleChangedData struct { - // The new display title for the session - Title string `json:"title"` +// Context window breakdown at the start of LLM-powered conversation compaction +type SessionCompactionStartData struct { + // Token count from non-system messages (user, assistant, tool) at compaction start + ConversationTokens *float64 `json:"conversationTokens,omitempty"` + // Token count from system message(s) at compaction start + SystemTokens *float64 `json:"systemTokens,omitempty"` + // Token count from tool definitions at compaction start + ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` } -func (*SessionTitleChangedData) sessionEventData() {} +func (*SessionCompactionStartData) sessionEventData() {} -// Informational message for timeline display with categorization -type SessionInfoData struct { - // Category of informational message (e.g., "notification", "timing", "context_window", "mcp", "snapshot", "configuration", "authentication", "model") - InfoType string `json:"infoType"` - // Human-readable informational message for display in the timeline - Message string `json:"message"` - // Optional URL associated with this message that the user can open in a browser - URL *string `json:"url,omitempty"` +// Conversation compaction results including success status, metrics, and optional error details +type SessionCompactionCompleteData struct { + // Checkpoint snapshot number created for recovery + CheckpointNumber *float64 `json:"checkpointNumber,omitempty"` + // File path where the checkpoint was stored + CheckpointPath *string `json:"checkpointPath,omitempty"` + // Token usage breakdown for the compaction LLM call + CompactionTokensUsed *CompactionCompleteCompactionTokensUsed `json:"compactionTokensUsed,omitempty"` + // Token count from non-system messages (user, assistant, tool) after compaction + ConversationTokens *float64 `json:"conversationTokens,omitempty"` + // Error message if compaction failed + Error *string `json:"error,omitempty"` + // Number of messages removed during compaction + MessagesRemoved *float64 `json:"messagesRemoved,omitempty"` + // Total tokens in conversation after compaction + PostCompactionTokens *float64 `json:"postCompactionTokens,omitempty"` + // Number of messages before compaction + PreCompactionMessagesLength *float64 `json:"preCompactionMessagesLength,omitempty"` + // Total tokens in conversation before compaction + PreCompactionTokens *float64 `json:"preCompactionTokens,omitempty"` + // GitHub request tracing ID (x-github-request-id header) for the compaction LLM call + RequestID *string `json:"requestId,omitempty"` + // Whether compaction completed successfully + Success bool `json:"success"` + // LLM-generated summary of the compacted conversation history + SummaryContent *string `json:"summaryContent,omitempty"` + // Token count from system message(s) after compaction + SystemTokens *float64 `json:"systemTokens,omitempty"` + // Number of tokens removed during compaction + TokensRemoved *float64 `json:"tokensRemoved,omitempty"` + // Token count from tool definitions after compaction + ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` } -func (*SessionInfoData) sessionEventData() {} +func (*SessionCompactionCompleteData) sessionEventData() {} -// Warning message for timeline display with categorization -type SessionWarningData struct { - // Category of warning (e.g., "subscription", "policy", "mcp") - WarningType string `json:"warningType"` - // Human-readable warning message for display in the timeline - Message string `json:"message"` - // Optional URL associated with this warning that the user can open in a browser - URL *string `json:"url,omitempty"` +// Conversation truncation statistics including token counts and removed content metrics +type SessionTruncationData struct { + // Number of messages removed by truncation + MessagesRemovedDuringTruncation float64 `json:"messagesRemovedDuringTruncation"` + // Identifier of the component that performed truncation (e.g., "BasicTruncator") + PerformedBy string `json:"performedBy"` + // Number of conversation messages after truncation + PostTruncationMessagesLength float64 `json:"postTruncationMessagesLength"` + // Total tokens in conversation messages after truncation + PostTruncationTokensInMessages float64 `json:"postTruncationTokensInMessages"` + // Number of conversation messages before truncation + PreTruncationMessagesLength float64 `json:"preTruncationMessagesLength"` + // Total tokens in conversation messages before truncation + PreTruncationTokensInMessages float64 `json:"preTruncationTokensInMessages"` + // Maximum token count for the model's context window + TokenLimit float64 `json:"tokenLimit"` + // Number of tokens removed by truncation + TokensRemovedDuringTruncation float64 `json:"tokensRemovedDuringTruncation"` } -func (*SessionWarningData) sessionEventData() {} +func (*SessionTruncationData) sessionEventData() {} -// Model change details including previous and new model identifiers -type SessionModelChangeData struct { - // Model that was previously selected, if any - PreviousModel *string `json:"previousModel,omitempty"` - // Newly selected model identifier - NewModel string `json:"newModel"` - // Reasoning effort level before the model change, if applicable - PreviousReasoningEffort *string `json:"previousReasoningEffort,omitempty"` - // Reasoning effort level after the model change, if applicable - ReasoningEffort *string `json:"reasoningEffort,omitempty"` +// Current context window usage statistics including token and message counts +type SessionUsageInfoData struct { + // Token count from non-system messages (user, assistant, tool) + ConversationTokens *float64 `json:"conversationTokens,omitempty"` + // Current number of tokens in the context window + CurrentTokens float64 `json:"currentTokens"` + // Whether this is the first usage_info event emitted in this session + IsInitial *bool `json:"isInitial,omitempty"` + // Current number of messages in the conversation + MessagesLength float64 `json:"messagesLength"` + // Token count from system message(s) + SystemTokens *float64 `json:"systemTokens,omitempty"` + // Maximum token count for the model's context window + TokenLimit float64 `json:"tokenLimit"` + // Token count from tool definitions + ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` } -func (*SessionModelChangeData) sessionEventData() {} +func (*SessionUsageInfoData) sessionEventData() {} -// Agent mode change details including previous and new modes -type SessionModeChangedData struct { - // Agent mode before the change (e.g., "interactive", "plan", "autopilot") - PreviousMode string `json:"previousMode"` - // Agent mode after the change (e.g., "interactive", "plan", "autopilot") - NewMode string `json:"newMode"` +// Custom agent selection details including name and available tools +type SubagentSelectedData struct { + // Human-readable display name of the selected custom agent + AgentDisplayName string `json:"agentDisplayName"` + // Internal name of the selected custom agent + AgentName string `json:"agentName"` + // List of tool names available to this agent, or null for all tools + Tools []string `json:"tools"` } -func (*SessionModeChangedData) sessionEventData() {} +func (*SubagentSelectedData) sessionEventData() {} -// Plan file operation details indicating what changed -type SessionPlanChangedData struct { - // The type of operation performed on the plan file - Operation PlanChangedOperation `json:"operation"` +// Elicitation request completion with the user's response +type ElicitationCompletedData struct { + // The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) + Action *ElicitationCompletedAction `json:"action,omitempty"` + // The submitted form data when action is 'accept'; keys match the requested schema fields + Content map[string]any `json:"content,omitempty"` + // Request ID of the resolved elicitation request; clients should dismiss any UI for this request + RequestID string `json:"requestId"` } -func (*SessionPlanChangedData) sessionEventData() {} +func (*ElicitationCompletedData) sessionEventData() {} -// Workspace file change details including path and operation type -type SessionWorkspaceFileChangedData struct { - // Relative path within the session workspace files directory - Path string `json:"path"` - // Whether the file was newly created or updated - Operation WorkspaceFileChangedOperation `json:"operation"` -} - -func (*SessionWorkspaceFileChangedData) sessionEventData() {} - -// Session handoff metadata including source, context, and repository information -type SessionHandoffData struct { - // ISO 8601 timestamp when the handoff occurred - HandoffTime time.Time `json:"handoffTime"` - // Origin type of the session being handed off - SourceType HandoffSourceType `json:"sourceType"` - // Repository context for the handed-off session - Repository *HandoffRepository `json:"repository,omitempty"` - // Additional context information for the handoff - Context *string `json:"context,omitempty"` - // Summary of the work done in the source session - Summary *string `json:"summary,omitempty"` - // Session ID of the remote session being handed off - RemoteSessionID *string `json:"remoteSessionId,omitempty"` - // GitHub host URL for the source session (e.g., https://github.com or https://tenant.ghe.com) - Host *string `json:"host,omitempty"` +// Elicitation request; may be form-based (structured input) or URL-based (browser redirect) +type ElicitationRequestedData struct { + // The source that initiated the request (MCP server name, or absent for agent-initiated) + ElicitationSource *string `json:"elicitationSource,omitempty"` + // Message describing what information is needed from the user + Message string `json:"message"` + // Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. + Mode *ElicitationRequestedMode `json:"mode,omitempty"` + // JSON Schema describing the form fields to present to the user (form mode only) + RequestedSchema *ElicitationRequestedSchema `json:"requestedSchema,omitempty"` + // Unique identifier for this elicitation request; used to respond via session.respondToElicitation() + RequestID string `json:"requestId"` + // Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id for remote UIs + ToolCallID *string `json:"toolCallId,omitempty"` + // URL to open in the user's browser (url mode only) + URL *string `json:"url,omitempty"` } -func (*SessionHandoffData) sessionEventData() {} +func (*ElicitationRequestedData) sessionEventData() {} -// Conversation truncation statistics including token counts and removed content metrics -type SessionTruncationData struct { - // Maximum token count for the model's context window - TokenLimit float64 `json:"tokenLimit"` - // Total tokens in conversation messages before truncation - PreTruncationTokensInMessages float64 `json:"preTruncationTokensInMessages"` - // Number of conversation messages before truncation - PreTruncationMessagesLength float64 `json:"preTruncationMessagesLength"` - // Total tokens in conversation messages after truncation - PostTruncationTokensInMessages float64 `json:"postTruncationTokensInMessages"` - // Number of conversation messages after truncation - PostTruncationMessagesLength float64 `json:"postTruncationMessagesLength"` - // Number of tokens removed by truncation - TokensRemovedDuringTruncation float64 `json:"tokensRemovedDuringTruncation"` - // Number of messages removed by truncation - MessagesRemovedDuringTruncation float64 `json:"messagesRemovedDuringTruncation"` - // Identifier of the component that performed truncation (e.g., "BasicTruncator") - PerformedBy string `json:"performedBy"` +// Empty payload; the event signals that the custom agent was deselected, returning to the default agent +type SubagentDeselectedData struct { } -func (*SessionTruncationData) sessionEventData() {} +func (*SubagentDeselectedData) sessionEventData() {} -// Session rewind details including target event and count of removed events -type SessionSnapshotRewindData struct { - // Event ID that was rewound to; this event and all after it were removed - UpToEventID string `json:"upToEventId"` - // Number of events that were removed by the rewind - EventsRemoved float64 `json:"eventsRemoved"` +// Empty payload; the event signals that the pending message queue has changed +type PendingMessagesModifiedData struct { } -func (*SessionSnapshotRewindData) sessionEventData() {} +func (*PendingMessagesModifiedData) sessionEventData() {} -// Session termination metrics including usage statistics, code changes, and shutdown reason -type SessionShutdownData struct { - // Whether the session ended normally ("routine") or due to a crash/fatal error ("error") - ShutdownType ShutdownType `json:"shutdownType"` - // Error description when shutdownType is "error" - ErrorReason *string `json:"errorReason,omitempty"` - // Total number of premium API requests used during the session - TotalPremiumRequests float64 `json:"totalPremiumRequests"` - // Cumulative time spent in API calls during the session, in milliseconds - TotalAPIDurationMs float64 `json:"totalApiDurationMs"` - // Unix timestamp (milliseconds) when the session started - SessionStartTime float64 `json:"sessionStartTime"` - // Aggregate code change metrics for the session - CodeChanges ShutdownCodeChanges `json:"codeChanges"` - // Per-model usage breakdown, keyed by model identifier - ModelMetrics map[string]ShutdownModelMetric `json:"modelMetrics"` - // Model that was selected at the time of shutdown - CurrentModel *string `json:"currentModel,omitempty"` - // Total tokens in context window at shutdown - CurrentTokens *float64 `json:"currentTokens,omitempty"` - // System message token count at shutdown - SystemTokens *float64 `json:"systemTokens,omitempty"` - // Non-system message token count at shutdown - ConversationTokens *float64 `json:"conversationTokens,omitempty"` - // Tool definitions token count at shutdown - ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` +// Error details for timeline display including message and optional diagnostic information +type SessionErrorData struct { + // Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") + ErrorType string `json:"errorType"` + // Human-readable error message + Message string `json:"message"` + // GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs + ProviderCallID *string `json:"providerCallId,omitempty"` + // Error stack trace, when available + Stack *string `json:"stack,omitempty"` + // HTTP status code from the upstream request, if applicable + StatusCode *int64 `json:"statusCode,omitempty"` + // Optional URL associated with this error that the user can open in a browser + URL *string `json:"url,omitempty"` } -func (*SessionShutdownData) sessionEventData() {} +func (*SessionErrorData) sessionEventData() {} -// Working directory and git context at session start -type SessionContextChangedData struct { - // Current working directory path - Cwd string `json:"cwd"` - // Root directory of the git repository, resolved via git rev-parse - GitRoot *string `json:"gitRoot,omitempty"` - // Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) - Repository *string `json:"repository,omitempty"` - // Hosting platform type of the repository (github or ado) - HostType *WorkingDirectoryContextHostType `json:"hostType,omitempty"` - // Current git branch name - Branch *string `json:"branch,omitempty"` - // Head commit of current git branch at session start time - HeadCommit *string `json:"headCommit,omitempty"` - // Base commit of current git branch at session start time - BaseCommit *string `json:"baseCommit,omitempty"` +// External tool completion notification signaling UI dismissal +type ExternalToolCompletedData struct { + // Request ID of the resolved external tool request; clients should dismiss any UI for this request + RequestID string `json:"requestId"` } -func (*SessionContextChangedData) sessionEventData() {} +func (*ExternalToolCompletedData) sessionEventData() {} -// Current context window usage statistics including token and message counts -type SessionUsageInfoData struct { - // Maximum token count for the model's context window - TokenLimit float64 `json:"tokenLimit"` - // Current number of tokens in the context window - CurrentTokens float64 `json:"currentTokens"` - // Current number of messages in the conversation - MessagesLength float64 `json:"messagesLength"` - // Token count from system message(s) - SystemTokens *float64 `json:"systemTokens,omitempty"` - // Token count from non-system messages (user, assistant, tool) - ConversationTokens *float64 `json:"conversationTokens,omitempty"` - // Token count from tool definitions - ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` - // Whether this is the first usage_info event emitted in this session - IsInitial *bool `json:"isInitial,omitempty"` +// External tool invocation request for client-side tool execution +type ExternalToolRequestedData struct { + // Arguments to pass to the external tool + Arguments any `json:"arguments,omitempty"` + // Unique identifier for this request; used to respond via session.respondToExternalTool() + RequestID string `json:"requestId"` + // Session ID that this external tool request belongs to + SessionID string `json:"sessionId"` + // Tool call ID assigned to this external tool invocation + ToolCallID string `json:"toolCallId"` + // Name of the external tool to invoke + ToolName string `json:"toolName"` + // W3C Trace Context traceparent header for the execute_tool span + Traceparent *string `json:"traceparent,omitempty"` + // W3C Trace Context tracestate header for the execute_tool span + Tracestate *string `json:"tracestate,omitempty"` } -func (*SessionUsageInfoData) sessionEventData() {} +func (*ExternalToolRequestedData) sessionEventData() {} -// Context window breakdown at the start of LLM-powered conversation compaction -type SessionCompactionStartData struct { - // Token count from system message(s) at compaction start - SystemTokens *float64 `json:"systemTokens,omitempty"` - // Token count from non-system messages (user, assistant, tool) at compaction start - ConversationTokens *float64 `json:"conversationTokens,omitempty"` - // Token count from tool definitions at compaction start - ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` +// Hook invocation completion details including output, success status, and error information +type HookEndData struct { + // Error details when the hook failed + Error *HookEndError `json:"error,omitempty"` + // Identifier matching the corresponding hook.start event + HookInvocationID string `json:"hookInvocationId"` + // Type of hook that was invoked (e.g., "preToolUse", "postToolUse", "sessionStart") + HookType string `json:"hookType"` + // Output data produced by the hook + Output any `json:"output,omitempty"` + // Whether the hook completed successfully + Success bool `json:"success"` } -func (*SessionCompactionStartData) sessionEventData() {} +func (*HookEndData) sessionEventData() {} -// Conversation compaction results including success status, metrics, and optional error details -type SessionCompactionCompleteData struct { - // Whether compaction completed successfully - Success bool `json:"success"` - // Error message if compaction failed - Error *string `json:"error,omitempty"` - // Total tokens in conversation before compaction - PreCompactionTokens *float64 `json:"preCompactionTokens,omitempty"` - // Total tokens in conversation after compaction - PostCompactionTokens *float64 `json:"postCompactionTokens,omitempty"` - // Number of messages before compaction - PreCompactionMessagesLength *float64 `json:"preCompactionMessagesLength,omitempty"` - // Number of messages removed during compaction - MessagesRemoved *float64 `json:"messagesRemoved,omitempty"` - // Number of tokens removed during compaction - TokensRemoved *float64 `json:"tokensRemoved,omitempty"` - // LLM-generated summary of the compacted conversation history - SummaryContent *string `json:"summaryContent,omitempty"` - // Checkpoint snapshot number created for recovery - CheckpointNumber *float64 `json:"checkpointNumber,omitempty"` - // File path where the checkpoint was stored - CheckpointPath *string `json:"checkpointPath,omitempty"` - // Token usage breakdown for the compaction LLM call - CompactionTokensUsed *CompactionCompleteCompactionTokensUsed `json:"compactionTokensUsed,omitempty"` - // GitHub request tracing ID (x-github-request-id header) for the compaction LLM call - RequestID *string `json:"requestId,omitempty"` - // Token count from system message(s) after compaction - SystemTokens *float64 `json:"systemTokens,omitempty"` - // Token count from non-system messages (user, assistant, tool) after compaction - ConversationTokens *float64 `json:"conversationTokens,omitempty"` - // Token count from tool definitions after compaction - ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` +// Hook invocation start details including type and input data +type HookStartData struct { + // Unique identifier for this hook invocation + HookInvocationID string `json:"hookInvocationId"` + // Type of hook being invoked (e.g., "preToolUse", "postToolUse", "sessionStart") + HookType string `json:"hookType"` + // Input data passed to the hook + Input any `json:"input,omitempty"` } -func (*SessionCompactionCompleteData) sessionEventData() {} +func (*HookStartData) sessionEventData() {} -// Task completion notification with summary from the agent -type SessionTaskCompleteData struct { - // Summary of the completed task, provided by the agent - Summary *string `json:"summary,omitempty"` - // Whether the tool call succeeded. False when validation failed (e.g., invalid arguments) - Success *bool `json:"success,omitempty"` +// Informational message for timeline display with categorization +type SessionInfoData struct { + // Category of informational message (e.g., "notification", "timing", "context_window", "mcp", "snapshot", "configuration", "authentication", "model") + InfoType string `json:"infoType"` + // Human-readable informational message for display in the timeline + Message string `json:"message"` + // Optional URL associated with this message that the user can open in a browser + URL *string `json:"url,omitempty"` } -func (*SessionTaskCompleteData) sessionEventData() {} - -// UserMessageData holds the payload for user.message events. -type UserMessageData struct { - // The user's message text as displayed in the timeline - Content string `json:"content"` - // Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching - TransformedContent *string `json:"transformedContent,omitempty"` - // Files, selections, or GitHub references attached to the message - Attachments []UserMessageAttachment `json:"attachments,omitempty"` - // Normalized document MIME types that were sent natively instead of through tagged_files XML - SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitempty"` - // Path-backed native document attachments that stayed on the tagged_files path flow because native upload would exceed the request size limit - NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitempty"` - // Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user) - Source *string `json:"source,omitempty"` - // The agent mode that was active when this message was sent - AgentMode *UserMessageAgentMode `json:"agentMode,omitempty"` - // CAPI interaction ID for correlating this user message with its turn - InteractionID *string `json:"interactionId,omitempty"` -} - -func (*UserMessageData) sessionEventData() {} - -// Empty payload; the event signals that the pending message queue has changed -type PendingMessagesModifiedData struct { -} - -func (*PendingMessagesModifiedData) sessionEventData() {} - -// Turn initialization metadata including identifier and interaction tracking -type AssistantTurnStartData struct { - // Identifier for this turn within the agentic loop, typically a stringified turn number - TurnID string `json:"turnId"` - // CAPI interaction ID for correlating this turn with upstream telemetry - InteractionID *string `json:"interactionId,omitempty"` -} - -func (*AssistantTurnStartData) sessionEventData() {} - -// Agent intent description for current activity or plan -type AssistantIntentData struct { - // Short description of what the agent is currently doing or planning to do - Intent string `json:"intent"` -} - -func (*AssistantIntentData) sessionEventData() {} - -// Assistant reasoning content for timeline display with complete thinking text -type AssistantReasoningData struct { - // Unique identifier for this reasoning block - ReasoningID string `json:"reasoningId"` - // The complete extended thinking text from the model - Content string `json:"content"` -} - -func (*AssistantReasoningData) sessionEventData() {} - -// Streaming reasoning delta for incremental extended thinking updates -type AssistantReasoningDeltaData struct { - // Reasoning block ID this delta belongs to, matching the corresponding assistant.reasoning event - ReasoningID string `json:"reasoningId"` - // Incremental text chunk to append to the reasoning content - DeltaContent string `json:"deltaContent"` -} - -func (*AssistantReasoningDeltaData) sessionEventData() {} - -// Streaming response progress with cumulative byte count -type AssistantStreamingDeltaData struct { - // Cumulative total bytes received from the streaming response so far - TotalResponseSizeBytes float64 `json:"totalResponseSizeBytes"` -} - -func (*AssistantStreamingDeltaData) sessionEventData() {} - -// Assistant response containing text content, optional tool requests, and interaction metadata -type AssistantMessageData struct { - // Unique identifier for this assistant message - MessageID string `json:"messageId"` - // The assistant's text response content - Content string `json:"content"` - // Tool invocations requested by the assistant in this message - ToolRequests []AssistantMessageToolRequest `json:"toolRequests,omitempty"` - // Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. - ReasoningOpaque *string `json:"reasoningOpaque,omitempty"` - // Readable reasoning text from the model's extended thinking - ReasoningText *string `json:"reasoningText,omitempty"` - // Encrypted reasoning content from OpenAI models. Session-bound and stripped on resume. - EncryptedContent *string `json:"encryptedContent,omitempty"` - // Generation phase for phased-output models (e.g., thinking vs. response phases) - Phase *string `json:"phase,omitempty"` - // Actual output token count from the API response (completion_tokens), used for accurate token accounting - OutputTokens *float64 `json:"outputTokens,omitempty"` - // CAPI interaction ID for correlating this message with upstream telemetry - InteractionID *string `json:"interactionId,omitempty"` - // GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs - RequestID *string `json:"requestId,omitempty"` - // Tool call ID of the parent tool invocation when this event originates from a sub-agent - // Deprecated: ParentToolCallID is deprecated. - ParentToolCallID *string `json:"parentToolCallId,omitempty"` -} - -func (*AssistantMessageData) sessionEventData() {} - -// Streaming assistant message delta for incremental response updates -type AssistantMessageDeltaData struct { - // Message ID this delta belongs to, matching the corresponding assistant.message event - MessageID string `json:"messageId"` - // Incremental text chunk to append to the message content - DeltaContent string `json:"deltaContent"` - // Tool call ID of the parent tool invocation when this event originates from a sub-agent - // Deprecated: ParentToolCallID is deprecated. - ParentToolCallID *string `json:"parentToolCallId,omitempty"` -} - -func (*AssistantMessageDeltaData) sessionEventData() {} - -// Turn completion metadata including the turn identifier -type AssistantTurnEndData struct { - // Identifier of the turn that has ended, matching the corresponding assistant.turn_start event - TurnID string `json:"turnId"` -} - -func (*AssistantTurnEndData) sessionEventData() {} +func (*SessionInfoData) sessionEventData() {} // LLM API call usage metrics including tokens, costs, quotas, and billing information type AssistantUsageData struct { - // Model identifier used for this API call - Model string `json:"model"` - // Number of input tokens consumed - InputTokens *float64 `json:"inputTokens,omitempty"` - // Number of output tokens produced - OutputTokens *float64 `json:"outputTokens,omitempty"` + // Completion ID from the model provider (e.g., chatcmpl-abc123) + APICallID *string `json:"apiCallId,omitempty"` // Number of tokens read from prompt cache CacheReadTokens *float64 `json:"cacheReadTokens,omitempty"` // Number of tokens written to prompt cache CacheWriteTokens *float64 `json:"cacheWriteTokens,omitempty"` - // Number of output tokens used for reasoning (e.g., chain-of-thought) - ReasoningTokens *float64 `json:"reasoningTokens,omitempty"` + // Per-request cost and usage data from the CAPI copilot_usage response field + CopilotUsage *AssistantUsageCopilotUsage `json:"copilotUsage,omitempty"` // Model multiplier cost for billing purposes Cost *float64 `json:"cost,omitempty"` // Duration of the API call in milliseconds Duration *float64 `json:"duration,omitempty"` - // Time to first token in milliseconds. Only available for streaming requests - TtftMs *float64 `json:"ttftMs,omitempty"` - // Average inter-token latency in milliseconds. Only available for streaming requests - InterTokenLatencyMs *float64 `json:"interTokenLatencyMs,omitempty"` // What initiated this API call (e.g., "sub-agent", "mcp-sampling"); absent for user-initiated calls Initiator *string `json:"initiator,omitempty"` - // Completion ID from the model provider (e.g., chatcmpl-abc123) - APICallID *string `json:"apiCallId,omitempty"` - // GitHub request tracing ID (x-github-request-id header) for server-side log correlation - ProviderCallID *string `json:"providerCallId,omitempty"` + // Number of input tokens consumed + InputTokens *float64 `json:"inputTokens,omitempty"` + // Average inter-token latency in milliseconds. Only available for streaming requests + InterTokenLatencyMs *float64 `json:"interTokenLatencyMs,omitempty"` + // Model identifier used for this API call + Model string `json:"model"` + // Number of output tokens produced + OutputTokens *float64 `json:"outputTokens,omitempty"` // Parent tool call ID when this usage originates from a sub-agent // Deprecated: ParentToolCallID is deprecated. ParentToolCallID *string `json:"parentToolCallId,omitempty"` + // 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 QuotaSnapshots map[string]AssistantUsageQuotaSnapshot `json:"quotaSnapshots,omitempty"` - // Per-request cost and usage data from the CAPI copilot_usage response field - CopilotUsage *AssistantUsageCopilotUsage `json:"copilotUsage,omitempty"` // Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // Number of output tokens used for reasoning (e.g., chain-of-thought) + ReasoningTokens *float64 `json:"reasoningTokens,omitempty"` + // Time to first token in milliseconds. Only available for streaming requests + TtftMs *float64 `json:"ttftMs,omitempty"` } func (*AssistantUsageData) sessionEventData() {} -// Turn abort information including the reason for termination -type AbortData struct { - // Reason the current turn was aborted (e.g., "user initiated") - Reason string `json:"reason"` +// MCP OAuth request completion notification +type McpOauthCompletedData struct { + // Request ID of the resolved OAuth request + RequestID string `json:"requestId"` } -func (*AbortData) sessionEventData() {} +func (*McpOauthCompletedData) sessionEventData() {} -// User-initiated tool invocation request with tool name and arguments -type ToolUserRequestedData struct { - // Unique identifier for this tool call - ToolCallID string `json:"toolCallId"` - // Name of the tool the user wants to invoke - ToolName string `json:"toolName"` - // Arguments for the tool invocation - Arguments any `json:"arguments,omitempty"` +// Model change details including previous and new model identifiers +type SessionModelChangeData struct { + // Newly selected model identifier + NewModel string `json:"newModel"` + // Model that was previously selected, if any + PreviousModel *string `json:"previousModel,omitempty"` + // Reasoning effort level before the model change, if applicable + PreviousReasoningEffort *string `json:"previousReasoningEffort,omitempty"` + // Reasoning effort level after the model change, if applicable + ReasoningEffort *string `json:"reasoningEffort,omitempty"` } -func (*ToolUserRequestedData) sessionEventData() {} +func (*SessionModelChangeData) sessionEventData() {} -// Tool execution startup details including MCP server information when applicable -type ToolExecutionStartData struct { - // Unique identifier for this tool call - ToolCallID string `json:"toolCallId"` - // Name of the tool being executed - ToolName string `json:"toolName"` - // Arguments passed to the tool - Arguments any `json:"arguments,omitempty"` - // Name of the MCP server hosting this tool, when the tool is an MCP tool - McpServerName *string `json:"mcpServerName,omitempty"` - // Original tool name on the MCP server, when the tool is an MCP tool - McpToolName *string `json:"mcpToolName,omitempty"` - // Tool call ID of the parent tool invocation when this event originates from a sub-agent - // Deprecated: ParentToolCallID is deprecated. - ParentToolCallID *string `json:"parentToolCallId,omitempty"` +// Notifies Mission Control that the session's remote steering capability has changed +type SessionRemoteSteerableChangedData struct { + // Whether this session now supports remote steering via Mission Control + RemoteSteerable bool `json:"remoteSteerable"` } -func (*ToolExecutionStartData) sessionEventData() {} +func (*SessionRemoteSteerableChangedData) sessionEventData() {} -// Streaming tool execution output for incremental result display -type ToolExecutionPartialResultData struct { - // Tool call ID this partial result belongs to - ToolCallID string `json:"toolCallId"` - // Incremental output chunk from the running tool - PartialOutput string `json:"partialOutput"` +// OAuth authentication request for an MCP server +type McpOauthRequiredData struct { + // Unique identifier for this OAuth request; used to respond via session.respondToMcpOAuth() + RequestID string `json:"requestId"` + // Display name of the MCP server that requires OAuth + ServerName string `json:"serverName"` + // URL of the MCP server that requires OAuth + ServerURL string `json:"serverUrl"` + // Static OAuth client configuration, if the server specifies one + StaticClientConfig *McpOauthRequiredStaticClientConfig `json:"staticClientConfig,omitempty"` } -func (*ToolExecutionPartialResultData) sessionEventData() {} +func (*McpOauthRequiredData) sessionEventData() {} -// Tool execution progress notification with status message -type ToolExecutionProgressData struct { - // Tool call ID this progress notification belongs to - ToolCallID string `json:"toolCallId"` - // Human-readable progress status message (e.g., from an MCP server) - ProgressMessage string `json:"progressMessage"` +// Payload indicating the session is idle with no background agents in flight +type SessionIdleData struct { + // True when the preceding agentic loop was cancelled via abort signal + Aborted *bool `json:"aborted,omitempty"` } -func (*ToolExecutionProgressData) sessionEventData() {} +func (*SessionIdleData) sessionEventData() {} -// Tool execution completion results including success status, detailed output, and error information -type ToolExecutionCompleteData struct { - // Unique identifier for the completed tool call - ToolCallID string `json:"toolCallId"` - // Whether the tool execution completed successfully - Success bool `json:"success"` - // Model identifier that generated this tool call - Model *string `json:"model,omitempty"` - // CAPI interaction ID for correlating this tool execution with upstream telemetry - InteractionID *string `json:"interactionId,omitempty"` - // Whether this tool call was explicitly requested by the user rather than the assistant - IsUserRequested *bool `json:"isUserRequested,omitempty"` - // Tool execution result on success - Result *ToolExecutionCompleteResult `json:"result,omitempty"` - // Error details when the tool execution failed - Error *ToolExecutionCompleteError `json:"error,omitempty"` - // Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts) - ToolTelemetry map[string]any `json:"toolTelemetry,omitempty"` - // Tool call ID of the parent tool invocation when this event originates from a sub-agent - // Deprecated: ParentToolCallID is deprecated. - ParentToolCallID *string `json:"parentToolCallId,omitempty"` +// Permission request completion notification signaling UI dismissal +type PermissionCompletedData struct { + // Request ID of the resolved permission request; clients should dismiss any UI for this request + RequestID string `json:"requestId"` + // The result of the permission request + Result PermissionCompletedResult `json:"result"` } -func (*ToolExecutionCompleteData) sessionEventData() {} +func (*PermissionCompletedData) sessionEventData() {} -// Skill invocation details including content, allowed tools, and plugin metadata -type SkillInvokedData struct { - // Name of the invoked skill - Name string `json:"name"` - // File path to the SKILL.md definition - Path string `json:"path"` - // Full content of the skill file, injected into the conversation for the model - Content string `json:"content"` - // Tool names that should be auto-approved when this skill is active - AllowedTools []string `json:"allowedTools,omitempty"` - // Name of the plugin this skill originated from, when applicable - PluginName *string `json:"pluginName,omitempty"` - // Version of the plugin this skill originated from, when applicable - PluginVersion *string `json:"pluginVersion,omitempty"` - // Description of the skill from its SKILL.md frontmatter - Description *string `json:"description,omitempty"` +// Permission request notification requiring client approval with request details +type PermissionRequestedData struct { + // Details of the permission being requested + PermissionRequest PermissionRequest `json:"permissionRequest"` + // Unique identifier for this permission request; used to respond via session.respondToPermission() + RequestID string `json:"requestId"` + // When true, this permission was already resolved by a permissionRequest hook and requires no client action + ResolvedByHook *bool `json:"resolvedByHook,omitempty"` } -func (*SkillInvokedData) sessionEventData() {} +func (*PermissionRequestedData) sessionEventData() {} -// Sub-agent startup details including parent tool call and agent information -type SubagentStartedData struct { - // Tool call ID of the parent tool invocation that spawned this sub-agent - ToolCallID string `json:"toolCallId"` - // Internal name of the sub-agent - AgentName string `json:"agentName"` - // Human-readable display name of the sub-agent - AgentDisplayName string `json:"agentDisplayName"` - // Description of what the sub-agent does - AgentDescription string `json:"agentDescription"` +// Plan approval request with plan content and available user actions +type ExitPlanModeRequestedData struct { + // Available actions the user can take (e.g., approve, edit, reject) + Actions []string `json:"actions"` + // Full content of the plan file + PlanContent string `json:"planContent"` + // The recommended action for the user to take + RecommendedAction string `json:"recommendedAction"` + // Unique identifier for this request; used to respond via session.respondToExitPlanMode() + RequestID string `json:"requestId"` + // Summary of the plan that was created + Summary string `json:"summary"` } -func (*SubagentStartedData) sessionEventData() {} +func (*ExitPlanModeRequestedData) sessionEventData() {} -// Sub-agent completion details for successful execution -type SubagentCompletedData struct { - // Tool call ID of the parent tool invocation that spawned this sub-agent - ToolCallID string `json:"toolCallId"` - // Internal name of the sub-agent - AgentName string `json:"agentName"` - // Human-readable display name of the sub-agent - AgentDisplayName string `json:"agentDisplayName"` - // Model used by the sub-agent - Model *string `json:"model,omitempty"` - // Total number of tool calls made by the sub-agent - TotalToolCalls *float64 `json:"totalToolCalls,omitempty"` - // Total tokens (input + output) consumed by the sub-agent - TotalTokens *float64 `json:"totalTokens,omitempty"` - // Wall-clock duration of the sub-agent execution in milliseconds - DurationMs *float64 `json:"durationMs,omitempty"` +// Plan file operation details indicating what changed +type SessionPlanChangedData struct { + // The type of operation performed on the plan file + Operation PlanChangedOperation `json:"operation"` } -func (*SubagentCompletedData) sessionEventData() {} +func (*SessionPlanChangedData) sessionEventData() {} -// Sub-agent failure details including error message and agent information -type SubagentFailedData struct { - // Tool call ID of the parent tool invocation that spawned this sub-agent - ToolCallID string `json:"toolCallId"` - // Internal name of the sub-agent - AgentName string `json:"agentName"` - // Human-readable display name of the sub-agent - AgentDisplayName string `json:"agentDisplayName"` - // Error message describing why the sub-agent failed - Error string `json:"error"` - // Model used by the sub-agent (if any model calls succeeded before failure) - Model *string `json:"model,omitempty"` - // Total number of tool calls made before the sub-agent failed - TotalToolCalls *float64 `json:"totalToolCalls,omitempty"` - // Total tokens (input + output) consumed before the sub-agent failed - TotalTokens *float64 `json:"totalTokens,omitempty"` - // Wall-clock duration of the sub-agent execution in milliseconds - DurationMs *float64 `json:"durationMs,omitempty"` +// Plan mode exit completion with the user's approval decision and optional feedback +type ExitPlanModeCompletedData struct { + // Whether the plan was approved by the user + Approved *bool `json:"approved,omitempty"` + // Whether edits should be auto-approved without confirmation + AutoApproveEdits *bool `json:"autoApproveEdits,omitempty"` + // Free-form feedback from the user if they requested changes to the plan + Feedback *string `json:"feedback,omitempty"` + // Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request + RequestID string `json:"requestId"` + // Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only') + SelectedAction *string `json:"selectedAction,omitempty"` } -func (*SubagentFailedData) sessionEventData() {} +func (*ExitPlanModeCompletedData) sessionEventData() {} -// Custom agent selection details including name and available tools -type SubagentSelectedData struct { - // Internal name of the selected custom agent - AgentName string `json:"agentName"` - // Human-readable display name of the selected custom agent - AgentDisplayName string `json:"agentDisplayName"` - // List of tool names available to this agent, or null for all tools - Tools []string `json:"tools"` +// Queued command completion notification signaling UI dismissal +type CommandCompletedData struct { + // Request ID of the resolved command request; clients should dismiss any UI for this request + RequestID string `json:"requestId"` } -func (*SubagentSelectedData) sessionEventData() {} +func (*CommandCompletedData) sessionEventData() {} -// Empty payload; the event signals that the custom agent was deselected, returning to the default agent -type SubagentDeselectedData struct { +// Queued slash command dispatch request for client execution +type CommandQueuedData struct { + // The slash command text to be executed (e.g., /help, /clear) + Command string `json:"command"` + // Unique identifier for this request; used to respond via session.respondToQueuedCommand() + RequestID string `json:"requestId"` } -func (*SubagentDeselectedData) sessionEventData() {} +func (*CommandQueuedData) sessionEventData() {} -// Hook invocation start details including type and input data -type HookStartData struct { - // Unique identifier for this hook invocation - HookInvocationID string `json:"hookInvocationId"` - // Type of hook being invoked (e.g., "preToolUse", "postToolUse", "sessionStart") - HookType string `json:"hookType"` - // Input data passed to the hook - Input any `json:"input,omitempty"` +// Registered command dispatch request routed to the owning client +type CommandExecuteData struct { + // Raw argument string after the command name + Args string `json:"args"` + // The full command text (e.g., /deploy production) + Command string `json:"command"` + // Command name without leading / + CommandName string `json:"commandName"` + // Unique identifier; used to respond via session.commands.handlePendingCommand() + RequestID string `json:"requestId"` } -func (*HookStartData) sessionEventData() {} +func (*CommandExecuteData) sessionEventData() {} -// Hook invocation completion details including output, success status, and error information -type HookEndData struct { - // Identifier matching the corresponding hook.start event - HookInvocationID string `json:"hookInvocationId"` - // Type of hook that was invoked (e.g., "preToolUse", "postToolUse", "sessionStart") - HookType string `json:"hookType"` - // Output data produced by the hook - Output any `json:"output,omitempty"` - // Whether the hook completed successfully - Success bool `json:"success"` - // Error details when the hook failed - Error *HookEndError `json:"error,omitempty"` +// SDK command registration change notification +type CommandsChangedData struct { + // Current list of registered SDK commands + Commands []CommandsChangedCommand `json:"commands"` } -func (*HookEndData) sessionEventData() {} +func (*CommandsChangedData) sessionEventData() {} -// System/developer instruction content with role and optional template metadata -type SystemMessageData struct { - // The system or developer prompt text sent as model input - Content string `json:"content"` - // Message role: "system" for system prompts, "developer" for developer-injected instructions - Role SystemMessageRole `json:"role"` - // Optional name identifier for the message source - Name *string `json:"name,omitempty"` - // Metadata about the prompt template and its construction - Metadata *SystemMessageMetadata `json:"metadata,omitempty"` +// Sampling request completion notification signaling UI dismissal +type SamplingCompletedData struct { + // Request ID of the resolved sampling request; clients should dismiss any UI for this request + RequestID string `json:"requestId"` } -func (*SystemMessageData) sessionEventData() {} +func (*SamplingCompletedData) sessionEventData() {} -// System-generated notification for runtime events like background task completion -type SystemNotificationData struct { - // The notification text, typically wrapped in XML tags - Content string `json:"content"` - // Structured metadata identifying what triggered this notification - Kind SystemNotification `json:"kind"` +// Sampling request from an MCP server; contains the server name and a requestId for correlation +type SamplingRequestedData struct { + // The JSON-RPC request ID from the MCP protocol + McpRequestID any `json:"mcpRequestId"` + // Unique identifier for this sampling request; used to respond via session.respondToSampling() + RequestID string `json:"requestId"` + // Name of the MCP server that initiated the sampling request + ServerName string `json:"serverName"` } -func (*SystemNotificationData) sessionEventData() {} +func (*SamplingRequestedData) sessionEventData() {} -// Permission request notification requiring client approval with request details -type PermissionRequestedData struct { - // Unique identifier for this permission request; used to respond via session.respondToPermission() - RequestID string `json:"requestId"` - // Details of the permission being requested - PermissionRequest PermissionRequest `json:"permissionRequest"` - // When true, this permission was already resolved by a permissionRequest hook and requires no client action - ResolvedByHook *bool `json:"resolvedByHook,omitempty"` +// Session capability change notification +type CapabilitiesChangedData struct { + // UI capability changes + UI *CapabilitiesChangedUI `json:"ui,omitempty"` } -func (*PermissionRequestedData) sessionEventData() {} +func (*CapabilitiesChangedData) sessionEventData() {} -// Permission request completion notification signaling UI dismissal -type PermissionCompletedData struct { - // Request ID of the resolved permission request; clients should dismiss any UI for this request - RequestID string `json:"requestId"` - // The result of the permission request - Result PermissionCompletedResult `json:"result"` +// Session handoff metadata including source, context, and repository information +type SessionHandoffData struct { + // Additional context information for the handoff + Context *string `json:"context,omitempty"` + // ISO 8601 timestamp when the handoff occurred + HandoffTime time.Time `json:"handoffTime"` + // GitHub host URL for the source session (e.g., https://github.com or https://tenant.ghe.com) + Host *string `json:"host,omitempty"` + // Session ID of the remote session being handed off + RemoteSessionID *string `json:"remoteSessionId,omitempty"` + // Repository context for the handed-off session + Repository *HandoffRepository `json:"repository,omitempty"` + // Origin type of the session being handed off + SourceType HandoffSourceType `json:"sourceType"` + // Summary of the work done in the source session + Summary *string `json:"summary,omitempty"` } -func (*PermissionCompletedData) sessionEventData() {} +func (*SessionHandoffData) sessionEventData() {} -// User input request notification with question and optional predefined choices -type UserInputRequestedData struct { - // Unique identifier for this input request; used to respond via session.respondToUserInput() - RequestID string `json:"requestId"` - // The question or prompt to present to the user - Question string `json:"question"` - // Predefined choices for the user to select from, if applicable - Choices []string `json:"choices,omitempty"` - // Whether the user can provide a free-form text response in addition to predefined choices - AllowFreeform *bool `json:"allowFreeform,omitempty"` - // The LLM-assigned tool call ID that triggered this request; used by remote UIs to correlate responses - ToolCallID *string `json:"toolCallId,omitempty"` -} - -func (*UserInputRequestedData) sessionEventData() {} - -// User input request completion with the user's response -type UserInputCompletedData struct { - // Request ID of the resolved user input request; clients should dismiss any UI for this request - RequestID string `json:"requestId"` - // The user's answer to the input request - Answer *string `json:"answer,omitempty"` - // Whether the answer was typed as free-form text rather than selected from choices - WasFreeform *bool `json:"wasFreeform,omitempty"` +// Session initialization metadata including context and configuration +type SessionStartData struct { + // Whether the session was already in use by another client at start time + AlreadyInUse *bool `json:"alreadyInUse,omitempty"` + // Working directory and git context at session start + Context *WorkingDirectoryContext `json:"context,omitempty"` + // Version string of the Copilot application + CopilotVersion string `json:"copilotVersion"` + // Identifier of the software producing the events (e.g., "copilot-agent") + Producer string `json:"producer"` + // Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") + ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // Whether this session supports remote steering via Mission Control + RemoteSteerable *bool `json:"remoteSteerable,omitempty"` + // Model selected at session creation time, if any + SelectedModel *string `json:"selectedModel,omitempty"` + // Unique identifier for the session + SessionID string `json:"sessionId"` + // ISO 8601 timestamp when the session was created + StartTime time.Time `json:"startTime"` + // Schema version number for the session event format + Version float64 `json:"version"` } -func (*UserInputCompletedData) sessionEventData() {} +func (*SessionStartData) sessionEventData() {} -// Elicitation request; may be form-based (structured input) or URL-based (browser redirect) -type ElicitationRequestedData struct { - // Unique identifier for this elicitation request; used to respond via session.respondToElicitation() - RequestID string `json:"requestId"` - // Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id for remote UIs - ToolCallID *string `json:"toolCallId,omitempty"` - // The source that initiated the request (MCP server name, or absent for agent-initiated) - ElicitationSource *string `json:"elicitationSource,omitempty"` - // Message describing what information is needed from the user - Message string `json:"message"` - // Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. - Mode *ElicitationRequestedMode `json:"mode,omitempty"` - // JSON Schema describing the form fields to present to the user (form mode only) - RequestedSchema *ElicitationRequestedSchema `json:"requestedSchema,omitempty"` - // URL to open in the user's browser (url mode only) - URL *string `json:"url,omitempty"` +// Session resume metadata including current context and event count +type SessionResumeData struct { + // Whether the session was already in use by another client at resume time + AlreadyInUse *bool `json:"alreadyInUse,omitempty"` + // Updated working directory and git context at resume time + Context *WorkingDirectoryContext `json:"context,omitempty"` + // Total number of persisted events in the session at the time of resume + EventCount float64 `json:"eventCount"` + // Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") + ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // Whether this session supports remote steering via Mission Control + RemoteSteerable *bool `json:"remoteSteerable,omitempty"` + // ISO 8601 timestamp when the session was resumed + ResumeTime time.Time `json:"resumeTime"` + // Model currently selected at resume time + SelectedModel *string `json:"selectedModel,omitempty"` } -func (*ElicitationRequestedData) sessionEventData() {} +func (*SessionResumeData) sessionEventData() {} -// Elicitation request completion with the user's response -type ElicitationCompletedData struct { - // Request ID of the resolved elicitation request; clients should dismiss any UI for this request - RequestID string `json:"requestId"` - // The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) - Action *ElicitationCompletedAction `json:"action,omitempty"` - // The submitted form data when action is 'accept'; keys match the requested schema fields - Content map[string]any `json:"content,omitempty"` +// Session rewind details including target event and count of removed events +type SessionSnapshotRewindData struct { + // Number of events that were removed by the rewind + EventsRemoved float64 `json:"eventsRemoved"` + // Event ID that was rewound to; this event and all after it were removed + UpToEventID string `json:"upToEventId"` } -func (*ElicitationCompletedData) sessionEventData() {} +func (*SessionSnapshotRewindData) sessionEventData() {} -// Sampling request from an MCP server; contains the server name and a requestId for correlation -type SamplingRequestedData struct { - // Unique identifier for this sampling request; used to respond via session.respondToSampling() - RequestID string `json:"requestId"` - // Name of the MCP server that initiated the sampling request - ServerName string `json:"serverName"` - // The JSON-RPC request ID from the MCP protocol - McpRequestID any `json:"mcpRequestId"` +// Session termination metrics including usage statistics, code changes, and shutdown reason +type SessionShutdownData struct { + // Aggregate code change metrics for the session + CodeChanges ShutdownCodeChanges `json:"codeChanges"` + // Non-system message token count at shutdown + ConversationTokens *float64 `json:"conversationTokens,omitempty"` + // Model that was selected at the time of shutdown + CurrentModel *string `json:"currentModel,omitempty"` + // Total tokens in context window at shutdown + CurrentTokens *float64 `json:"currentTokens,omitempty"` + // Error description when shutdownType is "error" + ErrorReason *string `json:"errorReason,omitempty"` + // Per-model usage breakdown, keyed by model identifier + ModelMetrics map[string]ShutdownModelMetric `json:"modelMetrics"` + // Unix timestamp (milliseconds) when the session started + SessionStartTime float64 `json:"sessionStartTime"` + // Whether the session ended normally ("routine") or due to a crash/fatal error ("error") + ShutdownType ShutdownType `json:"shutdownType"` + // System message token count at shutdown + SystemTokens *float64 `json:"systemTokens,omitempty"` + // Tool definitions token count at shutdown + ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"` + // Cumulative time spent in API calls during the session, in milliseconds + TotalAPIDurationMs float64 `json:"totalApiDurationMs"` + // Total number of premium API requests used during the session + TotalPremiumRequests float64 `json:"totalPremiumRequests"` } -func (*SamplingRequestedData) sessionEventData() {} +func (*SessionShutdownData) sessionEventData() {} -// Sampling request completion notification signaling UI dismissal -type SamplingCompletedData struct { - // Request ID of the resolved sampling request; clients should dismiss any UI for this request - RequestID string `json:"requestId"` +// Session title change payload containing the new display title +type SessionTitleChangedData struct { + // The new display title for the session + Title string `json:"title"` } -func (*SamplingCompletedData) sessionEventData() {} +func (*SessionTitleChangedData) sessionEventData() {} -// OAuth authentication request for an MCP server -type McpOauthRequiredData struct { - // Unique identifier for this OAuth request; used to respond via session.respondToMcpOAuth() - RequestID string `json:"requestId"` - // Display name of the MCP server that requires OAuth - ServerName string `json:"serverName"` - // URL of the MCP server that requires OAuth - ServerURL string `json:"serverUrl"` - // Static OAuth client configuration, if the server specifies one - StaticClientConfig *McpOauthRequiredStaticClientConfig `json:"staticClientConfig,omitempty"` +// SessionBackgroundTasksChangedData holds the payload for session.background_tasks_changed events. +type SessionBackgroundTasksChangedData struct { } -func (*McpOauthRequiredData) sessionEventData() {} +func (*SessionBackgroundTasksChangedData) sessionEventData() {} -// MCP OAuth request completion notification -type McpOauthCompletedData struct { - // Request ID of the resolved OAuth request - RequestID string `json:"requestId"` +// SessionCustomAgentsUpdatedData holds the payload for session.custom_agents_updated events. +type SessionCustomAgentsUpdatedData struct { + // Array of loaded custom agent metadata + Agents []CustomAgentsUpdatedAgent `json:"agents"` + // Fatal errors from agent loading + Errors []string `json:"errors"` + // Non-fatal warnings from agent loading + Warnings []string `json:"warnings"` } -func (*McpOauthCompletedData) sessionEventData() {} +func (*SessionCustomAgentsUpdatedData) sessionEventData() {} -// External tool invocation request for client-side tool execution -type ExternalToolRequestedData struct { - // Unique identifier for this request; used to respond via session.respondToExternalTool() - RequestID string `json:"requestId"` - // Session ID that this external tool request belongs to - SessionID string `json:"sessionId"` - // Tool call ID assigned to this external tool invocation - ToolCallID string `json:"toolCallId"` - // Name of the external tool to invoke - ToolName string `json:"toolName"` - // Arguments to pass to the external tool - Arguments any `json:"arguments,omitempty"` - // W3C Trace Context traceparent header for the execute_tool span - Traceparent *string `json:"traceparent,omitempty"` - // W3C Trace Context tracestate header for the execute_tool span - Tracestate *string `json:"tracestate,omitempty"` +// SessionExtensionsLoadedData holds the payload for session.extensions_loaded events. +type SessionExtensionsLoadedData struct { + // Array of discovered extensions and their status + Extensions []ExtensionsLoadedExtension `json:"extensions"` } -func (*ExternalToolRequestedData) sessionEventData() {} +func (*SessionExtensionsLoadedData) sessionEventData() {} -// External tool completion notification signaling UI dismissal -type ExternalToolCompletedData struct { - // Request ID of the resolved external tool request; clients should dismiss any UI for this request - RequestID string `json:"requestId"` +// SessionMcpServerStatusChangedData holds the payload for session.mcp_server_status_changed events. +type SessionMcpServerStatusChangedData struct { + // Name of the MCP server whose status changed + ServerName string `json:"serverName"` + // New connection status: connected, failed, needs-auth, pending, disabled, or not_configured + Status McpServerStatusChangedStatus `json:"status"` } -func (*ExternalToolCompletedData) sessionEventData() {} +func (*SessionMcpServerStatusChangedData) sessionEventData() {} -// Queued slash command dispatch request for client execution -type CommandQueuedData struct { - // Unique identifier for this request; used to respond via session.respondToQueuedCommand() - RequestID string `json:"requestId"` - // The slash command text to be executed (e.g., /help, /clear) - Command string `json:"command"` +// SessionMcpServersLoadedData holds the payload for session.mcp_servers_loaded events. +type SessionMcpServersLoadedData struct { + // Array of MCP server status summaries + Servers []McpServersLoadedServer `json:"servers"` } -func (*CommandQueuedData) sessionEventData() {} +func (*SessionMcpServersLoadedData) sessionEventData() {} -// Registered command dispatch request routed to the owning client -type CommandExecuteData struct { - // Unique identifier; used to respond via session.commands.handlePendingCommand() - RequestID string `json:"requestId"` - // The full command text (e.g., /deploy production) - Command string `json:"command"` - // Command name without leading / - CommandName string `json:"commandName"` - // Raw argument string after the command name - Args string `json:"args"` +// SessionSkillsLoadedData holds the payload for session.skills_loaded events. +type SessionSkillsLoadedData struct { + // Array of resolved skill metadata + Skills []SkillsLoadedSkill `json:"skills"` } -func (*CommandExecuteData) sessionEventData() {} +func (*SessionSkillsLoadedData) sessionEventData() {} -// Queued command completion notification signaling UI dismissal -type CommandCompletedData struct { - // Request ID of the resolved command request; clients should dismiss any UI for this request - RequestID string `json:"requestId"` +// SessionToolsUpdatedData holds the payload for session.tools_updated events. +type SessionToolsUpdatedData struct { + Model string `json:"model"` } -func (*CommandCompletedData) sessionEventData() {} +func (*SessionToolsUpdatedData) sessionEventData() {} -// SDK command registration change notification -type CommandsChangedData struct { - // Current list of registered SDK commands - Commands []CommandsChangedCommand `json:"commands"` +// Skill invocation details including content, allowed tools, and plugin metadata +type SkillInvokedData struct { + // Tool names that should be auto-approved when this skill is active + AllowedTools []string `json:"allowedTools,omitempty"` + // Full content of the skill file, injected into the conversation for the model + Content string `json:"content"` + // Description of the skill from its SKILL.md frontmatter + Description *string `json:"description,omitempty"` + // Name of the invoked skill + Name string `json:"name"` + // File path to the SKILL.md definition + Path string `json:"path"` + // Name of the plugin this skill originated from, when applicable + PluginName *string `json:"pluginName,omitempty"` + // Version of the plugin this skill originated from, when applicable + PluginVersion *string `json:"pluginVersion,omitempty"` } -func (*CommandsChangedData) sessionEventData() {} +func (*SkillInvokedData) sessionEventData() {} -// Session capability change notification -type CapabilitiesChangedData struct { - // UI capability changes - UI *CapabilitiesChangedUI `json:"ui,omitempty"` +// Streaming assistant message delta for incremental response updates +type AssistantMessageDeltaData struct { + // Incremental text chunk to append to the message content + DeltaContent string `json:"deltaContent"` + // Message ID this delta belongs to, matching the corresponding assistant.message event + MessageID string `json:"messageId"` + // Tool call ID of the parent tool invocation when this event originates from a sub-agent + // Deprecated: ParentToolCallID is deprecated. + ParentToolCallID *string `json:"parentToolCallId,omitempty"` } -func (*CapabilitiesChangedData) sessionEventData() {} +func (*AssistantMessageDeltaData) sessionEventData() {} -// Plan approval request with plan content and available user actions -type ExitPlanModeRequestedData struct { - // Unique identifier for this request; used to respond via session.respondToExitPlanMode() - RequestID string `json:"requestId"` - // Summary of the plan that was created - Summary string `json:"summary"` - // Full content of the plan file - PlanContent string `json:"planContent"` - // Available actions the user can take (e.g., approve, edit, reject) - Actions []string `json:"actions"` - // The recommended action for the user to take - RecommendedAction string `json:"recommendedAction"` +// Streaming reasoning delta for incremental extended thinking updates +type AssistantReasoningDeltaData struct { + // Incremental text chunk to append to the reasoning content + DeltaContent string `json:"deltaContent"` + // Reasoning block ID this delta belongs to, matching the corresponding assistant.reasoning event + ReasoningID string `json:"reasoningId"` } -func (*ExitPlanModeRequestedData) sessionEventData() {} +func (*AssistantReasoningDeltaData) sessionEventData() {} -// Plan mode exit completion with the user's approval decision and optional feedback -type ExitPlanModeCompletedData struct { - // Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request - RequestID string `json:"requestId"` - // Whether the plan was approved by the user - Approved *bool `json:"approved,omitempty"` - // Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only') - SelectedAction *string `json:"selectedAction,omitempty"` - // Whether edits should be auto-approved without confirmation - AutoApproveEdits *bool `json:"autoApproveEdits,omitempty"` - // Free-form feedback from the user if they requested changes to the plan - Feedback *string `json:"feedback,omitempty"` +// Streaming response progress with cumulative byte count +type AssistantStreamingDeltaData struct { + // Cumulative total bytes received from the streaming response so far + TotalResponseSizeBytes float64 `json:"totalResponseSizeBytes"` } -func (*ExitPlanModeCompletedData) sessionEventData() {} +func (*AssistantStreamingDeltaData) sessionEventData() {} -// SessionToolsUpdatedData holds the payload for session.tools_updated events. -type SessionToolsUpdatedData struct { - Model string `json:"model"` +// Streaming tool execution output for incremental result display +type ToolExecutionPartialResultData struct { + // Incremental output chunk from the running tool + PartialOutput string `json:"partialOutput"` + // Tool call ID this partial result belongs to + ToolCallID string `json:"toolCallId"` } -func (*SessionToolsUpdatedData) sessionEventData() {} +func (*ToolExecutionPartialResultData) sessionEventData() {} -// SessionBackgroundTasksChangedData holds the payload for session.background_tasks_changed events. -type SessionBackgroundTasksChangedData struct { +// Sub-agent completion details for successful execution +type SubagentCompletedData struct { + // Human-readable display name of the sub-agent + AgentDisplayName string `json:"agentDisplayName"` + // Internal name of the sub-agent + AgentName string `json:"agentName"` + // Wall-clock duration of the sub-agent execution in milliseconds + DurationMs *float64 `json:"durationMs,omitempty"` + // Model used by the sub-agent + Model *string `json:"model,omitempty"` + // Tool call ID of the parent tool invocation that spawned this sub-agent + ToolCallID string `json:"toolCallId"` + // Total tokens (input + output) consumed by the sub-agent + TotalTokens *float64 `json:"totalTokens,omitempty"` + // Total number of tool calls made by the sub-agent + TotalToolCalls *float64 `json:"totalToolCalls,omitempty"` } -func (*SessionBackgroundTasksChangedData) sessionEventData() {} +func (*SubagentCompletedData) sessionEventData() {} -// SessionSkillsLoadedData holds the payload for session.skills_loaded events. -type SessionSkillsLoadedData struct { - // Array of resolved skill metadata - Skills []SkillsLoadedSkill `json:"skills"` +// Sub-agent failure details including error message and agent information +type SubagentFailedData struct { + // Human-readable display name of the sub-agent + AgentDisplayName string `json:"agentDisplayName"` + // Internal name of the sub-agent + AgentName string `json:"agentName"` + // Wall-clock duration of the sub-agent execution in milliseconds + DurationMs *float64 `json:"durationMs,omitempty"` + // Error message describing why the sub-agent failed + Error string `json:"error"` + // Model used by the sub-agent (if any model calls succeeded before failure) + Model *string `json:"model,omitempty"` + // Tool call ID of the parent tool invocation that spawned this sub-agent + ToolCallID string `json:"toolCallId"` + // Total tokens (input + output) consumed before the sub-agent failed + TotalTokens *float64 `json:"totalTokens,omitempty"` + // Total number of tool calls made before the sub-agent failed + TotalToolCalls *float64 `json:"totalToolCalls,omitempty"` } -func (*SessionSkillsLoadedData) sessionEventData() {} +func (*SubagentFailedData) sessionEventData() {} -// SessionCustomAgentsUpdatedData holds the payload for session.custom_agents_updated events. -type SessionCustomAgentsUpdatedData struct { - // Array of loaded custom agent metadata - Agents []CustomAgentsUpdatedAgent `json:"agents"` - // Non-fatal warnings from agent loading - Warnings []string `json:"warnings"` - // Fatal errors from agent loading - Errors []string `json:"errors"` +// Sub-agent startup details including parent tool call and agent information +type SubagentStartedData struct { + // Description of what the sub-agent does + AgentDescription string `json:"agentDescription"` + // Human-readable display name of the sub-agent + AgentDisplayName string `json:"agentDisplayName"` + // Internal name of the sub-agent + AgentName string `json:"agentName"` + // Tool call ID of the parent tool invocation that spawned this sub-agent + ToolCallID string `json:"toolCallId"` } -func (*SessionCustomAgentsUpdatedData) sessionEventData() {} +func (*SubagentStartedData) sessionEventData() {} -// SessionMcpServersLoadedData holds the payload for session.mcp_servers_loaded events. -type SessionMcpServersLoadedData struct { - // Array of MCP server status summaries - Servers []McpServersLoadedServer `json:"servers"` +// System-generated notification for runtime events like background task completion +type SystemNotificationData struct { + // The notification text, typically wrapped in XML tags + Content string `json:"content"` + // Structured metadata identifying what triggered this notification + Kind SystemNotification `json:"kind"` } -func (*SessionMcpServersLoadedData) sessionEventData() {} +func (*SystemNotificationData) sessionEventData() {} -// SessionMcpServerStatusChangedData holds the payload for session.mcp_server_status_changed events. -type SessionMcpServerStatusChangedData struct { - // Name of the MCP server whose status changed - ServerName string `json:"serverName"` - // New connection status: connected, failed, needs-auth, pending, disabled, or not_configured - Status McpServerStatusChangedStatus `json:"status"` +// System/developer instruction content with role and optional template metadata +type SystemMessageData struct { + // The system or developer prompt text sent as model input + Content string `json:"content"` + // Metadata about the prompt template and its construction + Metadata *SystemMessageMetadata `json:"metadata,omitempty"` + // Optional name identifier for the message source + Name *string `json:"name,omitempty"` + // Message role: "system" for system prompts, "developer" for developer-injected instructions + Role SystemMessageRole `json:"role"` } -func (*SessionMcpServerStatusChangedData) sessionEventData() {} +func (*SystemMessageData) sessionEventData() {} -// SessionExtensionsLoadedData holds the payload for session.extensions_loaded events. -type SessionExtensionsLoadedData struct { - // Array of discovered extensions and their status - Extensions []ExtensionsLoadedExtension `json:"extensions"` +// Task completion notification with summary from the agent +type SessionTaskCompleteData struct { + // Whether the tool call succeeded. False when validation failed (e.g., invalid arguments) + Success *bool `json:"success,omitempty"` + // Summary of the completed task, provided by the agent + Summary *string `json:"summary,omitempty"` } -func (*SessionExtensionsLoadedData) sessionEventData() {} +func (*SessionTaskCompleteData) sessionEventData() {} -// Working directory and git context at session start -type WorkingDirectoryContext struct { - // Current working directory path - Cwd string `json:"cwd"` - // Root directory of the git repository, resolved via git rev-parse - GitRoot *string `json:"gitRoot,omitempty"` - // Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) - Repository *string `json:"repository,omitempty"` - // Hosting platform type of the repository (github or ado) - HostType *WorkingDirectoryContextHostType `json:"hostType,omitempty"` - // Current git branch name - Branch *string `json:"branch,omitempty"` - // Head commit of current git branch at session start time - HeadCommit *string `json:"headCommit,omitempty"` - // Base commit of current git branch at session start time - BaseCommit *string `json:"baseCommit,omitempty"` +// Tool execution completion results including success status, detailed output, and error information +type ToolExecutionCompleteData struct { + // Error details when the tool execution failed + Error *ToolExecutionCompleteError `json:"error,omitempty"` + // CAPI interaction ID for correlating this tool execution with upstream telemetry + InteractionID *string `json:"interactionId,omitempty"` + // Whether this tool call was explicitly requested by the user rather than the assistant + IsUserRequested *bool `json:"isUserRequested,omitempty"` + // Model identifier that generated this tool call + Model *string `json:"model,omitempty"` + // Tool call ID of the parent tool invocation when this event originates from a sub-agent + // Deprecated: ParentToolCallID is deprecated. + ParentToolCallID *string `json:"parentToolCallId,omitempty"` + // Tool execution result on success + Result *ToolExecutionCompleteResult `json:"result,omitempty"` + // Whether the tool execution completed successfully + Success bool `json:"success"` + // Unique identifier for the completed tool call + ToolCallID string `json:"toolCallId"` + // Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts) + ToolTelemetry map[string]any `json:"toolTelemetry,omitempty"` } -// Repository context for the handed-off session -type HandoffRepository struct { - // Repository owner (user or organization) - Owner string `json:"owner"` - // Repository name - Name string `json:"name"` - // Git branch name, if applicable - Branch *string `json:"branch,omitempty"` -} +func (*ToolExecutionCompleteData) sessionEventData() {} -// Aggregate code change metrics for the session -type ShutdownCodeChanges struct { - // Total number of lines added during the session - LinesAdded float64 `json:"linesAdded"` - // Total number of lines removed during the session - LinesRemoved float64 `json:"linesRemoved"` - // List of file paths that were modified during the session - FilesModified []string `json:"filesModified"` +// Tool execution progress notification with status message +type ToolExecutionProgressData struct { + // Human-readable progress status message (e.g., from an MCP server) + ProgressMessage string `json:"progressMessage"` + // Tool call ID this progress notification belongs to + ToolCallID string `json:"toolCallId"` } -// Request count and cost metrics -type ShutdownModelMetricRequests struct { - // Total number of API requests made to this model - Count float64 `json:"count"` - // Cumulative cost multiplier for requests to this model - Cost float64 `json:"cost"` -} +func (*ToolExecutionProgressData) sessionEventData() {} -// Token usage breakdown -type ShutdownModelMetricUsage struct { - // Total input tokens consumed across all requests to this model - InputTokens float64 `json:"inputTokens"` - // Total output tokens produced across all requests to this model - OutputTokens float64 `json:"outputTokens"` - // Total tokens read from prompt cache across all requests - CacheReadTokens float64 `json:"cacheReadTokens"` - // Total tokens written to prompt cache across all requests - CacheWriteTokens float64 `json:"cacheWriteTokens"` - // Total reasoning tokens produced across all requests to this model - ReasoningTokens *float64 `json:"reasoningTokens,omitempty"` +// Tool execution startup details including MCP server information when applicable +type ToolExecutionStartData struct { + // Arguments passed to the tool + Arguments any `json:"arguments,omitempty"` + // Name of the MCP server hosting this tool, when the tool is an MCP tool + McpServerName *string `json:"mcpServerName,omitempty"` + // Original tool name on the MCP server, when the tool is an MCP tool + McpToolName *string `json:"mcpToolName,omitempty"` + // Tool call ID of the parent tool invocation when this event originates from a sub-agent + // Deprecated: ParentToolCallID is deprecated. + ParentToolCallID *string `json:"parentToolCallId,omitempty"` + // Unique identifier for this tool call + ToolCallID string `json:"toolCallId"` + // Name of the tool being executed + ToolName string `json:"toolName"` } -type ShutdownModelMetric struct { - // Request count and cost metrics - Requests ShutdownModelMetricRequests `json:"requests"` - // Token usage breakdown - Usage ShutdownModelMetricUsage `json:"usage"` -} +func (*ToolExecutionStartData) sessionEventData() {} -// Token usage breakdown for the compaction LLM call -type CompactionCompleteCompactionTokensUsed struct { - // Input tokens consumed by the compaction LLM call - Input float64 `json:"input"` - // Output tokens produced by the compaction LLM call - Output float64 `json:"output"` - // Cached input tokens reused in the compaction LLM call - CachedInput float64 `json:"cachedInput"` +// Turn abort information including the reason for termination +type AbortData struct { + // Reason the current turn was aborted (e.g., "user initiated") + Reason string `json:"reason"` } -// Optional line range to scope the attachment to a specific section of the file -type UserMessageAttachmentFileLineRange struct { - // Start line number (1-based) - Start float64 `json:"start"` - // End line number (1-based, inclusive) - End float64 `json:"end"` -} +func (*AbortData) sessionEventData() {} -// Start position of the selection -type UserMessageAttachmentSelectionDetailsStart struct { - // Start line number (0-based) - Line float64 `json:"line"` - // Start character offset within the line (0-based) - Character float64 `json:"character"` +// Turn completion metadata including the turn identifier +type AssistantTurnEndData struct { + // Identifier of the turn that has ended, matching the corresponding assistant.turn_start event + TurnID string `json:"turnId"` } -// End position of the selection -type UserMessageAttachmentSelectionDetailsEnd struct { - // End line number (0-based) - Line float64 `json:"line"` - // End character offset within the line (0-based) - Character float64 `json:"character"` +func (*AssistantTurnEndData) sessionEventData() {} + +// Turn initialization metadata including identifier and interaction tracking +type AssistantTurnStartData struct { + // CAPI interaction ID for correlating this turn with upstream telemetry + InteractionID *string `json:"interactionId,omitempty"` + // Identifier for this turn within the agentic loop, typically a stringified turn number + TurnID string `json:"turnId"` } -// Position range of the selection within the file -type UserMessageAttachmentSelectionDetails struct { - // Start position of the selection - Start UserMessageAttachmentSelectionDetailsStart `json:"start"` - // End position of the selection - End UserMessageAttachmentSelectionDetailsEnd `json:"end"` +func (*AssistantTurnStartData) sessionEventData() {} + +// User input request completion with the user's response +type UserInputCompletedData struct { + // The user's answer to the input request + Answer *string `json:"answer,omitempty"` + // Request ID of the resolved user input request; clients should dismiss any UI for this request + RequestID string `json:"requestId"` + // Whether the answer was typed as free-form text rather than selected from choices + WasFreeform *bool `json:"wasFreeform,omitempty"` } -// A user message attachment — a file, directory, code selection, blob, or GitHub reference -type UserMessageAttachment struct { - // Type discriminator - Type UserMessageAttachmentType `json:"type"` - // Absolute file path - Path *string `json:"path,omitempty"` - // User-facing display name for the attachment - DisplayName *string `json:"displayName,omitempty"` - // Optional line range to scope the attachment to a specific section of the file - LineRange *UserMessageAttachmentFileLineRange `json:"lineRange,omitempty"` - // Absolute path to the file containing the selection - FilePath *string `json:"filePath,omitempty"` - // The selected text content - Text *string `json:"text,omitempty"` - // Position range of the selection within the file - Selection *UserMessageAttachmentSelectionDetails `json:"selection,omitempty"` - // Issue, pull request, or discussion number - Number *float64 `json:"number,omitempty"` - // Title of the referenced item - Title *string `json:"title,omitempty"` - // Type of GitHub reference - ReferenceType *UserMessageAttachmentGithubReferenceType `json:"referenceType,omitempty"` - // Current state of the referenced item (e.g., open, closed, merged) - State *string `json:"state,omitempty"` - // URL to the referenced item on GitHub - URL *string `json:"url,omitempty"` - // Base64-encoded content - Data *string `json:"data,omitempty"` - // MIME type of the inline data - MIMEType *string `json:"mimeType,omitempty"` +func (*UserInputCompletedData) sessionEventData() {} + +// User input request notification with question and optional predefined choices +type UserInputRequestedData struct { + // Whether the user can provide a free-form text response in addition to predefined choices + AllowFreeform *bool `json:"allowFreeform,omitempty"` + // Predefined choices for the user to select from, if applicable + Choices []string `json:"choices,omitempty"` + // The question or prompt to present to the user + Question string `json:"question"` + // Unique identifier for this input request; used to respond via session.respondToUserInput() + RequestID string `json:"requestId"` + // The LLM-assigned tool call ID that triggered this request; used by remote UIs to correlate responses + ToolCallID *string `json:"toolCallId,omitempty"` } -// A tool invocation request from the assistant -type AssistantMessageToolRequest struct { +func (*UserInputRequestedData) sessionEventData() {} + +// User-initiated tool invocation request with tool name and arguments +type ToolUserRequestedData struct { + // Arguments for the tool invocation + Arguments any `json:"arguments,omitempty"` // Unique identifier for this tool call ToolCallID string `json:"toolCallId"` - // Name of the tool being invoked - Name string `json:"name"` - // Arguments to pass to the tool, format depends on the tool - Arguments any `json:"arguments,omitempty"` - // Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. - Type *AssistantMessageToolRequestType `json:"type,omitempty"` - // Human-readable display title for the tool - ToolTitle *string `json:"toolTitle,omitempty"` - // Name of the MCP server hosting this tool, when the tool is an MCP tool - McpServerName *string `json:"mcpServerName,omitempty"` - // Resolved intention summary describing what this specific call does - IntentionSummary *string `json:"intentionSummary,omitempty"` + // Name of the tool the user wants to invoke + ToolName string `json:"toolName"` } -type AssistantUsageQuotaSnapshot struct { - // Whether the user has an unlimited usage entitlement - IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` - // Total requests allowed by the entitlement - EntitlementRequests float64 `json:"entitlementRequests"` - // Number of requests already consumed - UsedRequests float64 `json:"usedRequests"` - // Whether usage is still permitted after quota exhaustion - UsageAllowedWithExhaustedQuota bool `json:"usageAllowedWithExhaustedQuota"` - // Number of requests over the entitlement limit - Overage float64 `json:"overage"` - // Whether overage is allowed when quota is exhausted - OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` - // Percentage of quota remaining (0.0 to 1.0) - RemainingPercentage float64 `json:"remainingPercentage"` - // Date when the quota resets - ResetDate *time.Time `json:"resetDate,omitempty"` +func (*ToolUserRequestedData) sessionEventData() {} + +// UserMessageData holds the payload for user.message events. +type UserMessageData struct { + // The agent mode that was active when this message was sent + AgentMode *UserMessageAgentMode `json:"agentMode,omitempty"` + // Files, selections, or GitHub references attached to the message + Attachments []UserMessageAttachment `json:"attachments,omitempty"` + // The user's message text as displayed in the timeline + Content string `json:"content"` + // CAPI interaction ID for correlating this user message with its turn + InteractionID *string `json:"interactionId,omitempty"` + // Path-backed native document attachments that stayed on the tagged_files path flow because native upload would exceed the request size limit + NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitempty"` + // Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user) + Source *string `json:"source,omitempty"` + // Normalized document MIME types that were sent natively instead of through tagged_files XML + SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitempty"` + // Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching + TransformedContent *string `json:"transformedContent,omitempty"` } -// Token usage detail for a single billing category -type AssistantUsageCopilotUsageTokenDetail struct { - // Number of tokens in this billing batch - BatchSize float64 `json:"batchSize"` - // Cost per batch of tokens - CostPerBatch float64 `json:"costPerBatch"` - // Total token count for this entry - TokenCount float64 `json:"tokenCount"` - // Token category (e.g., "input", "output") - TokenType string `json:"tokenType"` +func (*UserMessageData) sessionEventData() {} + +// Warning message for timeline display with categorization +type SessionWarningData struct { + // Human-readable warning message for display in the timeline + Message string `json:"message"` + // Optional URL associated with this warning that the user can open in a browser + URL *string `json:"url,omitempty"` + // Category of warning (e.g., "subscription", "policy", "mcp") + WarningType string `json:"warningType"` } -// Per-request cost and usage data from the CAPI copilot_usage response field -type AssistantUsageCopilotUsage struct { - // Itemized token usage breakdown - TokenDetails []AssistantUsageCopilotUsageTokenDetail `json:"tokenDetails"` - // Total cost in nano-AIU (AI Units) for this request - TotalNanoAiu float64 `json:"totalNanoAiu"` +func (*SessionWarningData) sessionEventData() {} + +// Working directory and git context at session start +type SessionContextChangedData struct { + // Base commit of current git branch at session start time + BaseCommit *string `json:"baseCommit,omitempty"` + // Current git branch name + Branch *string `json:"branch,omitempty"` + // Current working directory path + Cwd string `json:"cwd"` + // Root directory of the git repository, resolved via git rev-parse + GitRoot *string `json:"gitRoot,omitempty"` + // Head commit of current git branch at session start time + HeadCommit *string `json:"headCommit,omitempty"` + // Hosting platform type of the repository (github or ado) + HostType *WorkingDirectoryContextHostType `json:"hostType,omitempty"` + // Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) + Repository *string `json:"repository,omitempty"` + // Raw host string from the git remote URL (e.g. "github.com", "mycompany.ghe.com", "dev.azure.com") + RepositoryHost *string `json:"repositoryHost,omitempty"` +} + +func (*SessionContextChangedData) sessionEventData() {} + +// Workspace file change details including path and operation type +type SessionWorkspaceFileChangedData struct { + // Whether the file was newly created or updated + Operation WorkspaceFileChangedOperation `json:"operation"` + // Relative path within the session workspace files directory + Path string `json:"path"` } -// Icon image for a resource -type ToolExecutionCompleteContentResourceLinkIcon struct { - // URL or path to the icon image - Src string `json:"src"` - // MIME type of the icon image - MIMEType *string `json:"mimeType,omitempty"` - // Available icon sizes (e.g., ['16x16', '32x32']) - Sizes []string `json:"sizes,omitempty"` - // Theme variant this icon is intended for - Theme *ToolExecutionCompleteContentResourceLinkIconTheme `json:"theme,omitempty"` -} +func (*SessionWorkspaceFileChangedData) sessionEventData() {} // A content block within a tool result, which may be text, terminal output, image, audio, or a resource type ToolExecutionCompleteContent struct { // Type discriminator Type ToolExecutionCompleteContentType `json:"type"` - // The text content - Text *string `json:"text,omitempty"` - // Process exit code, if the command has completed - ExitCode *float64 `json:"exitCode,omitempty"` // Working directory where the command was executed Cwd *string `json:"cwd,omitempty"` // Base64-encoded image data Data *string `json:"data,omitempty"` - // MIME type of the image (e.g., image/png, image/jpeg) - MIMEType *string `json:"mimeType,omitempty"` + // Human-readable description of the resource + Description *string `json:"description,omitempty"` + // Process exit code, if the command has completed + ExitCode *float64 `json:"exitCode,omitempty"` // Icons associated with this resource Icons []ToolExecutionCompleteContentResourceLinkIcon `json:"icons,omitempty"` + // MIME type of the image (e.g., image/png, image/jpeg) + MIMEType *string `json:"mimeType,omitempty"` // Resource name identifier Name *string `json:"name,omitempty"` + // The embedded resource contents, either text or base64-encoded binary + Resource any `json:"resource,omitempty"` + // Size of the resource in bytes + Size *float64 `json:"size,omitempty"` + // The text content + Text *string `json:"text,omitempty"` // Human-readable display title for the resource Title *string `json:"title,omitempty"` // URI identifying the resource URI *string `json:"uri,omitempty"` - // Human-readable description of the resource - Description *string `json:"description,omitempty"` - // Size of the resource in bytes - Size *float64 `json:"size,omitempty"` - // The embedded resource contents, either text or base64-encoded binary - Resource any `json:"resource,omitempty"` } -// Tool execution result on success -type ToolExecutionCompleteResult struct { - // Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency - Content string `json:"content"` - // Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. - DetailedContent *string `json:"detailedContent,omitempty"` - // Structured content blocks (text, images, audio, resources) returned by the tool in their native format - Contents []ToolExecutionCompleteContent `json:"contents,omitempty"` +// A tool invocation request from the assistant +type AssistantMessageToolRequest struct { + // Arguments to pass to the tool, format depends on the tool + Arguments any `json:"arguments,omitempty"` + // Resolved intention summary describing what this specific call does + IntentionSummary *string `json:"intentionSummary,omitempty"` + // Name of the MCP server hosting this tool, when the tool is an MCP tool + McpServerName *string `json:"mcpServerName,omitempty"` + // Name of the tool being invoked + Name string `json:"name"` + // Unique identifier for this tool call + ToolCallID string `json:"toolCallId"` + // Human-readable display title for the tool + ToolTitle *string `json:"toolTitle,omitempty"` + // Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. + Type *AssistantMessageToolRequestType `json:"type,omitempty"` } -// Error details when the tool execution failed -type ToolExecutionCompleteError struct { - // Human-readable error message - Message string `json:"message"` - // Machine-readable error code - Code *string `json:"code,omitempty"` +// A user message attachment — a file, directory, code selection, blob, or GitHub reference +type UserMessageAttachment struct { + // Type discriminator + Type UserMessageAttachmentType `json:"type"` + // Base64-encoded content + Data *string `json:"data,omitempty"` + // User-facing display name for the attachment + DisplayName *string `json:"displayName,omitempty"` + // Absolute path to the file containing the selection + FilePath *string `json:"filePath,omitempty"` + // Optional line range to scope the attachment to a specific section of the file + LineRange *UserMessageAttachmentFileLineRange `json:"lineRange,omitempty"` + // MIME type of the inline data + MIMEType *string `json:"mimeType,omitempty"` + // Issue, pull request, or discussion number + Number *float64 `json:"number,omitempty"` + // Absolute file path + Path *string `json:"path,omitempty"` + // Type of GitHub reference + ReferenceType *UserMessageAttachmentGithubReferenceType `json:"referenceType,omitempty"` + // Position range of the selection within the file + Selection *UserMessageAttachmentSelectionDetails `json:"selection,omitempty"` + // Current state of the referenced item (e.g., open, closed, merged) + State *string `json:"state,omitempty"` + // The selected text content + Text *string `json:"text,omitempty"` + // Title of the referenced item + Title *string `json:"title,omitempty"` + // URL to the referenced item on GitHub + URL *string `json:"url,omitempty"` +} + +// Aggregate code change metrics for the session +type ShutdownCodeChanges struct { + // List of file paths that were modified during the session + FilesModified []string `json:"filesModified"` + // Total number of lines added during the session + LinesAdded float64 `json:"linesAdded"` + // Total number of lines removed during the session + LinesRemoved float64 `json:"linesRemoved"` +} + +// Details of the permission being requested +type PermissionRequest struct { + // Kind discriminator + Kind PermissionRequestKind `json:"kind"` + // Whether this is a store or vote memory operation + Action *PermissionRequestMemoryAction `json:"action,omitempty"` + // Arguments to pass to the MCP tool + Args any `json:"args,omitempty"` + // Whether the UI can offer session-wide approval for this command pattern + CanOfferSessionApproval *bool `json:"canOfferSessionApproval,omitempty"` + // Source references for the stored fact (store only) + Citations *string `json:"citations,omitempty"` + // Parsed command identifiers found in the command text + Commands []PermissionRequestShellCommand `json:"commands,omitempty"` + // Unified diff showing the proposed changes + Diff *string `json:"diff,omitempty"` + // Vote direction (vote only) + Direction *PermissionRequestMemoryDirection `json:"direction,omitempty"` + // The fact being stored or voted on + Fact *string `json:"fact,omitempty"` + // Path of the file being written to + FileName *string `json:"fileName,omitempty"` + // The complete shell command text to be executed + FullCommandText *string `json:"fullCommandText,omitempty"` + // Whether the command includes a file write redirection (e.g., > or >>) + HasWriteFileRedirection *bool `json:"hasWriteFileRedirection,omitempty"` + // Optional message from the hook explaining why confirmation is needed + HookMessage *string `json:"hookMessage,omitempty"` + // Human-readable description of what the command intends to do + Intention *string `json:"intention,omitempty"` + // Complete new file contents for newly created files + NewFileContents *string `json:"newFileContents,omitempty"` + // Path of the file or directory being read + Path *string `json:"path,omitempty"` + // File paths that may be read or written by the command + PossiblePaths []string `json:"possiblePaths,omitempty"` + // URLs that may be accessed by the command + PossibleUrls []PermissionRequestShellPossibleURL `json:"possibleUrls,omitempty"` + // Whether this MCP tool is read-only (no side effects) + ReadOnly *bool `json:"readOnly,omitempty"` + // Reason for the vote (vote only) + Reason *string `json:"reason,omitempty"` + // Name of the MCP server providing the tool + ServerName *string `json:"serverName,omitempty"` + // Topic or subject of the memory (store only) + Subject *string `json:"subject,omitempty"` + // Arguments of the tool call being gated + ToolArgs any `json:"toolArgs,omitempty"` + // Tool call ID that triggered this permission request + ToolCallID *string `json:"toolCallId,omitempty"` + // Description of what the custom tool does + ToolDescription *string `json:"toolDescription,omitempty"` + // Internal name of the MCP tool + ToolName *string `json:"toolName,omitempty"` + // Human-readable title of the MCP tool + ToolTitle *string `json:"toolTitle,omitempty"` + // URL to be fetched + URL *string `json:"url,omitempty"` + // Optional warning message about risks of running this command + Warning *string `json:"warning,omitempty"` +} + +// End position of the selection +type UserMessageAttachmentSelectionDetailsEnd struct { + // End character offset within the line (0-based) + Character float64 `json:"character"` + // End line number (0-based) + Line float64 `json:"line"` } // Error details when the hook failed @@ -1906,6 +1810,36 @@ type HookEndError struct { Stack *string `json:"stack,omitempty"` } +// Error details when the tool execution failed +type ToolExecutionCompleteError struct { + // Machine-readable error code + Code *string `json:"code,omitempty"` + // Human-readable error message + Message string `json:"message"` +} + +// Icon image for a resource +type ToolExecutionCompleteContentResourceLinkIcon struct { + // MIME type of the icon image + MIMEType *string `json:"mimeType,omitempty"` + // Available icon sizes (e.g., ['16x16', '32x32']) + Sizes []string `json:"sizes,omitempty"` + // URL or path to the icon image + Src string `json:"src"` + // Theme variant this icon is intended for + Theme *ToolExecutionCompleteContentResourceLinkIconTheme `json:"theme,omitempty"` +} + +// JSON Schema describing the form fields to present to the user (form mode only) +type ElicitationRequestedSchema struct { + // Form field definitions, keyed by field name + Properties map[string]any `json:"properties"` + // List of required field names + Required []string `json:"required,omitempty"` + // Schema type indicator (always 'object') + Type string `json:"type"` +} + // Metadata about the prompt template and its construction type SystemMessageMetadata struct { // Version identifier of the prompt template used @@ -1914,6 +1848,64 @@ type SystemMessageMetadata struct { Variables map[string]any `json:"variables,omitempty"` } +// Optional line range to scope the attachment to a specific section of the file +type UserMessageAttachmentFileLineRange struct { + // End line number (1-based, inclusive) + End float64 `json:"end"` + // Start line number (1-based) + Start float64 `json:"start"` +} + +// Per-request cost and usage data from the CAPI copilot_usage response field +type AssistantUsageCopilotUsage struct { + // Itemized token usage breakdown + TokenDetails []AssistantUsageCopilotUsageTokenDetail `json:"tokenDetails"` + // Total cost in nano-AIU (AI Units) for this request + TotalNanoAiu float64 `json:"totalNanoAiu"` +} + +// Position range of the selection within the file +type UserMessageAttachmentSelectionDetails struct { + // End position of the selection + End UserMessageAttachmentSelectionDetailsEnd `json:"end"` + // Start position of the selection + Start UserMessageAttachmentSelectionDetailsStart `json:"start"` +} + +// Repository context for the handed-off session +type HandoffRepository struct { + // Git branch name, if applicable + Branch *string `json:"branch,omitempty"` + // Repository name + Name string `json:"name"` + // Repository owner (user or organization) + Owner string `json:"owner"` +} + +// Request count and cost metrics +type ShutdownModelMetricRequests struct { + // Cumulative cost multiplier for requests to this model + Cost float64 `json:"cost"` + // Total number of API requests made to this model + Count float64 `json:"count"` +} + +// Start position of the selection +type UserMessageAttachmentSelectionDetailsStart struct { + // Start character offset within the line (0-based) + Character float64 `json:"character"` + // Start line number (0-based) + Line float64 `json:"line"` +} + +// Static OAuth client configuration, if the server specifies one +type McpOauthRequiredStaticClientConfig struct { + // OAuth client ID for the server + ClientID string `json:"clientId"` + // Whether this is a public OAuth client + PublicClient *bool `json:"publicClient,omitempty"` +} + // Structured metadata identifying what triggered this notification type SystemNotification struct { // Type discriminator @@ -1922,90 +1914,24 @@ type SystemNotification struct { AgentID *string `json:"agentId,omitempty"` // Type of the agent (e.g., explore, task, general-purpose) AgentType *string `json:"agentType,omitempty"` - // Whether the agent completed successfully or failed - Status *SystemNotificationAgentCompletedStatus `json:"status,omitempty"` // Human-readable description of the agent task Description *string `json:"description,omitempty"` + // Unique identifier of the inbox entry + EntryID *string `json:"entryId,omitempty"` + // Exit code of the shell command, if available + ExitCode *float64 `json:"exitCode,omitempty"` // The full prompt given to the background agent Prompt *string `json:"prompt,omitempty"` + // Human-readable name of the sender + SenderName *string `json:"senderName,omitempty"` + // Category of the sender (e.g., ambient-agent, plugin, hook) + SenderType *string `json:"senderType,omitempty"` // Unique identifier of the shell session ShellID *string `json:"shellId,omitempty"` - // Exit code of the shell command, if available - ExitCode *float64 `json:"exitCode,omitempty"` -} - -type PermissionRequestShellCommand struct { - // Command identifier (e.g., executable name) - Identifier string `json:"identifier"` - // Whether this command is read-only (no side effects) - ReadOnly bool `json:"readOnly"` -} - -type PermissionRequestShellPossibleUrl struct { - // URL that may be accessed by the command - URL string `json:"url"` -} - -// Details of the permission being requested -type PermissionRequest struct { - // Kind discriminator - Kind PermissionRequestKind `json:"kind"` - // Tool call ID that triggered this permission request - ToolCallID *string `json:"toolCallId,omitempty"` - // The complete shell command text to be executed - FullCommandText *string `json:"fullCommandText,omitempty"` - // Human-readable description of what the command intends to do - Intention *string `json:"intention,omitempty"` - // Parsed command identifiers found in the command text - Commands []PermissionRequestShellCommand `json:"commands,omitempty"` - // File paths that may be read or written by the command - PossiblePaths []string `json:"possiblePaths,omitempty"` - // URLs that may be accessed by the command - PossibleUrls []PermissionRequestShellPossibleUrl `json:"possibleUrls,omitempty"` - // Whether the command includes a file write redirection (e.g., > or >>) - HasWriteFileRedirection *bool `json:"hasWriteFileRedirection,omitempty"` - // Whether the UI can offer session-wide approval for this command pattern - CanOfferSessionApproval *bool `json:"canOfferSessionApproval,omitempty"` - // Optional warning message about risks of running this command - Warning *string `json:"warning,omitempty"` - // Path of the file being written to - FileName *string `json:"fileName,omitempty"` - // Unified diff showing the proposed changes - Diff *string `json:"diff,omitempty"` - // Complete new file contents for newly created files - NewFileContents *string `json:"newFileContents,omitempty"` - // Path of the file or directory being read - Path *string `json:"path,omitempty"` - // Name of the MCP server providing the tool - ServerName *string `json:"serverName,omitempty"` - // Internal name of the MCP tool - ToolName *string `json:"toolName,omitempty"` - // Human-readable title of the MCP tool - ToolTitle *string `json:"toolTitle,omitempty"` - // Arguments to pass to the MCP tool - Args any `json:"args,omitempty"` - // Whether this MCP tool is read-only (no side effects) - ReadOnly *bool `json:"readOnly,omitempty"` - // URL to be fetched - URL *string `json:"url,omitempty"` - // Whether this is a store or vote memory operation - Action *PermissionRequestMemoryAction `json:"action,omitempty"` - // Topic or subject of the memory (store only) - Subject *string `json:"subject,omitempty"` - // The fact being stored or voted on - Fact *string `json:"fact,omitempty"` - // Source references for the stored fact (store only) - Citations *string `json:"citations,omitempty"` - // Vote direction (vote only) - Direction *PermissionRequestMemoryDirection `json:"direction,omitempty"` - // Reason for the vote (vote only) - Reason *string `json:"reason,omitempty"` - // Description of what the custom tool does - ToolDescription *string `json:"toolDescription,omitempty"` - // Arguments of the tool call being gated - ToolArgs any `json:"toolArgs,omitempty"` - // Optional message from the hook explaining why confirmation is needed - HookMessage *string `json:"hookMessage,omitempty"` + // Whether the agent completed successfully or failed + Status *SystemNotificationAgentCompletedStatus `json:"status,omitempty"` + // Short summary shown before the agent decides whether to read the inbox + Summary *string `json:"summary,omitempty"` } // The result of the permission request @@ -2014,27 +1940,50 @@ type PermissionCompletedResult struct { Kind PermissionCompletedKind `json:"kind"` } -// JSON Schema describing the form fields to present to the user (form mode only) -type ElicitationRequestedSchema struct { - // Schema type indicator (always 'object') - Type string `json:"type"` - // Form field definitions, keyed by field name - Properties map[string]any `json:"properties"` - // List of required field names - Required []string `json:"required,omitempty"` +// Token usage breakdown +type ShutdownModelMetricUsage struct { + // Total tokens read from prompt cache across all requests + CacheReadTokens float64 `json:"cacheReadTokens"` + // Total tokens written to prompt cache across all requests + CacheWriteTokens float64 `json:"cacheWriteTokens"` + // Total input tokens consumed across all requests to this model + InputTokens float64 `json:"inputTokens"` + // Total output tokens produced across all requests to this model + OutputTokens float64 `json:"outputTokens"` + // Total reasoning tokens produced across all requests to this model + ReasoningTokens *float64 `json:"reasoningTokens,omitempty"` } -// Static OAuth client configuration, if the server specifies one -type McpOauthRequiredStaticClientConfig struct { - // OAuth client ID for the server - ClientID string `json:"clientId"` - // Whether this is a public OAuth client - PublicClient *bool `json:"publicClient,omitempty"` +// Token usage breakdown for the compaction LLM call +type CompactionCompleteCompactionTokensUsed struct { + // Cached input tokens reused in the compaction LLM call + CachedInput float64 `json:"cachedInput"` + // Input tokens consumed by the compaction LLM call + Input float64 `json:"input"` + // Output tokens produced by the compaction LLM call + Output float64 `json:"output"` } -type CommandsChangedCommand struct { - Name string `json:"name"` - Description *string `json:"description,omitempty"` +// Token usage detail for a single billing category +type AssistantUsageCopilotUsageTokenDetail struct { + // Number of tokens in this billing batch + BatchSize float64 `json:"batchSize"` + // Cost per batch of tokens + CostPerBatch float64 `json:"costPerBatch"` + // Total token count for this entry + TokenCount float64 `json:"tokenCount"` + // Token category (e.g., "input", "output") + TokenType string `json:"tokenType"` +} + +// Tool execution result on success +type ToolExecutionCompleteResult struct { + // Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency + Content string `json:"content"` + // Structured content blocks (text, images, audio, resources) returned by the tool in their native format + Contents []ToolExecutionCompleteContent `json:"contents,omitempty"` + // Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. + DetailedContent *string `json:"detailedContent,omitempty"` } // UI capability changes @@ -2043,121 +1992,211 @@ type CapabilitiesChangedUI struct { Elicitation *bool `json:"elicitation,omitempty"` } -type SkillsLoadedSkill struct { - // Unique identifier for the skill - Name string `json:"name"` - // Description of what the skill does - Description string `json:"description"` - // Source location type of the skill (e.g., project, personal, plugin) - Source string `json:"source"` - // Whether the skill can be invoked by the user as a slash command - UserInvocable bool `json:"userInvocable"` - // Whether the skill is currently enabled - Enabled bool `json:"enabled"` - // Absolute path to the skill file, if available - Path *string `json:"path,omitempty"` +// Working directory and git context at session start +type WorkingDirectoryContext struct { + // Base commit of current git branch at session start time + BaseCommit *string `json:"baseCommit,omitempty"` + // Current git branch name + Branch *string `json:"branch,omitempty"` + // Current working directory path + Cwd string `json:"cwd"` + // Root directory of the git repository, resolved via git rev-parse + GitRoot *string `json:"gitRoot,omitempty"` + // Head commit of current git branch at session start time + HeadCommit *string `json:"headCommit,omitempty"` + // Hosting platform type of the repository (github or ado) + HostType *WorkingDirectoryContextHostType `json:"hostType,omitempty"` + // Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) + Repository *string `json:"repository,omitempty"` + // Raw host string from the git remote URL (e.g. "github.com", "mycompany.ghe.com", "dev.azure.com") + RepositoryHost *string `json:"repositoryHost,omitempty"` +} + +type AssistantUsageQuotaSnapshot struct { + // Total requests allowed by the entitlement + EntitlementRequests float64 `json:"entitlementRequests"` + // Whether the user has an unlimited usage entitlement + IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` + // Number of requests over the entitlement limit + Overage float64 `json:"overage"` + // Whether overage is allowed when quota is exhausted + OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` + // Percentage of quota remaining (0.0 to 1.0) + RemainingPercentage float64 `json:"remainingPercentage"` + // Date when the quota resets + ResetDate *time.Time `json:"resetDate,omitempty"` + // Whether usage is still permitted after quota exhaustion + UsageAllowedWithExhaustedQuota bool `json:"usageAllowedWithExhaustedQuota"` + // Number of requests already consumed + UsedRequests float64 `json:"usedRequests"` +} + +type CommandsChangedCommand struct { + Description *string `json:"description,omitempty"` + Name string `json:"name"` } type CustomAgentsUpdatedAgent struct { + // Description of what the agent does + Description string `json:"description"` + // Human-readable display name + DisplayName string `json:"displayName"` // Unique identifier for the agent ID string `json:"id"` + // Model override for this agent, if set + Model *string `json:"model,omitempty"` // Internal name of the agent Name string `json:"name"` - // Human-readable display name - DisplayName string `json:"displayName"` - // Description of what the agent does - Description string `json:"description"` // Source location: user, project, inherited, remote, or plugin Source string `json:"source"` // List of tool names available to this agent Tools []string `json:"tools"` // Whether the agent can be selected by the user UserInvocable bool `json:"userInvocable"` - // Model override for this agent, if set - Model *string `json:"model,omitempty"` +} + +type ExtensionsLoadedExtension struct { + // Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper') + ID string `json:"id"` + // Extension name (directory name) + Name string `json:"name"` + // Discovery source + Source ExtensionsLoadedExtensionSource `json:"source"` + // Current status: running, disabled, failed, or starting + Status ExtensionsLoadedExtensionStatus `json:"status"` } type McpServersLoadedServer struct { + // Error message if the server failed to connect + Error *string `json:"error,omitempty"` // Server name (config key) Name string `json:"name"` - // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured - Status McpServersLoadedServerStatus `json:"status"` // Configuration source: user, workspace, plugin, or builtin Source *string `json:"source,omitempty"` - // Error message if the server failed to connect - Error *string `json:"error,omitempty"` + // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured + Status McpServersLoadedServerStatus `json:"status"` } -type ExtensionsLoadedExtension struct { - // Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper') - ID string `json:"id"` - // Extension name (directory name) +type PermissionRequestShellCommand struct { + // Command identifier (e.g., executable name) + Identifier string `json:"identifier"` + // Whether this command is read-only (no side effects) + ReadOnly bool `json:"readOnly"` +} + +type PermissionRequestShellPossibleURL struct { + // URL that may be accessed by the command + URL string `json:"url"` +} + +type ShutdownModelMetric struct { + // Request count and cost metrics + Requests ShutdownModelMetricRequests `json:"requests"` + // Token usage breakdown + Usage ShutdownModelMetricUsage `json:"usage"` +} + +type SkillsLoadedSkill struct { + // Description of what the skill does + Description string `json:"description"` + // Whether the skill is currently enabled + Enabled bool `json:"enabled"` + // Unique identifier for the skill Name string `json:"name"` - // Discovery source - Source ExtensionsLoadedExtensionSource `json:"source"` - // Current status: running, disabled, failed, or starting - Status ExtensionsLoadedExtensionStatus `json:"status"` + // Absolute path to the skill file, if available + Path *string `json:"path,omitempty"` + // Source location type of the skill (e.g., project, personal, plugin) + Source string `json:"source"` + // Whether the skill can be invoked by the user as a slash command + UserInvocable bool `json:"userInvocable"` } -// Hosting platform type of the repository (github or ado) -type WorkingDirectoryContextHostType string +// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured +type McpServersLoadedServerStatus string const ( - WorkingDirectoryContextHostTypeGithub WorkingDirectoryContextHostType = "github" - WorkingDirectoryContextHostTypeAdo WorkingDirectoryContextHostType = "ado" + McpServersLoadedServerStatusConnected McpServersLoadedServerStatus = "connected" + McpServersLoadedServerStatusFailed McpServersLoadedServerStatus = "failed" + McpServersLoadedServerStatusNeedsAuth McpServersLoadedServerStatus = "needs-auth" + McpServersLoadedServerStatusPending McpServersLoadedServerStatus = "pending" + McpServersLoadedServerStatusDisabled McpServersLoadedServerStatus = "disabled" + McpServersLoadedServerStatusNotConfigured McpServersLoadedServerStatus = "not_configured" ) -// The type of operation performed on the plan file -type PlanChangedOperation string +// Current status: running, disabled, failed, or starting +type ExtensionsLoadedExtensionStatus string const ( - PlanChangedOperationCreate PlanChangedOperation = "create" - PlanChangedOperationUpdate PlanChangedOperation = "update" - PlanChangedOperationDelete PlanChangedOperation = "delete" + ExtensionsLoadedExtensionStatusRunning ExtensionsLoadedExtensionStatus = "running" + ExtensionsLoadedExtensionStatusDisabled ExtensionsLoadedExtensionStatus = "disabled" + ExtensionsLoadedExtensionStatusFailed ExtensionsLoadedExtensionStatus = "failed" + ExtensionsLoadedExtensionStatusStarting ExtensionsLoadedExtensionStatus = "starting" ) -// Whether the file was newly created or updated -type WorkspaceFileChangedOperation string +// Discovery source +type ExtensionsLoadedExtensionSource string const ( - WorkspaceFileChangedOperationCreate WorkspaceFileChangedOperation = "create" - WorkspaceFileChangedOperationUpdate WorkspaceFileChangedOperation = "update" + ExtensionsLoadedExtensionSourceProject ExtensionsLoadedExtensionSource = "project" + ExtensionsLoadedExtensionSourceUser ExtensionsLoadedExtensionSource = "user" ) -// Origin type of the session being handed off -type HandoffSourceType string +// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. +type ElicitationRequestedMode string const ( - HandoffSourceTypeRemote HandoffSourceType = "remote" - HandoffSourceTypeLocal HandoffSourceType = "local" + ElicitationRequestedModeForm ElicitationRequestedMode = "form" + ElicitationRequestedModeURL ElicitationRequestedMode = "url" ) -// Whether the session ended normally ("routine") or due to a crash/fatal error ("error") -type ShutdownType string +// Hosting platform type of the repository (github or ado) +type WorkingDirectoryContextHostType string const ( - ShutdownTypeRoutine ShutdownType = "routine" - ShutdownTypeError ShutdownType = "error" + WorkingDirectoryContextHostTypeGithub WorkingDirectoryContextHostType = "github" + WorkingDirectoryContextHostTypeAdo WorkingDirectoryContextHostType = "ado" ) -// Type discriminator for UserMessageAttachment. -type UserMessageAttachmentType string +// Kind discriminator for PermissionRequest. +type PermissionRequestKind string const ( - UserMessageAttachmentTypeFile UserMessageAttachmentType = "file" - UserMessageAttachmentTypeDirectory UserMessageAttachmentType = "directory" - UserMessageAttachmentTypeSelection UserMessageAttachmentType = "selection" - UserMessageAttachmentTypeGithubReference UserMessageAttachmentType = "github_reference" - UserMessageAttachmentTypeBlob UserMessageAttachmentType = "blob" + PermissionRequestKindShell PermissionRequestKind = "shell" + PermissionRequestKindWrite PermissionRequestKind = "write" + PermissionRequestKindRead PermissionRequestKind = "read" + PermissionRequestKindMcp PermissionRequestKind = "mcp" + PermissionRequestKindURL PermissionRequestKind = "url" + PermissionRequestKindMemory PermissionRequestKind = "memory" + PermissionRequestKindCustomTool PermissionRequestKind = "custom-tool" + PermissionRequestKindHook PermissionRequestKind = "hook" ) -// Type of GitHub reference -type UserMessageAttachmentGithubReferenceType string +// Message role: "system" for system prompts, "developer" for developer-injected instructions +type SystemMessageRole string const ( - UserMessageAttachmentGithubReferenceTypeIssue UserMessageAttachmentGithubReferenceType = "issue" - UserMessageAttachmentGithubReferenceTypePr UserMessageAttachmentGithubReferenceType = "pr" - UserMessageAttachmentGithubReferenceTypeDiscussion UserMessageAttachmentGithubReferenceType = "discussion" + SystemMessageRoleSystem SystemMessageRole = "system" + SystemMessageRoleDeveloper SystemMessageRole = "developer" +) + +// New connection status: connected, failed, needs-auth, pending, disabled, or not_configured +type McpServerStatusChangedStatus string + +const ( + McpServerStatusChangedStatusConnected McpServerStatusChangedStatus = "connected" + McpServerStatusChangedStatusFailed McpServerStatusChangedStatus = "failed" + McpServerStatusChangedStatusNeedsAuth McpServerStatusChangedStatus = "needs-auth" + McpServerStatusChangedStatusPending McpServerStatusChangedStatus = "pending" + McpServerStatusChangedStatusDisabled McpServerStatusChangedStatus = "disabled" + McpServerStatusChangedStatusNotConfigured McpServerStatusChangedStatus = "not_configured" +) + +// Origin type of the session being handed off +type HandoffSourceType string + +const ( + HandoffSourceTypeRemote HandoffSourceType = "remote" + HandoffSourceTypeLocal HandoffSourceType = "local" ) // The agent mode that was active when this message was sent @@ -2170,24 +2209,34 @@ const ( UserMessageAgentModeShell UserMessageAgentMode = "shell" ) -// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. -type AssistantMessageToolRequestType string +// The outcome of the permission request +type PermissionCompletedKind string const ( - AssistantMessageToolRequestTypeFunction AssistantMessageToolRequestType = "function" - AssistantMessageToolRequestTypeCustom AssistantMessageToolRequestType = "custom" + PermissionCompletedKindApproved PermissionCompletedKind = "approved" + PermissionCompletedKindDeniedByRules PermissionCompletedKind = "denied-by-rules" + PermissionCompletedKindDeniedNoApprovalRuleAndCouldNotRequestFromUser PermissionCompletedKind = "denied-no-approval-rule-and-could-not-request-from-user" + PermissionCompletedKindDeniedInteractivelyByUser PermissionCompletedKind = "denied-interactively-by-user" + PermissionCompletedKindDeniedByContentExclusionPolicy PermissionCompletedKind = "denied-by-content-exclusion-policy" + PermissionCompletedKindDeniedByPermissionRequestHook PermissionCompletedKind = "denied-by-permission-request-hook" ) -// Type discriminator for ToolExecutionCompleteContent. -type ToolExecutionCompleteContentType string +// The type of operation performed on the plan file +type PlanChangedOperation string const ( - ToolExecutionCompleteContentTypeText ToolExecutionCompleteContentType = "text" - ToolExecutionCompleteContentTypeTerminal ToolExecutionCompleteContentType = "terminal" - ToolExecutionCompleteContentTypeImage ToolExecutionCompleteContentType = "image" - ToolExecutionCompleteContentTypeAudio ToolExecutionCompleteContentType = "audio" - ToolExecutionCompleteContentTypeResourceLink ToolExecutionCompleteContentType = "resource_link" - ToolExecutionCompleteContentTypeResource ToolExecutionCompleteContentType = "resource" + PlanChangedOperationCreate PlanChangedOperation = "create" + PlanChangedOperationUpdate PlanChangedOperation = "update" + PlanChangedOperationDelete PlanChangedOperation = "delete" +) + +// The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) +type ElicitationCompletedAction string + +const ( + ElicitationCompletedActionAccept ElicitationCompletedAction = "accept" + ElicitationCompletedActionDecline ElicitationCompletedAction = "decline" + ElicitationCompletedActionCancel ElicitationCompletedAction = "cancel" ) // Theme variant this icon is intended for @@ -2198,12 +2247,12 @@ const ( ToolExecutionCompleteContentResourceLinkIconThemeDark ToolExecutionCompleteContentResourceLinkIconTheme = "dark" ) -// Message role: "system" for system prompts, "developer" for developer-injected instructions -type SystemMessageRole string +// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. +type AssistantMessageToolRequestType string const ( - SystemMessageRoleSystem SystemMessageRole = "system" - SystemMessageRoleDeveloper SystemMessageRole = "developer" + AssistantMessageToolRequestTypeFunction AssistantMessageToolRequestType = "function" + AssistantMessageToolRequestTypeCustom AssistantMessageToolRequestType = "custom" ) // Type discriminator for SystemNotification. @@ -2212,38 +2261,41 @@ type SystemNotificationType string const ( SystemNotificationTypeAgentCompleted SystemNotificationType = "agent_completed" SystemNotificationTypeAgentIdle SystemNotificationType = "agent_idle" + SystemNotificationTypeNewInboxMessage SystemNotificationType = "new_inbox_message" SystemNotificationTypeShellCompleted SystemNotificationType = "shell_completed" SystemNotificationTypeShellDetachedCompleted SystemNotificationType = "shell_detached_completed" ) -// Whether the agent completed successfully or failed -type SystemNotificationAgentCompletedStatus string +// Type discriminator for ToolExecutionCompleteContent. +type ToolExecutionCompleteContentType string const ( - SystemNotificationAgentCompletedStatusCompleted SystemNotificationAgentCompletedStatus = "completed" - SystemNotificationAgentCompletedStatusFailed SystemNotificationAgentCompletedStatus = "failed" + ToolExecutionCompleteContentTypeText ToolExecutionCompleteContentType = "text" + ToolExecutionCompleteContentTypeTerminal ToolExecutionCompleteContentType = "terminal" + ToolExecutionCompleteContentTypeImage ToolExecutionCompleteContentType = "image" + ToolExecutionCompleteContentTypeAudio ToolExecutionCompleteContentType = "audio" + ToolExecutionCompleteContentTypeResourceLink ToolExecutionCompleteContentType = "resource_link" + ToolExecutionCompleteContentTypeResource ToolExecutionCompleteContentType = "resource" ) -// Kind discriminator for PermissionRequest. -type PermissionRequestKind string +// Type discriminator for UserMessageAttachment. +type UserMessageAttachmentType string const ( - PermissionRequestKindShell PermissionRequestKind = "shell" - PermissionRequestKindWrite PermissionRequestKind = "write" - PermissionRequestKindRead PermissionRequestKind = "read" - PermissionRequestKindMcp PermissionRequestKind = "mcp" - PermissionRequestKindURL PermissionRequestKind = "url" - PermissionRequestKindMemory PermissionRequestKind = "memory" - PermissionRequestKindCustomTool PermissionRequestKind = "custom-tool" - PermissionRequestKindHook PermissionRequestKind = "hook" + UserMessageAttachmentTypeFile UserMessageAttachmentType = "file" + UserMessageAttachmentTypeDirectory UserMessageAttachmentType = "directory" + UserMessageAttachmentTypeSelection UserMessageAttachmentType = "selection" + UserMessageAttachmentTypeGithubReference UserMessageAttachmentType = "github_reference" + UserMessageAttachmentTypeBlob UserMessageAttachmentType = "blob" ) -// Whether this is a store or vote memory operation -type PermissionRequestMemoryAction string +// Type of GitHub reference +type UserMessageAttachmentGithubReferenceType string const ( - PermissionRequestMemoryActionStore PermissionRequestMemoryAction = "store" - PermissionRequestMemoryActionVote PermissionRequestMemoryAction = "vote" + UserMessageAttachmentGithubReferenceTypeIssue UserMessageAttachmentGithubReferenceType = "issue" + UserMessageAttachmentGithubReferenceTypePr UserMessageAttachmentGithubReferenceType = "pr" + UserMessageAttachmentGithubReferenceTypeDiscussion UserMessageAttachmentGithubReferenceType = "discussion" ) // Vote direction (vote only) @@ -2254,81 +2306,42 @@ const ( PermissionRequestMemoryDirectionDownvote PermissionRequestMemoryDirection = "downvote" ) -// The outcome of the permission request -type PermissionCompletedKind string - -const ( - PermissionCompletedKindApproved PermissionCompletedKind = "approved" - PermissionCompletedKindDeniedByRules PermissionCompletedKind = "denied-by-rules" - PermissionCompletedKindDeniedNoApprovalRuleAndCouldNotRequestFromUser PermissionCompletedKind = "denied-no-approval-rule-and-could-not-request-from-user" - PermissionCompletedKindDeniedInteractivelyByUser PermissionCompletedKind = "denied-interactively-by-user" - PermissionCompletedKindDeniedByContentExclusionPolicy PermissionCompletedKind = "denied-by-content-exclusion-policy" - PermissionCompletedKindDeniedByPermissionRequestHook PermissionCompletedKind = "denied-by-permission-request-hook" -) - -// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. -type ElicitationRequestedMode string - -const ( - ElicitationRequestedModeForm ElicitationRequestedMode = "form" - ElicitationRequestedModeURL ElicitationRequestedMode = "url" -) - -// The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) -type ElicitationCompletedAction string - -const ( - ElicitationCompletedActionAccept ElicitationCompletedAction = "accept" - ElicitationCompletedActionDecline ElicitationCompletedAction = "decline" - ElicitationCompletedActionCancel ElicitationCompletedAction = "cancel" -) - -// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured -type McpServersLoadedServerStatus string +// Whether the agent completed successfully or failed +type SystemNotificationAgentCompletedStatus string const ( - McpServersLoadedServerStatusConnected McpServersLoadedServerStatus = "connected" - McpServersLoadedServerStatusFailed McpServersLoadedServerStatus = "failed" - McpServersLoadedServerStatusNeedsAuth McpServersLoadedServerStatus = "needs-auth" - McpServersLoadedServerStatusPending McpServersLoadedServerStatus = "pending" - McpServersLoadedServerStatusDisabled McpServersLoadedServerStatus = "disabled" - McpServersLoadedServerStatusNotConfigured McpServersLoadedServerStatus = "not_configured" + SystemNotificationAgentCompletedStatusCompleted SystemNotificationAgentCompletedStatus = "completed" + SystemNotificationAgentCompletedStatusFailed SystemNotificationAgentCompletedStatus = "failed" ) -// New connection status: connected, failed, needs-auth, pending, disabled, or not_configured -type McpServerStatusChangedStatus string +// Whether the file was newly created or updated +type WorkspaceFileChangedOperation string const ( - McpServerStatusChangedStatusConnected McpServerStatusChangedStatus = "connected" - McpServerStatusChangedStatusFailed McpServerStatusChangedStatus = "failed" - McpServerStatusChangedStatusNeedsAuth McpServerStatusChangedStatus = "needs-auth" - McpServerStatusChangedStatusPending McpServerStatusChangedStatus = "pending" - McpServerStatusChangedStatusDisabled McpServerStatusChangedStatus = "disabled" - McpServerStatusChangedStatusNotConfigured McpServerStatusChangedStatus = "not_configured" + WorkspaceFileChangedOperationCreate WorkspaceFileChangedOperation = "create" + WorkspaceFileChangedOperationUpdate WorkspaceFileChangedOperation = "update" ) -// Discovery source -type ExtensionsLoadedExtensionSource string +// Whether the session ended normally ("routine") or due to a crash/fatal error ("error") +type ShutdownType string const ( - ExtensionsLoadedExtensionSourceProject ExtensionsLoadedExtensionSource = "project" - ExtensionsLoadedExtensionSourceUser ExtensionsLoadedExtensionSource = "user" + ShutdownTypeRoutine ShutdownType = "routine" + ShutdownTypeError ShutdownType = "error" ) -// Current status: running, disabled, failed, or starting -type ExtensionsLoadedExtensionStatus string +// Whether this is a store or vote memory operation +type PermissionRequestMemoryAction string const ( - ExtensionsLoadedExtensionStatusRunning ExtensionsLoadedExtensionStatus = "running" - ExtensionsLoadedExtensionStatusDisabled ExtensionsLoadedExtensionStatus = "disabled" - ExtensionsLoadedExtensionStatusFailed ExtensionsLoadedExtensionStatus = "failed" - ExtensionsLoadedExtensionStatusStarting ExtensionsLoadedExtensionStatus = "starting" + PermissionRequestMemoryActionStore PermissionRequestMemoryAction = "store" + PermissionRequestMemoryActionVote PermissionRequestMemoryAction = "vote" ) // Type aliases for convenience. type ( PermissionRequestCommand = PermissionRequestShellCommand - PossibleURL = PermissionRequestShellPossibleUrl + PossibleURL = PermissionRequestShellPossibleURL Attachment = UserMessageAttachment AttachmentType = UserMessageAttachmentType ) diff --git a/go/internal/e2e/compaction_test.go b/go/internal/e2e/compaction_test.go index c980e558d..a4c5471fc 100644 --- a/go/internal/e2e/compaction_test.go +++ b/go/internal/e2e/compaction_test.go @@ -9,6 +9,7 @@ import ( ) func TestCompaction(t *testing.T) { + t.Skip("Compaction tests are skipped due to flakiness — re-enable once stabilized") ctx := testharness.NewTestContext(t) client := ctx.NewClient() t.Cleanup(func() { client.ForceStop() }) diff --git a/go/internal/e2e/session_fs_test.go b/go/internal/e2e/session_fs_test.go index 7fba219f7..05cbd23b4 100644 --- a/go/internal/e2e/session_fs_test.go +++ b/go/internal/e2e/session_fs_test.go @@ -17,7 +17,7 @@ import ( func TestSessionFs(t *testing.T) { ctx := testharness.NewTestContext(t) providerRoot := t.TempDir() - createSessionFsHandler := func(session *copilot.Session) rpc.SessionFsHandler { + createSessionFsHandler := func(session *copilot.Session) copilot.SessionFsProvider { return &testSessionFsHandler{ root: providerRoot, sessionID: session.SessionID, @@ -245,6 +245,90 @@ func TestSessionFs(t *testing.T) { t.Fatalf("Timed out waiting for checkpoint rewrite: %v", err) } }) + t.Run("should write workspace metadata via sessionFs", func(t *testing.T) { + ctx.ConfigureForTest(t) + + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + CreateSessionFsHandler: createSessionFsHandler, + }) + if err != nil { + t.Fatalf("Failed to create session: %v", err) + } + + msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 7 * 8?"}) + if err != nil { + t.Fatalf("Failed to send message: %v", err) + } + content := "" + if msg != nil { + if d, ok := msg.Data.(*copilot.AssistantMessageData); ok { + content = d.Content + } + } + if !strings.Contains(content, "56") { + t.Fatalf("Expected response to contain 56, got %q", content) + } + + // WorkspaceManager should have created workspace.yaml via sessionFs + workspaceYamlPath := p(session.SessionID, "/session-state/workspace.yaml") + if err := waitForFile(workspaceYamlPath, 5*time.Second); err != nil { + t.Fatalf("Timed out waiting for workspace.yaml: %v", err) + } + yaml, err := os.ReadFile(workspaceYamlPath) + if err != nil { + t.Fatalf("Failed to read workspace.yaml: %v", err) + } + if !strings.Contains(string(yaml), "id:") { + t.Fatalf("Expected workspace.yaml to contain 'id:', got %q", string(yaml)) + } + + // Checkpoint index should also exist + indexPath := p(session.SessionID, "/session-state/checkpoints/index.md") + if err := waitForFile(indexPath, 5*time.Second); err != nil { + t.Fatalf("Timed out waiting for checkpoints/index.md: %v", err) + } + + if err := session.Disconnect(); err != nil { + t.Fatalf("Failed to disconnect session: %v", err) + } + }) + + t.Run("should persist plan.md via sessionFs", func(t *testing.T) { + ctx.ConfigureForTest(t) + + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + CreateSessionFsHandler: createSessionFsHandler, + }) + if err != nil { + t.Fatalf("Failed to create session: %v", err) + } + + // Write a plan via the session RPC + if _, err := session.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 2 + 3?"}); err != nil { + t.Fatalf("Failed to send message: %v", err) + } + if _, err := session.RPC.Plan.Update(t.Context(), &rpc.PlanUpdateRequest{Content: "# Test Plan\n\nThis is a test."}); err != nil { + t.Fatalf("Failed to update plan: %v", err) + } + + planPath := p(session.SessionID, "/session-state/plan.md") + if err := waitForFile(planPath, 5*time.Second); err != nil { + t.Fatalf("Timed out waiting for plan.md: %v", err) + } + planContent, err := os.ReadFile(planPath) + if err != nil { + t.Fatalf("Failed to read plan.md: %v", err) + } + if !strings.Contains(string(planContent), "# Test Plan") { + t.Fatalf("Expected plan.md to contain '# Test Plan', got %q", string(planContent)) + } + + if err := session.Disconnect(); err != nil { + t.Fatalf("Failed to disconnect session: %v", err) + } + }) } var sessionFsConfig = &copilot.SessionFsConfig{ @@ -258,65 +342,62 @@ type testSessionFsHandler struct { sessionID string } -func (h *testSessionFsHandler) ReadFile(request *rpc.SessionFSReadFileRequest) (*rpc.SessionFSReadFileResult, error) { - content, err := os.ReadFile(providerPath(h.root, h.sessionID, request.Path)) +func (h *testSessionFsHandler) ReadFile(path string) (string, error) { + content, err := os.ReadFile(providerPath(h.root, h.sessionID, path)) if err != nil { - return nil, err + return "", err } - return &rpc.SessionFSReadFileResult{Content: string(content)}, nil + return string(content), nil } -func (h *testSessionFsHandler) WriteFile(request *rpc.SessionFSWriteFileRequest) (*rpc.SessionFSWriteFileResult, error) { - path := providerPath(h.root, h.sessionID, request.Path) - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - return nil, err +func (h *testSessionFsHandler) WriteFile(path string, content string, mode *int) error { + fullPath := providerPath(h.root, h.sessionID, path) + if err := os.MkdirAll(filepath.Dir(fullPath), 0o755); err != nil { + return err } - mode := os.FileMode(0o666) - if request.Mode != nil { - mode = os.FileMode(uint32(*request.Mode)) + perm := os.FileMode(0o666) + if mode != nil { + perm = os.FileMode(*mode) } - return &rpc.SessionFSWriteFileResult{}, os.WriteFile(path, []byte(request.Content), mode) + return os.WriteFile(fullPath, []byte(content), perm) } -func (h *testSessionFsHandler) AppendFile(request *rpc.SessionFSAppendFileRequest) (*rpc.SessionFSAppendFileResult, error) { - path := providerPath(h.root, h.sessionID, request.Path) - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - return nil, err +func (h *testSessionFsHandler) AppendFile(path string, content string, mode *int) error { + fullPath := providerPath(h.root, h.sessionID, path) + if err := os.MkdirAll(filepath.Dir(fullPath), 0o755); err != nil { + return err } - mode := os.FileMode(0o666) - if request.Mode != nil { - mode = os.FileMode(uint32(*request.Mode)) + perm := os.FileMode(0o666) + if mode != nil { + perm = os.FileMode(*mode) } - f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, mode) + f, err := os.OpenFile(fullPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, perm) if err != nil { - return nil, err + return err } defer f.Close() - _, err = f.WriteString(request.Content) - if err != nil { - return nil, err - } - return &rpc.SessionFSAppendFileResult{}, nil + _, err = f.WriteString(content) + return err } -func (h *testSessionFsHandler) Exists(request *rpc.SessionFSExistsRequest) (*rpc.SessionFSExistsResult, error) { - _, err := os.Stat(providerPath(h.root, h.sessionID, request.Path)) +func (h *testSessionFsHandler) Exists(path string) (bool, error) { + _, err := os.Stat(providerPath(h.root, h.sessionID, path)) if err == nil { - return &rpc.SessionFSExistsResult{Exists: true}, nil + return true, nil } if os.IsNotExist(err) { - return &rpc.SessionFSExistsResult{Exists: false}, nil + return false, nil } - return nil, err + return false, err } -func (h *testSessionFsHandler) Stat(request *rpc.SessionFSStatRequest) (*rpc.SessionFSStatResult, error) { - info, err := os.Stat(providerPath(h.root, h.sessionID, request.Path)) +func (h *testSessionFsHandler) Stat(path string) (*copilot.SessionFsFileInfo, error) { + info, err := os.Stat(providerPath(h.root, h.sessionID, path)) if err != nil { return nil, err } ts := info.ModTime().UTC() - return &rpc.SessionFSStatResult{ + return &copilot.SessionFsFileInfo{ IsFile: !info.IsDir(), IsDirectory: info.IsDir(), Size: info.Size(), @@ -325,20 +406,20 @@ func (h *testSessionFsHandler) Stat(request *rpc.SessionFSStatRequest) (*rpc.Ses }, nil } -func (h *testSessionFsHandler) Mkdir(request *rpc.SessionFSMkdirRequest) (*rpc.SessionFSMkdirResult, error) { - path := providerPath(h.root, h.sessionID, request.Path) - mode := os.FileMode(0o777) - if request.Mode != nil { - mode = os.FileMode(uint32(*request.Mode)) +func (h *testSessionFsHandler) Mkdir(path string, recursive bool, mode *int) error { + fullPath := providerPath(h.root, h.sessionID, path) + perm := os.FileMode(0o777) + if mode != nil { + perm = os.FileMode(*mode) } - if request.Recursive != nil && *request.Recursive { - return &rpc.SessionFSMkdirResult{}, os.MkdirAll(path, mode) + if recursive { + return os.MkdirAll(fullPath, perm) } - return &rpc.SessionFSMkdirResult{}, os.Mkdir(path, mode) + return os.Mkdir(fullPath, perm) } -func (h *testSessionFsHandler) Readdir(request *rpc.SessionFSReaddirRequest) (*rpc.SessionFSReaddirResult, error) { - entries, err := os.ReadDir(providerPath(h.root, h.sessionID, request.Path)) +func (h *testSessionFsHandler) Readdir(path string) ([]string, error) { + entries, err := os.ReadDir(providerPath(h.root, h.sessionID, path)) if err != nil { return nil, err } @@ -346,11 +427,11 @@ func (h *testSessionFsHandler) Readdir(request *rpc.SessionFSReaddirRequest) (*r for _, entry := range entries { names = append(names, entry.Name()) } - return &rpc.SessionFSReaddirResult{Entries: names}, nil + return names, nil } -func (h *testSessionFsHandler) ReaddirWithTypes(request *rpc.SessionFSReaddirWithTypesRequest) (*rpc.SessionFSReaddirWithTypesResult, error) { - entries, err := os.ReadDir(providerPath(h.root, h.sessionID, request.Path)) +func (h *testSessionFsHandler) ReaddirWithTypes(path string) ([]rpc.SessionFSReaddirWithTypesEntry, error) { + entries, err := os.ReadDir(providerPath(h.root, h.sessionID, path)) if err != nil { return nil, err } @@ -365,34 +446,29 @@ func (h *testSessionFsHandler) ReaddirWithTypes(request *rpc.SessionFSReaddirWit Type: entryType, }) } - return &rpc.SessionFSReaddirWithTypesResult{Entries: result}, nil + return result, nil } -func (h *testSessionFsHandler) Rm(request *rpc.SessionFSRmRequest) (*rpc.SessionFSRmResult, error) { - path := providerPath(h.root, h.sessionID, request.Path) - if request.Recursive != nil && *request.Recursive { - err := os.RemoveAll(path) - if err != nil && request.Force != nil && *request.Force && os.IsNotExist(err) { - return &rpc.SessionFSRmResult{}, nil - } - return &rpc.SessionFSRmResult{}, err +func (h *testSessionFsHandler) Rm(path string, recursive bool, force bool) error { + fullPath := providerPath(h.root, h.sessionID, path) + var err error + if recursive { + err = os.RemoveAll(fullPath) + } else { + err = os.Remove(fullPath) } - err := os.Remove(path) - if err != nil && request.Force != nil && *request.Force && os.IsNotExist(err) { - return &rpc.SessionFSRmResult{}, nil + if err != nil && force && os.IsNotExist(err) { + return nil } - return &rpc.SessionFSRmResult{}, err + return err } -func (h *testSessionFsHandler) Rename(request *rpc.SessionFSRenameRequest) (*rpc.SessionFSRenameResult, error) { - dest := providerPath(h.root, h.sessionID, request.Dest) - if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil { - return nil, err +func (h *testSessionFsHandler) Rename(src string, dest string) error { + destPath := providerPath(h.root, h.sessionID, dest) + if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil { + return err } - return &rpc.SessionFSRenameResult{}, os.Rename( - providerPath(h.root, h.sessionID, request.Src), - dest, - ) + return os.Rename(providerPath(h.root, h.sessionID, src), destPath) } func providerPath(root string, sessionID string, path string) string { diff --git a/go/rpc/generated_rpc.go b/go/rpc/generated_rpc.go index 528a933b5..683fb2a5c 100644 --- a/go/rpc/generated_rpc.go +++ b/go/rpc/generated_rpc.go @@ -12,74 +12,273 @@ import ( "time" ) -type UIElicitationResponseContent map[string]*UIElicitationFieldValue +type RPCTypes struct { + AccountGetQuotaResult AccountGetQuotaResult `json:"AccountGetQuotaResult"` + AccountQuotaSnapshot AccountQuotaSnapshot `json:"AccountQuotaSnapshot"` + AgentDeselectResult AgentDeselectResult `json:"AgentDeselectResult"` + AgentGetCurrentResult AgentGetCurrentResult `json:"AgentGetCurrentResult"` + AgentInfo AgentInfo `json:"AgentInfo"` + AgentList AgentList `json:"AgentList"` + AgentReloadResult AgentReloadResult `json:"AgentReloadResult"` + AgentSelectRequest AgentSelectRequest `json:"AgentSelectRequest"` + AgentSelectResult AgentSelectResult `json:"AgentSelectResult"` + CommandsHandlePendingCommandRequest CommandsHandlePendingCommandRequest `json:"CommandsHandlePendingCommandRequest"` + CommandsHandlePendingCommandResult CommandsHandlePendingCommandResult `json:"CommandsHandlePendingCommandResult"` + CurrentModel CurrentModel `json:"CurrentModel"` + DiscoveredMCPServer DiscoveredMCPServer `json:"DiscoveredMcpServer"` + DiscoveredMCPServerSource MCPServerSource `json:"DiscoveredMcpServerSource"` + DiscoveredMCPServerType DiscoveredMCPServerType `json:"DiscoveredMcpServerType"` + Extension Extension `json:"Extension"` + ExtensionList ExtensionList `json:"ExtensionList"` + ExtensionsDisableRequest ExtensionsDisableRequest `json:"ExtensionsDisableRequest"` + ExtensionsDisableResult ExtensionsDisableResult `json:"ExtensionsDisableResult"` + ExtensionsEnableRequest ExtensionsEnableRequest `json:"ExtensionsEnableRequest"` + ExtensionsEnableResult ExtensionsEnableResult `json:"ExtensionsEnableResult"` + ExtensionSource ExtensionSource `json:"ExtensionSource"` + ExtensionsReloadResult ExtensionsReloadResult `json:"ExtensionsReloadResult"` + ExtensionStatus ExtensionStatus `json:"ExtensionStatus"` + FilterMapping *FilterMapping `json:"FilterMapping"` + FilterMappingString FilterMappingString `json:"FilterMappingString"` + FilterMappingValue FilterMappingString `json:"FilterMappingValue"` + FleetStartRequest FleetStartRequest `json:"FleetStartRequest"` + FleetStartResult FleetStartResult `json:"FleetStartResult"` + HandleToolCallResult HandleToolCallResult `json:"HandleToolCallResult"` + HistoryCompactContextWindow HistoryCompactContextWindow `json:"HistoryCompactContextWindow"` + HistoryCompactResult HistoryCompactResult `json:"HistoryCompactResult"` + HistoryTruncateRequest HistoryTruncateRequest `json:"HistoryTruncateRequest"` + HistoryTruncateResult HistoryTruncateResult `json:"HistoryTruncateResult"` + InstructionsGetSourcesResult InstructionsGetSourcesResult `json:"InstructionsGetSourcesResult"` + InstructionsSources InstructionsSources `json:"InstructionsSources"` + InstructionsSourcesLocation InstructionsSourcesLocation `json:"InstructionsSourcesLocation"` + InstructionsSourcesType InstructionsSourcesType `json:"InstructionsSourcesType"` + LogRequest LogRequest `json:"LogRequest"` + LogResult LogResult `json:"LogResult"` + MCPConfigAddRequest MCPConfigAddRequest `json:"McpConfigAddRequest"` + MCPConfigAddResult MCPConfigAddResult `json:"McpConfigAddResult"` + MCPConfigList MCPConfigList `json:"McpConfigList"` + MCPConfigRemoveRequest MCPConfigRemoveRequest `json:"McpConfigRemoveRequest"` + MCPConfigRemoveResult MCPConfigRemoveResult `json:"McpConfigRemoveResult"` + MCPConfigUpdateRequest MCPConfigUpdateRequest `json:"McpConfigUpdateRequest"` + MCPConfigUpdateResult MCPConfigUpdateResult `json:"McpConfigUpdateResult"` + MCPDisableRequest MCPDisableRequest `json:"McpDisableRequest"` + MCPDisableResult MCPDisableResult `json:"McpDisableResult"` + MCPDiscoverRequest MCPDiscoverRequest `json:"McpDiscoverRequest"` + MCPDiscoverResult MCPDiscoverResult `json:"McpDiscoverResult"` + MCPEnableRequest MCPEnableRequest `json:"McpEnableRequest"` + MCPEnableResult MCPEnableResult `json:"McpEnableResult"` + MCPReloadResult MCPReloadResult `json:"McpReloadResult"` + MCPServer MCPServer `json:"McpServer"` + MCPServerConfig MCPServerConfig `json:"McpServerConfig"` + MCPServerConfigHTTP MCPServerConfigHTTP `json:"McpServerConfigHttp"` + MCPServerConfigHTTPType MCPServerConfigHTTPType `json:"McpServerConfigHttpType"` + MCPServerConfigLocal MCPServerConfigLocal `json:"McpServerConfigLocal"` + MCPServerConfigLocalType MCPServerConfigLocalType `json:"McpServerConfigLocalType"` + MCPServerList MCPServerList `json:"McpServerList"` + MCPServerSource MCPServerSource `json:"McpServerSource"` + MCPServerStatus MCPServerStatus `json:"McpServerStatus"` + Model ModelElement `json:"Model"` + ModelBilling ModelBilling `json:"ModelBilling"` + ModelCapabilities ModelCapabilities `json:"ModelCapabilities"` + ModelCapabilitiesLimits ModelCapabilitiesLimits `json:"ModelCapabilitiesLimits"` + ModelCapabilitiesLimitsVision ModelCapabilitiesLimitsVision `json:"ModelCapabilitiesLimitsVision"` + ModelCapabilitiesOverride ModelCapabilitiesOverride `json:"ModelCapabilitiesOverride"` + ModelCapabilitiesOverrideLimits ModelCapabilitiesOverrideLimits `json:"ModelCapabilitiesOverrideLimits"` + ModelCapabilitiesOverrideLimitsVision ModelCapabilitiesOverrideLimitsVision `json:"ModelCapabilitiesOverrideLimitsVision"` + ModelCapabilitiesOverrideSupports ModelCapabilitiesOverrideSupports `json:"ModelCapabilitiesOverrideSupports"` + ModelCapabilitiesSupports ModelCapabilitiesSupports `json:"ModelCapabilitiesSupports"` + ModelList ModelList `json:"ModelList"` + ModelPolicy ModelPolicy `json:"ModelPolicy"` + ModelSwitchToRequest ModelSwitchToRequest `json:"ModelSwitchToRequest"` + ModelSwitchToResult ModelSwitchToResult `json:"ModelSwitchToResult"` + ModeSetRequest ModeSetRequest `json:"ModeSetRequest"` + ModeSetResult ModeSetResult `json:"ModeSetResult"` + NameGetResult NameGetResult `json:"NameGetResult"` + NameSetRequest NameSetRequest `json:"NameSetRequest"` + NameSetResult NameSetResult `json:"NameSetResult"` + PermissionDecision PermissionDecision `json:"PermissionDecision"` + PermissionDecisionApproved PermissionDecisionApproved `json:"PermissionDecisionApproved"` + PermissionDecisionDeniedByContentExclusionPolicy PermissionDecisionDeniedByContentExclusionPolicy `json:"PermissionDecisionDeniedByContentExclusionPolicy"` + PermissionDecisionDeniedByPermissionRequestHook PermissionDecisionDeniedByPermissionRequestHook `json:"PermissionDecisionDeniedByPermissionRequestHook"` + PermissionDecisionDeniedByRules PermissionDecisionDeniedByRules `json:"PermissionDecisionDeniedByRules"` + PermissionDecisionDeniedInteractivelyByUser PermissionDecisionDeniedInteractivelyByUser `json:"PermissionDecisionDeniedInteractivelyByUser"` + PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser `json:"PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser"` + PermissionDecisionRequest PermissionDecisionRequest `json:"PermissionDecisionRequest"` + PermissionRequestResult PermissionRequestResult `json:"PermissionRequestResult"` + PingRequest PingRequest `json:"PingRequest"` + PingResult PingResult `json:"PingResult"` + PlanDeleteResult PlanDeleteResult `json:"PlanDeleteResult"` + PlanReadResult PlanReadResult `json:"PlanReadResult"` + PlanUpdateRequest PlanUpdateRequest `json:"PlanUpdateRequest"` + PlanUpdateResult PlanUpdateResult `json:"PlanUpdateResult"` + Plugin PluginElement `json:"Plugin"` + PluginList PluginList `json:"PluginList"` + ServerSkill ServerSkill `json:"ServerSkill"` + ServerSkillList ServerSkillList `json:"ServerSkillList"` + SessionFSAppendFileRequest SessionFSAppendFileRequest `json:"SessionFsAppendFileRequest"` + SessionFSError SessionFSError `json:"SessionFsError"` + SessionFSErrorCode SessionFSErrorCode `json:"SessionFsErrorCode"` + SessionFSExistsRequest SessionFSExistsRequest `json:"SessionFsExistsRequest"` + SessionFSExistsResult SessionFSExistsResult `json:"SessionFsExistsResult"` + SessionFSMkdirRequest SessionFSMkdirRequest `json:"SessionFsMkdirRequest"` + SessionFSReaddirRequest SessionFSReaddirRequest `json:"SessionFsReaddirRequest"` + SessionFSReaddirResult SessionFSReaddirResult `json:"SessionFsReaddirResult"` + SessionFSReaddirWithTypesEntry SessionFSReaddirWithTypesEntry `json:"SessionFsReaddirWithTypesEntry"` + SessionFSReaddirWithTypesEntryType SessionFSReaddirWithTypesEntryType `json:"SessionFsReaddirWithTypesEntryType"` + SessionFSReaddirWithTypesRequest SessionFSReaddirWithTypesRequest `json:"SessionFsReaddirWithTypesRequest"` + SessionFSReaddirWithTypesResult SessionFSReaddirWithTypesResult `json:"SessionFsReaddirWithTypesResult"` + SessionFSReadFileRequest SessionFSReadFileRequest `json:"SessionFsReadFileRequest"` + SessionFSReadFileResult SessionFSReadFileResult `json:"SessionFsReadFileResult"` + SessionFSRenameRequest SessionFSRenameRequest `json:"SessionFsRenameRequest"` + SessionFSRmRequest SessionFSRmRequest `json:"SessionFsRmRequest"` + SessionFSSetProviderConventions SessionFSSetProviderConventions `json:"SessionFsSetProviderConventions"` + SessionFSSetProviderRequest SessionFSSetProviderRequest `json:"SessionFsSetProviderRequest"` + SessionFSSetProviderResult SessionFSSetProviderResult `json:"SessionFsSetProviderResult"` + SessionFSStatRequest SessionFSStatRequest `json:"SessionFsStatRequest"` + SessionFSStatResult SessionFSStatResult `json:"SessionFsStatResult"` + SessionFSWriteFileRequest SessionFSWriteFileRequest `json:"SessionFsWriteFileRequest"` + SessionLogLevel SessionLogLevel `json:"SessionLogLevel"` + SessionMode SessionMode `json:"SessionMode"` + SessionsForkRequest SessionsForkRequest `json:"SessionsForkRequest"` + SessionsForkResult SessionsForkResult `json:"SessionsForkResult"` + ShellExecRequest ShellExecRequest `json:"ShellExecRequest"` + ShellExecResult ShellExecResult `json:"ShellExecResult"` + ShellKillRequest ShellKillRequest `json:"ShellKillRequest"` + ShellKillResult ShellKillResult `json:"ShellKillResult"` + ShellKillSignal ShellKillSignal `json:"ShellKillSignal"` + Skill Skill `json:"Skill"` + SkillList SkillList `json:"SkillList"` + SkillsConfigSetDisabledSkillsRequest SkillsConfigSetDisabledSkillsRequest `json:"SkillsConfigSetDisabledSkillsRequest"` + SkillsConfigSetDisabledSkillsResult SkillsConfigSetDisabledSkillsResult `json:"SkillsConfigSetDisabledSkillsResult"` + SkillsDisableRequest SkillsDisableRequest `json:"SkillsDisableRequest"` + SkillsDisableResult SkillsDisableResult `json:"SkillsDisableResult"` + SkillsDiscoverRequest SkillsDiscoverRequest `json:"SkillsDiscoverRequest"` + SkillsEnableRequest SkillsEnableRequest `json:"SkillsEnableRequest"` + SkillsEnableResult SkillsEnableResult `json:"SkillsEnableResult"` + SkillsReloadResult SkillsReloadResult `json:"SkillsReloadResult"` + Tool Tool `json:"Tool"` + ToolCallResult ToolCallResult `json:"ToolCallResult"` + ToolList ToolList `json:"ToolList"` + ToolsHandlePendingToolCall *ToolsHandlePendingToolCall `json:"ToolsHandlePendingToolCall"` + ToolsHandlePendingToolCallRequest ToolsHandlePendingToolCallRequest `json:"ToolsHandlePendingToolCallRequest"` + ToolsListRequest ToolsListRequest `json:"ToolsListRequest"` + UIElicitationArrayAnyOfField UIElicitationArrayAnyOfField `json:"UIElicitationArrayAnyOfField"` + UIElicitationArrayAnyOfFieldItems UIElicitationArrayAnyOfFieldItems `json:"UIElicitationArrayAnyOfFieldItems"` + UIElicitationArrayAnyOfFieldItemsAnyOf UIElicitationArrayAnyOfFieldItemsAnyOf `json:"UIElicitationArrayAnyOfFieldItemsAnyOf"` + UIElicitationArrayEnumField UIElicitationArrayEnumField `json:"UIElicitationArrayEnumField"` + UIElicitationArrayEnumFieldItems UIElicitationArrayEnumFieldItems `json:"UIElicitationArrayEnumFieldItems"` + UIElicitationFieldValue *UIElicitationFieldValue `json:"UIElicitationFieldValue"` + UIElicitationRequest UIElicitationRequest `json:"UIElicitationRequest"` + UIElicitationResponse UIElicitationResponse `json:"UIElicitationResponse"` + UIElicitationResponseAction UIElicitationResponseAction `json:"UIElicitationResponseAction"` + UIElicitationResponseContent map[string]*UIElicitationFieldValue `json:"UIElicitationResponseContent"` + UIElicitationResult UIElicitationResult `json:"UIElicitationResult"` + UIElicitationSchema UIElicitationSchema `json:"UIElicitationSchema"` + UIElicitationSchemaProperty UIElicitationSchemaProperty `json:"UIElicitationSchemaProperty"` + UIElicitationSchemaPropertyBoolean UIElicitationSchemaPropertyBoolean `json:"UIElicitationSchemaPropertyBoolean"` + UIElicitationSchemaPropertyNumber UIElicitationSchemaPropertyNumber `json:"UIElicitationSchemaPropertyNumber"` + UIElicitationSchemaPropertyNumberType UIElicitationSchemaPropertyNumberTypeEnum `json:"UIElicitationSchemaPropertyNumberType"` + UIElicitationSchemaPropertyString UIElicitationSchemaPropertyString `json:"UIElicitationSchemaPropertyString"` + UIElicitationSchemaPropertyStringFormat UIElicitationSchemaPropertyStringFormat `json:"UIElicitationSchemaPropertyStringFormat"` + UIElicitationStringEnumField UIElicitationStringEnumField `json:"UIElicitationStringEnumField"` + UIElicitationStringOneOfField UIElicitationStringOneOfField `json:"UIElicitationStringOneOfField"` + UIElicitationStringOneOfFieldOneOf UIElicitationStringOneOfFieldOneOf `json:"UIElicitationStringOneOfFieldOneOf"` + UIHandlePendingElicitationRequest UIHandlePendingElicitationRequest `json:"UIHandlePendingElicitationRequest"` + UsageGetMetricsResult UsageGetMetricsResult `json:"UsageGetMetricsResult"` + UsageMetricsCodeChanges UsageMetricsCodeChanges `json:"UsageMetricsCodeChanges"` + UsageMetricsModelMetric UsageMetricsModelMetric `json:"UsageMetricsModelMetric"` + UsageMetricsModelMetricRequests UsageMetricsModelMetricRequests `json:"UsageMetricsModelMetricRequests"` + UsageMetricsModelMetricUsage UsageMetricsModelMetricUsage `json:"UsageMetricsModelMetricUsage"` + WorkspacesCreateFileRequest WorkspacesCreateFileRequest `json:"WorkspacesCreateFileRequest"` + WorkspacesCreateFileResult WorkspacesCreateFileResult `json:"WorkspacesCreateFileResult"` + WorkspacesGetWorkspaceResult WorkspacesGetWorkspaceResult `json:"WorkspacesGetWorkspaceResult"` + WorkspacesListFilesResult WorkspacesListFilesResult `json:"WorkspacesListFilesResult"` + WorkspacesReadFileRequest WorkspacesReadFileRequest `json:"WorkspacesReadFileRequest"` + WorkspacesReadFileResult WorkspacesReadFileResult `json:"WorkspacesReadFileResult"` +} -// Model capabilities and limits -type ModelCapabilities struct { - // Token limits for prompts, outputs, and context window - Limits *ModelCapabilitiesLimits `json:"limits,omitempty"` - // Feature flags indicating what the model supports - Supports *ModelCapabilitiesSupports `json:"supports,omitempty"` +type AccountGetQuotaResult struct { + // Quota snapshots keyed by type (e.g., chat, completions, premium_interactions) + QuotaSnapshots map[string]AccountQuotaSnapshot `json:"quotaSnapshots"` } -// Token limits for prompts, outputs, and context window -type ModelCapabilitiesLimits struct { - // Maximum total context window size in tokens - MaxContextWindowTokens *int64 `json:"max_context_window_tokens,omitempty"` - // Maximum number of output/completion tokens - MaxOutputTokens *int64 `json:"max_output_tokens,omitempty"` - // Maximum number of prompt/input tokens - MaxPromptTokens *int64 `json:"max_prompt_tokens,omitempty"` - // Vision-specific limits - Vision *PurpleModelCapabilitiesLimitsVision `json:"vision,omitempty"` +type AccountQuotaSnapshot struct { + // Number of requests included in the entitlement + EntitlementRequests int64 `json:"entitlementRequests"` + // Whether the user has an unlimited usage entitlement + IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` + // Number of overage requests made this period + Overage float64 `json:"overage"` + // Whether overage is allowed when quota is exhausted + OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` + // Percentage of entitlement remaining + RemainingPercentage float64 `json:"remainingPercentage"` + // Date when the quota resets (ISO 8601 string) + ResetDate *string `json:"resetDate,omitempty"` + // Whether usage is still permitted after quota exhaustion + UsageAllowedWithExhaustedQuota bool `json:"usageAllowedWithExhaustedQuota"` + // Number of requests used so far this period + UsedRequests int64 `json:"usedRequests"` } -// Vision-specific limits -type PurpleModelCapabilitiesLimitsVision struct { - // Maximum image size in bytes - MaxPromptImageSize int64 `json:"max_prompt_image_size"` - // Maximum number of images per prompt - MaxPromptImages int64 `json:"max_prompt_images"` - // MIME types the model accepts - SupportedMediaTypes []string `json:"supported_media_types"` +// Experimental: AgentDeselectResult is part of an experimental API and may change or be removed. +type AgentDeselectResult struct { } -// Feature flags indicating what the model supports -type ModelCapabilitiesSupports struct { - // Whether this model supports reasoning effort configuration - ReasoningEffort *bool `json:"reasoningEffort,omitempty"` - // Whether this model supports vision/image input - Vision *bool `json:"vision,omitempty"` +// Experimental: AgentGetCurrentResult is part of an experimental API and may change or be removed. +type AgentGetCurrentResult struct { + // Currently selected custom agent, or null if using the default agent + Agent *AgentInfo `json:"agent"` } -// Vision-specific limits -type ModelCapabilitiesLimitsVision struct { - // Maximum image size in bytes - MaxPromptImageSize int64 `json:"max_prompt_image_size"` - // Maximum number of images per prompt - MaxPromptImages int64 `json:"max_prompt_images"` - // MIME types the model accepts - SupportedMediaTypes []string `json:"supported_media_types"` +// The newly selected custom agent +type AgentInfo struct { + // Description of the agent's purpose + Description string `json:"description"` + // Human-readable display name + DisplayName string `json:"displayName"` + // Unique identifier of the custom agent + Name string `json:"name"` } -// MCP server configuration (local/stdio or remote/http) -type MCPServerConfig struct { - Args []string `json:"args,omitempty"` - Command *string `json:"command,omitempty"` - Cwd *string `json:"cwd,omitempty"` - Env map[string]string `json:"env,omitempty"` - FilterMapping *FilterMapping `json:"filterMapping"` - IsDefaultServer *bool `json:"isDefaultServer,omitempty"` - // Timeout in milliseconds for tool calls to this server. - Timeout *int64 `json:"timeout,omitempty"` - // Tools to include. Defaults to all tools if not specified. - Tools []string `json:"tools,omitempty"` - // Remote transport type. Defaults to "http" when omitted. - Type *MCPServerConfigType `json:"type,omitempty"` - Headers map[string]string `json:"headers,omitempty"` - OauthClientID *string `json:"oauthClientId,omitempty"` - OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` - URL *string `json:"url,omitempty"` +// Experimental: AgentList is part of an experimental API and may change or be removed. +type AgentList struct { + // Available custom agents + Agents []AgentInfo `json:"agents"` +} + +// Experimental: AgentReloadResult is part of an experimental API and may change or be removed. +type AgentReloadResult struct { + // Reloaded custom agents + Agents []AgentInfo `json:"agents"` +} + +// Experimental: AgentSelectRequest is part of an experimental API and may change or be removed. +type AgentSelectRequest struct { + // Name of the custom agent to select + Name string `json:"name"` +} + +// Experimental: AgentSelectResult is part of an experimental API and may change or be removed. +type AgentSelectResult struct { + // The newly selected custom agent + Agent AgentInfo `json:"agent"` +} + +type CommandsHandlePendingCommandRequest struct { + // Error message if the command handler failed + Error *string `json:"error,omitempty"` + // Request ID from the command invocation event + RequestID string `json:"requestId"` +} + +type CommandsHandlePendingCommandResult struct { + // Whether the command was handled successfully + Success bool `json:"success"` +} + +type CurrentModel struct { + // Currently active model identifier + ModelID *string `json:"modelId,omitempty"` } type DiscoveredMCPServer struct { @@ -93,262 +292,287 @@ type DiscoveredMCPServer struct { Type *DiscoveredMCPServerType `json:"type,omitempty"` } -type ServerSkillList struct { - // All discovered skills across all sources - Skills []SkillElement `json:"skills"` +type Extension struct { + // Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper') + ID string `json:"id"` + // Extension name (directory name) + Name string `json:"name"` + // Process ID if the extension is running + PID *int64 `json:"pid,omitempty"` + // Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) + Source ExtensionSource `json:"source"` + // Current status: running, disabled, failed, or starting + Status ExtensionStatus `json:"status"` } -type SkillElement struct { - // Description of what the skill does - Description string `json:"description"` - // Whether the skill is currently enabled (based on global config) - Enabled bool `json:"enabled"` - // Unique identifier for the skill - Name string `json:"name"` - // Absolute path to the skill file - Path *string `json:"path,omitempty"` - // The project path this skill belongs to (only for project/inherited skills) - ProjectPath *string `json:"projectPath,omitempty"` - // Source location type (e.g., project, personal-copilot, plugin, builtin) - Source string `json:"source"` - // Whether the skill can be invoked by the user as a slash command - UserInvocable bool `json:"userInvocable"` +// Experimental: ExtensionList is part of an experimental API and may change or be removed. +type ExtensionList struct { + // Discovered extensions and their current status + Extensions []Extension `json:"extensions"` } -type ServerSkill struct { - // Description of what the skill does - Description string `json:"description"` - // Whether the skill is currently enabled (based on global config) - Enabled bool `json:"enabled"` - // Unique identifier for the skill - Name string `json:"name"` - // Absolute path to the skill file - Path *string `json:"path,omitempty"` - // The project path this skill belongs to (only for project/inherited skills) - ProjectPath *string `json:"projectPath,omitempty"` - // Source location type (e.g., project, personal-copilot, plugin, builtin) - Source string `json:"source"` - // Whether the skill can be invoked by the user as a slash command - UserInvocable bool `json:"userInvocable"` +// Experimental: ExtensionsDisableRequest is part of an experimental API and may change or be removed. +type ExtensionsDisableRequest struct { + // Source-qualified extension ID to disable + ID string `json:"id"` } -type CurrentModel struct { - // Currently active model identifier - ModelID *string `json:"modelId,omitempty"` +// Experimental: ExtensionsDisableResult is part of an experimental API and may change or be removed. +type ExtensionsDisableResult struct { } -// Override individual model capabilities resolved by the runtime -type ModelCapabilitiesOverride struct { - // Token limits for prompts, outputs, and context window - Limits *ModelCapabilitiesOverrideLimits `json:"limits,omitempty"` - // Feature flags indicating what the model supports - Supports *ModelCapabilitiesOverrideSupports `json:"supports,omitempty"` +// Experimental: ExtensionsEnableRequest is part of an experimental API and may change or be removed. +type ExtensionsEnableRequest struct { + // Source-qualified extension ID to enable + ID string `json:"id"` } -// Token limits for prompts, outputs, and context window -type ModelCapabilitiesOverrideLimits struct { - // Maximum total context window size in tokens - MaxContextWindowTokens *int64 `json:"max_context_window_tokens,omitempty"` - MaxOutputTokens *int64 `json:"max_output_tokens,omitempty"` - MaxPromptTokens *int64 `json:"max_prompt_tokens,omitempty"` - Vision *PurpleModelCapabilitiesOverrideLimitsVision `json:"vision,omitempty"` +// Experimental: ExtensionsEnableResult is part of an experimental API and may change or be removed. +type ExtensionsEnableResult struct { } -type PurpleModelCapabilitiesOverrideLimitsVision struct { - // Maximum image size in bytes - MaxPromptImageSize *int64 `json:"max_prompt_image_size,omitempty"` - // Maximum number of images per prompt - MaxPromptImages *int64 `json:"max_prompt_images,omitempty"` - // MIME types the model accepts - SupportedMediaTypes []string `json:"supported_media_types,omitempty"` +// Experimental: ExtensionsReloadResult is part of an experimental API and may change or be removed. +type ExtensionsReloadResult struct { } -// Feature flags indicating what the model supports -type ModelCapabilitiesOverrideSupports struct { - ReasoningEffort *bool `json:"reasoningEffort,omitempty"` - Vision *bool `json:"vision,omitempty"` +// Experimental: FleetStartRequest is part of an experimental API and may change or be removed. +type FleetStartRequest struct { + // Optional user prompt to combine with fleet instructions + Prompt *string `json:"prompt,omitempty"` } -type AgentInfo struct { - // Description of the agent's purpose - Description string `json:"description"` - // Human-readable display name - DisplayName string `json:"displayName"` - // Unique identifier of the custom agent - Name string `json:"name"` +// Experimental: FleetStartResult is part of an experimental API and may change or be removed. +type FleetStartResult struct { + // Whether fleet mode was successfully activated + Started bool `json:"started"` } -type MCPServerList struct { - // Configured MCP servers - Servers []MCPServer `json:"servers"` +type HandleToolCallResult struct { + // Whether the tool call result was handled successfully + Success bool `json:"success"` } -type MCPServer struct { - // Error message if the server failed to connect - Error *string `json:"error,omitempty"` - // Server name (config key) +// Post-compaction context window usage breakdown +type HistoryCompactContextWindow struct { + // Token count from non-system messages (user, assistant, tool) + ConversationTokens *int64 `json:"conversationTokens,omitempty"` + // Current total tokens in the context window (system + conversation + tool definitions) + CurrentTokens int64 `json:"currentTokens"` + // Current number of messages in the conversation + MessagesLength int64 `json:"messagesLength"` + // Token count from system message(s) + SystemTokens *int64 `json:"systemTokens,omitempty"` + // Maximum token count for the model's context window + TokenLimit int64 `json:"tokenLimit"` + // Token count from tool definitions + ToolDefinitionsTokens *int64 `json:"toolDefinitionsTokens,omitempty"` +} + +// Experimental: HistoryCompactResult is part of an experimental API and may change or be removed. +type HistoryCompactResult struct { + // Post-compaction context window usage breakdown + ContextWindow *HistoryCompactContextWindow `json:"contextWindow,omitempty"` + // Number of messages removed during compaction + MessagesRemoved int64 `json:"messagesRemoved"` + // Whether compaction completed successfully + Success bool `json:"success"` + // Number of tokens freed by compaction + TokensRemoved int64 `json:"tokensRemoved"` +} + +// Experimental: HistoryTruncateRequest is part of an experimental API and may change or be removed. +type HistoryTruncateRequest struct { + // Event ID to truncate to. This event and all events after it are removed from the session. + EventID string `json:"eventId"` +} + +// Experimental: HistoryTruncateResult is part of an experimental API and may change or be removed. +type HistoryTruncateResult struct { + // Number of events that were removed + EventsRemoved int64 `json:"eventsRemoved"` +} + +type InstructionsGetSourcesResult struct { + // Instruction sources for the session + Sources []InstructionsSources `json:"sources"` +} + +type InstructionsSources struct { + // Glob pattern from frontmatter — when set, this instruction applies only to matching files + ApplyTo *string `json:"applyTo,omitempty"` + // Raw content of the instruction file + Content string `json:"content"` + // Short description (body after frontmatter) for use in instruction tables + Description *string `json:"description,omitempty"` + // Unique identifier for this source (used for toggling) + ID string `json:"id"` + // Human-readable label + Label string `json:"label"` + // Where this source lives — used for UI grouping + Location InstructionsSourcesLocation `json:"location"` + // File path relative to repo or absolute for home + SourcePath string `json:"sourcePath"` + // Category of instruction source — used for merge logic + Type InstructionsSourcesType `json:"type"` +} + +type LogRequest struct { + // When true, the message is transient and not persisted to the session event log on disk + Ephemeral *bool `json:"ephemeral,omitempty"` + // Log severity level. Determines how the message is displayed in the timeline. Defaults to + // "info". + Level *SessionLogLevel `json:"level,omitempty"` + // Human-readable message + Message string `json:"message"` + // Optional URL the user can open in their browser for more details + URL *string `json:"url,omitempty"` +} + +type LogResult struct { + // The unique identifier of the emitted session event + EventID string `json:"eventId"` +} + +type MCPConfigAddRequest struct { + // MCP server configuration (local/stdio or remote/http) + Config MCPServerConfig `json:"config"` + // Unique name for the MCP server Name string `json:"name"` - // Configuration source: user, workspace, plugin, or builtin - Source *MCPServerSource `json:"source,omitempty"` - // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured - Status MCPServerStatus `json:"status"` } -type ToolCallResult struct { - // Error message if the tool call failed - Error *string `json:"error,omitempty"` - // Type of the tool result - ResultType *string `json:"resultType,omitempty"` - // Text result to send back to the LLM - TextResultForLlm string `json:"textResultForLlm"` - // Telemetry data from tool execution - ToolTelemetry map[string]any `json:"toolTelemetry,omitempty"` +// MCP server configuration (local/stdio or remote/http) +type MCPServerConfig struct { + Args []string `json:"args,omitempty"` + Command *string `json:"command,omitempty"` + Cwd *string `json:"cwd,omitempty"` + Env map[string]string `json:"env,omitempty"` + FilterMapping *FilterMapping `json:"filterMapping"` + IsDefaultServer *bool `json:"isDefaultServer,omitempty"` + // Timeout in milliseconds for tool calls to this server. + Timeout *int64 `json:"timeout,omitempty"` + // Tools to include. Defaults to all tools if not specified. + Tools []string `json:"tools,omitempty"` + // Remote transport type. Defaults to "http" when omitted. + Type *MCPServerConfigType `json:"type,omitempty"` + Headers map[string]string `json:"headers,omitempty"` + OauthClientID *string `json:"oauthClientId,omitempty"` + OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` + URL *string `json:"url,omitempty"` } -type HandleToolCallResult struct { - // Whether the tool call result was handled successfully - Success bool `json:"success"` +type MCPConfigAddResult struct { } -type UIElicitationStringEnumField struct { - Default *string `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - Enum []string `json:"enum"` - EnumNames []string `json:"enumNames,omitempty"` - Title *string `json:"title,omitempty"` - Type UIElicitationStringEnumFieldType `json:"type"` +type MCPConfigList struct { + // All MCP servers from user config, keyed by name + Servers map[string]MCPServerConfig `json:"servers"` } -type UIElicitationStringOneOfField struct { - Default *string `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - OneOf []UIElicitationStringOneOfFieldOneOf `json:"oneOf"` - Title *string `json:"title,omitempty"` - Type UIElicitationStringEnumFieldType `json:"type"` +type MCPConfigRemoveRequest struct { + // Name of the MCP server to remove + Name string `json:"name"` } -type UIElicitationStringOneOfFieldOneOf struct { - Const string `json:"const"` - Title string `json:"title"` +type MCPConfigRemoveResult struct { } -type UIElicitationArrayEnumField struct { - Default []string `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - Items UIElicitationArrayEnumFieldItems `json:"items"` - MaxItems *float64 `json:"maxItems,omitempty"` - MinItems *float64 `json:"minItems,omitempty"` - Title *string `json:"title,omitempty"` - Type UIElicitationArrayEnumFieldType `json:"type"` +type MCPConfigUpdateRequest struct { + // MCP server configuration (local/stdio or remote/http) + Config MCPServerConfig `json:"config"` + // Name of the MCP server to update + Name string `json:"name"` } -type UIElicitationArrayEnumFieldItems struct { - Enum []string `json:"enum"` - Type UIElicitationStringEnumFieldType `json:"type"` +type MCPConfigUpdateResult struct { } -type UIElicitationArrayAnyOfField struct { - Default []string `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - Items UIElicitationArrayAnyOfFieldItems `json:"items"` - MaxItems *float64 `json:"maxItems,omitempty"` - MinItems *float64 `json:"minItems,omitempty"` - Title *string `json:"title,omitempty"` - Type UIElicitationArrayEnumFieldType `json:"type"` +type MCPDisableRequest struct { + // Name of the MCP server to disable + ServerName string `json:"serverName"` } -type UIElicitationArrayAnyOfFieldItems struct { - AnyOf []PurpleUIElicitationArrayAnyOfFieldItemsAnyOf `json:"anyOf"` +type MCPDisableResult struct { } -type PurpleUIElicitationArrayAnyOfFieldItemsAnyOf struct { - Const string `json:"const"` - Title string `json:"title"` +type MCPDiscoverRequest struct { + // Working directory used as context for discovery (e.g., plugin resolution) + WorkingDirectory *string `json:"workingDirectory,omitempty"` } -// The elicitation response (accept with form values, decline, or cancel) -type UIElicitationResponse struct { - // The user's response: accept (submitted), decline (rejected), or cancel (dismissed) - Action UIElicitationResponseAction `json:"action"` - // The form values submitted by the user (present when action is 'accept') - Content map[string]*UIElicitationFieldValue `json:"content,omitempty"` +type MCPDiscoverResult struct { + // MCP servers discovered from all sources + Servers []DiscoveredMCPServer `json:"servers"` } -type UIHandlePendingElicitationRequest struct { - // The unique request ID from the elicitation.requested event - RequestID string `json:"requestId"` - // The elicitation response (accept with form values, decline, or cancel) - Result UIElicitationResponse `json:"result"` +type MCPEnableRequest struct { + // Name of the MCP server to enable + ServerName string `json:"serverName"` } -type UIElicitationResult struct { - // Whether the response was accepted. False if the request was already resolved by another - // client. - Success bool `json:"success"` +type MCPEnableResult struct { } -type PermissionDecisionRequest struct { - // Request ID of the pending permission request - RequestID string `json:"requestId"` - Result PermissionDecision `json:"result"` +type MCPReloadResult struct { } -type PermissionDecision struct { - // The permission request was approved - // - // Denied because approval rules explicitly blocked it - // - // Denied because no approval rule matched and user confirmation was unavailable - // - // Denied by the user during an interactive prompt - // - // Denied by the organization's content exclusion policy - // - // Denied by a permission request hook registered by an extension or plugin - Kind Kind `json:"kind"` - // Rules that denied the request - Rules []any `json:"rules,omitempty"` - // Optional feedback from the user explaining the denial - Feedback *string `json:"feedback,omitempty"` - // Human-readable explanation of why the path was excluded - // - // Optional message from the hook explaining the denial - Message *string `json:"message,omitempty"` - // File path that triggered the exclusion - Path *string `json:"path,omitempty"` - // Whether to interrupt the current agent turn - Interrupt *bool `json:"interrupt,omitempty"` +type MCPServer struct { + // Error message if the server failed to connect + Error *string `json:"error,omitempty"` + // Server name (config key) + Name string `json:"name"` + // Configuration source: user, workspace, plugin, or builtin + Source *MCPServerSource `json:"source,omitempty"` + // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured + Status MCPServerStatus `json:"status"` } -type PermissionRequestResult struct { - // Whether the permission request was handled successfully - Success bool `json:"success"` +type MCPServerConfigHTTP struct { + FilterMapping *FilterMapping `json:"filterMapping"` + Headers map[string]string `json:"headers,omitempty"` + IsDefaultServer *bool `json:"isDefaultServer,omitempty"` + OauthClientID *string `json:"oauthClientId,omitempty"` + OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` + // Timeout in milliseconds for tool calls to this server. + Timeout *int64 `json:"timeout,omitempty"` + // Tools to include. Defaults to all tools if not specified. + Tools []string `json:"tools,omitempty"` + // Remote transport type. Defaults to "http" when omitted. + Type *MCPServerConfigHTTPType `json:"type,omitempty"` + URL string `json:"url"` } -type PingResult struct { - // Echoed message (or default greeting) - Message string `json:"message"` - // Server protocol version number - ProtocolVersion int64 `json:"protocolVersion"` - // Server timestamp in milliseconds - Timestamp int64 `json:"timestamp"` +type MCPServerConfigLocal struct { + Args []string `json:"args"` + Command string `json:"command"` + Cwd *string `json:"cwd,omitempty"` + Env map[string]string `json:"env,omitempty"` + FilterMapping *FilterMapping `json:"filterMapping"` + IsDefaultServer *bool `json:"isDefaultServer,omitempty"` + // Timeout in milliseconds for tool calls to this server. + Timeout *int64 `json:"timeout,omitempty"` + // Tools to include. Defaults to all tools if not specified. + Tools []string `json:"tools,omitempty"` + Type *MCPServerConfigLocalType `json:"type,omitempty"` } -type PingRequest struct { - // Optional message to echo back - Message *string `json:"message,omitempty"` +type MCPServerList struct { + // Configured MCP servers + Servers []MCPServer `json:"servers"` } -type ModelList struct { - // List of available models with full metadata - Models []ModelElement `json:"models"` +type ModeSetRequest struct { + // The agent mode. Valid values: "interactive", "plan", "autopilot". + Mode SessionMode `json:"mode"` +} + +type ModeSetResult struct { } type ModelElement struct { // Billing information Billing *ModelBilling `json:"billing,omitempty"` // Model capabilities and limits - Capabilities CapabilitiesClass `json:"capabilities"` + Capabilities ModelCapabilities `json:"capabilities"` // Default reasoning effort level (only present if model supports reasoning effort) DefaultReasoningEffort *string `json:"defaultReasoningEffort,omitempty"` // Model identifier (e.g., "claude-sonnet-4.5") @@ -368,15 +592,15 @@ type ModelBilling struct { } // Model capabilities and limits -type CapabilitiesClass struct { +type ModelCapabilities struct { // Token limits for prompts, outputs, and context window - Limits *CapabilitiesLimits `json:"limits,omitempty"` + Limits *ModelCapabilitiesLimits `json:"limits,omitempty"` // Feature flags indicating what the model supports - Supports *CapabilitiesSupports `json:"supports,omitempty"` + Supports *ModelCapabilitiesSupports `json:"supports,omitempty"` } // Token limits for prompts, outputs, and context window -type CapabilitiesLimits struct { +type ModelCapabilitiesLimits struct { // Maximum total context window size in tokens MaxContextWindowTokens *int64 `json:"max_context_window_tokens,omitempty"` // Maximum number of output/completion tokens @@ -384,11 +608,11 @@ type CapabilitiesLimits struct { // Maximum number of prompt/input tokens MaxPromptTokens *int64 `json:"max_prompt_tokens,omitempty"` // Vision-specific limits - Vision *FluffyModelCapabilitiesLimitsVision `json:"vision,omitempty"` + Vision *ModelCapabilitiesLimitsVision `json:"vision,omitempty"` } // Vision-specific limits -type FluffyModelCapabilitiesLimitsVision struct { +type ModelCapabilitiesLimitsVision struct { // Maximum image size in bytes MaxPromptImageSize int64 `json:"max_prompt_image_size"` // Maximum number of images per prompt @@ -398,7 +622,7 @@ type FluffyModelCapabilitiesLimitsVision struct { } // Feature flags indicating what the model supports -type CapabilitiesSupports struct { +type ModelCapabilitiesSupports struct { // Whether this model supports reasoning effort configuration ReasoningEffort *bool `json:"reasoningEffort,omitempty"` // Whether this model supports vision/image input @@ -413,268 +637,165 @@ type ModelPolicy struct { Terms string `json:"terms"` } -type ToolList struct { - // List of available built-in tools with metadata - Tools []Tool `json:"tools"` -} - -type Tool struct { - // Description of what the tool does - Description string `json:"description"` - // Optional instructions for how to use this tool effectively - Instructions *string `json:"instructions,omitempty"` - // Tool identifier (e.g., "bash", "grep", "str_replace_editor") - Name string `json:"name"` - // Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP - // tools) - NamespacedName *string `json:"namespacedName,omitempty"` - // JSON Schema for the tool's input parameters - Parameters map[string]any `json:"parameters,omitempty"` -} - -type ToolsListRequest struct { - // Optional model ID — when provided, the returned tool list reflects model-specific - // overrides - Model *string `json:"model,omitempty"` -} - -type AccountGetQuotaResult struct { - // Quota snapshots keyed by type (e.g., chat, completions, premium_interactions) - QuotaSnapshots map[string]AccountQuotaSnapshot `json:"quotaSnapshots"` -} - -type AccountQuotaSnapshot struct { - // Number of requests included in the entitlement - EntitlementRequests int64 `json:"entitlementRequests"` - // Number of overage requests made this period - Overage int64 `json:"overage"` - // Whether pay-per-request usage is allowed when quota is exhausted - OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` - // Percentage of entitlement remaining - RemainingPercentage float64 `json:"remainingPercentage"` - // Date when the quota resets (ISO 8601) - ResetDate *time.Time `json:"resetDate,omitempty"` - // Number of requests used so far this period - UsedRequests int64 `json:"usedRequests"` -} - -type MCPConfigList struct { - // All MCP servers from user config, keyed by name - Servers map[string]MCPServerConfigValue `json:"servers"` -} - -// MCP server configuration (local/stdio or remote/http) -type MCPServerConfigValue struct { - Args []string `json:"args,omitempty"` - Command *string `json:"command,omitempty"` - Cwd *string `json:"cwd,omitempty"` - Env map[string]string `json:"env,omitempty"` - FilterMapping *FilterMapping `json:"filterMapping"` - IsDefaultServer *bool `json:"isDefaultServer,omitempty"` - // Timeout in milliseconds for tool calls to this server. - Timeout *int64 `json:"timeout,omitempty"` - // Tools to include. Defaults to all tools if not specified. - Tools []string `json:"tools,omitempty"` - // Remote transport type. Defaults to "http" when omitted. - Type *MCPServerConfigType `json:"type,omitempty"` - Headers map[string]string `json:"headers,omitempty"` - OauthClientID *string `json:"oauthClientId,omitempty"` - OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` - URL *string `json:"url,omitempty"` -} - -type MCPConfigAddResult struct { -} - -type MCPConfigAddRequest struct { - // MCP server configuration (local/stdio or remote/http) - Config MCPConfigAddRequestMCPServerConfig `json:"config"` - // Unique name for the MCP server - Name string `json:"name"` -} - -// MCP server configuration (local/stdio or remote/http) -type MCPConfigAddRequestMCPServerConfig struct { - Args []string `json:"args,omitempty"` - Command *string `json:"command,omitempty"` - Cwd *string `json:"cwd,omitempty"` - Env map[string]string `json:"env,omitempty"` - FilterMapping *FilterMapping `json:"filterMapping"` - IsDefaultServer *bool `json:"isDefaultServer,omitempty"` - // Timeout in milliseconds for tool calls to this server. - Timeout *int64 `json:"timeout,omitempty"` - // Tools to include. Defaults to all tools if not specified. - Tools []string `json:"tools,omitempty"` - // Remote transport type. Defaults to "http" when omitted. - Type *MCPServerConfigType `json:"type,omitempty"` - Headers map[string]string `json:"headers,omitempty"` - OauthClientID *string `json:"oauthClientId,omitempty"` - OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` - URL *string `json:"url,omitempty"` -} - -type MCPConfigUpdateResult struct { -} - -type MCPConfigUpdateRequest struct { - // MCP server configuration (local/stdio or remote/http) - Config MCPConfigUpdateRequestMCPServerConfig `json:"config"` - // Name of the MCP server to update - Name string `json:"name"` -} - -// MCP server configuration (local/stdio or remote/http) -type MCPConfigUpdateRequestMCPServerConfig struct { - Args []string `json:"args,omitempty"` - Command *string `json:"command,omitempty"` - Cwd *string `json:"cwd,omitempty"` - Env map[string]string `json:"env,omitempty"` - FilterMapping *FilterMapping `json:"filterMapping"` - IsDefaultServer *bool `json:"isDefaultServer,omitempty"` - // Timeout in milliseconds for tool calls to this server. - Timeout *int64 `json:"timeout,omitempty"` - // Tools to include. Defaults to all tools if not specified. - Tools []string `json:"tools,omitempty"` - // Remote transport type. Defaults to "http" when omitted. - Type *MCPServerConfigType `json:"type,omitempty"` - Headers map[string]string `json:"headers,omitempty"` - OauthClientID *string `json:"oauthClientId,omitempty"` - OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` - URL *string `json:"url,omitempty"` -} - -type MCPConfigRemoveResult struct { -} - -type MCPConfigRemoveRequest struct { - // Name of the MCP server to remove - Name string `json:"name"` -} - -type MCPDiscoverResult struct { - // MCP servers discovered from all sources - Servers []ServerElement `json:"servers"` -} - -type ServerElement struct { - // Whether the server is enabled (not in the disabled list) - Enabled bool `json:"enabled"` - // Server name (config key) - Name string `json:"name"` - // Configuration source - Source MCPServerSource `json:"source"` - // Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio) - Type *DiscoveredMCPServerType `json:"type,omitempty"` -} - -type MCPDiscoverRequest struct { - // Working directory used as context for discovery (e.g., plugin resolution) - WorkingDirectory *string `json:"workingDirectory,omitempty"` -} - -type SkillsConfigSetDisabledSkillsResult struct { -} - -type SkillsConfigSetDisabledSkillsRequest struct { - // List of skill names to disable - DisabledSkills []string `json:"disabledSkills"` -} - -type SkillsDiscoverRequest struct { - // Optional list of project directory paths to scan for project-scoped skills - ProjectPaths []string `json:"projectPaths,omitempty"` - // Optional list of additional skill directory paths to include - SkillDirectories []string `json:"skillDirectories,omitempty"` -} - -type SessionFSSetProviderResult struct { - // Whether the provider was set successfully - Success bool `json:"success"` +// Override individual model capabilities resolved by the runtime +type ModelCapabilitiesOverride struct { + // Token limits for prompts, outputs, and context window + Limits *ModelCapabilitiesOverrideLimits `json:"limits,omitempty"` + // Feature flags indicating what the model supports + Supports *ModelCapabilitiesOverrideSupports `json:"supports,omitempty"` } -type SessionFSSetProviderRequest struct { - // Path conventions used by this filesystem - Conventions SessionFSSetProviderConventions `json:"conventions"` - // Initial working directory for sessions - InitialCwd string `json:"initialCwd"` - // Path within each session's SessionFs where the runtime stores files for that session - SessionStatePath string `json:"sessionStatePath"` +// Token limits for prompts, outputs, and context window +type ModelCapabilitiesOverrideLimits struct { + // Maximum total context window size in tokens + MaxContextWindowTokens *int64 `json:"max_context_window_tokens,omitempty"` + MaxOutputTokens *int64 `json:"max_output_tokens,omitempty"` + MaxPromptTokens *int64 `json:"max_prompt_tokens,omitempty"` + Vision *ModelCapabilitiesOverrideLimitsVision `json:"vision,omitempty"` } -// Experimental: SessionsForkResult is part of an experimental API and may change or be removed. -type SessionsForkResult struct { - // The new forked session's ID - SessionID string `json:"sessionId"` +type ModelCapabilitiesOverrideLimitsVision struct { + // Maximum image size in bytes + MaxPromptImageSize *int64 `json:"max_prompt_image_size,omitempty"` + // Maximum number of images per prompt + MaxPromptImages *int64 `json:"max_prompt_images,omitempty"` + // MIME types the model accepts + SupportedMediaTypes []string `json:"supported_media_types,omitempty"` } -// Experimental: SessionsForkRequest is part of an experimental API and may change or be removed. -type SessionsForkRequest struct { - // Source session ID to fork from - SessionID string `json:"sessionId"` - // Optional event ID boundary. When provided, the fork includes only events before this ID - // (exclusive). When omitted, all events are included. - ToEventID *string `json:"toEventId,omitempty"` +// Feature flags indicating what the model supports +type ModelCapabilitiesOverrideSupports struct { + ReasoningEffort *bool `json:"reasoningEffort,omitempty"` + Vision *bool `json:"vision,omitempty"` } -type ModelSwitchToResult struct { - // Currently active model identifier after the switch - ModelID *string `json:"modelId,omitempty"` +type ModelList struct { + // List of available models with full metadata + Models []ModelElement `json:"models"` } type ModelSwitchToRequest struct { // Override individual model capabilities resolved by the runtime - ModelCapabilities *ModelCapabilitiesClass `json:"modelCapabilities,omitempty"` + ModelCapabilities *ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"` // Model identifier to switch to ModelID string `json:"modelId"` // Reasoning effort level to use for the model ReasoningEffort *string `json:"reasoningEffort,omitempty"` } -// Override individual model capabilities resolved by the runtime -type ModelCapabilitiesClass struct { - // Token limits for prompts, outputs, and context window - Limits *ModelCapabilitiesLimitsClass `json:"limits,omitempty"` - // Feature flags indicating what the model supports - Supports *ModelCapabilitiesOverrideSupports `json:"supports,omitempty"` +type ModelSwitchToResult struct { + // Currently active model identifier after the switch + ModelID *string `json:"modelId,omitempty"` } -// Token limits for prompts, outputs, and context window -type ModelCapabilitiesLimitsClass struct { - // Maximum total context window size in tokens - MaxContextWindowTokens *int64 `json:"max_context_window_tokens,omitempty"` - MaxOutputTokens *int64 `json:"max_output_tokens,omitempty"` - MaxPromptTokens *int64 `json:"max_prompt_tokens,omitempty"` - Vision *FluffyModelCapabilitiesOverrideLimitsVision `json:"vision,omitempty"` +type NameGetResult struct { + // The session name, falling back to the auto-generated summary, or null if neither exists + Name *string `json:"name"` } -type FluffyModelCapabilitiesOverrideLimitsVision struct { - // Maximum image size in bytes - MaxPromptImageSize *int64 `json:"max_prompt_image_size,omitempty"` - // Maximum number of images per prompt - MaxPromptImages *int64 `json:"max_prompt_images,omitempty"` - // MIME types the model accepts - SupportedMediaTypes []string `json:"supported_media_types,omitempty"` +type NameSetRequest struct { + // New session name (1–100 characters, trimmed of leading/trailing whitespace) + Name string `json:"name"` } -type ModeSetResult struct { +type NameSetResult struct { } -type ModeSetRequest struct { - // The agent mode. Valid values: "interactive", "plan", "autopilot". - Mode SessionMode `json:"mode"` +type PermissionDecision struct { + // The permission request was approved + // + // Denied because approval rules explicitly blocked it + // + // Denied because no approval rule matched and user confirmation was unavailable + // + // Denied by the user during an interactive prompt + // + // Denied by the organization's content exclusion policy + // + // Denied by a permission request hook registered by an extension or plugin + Kind PermissionDecisionKind `json:"kind"` + // Rules that denied the request + Rules []any `json:"rules,omitempty"` + // Optional feedback from the user explaining the denial + Feedback *string `json:"feedback,omitempty"` + // Human-readable explanation of why the path was excluded + // + // Optional message from the hook explaining the denial + Message *string `json:"message,omitempty"` + // File path that triggered the exclusion + Path *string `json:"path,omitempty"` + // Whether to interrupt the current agent turn + Interrupt *bool `json:"interrupt,omitempty"` } -type NameGetResult struct { - // The session name, falling back to the auto-generated summary, or null if neither exists - Name *string `json:"name"` +type PermissionDecisionApproved struct { + // The permission request was approved + Kind PermissionDecisionApprovedKind `json:"kind"` } -type NameSetResult struct { +type PermissionDecisionDeniedByContentExclusionPolicy struct { + // Denied by the organization's content exclusion policy + Kind PermissionDecisionDeniedByContentExclusionPolicyKind `json:"kind"` + // Human-readable explanation of why the path was excluded + Message string `json:"message"` + // File path that triggered the exclusion + Path string `json:"path"` } -type NameSetRequest struct { - // New session name (1–100 characters, trimmed of leading/trailing whitespace) - Name string `json:"name"` +type PermissionDecisionDeniedByPermissionRequestHook struct { + // Whether to interrupt the current agent turn + Interrupt *bool `json:"interrupt,omitempty"` + // Denied by a permission request hook registered by an extension or plugin + Kind PermissionDecisionDeniedByPermissionRequestHookKind `json:"kind"` + // Optional message from the hook explaining the denial + Message *string `json:"message,omitempty"` +} + +type PermissionDecisionDeniedByRules struct { + // Denied because approval rules explicitly blocked it + Kind PermissionDecisionDeniedByRulesKind `json:"kind"` + // Rules that denied the request + Rules []any `json:"rules"` +} + +type PermissionDecisionDeniedInteractivelyByUser struct { + // Optional feedback from the user explaining the denial + Feedback *string `json:"feedback,omitempty"` + // Denied by the user during an interactive prompt + Kind PermissionDecisionDeniedInteractivelyByUserKind `json:"kind"` +} + +type PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser struct { + // Denied because no approval rule matched and user confirmation was unavailable + Kind PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind `json:"kind"` +} + +type PermissionDecisionRequest struct { + // Request ID of the pending permission request + RequestID string `json:"requestId"` + Result PermissionDecision `json:"result"` +} + +type PermissionRequestResult struct { + // Whether the permission request was handled successfully + Success bool `json:"success"` +} + +type PingRequest struct { + // Optional message to echo back + Message *string `json:"message,omitempty"` +} + +type PingResult struct { + // Echoed message (or default greeting) + Message string `json:"message"` + // Server protocol version number + ProtocolVersion int64 `json:"protocolVersion"` + // Server timestamp in milliseconds + Timestamp int64 `json:"timestamp"` +} + +type PlanDeleteResult struct { } type PlanReadResult struct { @@ -686,169 +807,250 @@ type PlanReadResult struct { Path *string `json:"path"` } -type PlanUpdateResult struct { -} - type PlanUpdateRequest struct { // The new content for the plan file Content string `json:"content"` } -type PlanDeleteResult struct { +type PlanUpdateResult struct { } -type WorkspacesGetWorkspaceResult struct { - // Current workspace metadata, or null if not available - Workspace *WorkspaceClass `json:"workspace"` +type PluginElement struct { + // Whether the plugin is currently enabled + Enabled bool `json:"enabled"` + // Marketplace the plugin came from + Marketplace string `json:"marketplace"` + // Plugin name + Name string `json:"name"` + // Installed version + Version *string `json:"version,omitempty"` } -type WorkspaceClass struct { - Branch *string `json:"branch,omitempty"` - ChronicleSyncDismissed *bool `json:"chronicle_sync_dismissed,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - Cwd *string `json:"cwd,omitempty"` - GitRoot *string `json:"git_root,omitempty"` - HostType *HostType `json:"host_type,omitempty"` - ID string `json:"id"` - McLastEventID *string `json:"mc_last_event_id,omitempty"` - McSessionID *string `json:"mc_session_id,omitempty"` - McTaskID *string `json:"mc_task_id,omitempty"` - Name *string `json:"name,omitempty"` - PRCreateSyncDismissed *bool `json:"pr_create_sync_dismissed,omitempty"` - Repository *string `json:"repository,omitempty"` - SessionSyncLevel *SessionSyncLevel `json:"session_sync_level,omitempty"` - Summary *string `json:"summary,omitempty"` - SummaryCount *int64 `json:"summary_count,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` +// Experimental: PluginList is part of an experimental API and may change or be removed. +type PluginList struct { + // Installed plugins + Plugins []PluginElement `json:"plugins"` } -type WorkspacesListFilesResult struct { - // Relative file paths in the workspace files directory - Files []string `json:"files"` +type ServerSkill struct { + // Description of what the skill does + Description string `json:"description"` + // Whether the skill is currently enabled (based on global config) + Enabled bool `json:"enabled"` + // Unique identifier for the skill + Name string `json:"name"` + // Absolute path to the skill file + Path *string `json:"path,omitempty"` + // The project path this skill belongs to (only for project/inherited skills) + ProjectPath *string `json:"projectPath,omitempty"` + // Source location type (e.g., project, personal-copilot, plugin, builtin) + Source string `json:"source"` + // Whether the skill can be invoked by the user as a slash command + UserInvocable bool `json:"userInvocable"` } -type WorkspacesReadFileResult struct { - // File content as a UTF-8 string +type ServerSkillList struct { + // All discovered skills across all sources + Skills []ServerSkill `json:"skills"` +} + +type SessionFSAppendFileRequest struct { + // Content to append Content string `json:"content"` + // Optional POSIX-style mode for newly created files + Mode *int64 `json:"mode,omitempty"` + // Path using SessionFs conventions + Path string `json:"path"` + // Target session identifier + SessionID string `json:"sessionId"` } -type WorkspacesReadFileRequest struct { - // Relative path within the workspace files directory +// Describes a filesystem error. +type SessionFSError struct { + // Error classification + Code SessionFSErrorCode `json:"code"` + // Free-form detail about the error, for logging/diagnostics + Message *string `json:"message,omitempty"` +} + +type SessionFSExistsRequest struct { + // Path using SessionFs conventions Path string `json:"path"` + // Target session identifier + SessionID string `json:"sessionId"` } -type WorkspacesCreateFileResult struct { +type SessionFSExistsResult struct { + // Whether the path exists + Exists bool `json:"exists"` } -type WorkspacesCreateFileRequest struct { - // File content to write as a UTF-8 string - Content string `json:"content"` - // Relative path within the workspace files directory +type SessionFSMkdirRequest struct { + // Optional POSIX-style mode for newly created directories + Mode *int64 `json:"mode,omitempty"` + // Path using SessionFs conventions Path string `json:"path"` + // Create parent directories as needed + Recursive *bool `json:"recursive,omitempty"` + // Target session identifier + SessionID string `json:"sessionId"` } -type InstructionsGetSourcesResult struct { - // Instruction sources for the session - Sources []InstructionsSources `json:"sources"` +type SessionFSReadFileRequest struct { + // Path using SessionFs conventions + Path string `json:"path"` + // Target session identifier + SessionID string `json:"sessionId"` } -type InstructionsSources struct { - // Glob pattern from frontmatter — when set, this instruction applies only to matching files - ApplyTo *string `json:"applyTo,omitempty"` - // Raw content of the instruction file +type SessionFSReadFileResult struct { + // File content as UTF-8 string Content string `json:"content"` - // Short description (body after frontmatter) for use in instruction tables - Description *string `json:"description,omitempty"` - // Unique identifier for this source (used for toggling) - ID string `json:"id"` - // Human-readable label - Label string `json:"label"` - // Where this source lives — used for UI grouping - Location InstructionsSourcesLocation `json:"location"` - // File path relative to repo or absolute for home - SourcePath string `json:"sourcePath"` - // Category of instruction source — used for merge logic - Type InstructionsSourcesType `json:"type"` + // Describes a filesystem error. + Error *SessionFSError `json:"error,omitempty"` +} + +type SessionFSReaddirRequest struct { + // Path using SessionFs conventions + Path string `json:"path"` + // Target session identifier + SessionID string `json:"sessionId"` +} + +type SessionFSReaddirResult struct { + // Entry names in the directory + Entries []string `json:"entries"` + // Describes a filesystem error. + Error *SessionFSError `json:"error,omitempty"` +} + +type SessionFSReaddirWithTypesEntry struct { + // Entry name + Name string `json:"name"` + // Entry type + Type SessionFSReaddirWithTypesEntryType `json:"type"` +} + +type SessionFSReaddirWithTypesRequest struct { + // Path using SessionFs conventions + Path string `json:"path"` + // Target session identifier + SessionID string `json:"sessionId"` +} + +type SessionFSReaddirWithTypesResult struct { + // Directory entries with type information + Entries []SessionFSReaddirWithTypesEntry `json:"entries"` + // Describes a filesystem error. + Error *SessionFSError `json:"error,omitempty"` } -// Experimental: FleetStartResult is part of an experimental API and may change or be removed. -type FleetStartResult struct { - // Whether fleet mode was successfully activated - Started bool `json:"started"` +type SessionFSRenameRequest struct { + // Destination path using SessionFs conventions + Dest string `json:"dest"` + // Target session identifier + SessionID string `json:"sessionId"` + // Source path using SessionFs conventions + Src string `json:"src"` } -// Experimental: FleetStartRequest is part of an experimental API and may change or be removed. -type FleetStartRequest struct { - // Optional user prompt to combine with fleet instructions - Prompt *string `json:"prompt,omitempty"` +type SessionFSRmRequest struct { + // Ignore errors if the path does not exist + Force *bool `json:"force,omitempty"` + // Path using SessionFs conventions + Path string `json:"path"` + // Remove directories and their contents recursively + Recursive *bool `json:"recursive,omitempty"` + // Target session identifier + SessionID string `json:"sessionId"` } -// Experimental: AgentList is part of an experimental API and may change or be removed. -type AgentList struct { - // Available custom agents - Agents []AgentListAgent `json:"agents"` +type SessionFSSetProviderRequest struct { + // Path conventions used by this filesystem + Conventions SessionFSSetProviderConventions `json:"conventions"` + // Initial working directory for sessions + InitialCwd string `json:"initialCwd"` + // Path within each session's SessionFs where the runtime stores files for that session + SessionStatePath string `json:"sessionStatePath"` } -type AgentListAgent struct { - // Description of the agent's purpose - Description string `json:"description"` - // Human-readable display name - DisplayName string `json:"displayName"` - // Unique identifier of the custom agent - Name string `json:"name"` +type SessionFSSetProviderResult struct { + // Whether the provider was set successfully + Success bool `json:"success"` } -// Experimental: AgentGetCurrentResult is part of an experimental API and may change or be removed. -type AgentGetCurrentResult struct { - // Currently selected custom agent, or null if using the default agent - Agent *AgentReloadResultAgent `json:"agent"` +type SessionFSStatRequest struct { + // Path using SessionFs conventions + Path string `json:"path"` + // Target session identifier + SessionID string `json:"sessionId"` } -// Experimental: AgentSelectResult is part of an experimental API and may change or be removed. -type AgentSelectResult struct { - // The newly selected custom agent - Agent AgentSelectResultAgent `json:"agent"` +type SessionFSStatResult struct { + // ISO 8601 timestamp of creation + Birthtime time.Time `json:"birthtime"` + // Describes a filesystem error. + Error *SessionFSError `json:"error,omitempty"` + // Whether the path is a directory + IsDirectory bool `json:"isDirectory"` + // Whether the path is a file + IsFile bool `json:"isFile"` + // ISO 8601 timestamp of last modification + Mtime time.Time `json:"mtime"` + // File size in bytes + Size int64 `json:"size"` } -// The newly selected custom agent -type AgentSelectResultAgent struct { - // Description of the agent's purpose - Description string `json:"description"` - // Human-readable display name - DisplayName string `json:"displayName"` - // Unique identifier of the custom agent - Name string `json:"name"` +type SessionFSWriteFileRequest struct { + // Content to write + Content string `json:"content"` + // Optional POSIX-style mode for newly created files + Mode *int64 `json:"mode,omitempty"` + // Path using SessionFs conventions + Path string `json:"path"` + // Target session identifier + SessionID string `json:"sessionId"` } -// Experimental: AgentSelectRequest is part of an experimental API and may change or be removed. -type AgentSelectRequest struct { - // Name of the custom agent to select - Name string `json:"name"` +// Experimental: SessionsForkRequest is part of an experimental API and may change or be removed. +type SessionsForkRequest struct { + // Source session ID to fork from + SessionID string `json:"sessionId"` + // Optional event ID boundary. When provided, the fork includes only events before this ID + // (exclusive). When omitted, all events are included. + ToEventID *string `json:"toEventId,omitempty"` } -// Experimental: AgentDeselectResult is part of an experimental API and may change or be removed. -type AgentDeselectResult struct { +// Experimental: SessionsForkResult is part of an experimental API and may change or be removed. +type SessionsForkResult struct { + // The new forked session's ID + SessionID string `json:"sessionId"` } -// Experimental: AgentReloadResult is part of an experimental API and may change or be removed. -type AgentReloadResult struct { - // Reloaded custom agents - Agents []AgentReloadResultAgent `json:"agents"` +type ShellExecRequest struct { + // Shell command to execute + Command string `json:"command"` + // Working directory (defaults to session working directory) + Cwd *string `json:"cwd,omitempty"` + // Timeout in milliseconds (default: 30000) + Timeout *int64 `json:"timeout,omitempty"` } -type AgentReloadResultAgent struct { - // Description of the agent's purpose - Description string `json:"description"` - // Human-readable display name - DisplayName string `json:"displayName"` - // Unique identifier of the custom agent - Name string `json:"name"` +type ShellExecResult struct { + // Unique identifier for tracking streamed output + ProcessID string `json:"processId"` } -// Experimental: SkillList is part of an experimental API and may change or be removed. -type SkillList struct { - // Available skills - Skills []Skill `json:"skills"` +type ShellKillRequest struct { + // Process identifier returned by shell.exec + ProcessID string `json:"processId"` + // Signal to send (default: SIGTERM) + Signal *ShellKillSignal `json:"signal,omitempty"` +} + +type ShellKillResult struct { + // Whether the signal was sent successfully + Killed bool `json:"killed"` } type Skill struct { @@ -866,18 +1068,18 @@ type Skill struct { UserInvocable bool `json:"userInvocable"` } -// Experimental: SkillsEnableResult is part of an experimental API and may change or be removed. -type SkillsEnableResult struct { +// Experimental: SkillList is part of an experimental API and may change or be removed. +type SkillList struct { + // Available skills + Skills []Skill `json:"skills"` } -// Experimental: SkillsEnableRequest is part of an experimental API and may change or be removed. -type SkillsEnableRequest struct { - // Name of the skill to enable - Name string `json:"name"` +type SkillsConfigSetDisabledSkillsRequest struct { + // List of skill names to disable + DisabledSkills []string `json:"disabledSkills"` } -// Experimental: SkillsDisableResult is part of an experimental API and may change or be removed. -type SkillsDisableResult struct { +type SkillsConfigSetDisabledSkillsResult struct { } // Experimental: SkillsDisableRequest is part of an experimental API and may change or be removed. @@ -886,108 +1088,108 @@ type SkillsDisableRequest struct { Name string `json:"name"` } -// Experimental: SkillsReloadResult is part of an experimental API and may change or be removed. -type SkillsReloadResult struct { -} - -type MCPEnableResult struct { -} - -type MCPEnableRequest struct { - // Name of the MCP server to enable - ServerName string `json:"serverName"` +// Experimental: SkillsDisableResult is part of an experimental API and may change or be removed. +type SkillsDisableResult struct { } -type MCPDisableResult struct { +type SkillsDiscoverRequest struct { + // Optional list of project directory paths to scan for project-scoped skills + ProjectPaths []string `json:"projectPaths,omitempty"` + // Optional list of additional skill directory paths to include + SkillDirectories []string `json:"skillDirectories,omitempty"` } -type MCPDisableRequest struct { - // Name of the MCP server to disable - ServerName string `json:"serverName"` +// Experimental: SkillsEnableRequest is part of an experimental API and may change or be removed. +type SkillsEnableRequest struct { + // Name of the skill to enable + Name string `json:"name"` } -type MCPReloadResult struct { +// Experimental: SkillsEnableResult is part of an experimental API and may change or be removed. +type SkillsEnableResult struct { } -// Experimental: PluginList is part of an experimental API and may change or be removed. -type PluginList struct { - // Installed plugins - Plugins []PluginElement `json:"plugins"` +// Experimental: SkillsReloadResult is part of an experimental API and may change or be removed. +type SkillsReloadResult struct { } -type PluginElement struct { - // Whether the plugin is currently enabled - Enabled bool `json:"enabled"` - // Marketplace the plugin came from - Marketplace string `json:"marketplace"` - // Plugin name +type Tool struct { + // Description of what the tool does + Description string `json:"description"` + // Optional instructions for how to use this tool effectively + Instructions *string `json:"instructions,omitempty"` + // Tool identifier (e.g., "bash", "grep", "str_replace_editor") Name string `json:"name"` - // Installed version - Version *string `json:"version,omitempty"` -} - -// Experimental: ExtensionList is part of an experimental API and may change or be removed. -type ExtensionList struct { - // Discovered extensions and their current status - Extensions []Extension `json:"extensions"` + // Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP + // tools) + NamespacedName *string `json:"namespacedName,omitempty"` + // JSON Schema for the tool's input parameters + Parameters map[string]any `json:"parameters,omitempty"` } -type Extension struct { - // Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper') - ID string `json:"id"` - // Extension name (directory name) - Name string `json:"name"` - // Process ID if the extension is running - PID *int64 `json:"pid,omitempty"` - // Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) - Source ExtensionSource `json:"source"` - // Current status: running, disabled, failed, or starting - Status ExtensionStatus `json:"status"` +type ToolCallResult struct { + // Error message if the tool call failed + Error *string `json:"error,omitempty"` + // Type of the tool result + ResultType *string `json:"resultType,omitempty"` + // Text result to send back to the LLM + TextResultForLlm string `json:"textResultForLlm"` + // Telemetry data from tool execution + ToolTelemetry map[string]any `json:"toolTelemetry,omitempty"` } -// Experimental: ExtensionsEnableResult is part of an experimental API and may change or be removed. -type ExtensionsEnableResult struct { +type ToolList struct { + // List of available built-in tools with metadata + Tools []Tool `json:"tools"` } -// Experimental: ExtensionsEnableRequest is part of an experimental API and may change or be removed. -type ExtensionsEnableRequest struct { - // Source-qualified extension ID to enable - ID string `json:"id"` +type ToolsHandlePendingToolCallRequest struct { + // Error message if the tool call failed + Error *string `json:"error,omitempty"` + // Request ID of the pending tool call + RequestID string `json:"requestId"` + // Tool call result (string or expanded result object) + Result *ToolsHandlePendingToolCall `json:"result"` } -// Experimental: ExtensionsDisableResult is part of an experimental API and may change or be removed. -type ExtensionsDisableResult struct { +type ToolsListRequest struct { + // Optional model ID — when provided, the returned tool list reflects model-specific + // overrides + Model *string `json:"model,omitempty"` } -// Experimental: ExtensionsDisableRequest is part of an experimental API and may change or be removed. -type ExtensionsDisableRequest struct { - // Source-qualified extension ID to disable - ID string `json:"id"` +type UIElicitationArrayAnyOfField struct { + Default []string `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Items UIElicitationArrayAnyOfFieldItems `json:"items"` + MaxItems *float64 `json:"maxItems,omitempty"` + MinItems *float64 `json:"minItems,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationArrayAnyOfFieldType `json:"type"` } -// Experimental: ExtensionsReloadResult is part of an experimental API and may change or be removed. -type ExtensionsReloadResult struct { +type UIElicitationArrayAnyOfFieldItems struct { + AnyOf []UIElicitationArrayAnyOfFieldItemsAnyOf `json:"anyOf"` } -type ToolsHandlePendingToolCallRequest struct { - // Error message if the tool call failed - Error *string `json:"error,omitempty"` - // Request ID of the pending tool call - RequestID string `json:"requestId"` - // Tool call result (string or expanded result object) - Result *ToolsHandlePendingToolCall `json:"result"` +type UIElicitationArrayAnyOfFieldItemsAnyOf struct { + Const string `json:"const"` + Title string `json:"title"` } -type CommandsHandlePendingCommandResult struct { - // Whether the command was handled successfully - Success bool `json:"success"` +type UIElicitationArrayEnumField struct { + Default []string `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Items UIElicitationArrayEnumFieldItems `json:"items"` + MaxItems *float64 `json:"maxItems,omitempty"` + MinItems *float64 `json:"minItems,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationArrayAnyOfFieldType `json:"type"` } -type CommandsHandlePendingCommandRequest struct { - // Error message if the command handler failed - Error *string `json:"error,omitempty"` - // Request ID from the command invocation event - RequestID string `json:"requestId"` +type UIElicitationArrayEnumFieldItems struct { + Enum []string `json:"enum"` + Type UIElicitationArrayEnumFieldItemsType `json:"type"` } type UIElicitationRequest struct { @@ -1004,7 +1206,7 @@ type UIElicitationSchema struct { // List of required field names Required []string `json:"required,omitempty"` // Schema type indicator (always 'object') - Type RequestedSchemaType `json:"type"` + Type UIElicitationSchemaType `json:"type"` } type UIElicitationSchemaProperty struct { @@ -1013,8 +1215,8 @@ type UIElicitationSchemaProperty struct { Enum []string `json:"enum,omitempty"` EnumNames []string `json:"enumNames,omitempty"` Title *string `json:"title,omitempty"` - Type UIElicitationSchemaPropertyNumberType `json:"type"` - OneOf []UIElicitationSchemaPropertyOneOf `json:"oneOf,omitempty"` + Type UIElicitationSchemaPropertyType `json:"type"` + OneOf []UIElicitationStringOneOfFieldOneOf `json:"oneOf,omitempty"` Items *UIElicitationArrayFieldItems `json:"items,omitempty"` MaxItems *float64 `json:"maxItems,omitempty"` MinItems *float64 `json:"minItems,omitempty"` @@ -1026,102 +1228,78 @@ type UIElicitationSchemaProperty struct { } type UIElicitationArrayFieldItems struct { - Enum []string `json:"enum,omitempty"` - Type *UIElicitationStringEnumFieldType `json:"type,omitempty"` - AnyOf []FluffyUIElicitationArrayAnyOfFieldItemsAnyOf `json:"anyOf,omitempty"` -} - -type FluffyUIElicitationArrayAnyOfFieldItemsAnyOf struct { - Const string `json:"const"` - Title string `json:"title"` + Enum []string `json:"enum,omitempty"` + Type *UIElicitationArrayEnumFieldItemsType `json:"type,omitempty"` + AnyOf []UIElicitationArrayAnyOfFieldItemsAnyOf `json:"anyOf,omitempty"` } -type UIElicitationSchemaPropertyOneOf struct { +type UIElicitationStringOneOfFieldOneOf struct { Const string `json:"const"` Title string `json:"title"` } -type LogResult struct { - // The unique identifier of the emitted session event - EventID string `json:"eventId"` -} - -type LogRequest struct { - // When true, the message is transient and not persisted to the session event log on disk - Ephemeral *bool `json:"ephemeral,omitempty"` - // Log severity level. Determines how the message is displayed in the timeline. Defaults to - // "info". - Level *SessionLogLevel `json:"level,omitempty"` - // Human-readable message - Message string `json:"message"` - // Optional URL the user can open in their browser for more details - URL *string `json:"url,omitempty"` -} - -type ShellExecResult struct { - // Unique identifier for tracking streamed output - ProcessID string `json:"processId"` +// The elicitation response (accept with form values, decline, or cancel) +type UIElicitationResponse struct { + // The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + Action UIElicitationResponseAction `json:"action"` + // The form values submitted by the user (present when action is 'accept') + Content map[string]*UIElicitationFieldValue `json:"content,omitempty"` } -type ShellExecRequest struct { - // Shell command to execute - Command string `json:"command"` - // Working directory (defaults to session working directory) - Cwd *string `json:"cwd,omitempty"` - // Timeout in milliseconds (default: 30000) - Timeout *int64 `json:"timeout,omitempty"` +type UIElicitationResult struct { + // Whether the response was accepted. False if the request was already resolved by another + // client. + Success bool `json:"success"` } -type ShellKillResult struct { - // Whether the signal was sent successfully - Killed bool `json:"killed"` +type UIElicitationSchemaPropertyBoolean struct { + Default *bool `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationSchemaPropertyBooleanType `json:"type"` } -type ShellKillRequest struct { - // Process identifier returned by shell.exec - ProcessID string `json:"processId"` - // Signal to send (default: SIGTERM) - Signal *ShellKillSignal `json:"signal,omitempty"` +type UIElicitationSchemaPropertyNumber struct { + Default *float64 `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Maximum *float64 `json:"maximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationSchemaPropertyNumberTypeEnum `json:"type"` } -// Experimental: HistoryCompactResult is part of an experimental API and may change or be removed. -type HistoryCompactResult struct { - // Post-compaction context window usage breakdown - ContextWindow *HistoryCompactContextWindow `json:"contextWindow,omitempty"` - // Number of messages removed during compaction - MessagesRemoved int64 `json:"messagesRemoved"` - // Whether compaction completed successfully - Success bool `json:"success"` - // Number of tokens freed by compaction - TokensRemoved int64 `json:"tokensRemoved"` +type UIElicitationSchemaPropertyString struct { + Default *string `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Format *UIElicitationSchemaPropertyStringFormat `json:"format,omitempty"` + MaxLength *float64 `json:"maxLength,omitempty"` + MinLength *float64 `json:"minLength,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationArrayEnumFieldItemsType `json:"type"` } -// Post-compaction context window usage breakdown -type HistoryCompactContextWindow struct { - // Token count from non-system messages (user, assistant, tool) - ConversationTokens *int64 `json:"conversationTokens,omitempty"` - // Current total tokens in the context window (system + conversation + tool definitions) - CurrentTokens int64 `json:"currentTokens"` - // Current number of messages in the conversation - MessagesLength int64 `json:"messagesLength"` - // Token count from system message(s) - SystemTokens *int64 `json:"systemTokens,omitempty"` - // Maximum token count for the model's context window - TokenLimit int64 `json:"tokenLimit"` - // Token count from tool definitions - ToolDefinitionsTokens *int64 `json:"toolDefinitionsTokens,omitempty"` +type UIElicitationStringEnumField struct { + Default *string `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Enum []string `json:"enum"` + EnumNames []string `json:"enumNames,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationArrayEnumFieldItemsType `json:"type"` } -// Experimental: HistoryTruncateResult is part of an experimental API and may change or be removed. -type HistoryTruncateResult struct { - // Number of events that were removed - EventsRemoved int64 `json:"eventsRemoved"` +type UIElicitationStringOneOfField struct { + Default *string `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + OneOf []UIElicitationStringOneOfFieldOneOf `json:"oneOf"` + Title *string `json:"title,omitempty"` + Type UIElicitationArrayEnumFieldItemsType `json:"type"` } -// Experimental: HistoryTruncateRequest is part of an experimental API and may change or be removed. -type HistoryTruncateRequest struct { - // Event ID to truncate to. This event and all events after it are removed from the session. - EventID string `json:"eventId"` +type UIHandlePendingElicitationRequest struct { + // The unique request ID from the elicitation.requested event + RequestID string `json:"requestId"` + // The elicitation response (accept with form values, decline, or cancel) + Result UIElicitationResponse `json:"result"` } // Experimental: UsageGetMetricsResult is part of an experimental API and may change or be removed. @@ -1186,166 +1364,55 @@ type UsageMetricsModelMetricUsage struct { ReasoningTokens *int64 `json:"reasoningTokens,omitempty"` } -type SessionFSReadFileResult struct { - // File content as UTF-8 string - Content string `json:"content"` -} - -type SessionFSReadFileRequest struct { - // Path using SessionFs conventions - Path string `json:"path"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSWriteFileResult struct { -} - -type SessionFSWriteFileRequest struct { - // Content to write - Content string `json:"content"` - // Optional POSIX-style mode for newly created files - Mode *int64 `json:"mode,omitempty"` - // Path using SessionFs conventions - Path string `json:"path"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSAppendFileResult struct { -} - -type SessionFSAppendFileRequest struct { - // Content to append - Content string `json:"content"` - // Optional POSIX-style mode for newly created files - Mode *int64 `json:"mode,omitempty"` - // Path using SessionFs conventions - Path string `json:"path"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSExistsResult struct { - // Whether the path exists - Exists bool `json:"exists"` -} - -type SessionFSExistsRequest struct { - // Path using SessionFs conventions - Path string `json:"path"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSStatResult struct { - // ISO 8601 timestamp of creation - Birthtime time.Time `json:"birthtime"` - // Whether the path is a directory - IsDirectory bool `json:"isDirectory"` - // Whether the path is a file - IsFile bool `json:"isFile"` - // ISO 8601 timestamp of last modification - Mtime time.Time `json:"mtime"` - // File size in bytes - Size int64 `json:"size"` -} - -type SessionFSStatRequest struct { - // Path using SessionFs conventions - Path string `json:"path"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSMkdirResult struct { -} - -type SessionFSMkdirRequest struct { - // Optional POSIX-style mode for newly created directories - Mode *int64 `json:"mode,omitempty"` - // Path using SessionFs conventions - Path string `json:"path"` - // Create parent directories as needed - Recursive *bool `json:"recursive,omitempty"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSReaddirResult struct { - // Entry names in the directory - Entries []string `json:"entries"` -} - -type SessionFSReaddirRequest struct { - // Path using SessionFs conventions - Path string `json:"path"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSReaddirWithTypesResult struct { - // Directory entries with type information - Entries []SessionFSReaddirWithTypesEntry `json:"entries"` -} - -type SessionFSReaddirWithTypesEntry struct { - // Entry name - Name string `json:"name"` - // Entry type - Type SessionFSReaddirWithTypesEntryType `json:"type"` -} - -type SessionFSReaddirWithTypesRequest struct { - // Path using SessionFs conventions - Path string `json:"path"` - // Target session identifier - SessionID string `json:"sessionId"` -} - -type SessionFSRmResult struct { -} - -type SessionFSRmRequest struct { - // Ignore errors if the path does not exist - Force *bool `json:"force,omitempty"` - // Path using SessionFs conventions +type WorkspacesCreateFileRequest struct { + // File content to write as a UTF-8 string + Content string `json:"content"` + // Relative path within the workspace files directory Path string `json:"path"` - // Remove directories and their contents recursively - Recursive *bool `json:"recursive,omitempty"` - // Target session identifier - SessionID string `json:"sessionId"` } -type SessionFSRenameResult struct { +type WorkspacesCreateFileResult struct { } -type SessionFSRenameRequest struct { - // Destination path using SessionFs conventions - Dest string `json:"dest"` - // Target session identifier - SessionID string `json:"sessionId"` - // Source path using SessionFs conventions - Src string `json:"src"` +type WorkspacesGetWorkspaceResult struct { + // Current workspace metadata, or null if not available + Workspace *WorkspaceClass `json:"workspace"` } -type FilterMappingString string +type WorkspaceClass struct { + Branch *string `json:"branch,omitempty"` + ChronicleSyncDismissed *bool `json:"chronicle_sync_dismissed,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + Cwd *string `json:"cwd,omitempty"` + GitRoot *string `json:"git_root,omitempty"` + HostType *HostType `json:"host_type,omitempty"` + ID string `json:"id"` + McLastEventID *string `json:"mc_last_event_id,omitempty"` + McSessionID *string `json:"mc_session_id,omitempty"` + McTaskID *string `json:"mc_task_id,omitempty"` + Name *string `json:"name,omitempty"` + RemoteSteerable *bool `json:"remote_steerable,omitempty"` + Repository *string `json:"repository,omitempty"` + SessionSyncLevel *SessionSyncLevel `json:"session_sync_level,omitempty"` + Summary *string `json:"summary,omitempty"` + SummaryCount *int64 `json:"summary_count,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` +} -const ( - FilterMappingStringHiddenCharacters FilterMappingString = "hidden_characters" - FilterMappingStringMarkdown FilterMappingString = "markdown" - FilterMappingStringNone FilterMappingString = "none" -) +type WorkspacesListFilesResult struct { + // Relative file paths in the workspace files directory + Files []string `json:"files"` +} -// Remote transport type. Defaults to "http" when omitted. -type MCPServerConfigType string +type WorkspacesReadFileRequest struct { + // Relative path within the workspace files directory + Path string `json:"path"` +} -const ( - MCPServerConfigTypeHTTP MCPServerConfigType = "http" - MCPServerConfigTypeLocal MCPServerConfigType = "local" - MCPServerConfigTypeSSE MCPServerConfigType = "sse" - MCPServerConfigTypeStdio MCPServerConfigType = "stdio" -) +type WorkspacesReadFileResult struct { + // File content as a UTF-8 string + Content string `json:"content"` +} // Configuration source // @@ -1369,6 +1436,73 @@ const ( DiscoveredMCPServerTypeMemory DiscoveredMCPServerType = "memory" ) +// Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) +type ExtensionSource string + +const ( + ExtensionSourceUser ExtensionSource = "user" + ExtensionSourceProject ExtensionSource = "project" +) + +// Current status: running, disabled, failed, or starting +type ExtensionStatus string + +const ( + ExtensionStatusDisabled ExtensionStatus = "disabled" + ExtensionStatusFailed ExtensionStatus = "failed" + ExtensionStatusRunning ExtensionStatus = "running" + ExtensionStatusStarting ExtensionStatus = "starting" +) + +type FilterMappingString string + +const ( + FilterMappingStringHiddenCharacters FilterMappingString = "hidden_characters" + FilterMappingStringMarkdown FilterMappingString = "markdown" + FilterMappingStringNone FilterMappingString = "none" +) + +// Where this source lives — used for UI grouping +type InstructionsSourcesLocation string + +const ( + InstructionsSourcesLocationUser InstructionsSourcesLocation = "user" + InstructionsSourcesLocationRepository InstructionsSourcesLocation = "repository" + InstructionsSourcesLocationWorkingDirectory InstructionsSourcesLocation = "working-directory" +) + +// Category of instruction source — used for merge logic +type InstructionsSourcesType string + +const ( + InstructionsSourcesTypeChildInstructions InstructionsSourcesType = "child-instructions" + InstructionsSourcesTypeHome InstructionsSourcesType = "home" + InstructionsSourcesTypeModel InstructionsSourcesType = "model" + InstructionsSourcesTypeNestedAgents InstructionsSourcesType = "nested-agents" + InstructionsSourcesTypeRepo InstructionsSourcesType = "repo" + InstructionsSourcesTypeVscode InstructionsSourcesType = "vscode" +) + +// Log severity level. Determines how the message is displayed in the timeline. Defaults to +// "info". +type SessionLogLevel string + +const ( + SessionLogLevelError SessionLogLevel = "error" + SessionLogLevelInfo SessionLogLevel = "info" + SessionLogLevelWarning SessionLogLevel = "warning" +) + +// Remote transport type. Defaults to "http" when omitted. +type MCPServerConfigType string + +const ( + MCPServerConfigTypeHTTP MCPServerConfigType = "http" + MCPServerConfigTypeLocal MCPServerConfigType = "local" + MCPServerConfigTypeSSE MCPServerConfigType = "sse" + MCPServerConfigTypeStdio MCPServerConfigType = "stdio" +) + // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured type MCPServerStatus string @@ -1381,107 +1515,120 @@ const ( MCPServerStatusPending MCPServerStatus = "pending" ) -type UIElicitationStringEnumFieldType string +// Remote transport type. Defaults to "http" when omitted. +type MCPServerConfigHTTPType string const ( - UIElicitationStringEnumFieldTypeString UIElicitationStringEnumFieldType = "string" + MCPServerConfigHTTPTypeHTTP MCPServerConfigHTTPType = "http" + MCPServerConfigHTTPTypeSSE MCPServerConfigHTTPType = "sse" ) -type UIElicitationArrayEnumFieldType string +type MCPServerConfigLocalType string const ( - UIElicitationArrayEnumFieldTypeArray UIElicitationArrayEnumFieldType = "array" + MCPServerConfigLocalTypeLocal MCPServerConfigLocalType = "local" + MCPServerConfigLocalTypeStdio MCPServerConfigLocalType = "stdio" ) -// The user's response: accept (submitted), decline (rejected), or cancel (dismissed) -type UIElicitationResponseAction string +// The agent mode. Valid values: "interactive", "plan", "autopilot". +type SessionMode string const ( - UIElicitationResponseActionAccept UIElicitationResponseAction = "accept" - UIElicitationResponseActionCancel UIElicitationResponseAction = "cancel" - UIElicitationResponseActionDecline UIElicitationResponseAction = "decline" + SessionModeAutopilot SessionMode = "autopilot" + SessionModeInteractive SessionMode = "interactive" + SessionModePlan SessionMode = "plan" ) -type Kind string +type PermissionDecisionKind string const ( - KindApproved Kind = "approved" - KindDeniedByContentExclusionPolicy Kind = "denied-by-content-exclusion-policy" - KindDeniedByPermissionRequestHook Kind = "denied-by-permission-request-hook" - KindDeniedByRules Kind = "denied-by-rules" - KindDeniedInteractivelyByUser Kind = "denied-interactively-by-user" - KindDeniedNoApprovalRuleAndCouldNotRequestFromUser Kind = "denied-no-approval-rule-and-could-not-request-from-user" + PermissionDecisionKindApproved PermissionDecisionKind = "approved" + PermissionDecisionKindDeniedByContentExclusionPolicy PermissionDecisionKind = "denied-by-content-exclusion-policy" + PermissionDecisionKindDeniedByPermissionRequestHook PermissionDecisionKind = "denied-by-permission-request-hook" + PermissionDecisionKindDeniedByRules PermissionDecisionKind = "denied-by-rules" + PermissionDecisionKindDeniedInteractivelyByUser PermissionDecisionKind = "denied-interactively-by-user" + PermissionDecisionKindDeniedNoApprovalRuleAndCouldNotRequestFromUser PermissionDecisionKind = "denied-no-approval-rule-and-could-not-request-from-user" ) -// Path conventions used by this filesystem -type SessionFSSetProviderConventions string +type PermissionDecisionApprovedKind string const ( - SessionFSSetProviderConventionsPosix SessionFSSetProviderConventions = "posix" - SessionFSSetProviderConventionsWindows SessionFSSetProviderConventions = "windows" + PermissionDecisionApprovedKindApproved PermissionDecisionApprovedKind = "approved" ) -// The agent mode. Valid values: "interactive", "plan", "autopilot". -type SessionMode string +type PermissionDecisionDeniedByContentExclusionPolicyKind string const ( - SessionModeAutopilot SessionMode = "autopilot" - SessionModeInteractive SessionMode = "interactive" - SessionModePlan SessionMode = "plan" + PermissionDecisionDeniedByContentExclusionPolicyKindDeniedByContentExclusionPolicy PermissionDecisionDeniedByContentExclusionPolicyKind = "denied-by-content-exclusion-policy" ) -type HostType string +type PermissionDecisionDeniedByPermissionRequestHookKind string const ( - HostTypeAdo HostType = "ado" - HostTypeGithub HostType = "github" + PermissionDecisionDeniedByPermissionRequestHookKindDeniedByPermissionRequestHook PermissionDecisionDeniedByPermissionRequestHookKind = "denied-by-permission-request-hook" ) -type SessionSyncLevel string +type PermissionDecisionDeniedByRulesKind string const ( - SessionSyncLevelRepoAndUser SessionSyncLevel = "repo_and_user" - SessionSyncLevelLocal SessionSyncLevel = "local" - SessionSyncLevelUser SessionSyncLevel = "user" + PermissionDecisionDeniedByRulesKindDeniedByRules PermissionDecisionDeniedByRulesKind = "denied-by-rules" ) -// Where this source lives — used for UI grouping -type InstructionsSourcesLocation string +type PermissionDecisionDeniedInteractivelyByUserKind string const ( - InstructionsSourcesLocationUser InstructionsSourcesLocation = "user" - InstructionsSourcesLocationRepository InstructionsSourcesLocation = "repository" - InstructionsSourcesLocationWorkingDirectory InstructionsSourcesLocation = "working-directory" + PermissionDecisionDeniedInteractivelyByUserKindDeniedInteractivelyByUser PermissionDecisionDeniedInteractivelyByUserKind = "denied-interactively-by-user" ) -// Category of instruction source — used for merge logic -type InstructionsSourcesType string +type PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind string const ( - InstructionsSourcesTypeChildInstructions InstructionsSourcesType = "child-instructions" - InstructionsSourcesTypeHome InstructionsSourcesType = "home" - InstructionsSourcesTypeModel InstructionsSourcesType = "model" - InstructionsSourcesTypeNestedAgents InstructionsSourcesType = "nested-agents" - InstructionsSourcesTypeRepo InstructionsSourcesType = "repo" - InstructionsSourcesTypeVscode InstructionsSourcesType = "vscode" + PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKindDeniedNoApprovalRuleAndCouldNotRequestFromUser PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind = "denied-no-approval-rule-and-could-not-request-from-user" ) -// Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) -type ExtensionSource string +// Error classification +type SessionFSErrorCode string const ( - ExtensionSourceUser ExtensionSource = "user" - ExtensionSourceProject ExtensionSource = "project" + SessionFSErrorCodeENOENT SessionFSErrorCode = "ENOENT" + SessionFSErrorCodeUNKNOWN SessionFSErrorCode = "UNKNOWN" ) -// Current status: running, disabled, failed, or starting -type ExtensionStatus string +// Entry type +type SessionFSReaddirWithTypesEntryType string const ( - ExtensionStatusDisabled ExtensionStatus = "disabled" - ExtensionStatusFailed ExtensionStatus = "failed" - ExtensionStatusRunning ExtensionStatus = "running" - ExtensionStatusStarting ExtensionStatus = "starting" + SessionFSReaddirWithTypesEntryTypeDirectory SessionFSReaddirWithTypesEntryType = "directory" + SessionFSReaddirWithTypesEntryTypeFile SessionFSReaddirWithTypesEntryType = "file" +) + +// Path conventions used by this filesystem +type SessionFSSetProviderConventions string + +const ( + SessionFSSetProviderConventionsPosix SessionFSSetProviderConventions = "posix" + SessionFSSetProviderConventionsWindows SessionFSSetProviderConventions = "windows" +) + +// Signal to send (default: SIGTERM) +type ShellKillSignal string + +const ( + ShellKillSignalSIGINT ShellKillSignal = "SIGINT" + ShellKillSignalSIGKILL ShellKillSignal = "SIGKILL" + ShellKillSignalSIGTERM ShellKillSignal = "SIGTERM" +) + +type UIElicitationArrayAnyOfFieldType string + +const ( + UIElicitationArrayAnyOfFieldTypeArray UIElicitationArrayAnyOfFieldType = "array" +) + +type UIElicitationArrayEnumFieldItemsType string + +const ( + UIElicitationArrayEnumFieldItemsTypeString UIElicitationArrayEnumFieldItemsType = "string" ) type UIElicitationSchemaPropertyStringFormat string @@ -1493,47 +1640,57 @@ const ( UIElicitationSchemaPropertyStringFormatURI UIElicitationSchemaPropertyStringFormat = "uri" ) -type UIElicitationSchemaPropertyNumberType string +type UIElicitationSchemaPropertyType string const ( - UIElicitationSchemaPropertyNumberTypeBoolean UIElicitationSchemaPropertyNumberType = "boolean" - UIElicitationSchemaPropertyNumberTypeInteger UIElicitationSchemaPropertyNumberType = "integer" - UIElicitationSchemaPropertyNumberTypeNumber UIElicitationSchemaPropertyNumberType = "number" - UIElicitationSchemaPropertyNumberTypeArray UIElicitationSchemaPropertyNumberType = "array" - UIElicitationSchemaPropertyNumberTypeString UIElicitationSchemaPropertyNumberType = "string" + UIElicitationSchemaPropertyTypeInteger UIElicitationSchemaPropertyType = "integer" + UIElicitationSchemaPropertyTypeNumber UIElicitationSchemaPropertyType = "number" + UIElicitationSchemaPropertyTypeArray UIElicitationSchemaPropertyType = "array" + UIElicitationSchemaPropertyTypeBoolean UIElicitationSchemaPropertyType = "boolean" + UIElicitationSchemaPropertyTypeString UIElicitationSchemaPropertyType = "string" ) -type RequestedSchemaType string +type UIElicitationSchemaType string const ( - RequestedSchemaTypeObject RequestedSchemaType = "object" + UIElicitationSchemaTypeObject UIElicitationSchemaType = "object" ) -// Log severity level. Determines how the message is displayed in the timeline. Defaults to -// "info". -type SessionLogLevel string +// The user's response: accept (submitted), decline (rejected), or cancel (dismissed) +type UIElicitationResponseAction string const ( - SessionLogLevelError SessionLogLevel = "error" - SessionLogLevelInfo SessionLogLevel = "info" - SessionLogLevelWarning SessionLogLevel = "warning" + UIElicitationResponseActionAccept UIElicitationResponseAction = "accept" + UIElicitationResponseActionCancel UIElicitationResponseAction = "cancel" + UIElicitationResponseActionDecline UIElicitationResponseAction = "decline" ) -// Signal to send (default: SIGTERM) -type ShellKillSignal string +type UIElicitationSchemaPropertyBooleanType string const ( - ShellKillSignalSIGINT ShellKillSignal = "SIGINT" - ShellKillSignalSIGKILL ShellKillSignal = "SIGKILL" - ShellKillSignalSIGTERM ShellKillSignal = "SIGTERM" + UIElicitationSchemaPropertyBooleanTypeBoolean UIElicitationSchemaPropertyBooleanType = "boolean" ) -// Entry type -type SessionFSReaddirWithTypesEntryType string +type UIElicitationSchemaPropertyNumberTypeEnum string const ( - SessionFSReaddirWithTypesEntryTypeDirectory SessionFSReaddirWithTypesEntryType = "directory" - SessionFSReaddirWithTypesEntryTypeFile SessionFSReaddirWithTypesEntryType = "file" + UIElicitationSchemaPropertyNumberTypeEnumInteger UIElicitationSchemaPropertyNumberTypeEnum = "integer" + UIElicitationSchemaPropertyNumberTypeEnumNumber UIElicitationSchemaPropertyNumberTypeEnum = "number" +) + +type HostType string + +const ( + HostTypeAdo HostType = "ado" + HostTypeGithub HostType = "github" +) + +type SessionSyncLevel string + +const ( + SessionSyncLevelRepoAndUser SessionSyncLevel = "repo_and_user" + SessionSyncLevelLocal SessionSyncLevel = "local" + SessionSyncLevelUser SessionSyncLevel = "user" ) type FilterMapping struct { @@ -1541,6 +1698,12 @@ type FilterMapping struct { EnumMap map[string]FilterMappingString } +// Tool call result (string or expanded result object) +type ToolsHandlePendingToolCall struct { + String *string + ToolCallResult *ToolCallResult +} + type UIElicitationFieldValue struct { Bool *bool Double *float64 @@ -1548,12 +1711,6 @@ type UIElicitationFieldValue struct { StringArray []string } -// Tool call result (string or expanded result object) -type ToolsHandlePendingToolCall struct { - String *string - ToolCallResult *ToolCallResult -} - type serverApi struct { client *jsonrpc2.Client } @@ -2550,15 +2707,15 @@ func NewSessionRpc(client *jsonrpc2.Client, sessionID string) *SessionRpc { type SessionFsHandler interface { ReadFile(request *SessionFSReadFileRequest) (*SessionFSReadFileResult, error) - WriteFile(request *SessionFSWriteFileRequest) (*SessionFSWriteFileResult, error) - AppendFile(request *SessionFSAppendFileRequest) (*SessionFSAppendFileResult, error) + WriteFile(request *SessionFSWriteFileRequest) (*SessionFSError, error) + AppendFile(request *SessionFSAppendFileRequest) (*SessionFSError, error) Exists(request *SessionFSExistsRequest) (*SessionFSExistsResult, error) Stat(request *SessionFSStatRequest) (*SessionFSStatResult, error) - Mkdir(request *SessionFSMkdirRequest) (*SessionFSMkdirResult, error) + Mkdir(request *SessionFSMkdirRequest) (*SessionFSError, error) Readdir(request *SessionFSReaddirRequest) (*SessionFSReaddirResult, error) ReaddirWithTypes(request *SessionFSReaddirWithTypesRequest) (*SessionFSReaddirWithTypesResult, error) - Rm(request *SessionFSRmRequest) (*SessionFSRmResult, error) - Rename(request *SessionFSRenameRequest) (*SessionFSRenameResult, error) + Rm(request *SessionFSRmRequest) (*SessionFSError, error) + Rename(request *SessionFSRenameRequest) (*SessionFSError, error) } // ClientSessionApiHandlers provides all client session API handler groups for a session. diff --git a/go/session.go b/go/session.go index bf42bf03a..99256856d 100644 --- a/go/session.go +++ b/go/session.go @@ -704,10 +704,10 @@ func (ui *SessionUI) Confirm(ctx context.Context, message string) (bool, error) rpcResult, err := ui.session.RPC.UI.Elicitation(ctx, &rpc.UIElicitationRequest{ Message: message, RequestedSchema: rpc.UIElicitationSchema{ - Type: rpc.RequestedSchemaTypeObject, + Type: rpc.UIElicitationSchemaTypeObject, Properties: map[string]rpc.UIElicitationSchemaProperty{ "confirmed": { - Type: rpc.UIElicitationSchemaPropertyNumberTypeBoolean, + Type: rpc.UIElicitationSchemaPropertyTypeBoolean, Default: defaultTrue, }, }, @@ -734,10 +734,10 @@ func (ui *SessionUI) Select(ctx context.Context, message string, options []strin rpcResult, err := ui.session.RPC.UI.Elicitation(ctx, &rpc.UIElicitationRequest{ Message: message, RequestedSchema: rpc.UIElicitationSchema{ - Type: rpc.RequestedSchemaTypeObject, + Type: rpc.UIElicitationSchemaTypeObject, Properties: map[string]rpc.UIElicitationSchemaProperty{ "selection": { - Type: rpc.UIElicitationSchemaPropertyNumberTypeString, + Type: rpc.UIElicitationSchemaPropertyTypeString, Enum: options, }, }, @@ -761,7 +761,7 @@ func (ui *SessionUI) Input(ctx context.Context, message string, opts *InputOptio if err := ui.session.assertElicitation(); err != nil { return "", false, err } - prop := rpc.UIElicitationSchemaProperty{Type: rpc.UIElicitationSchemaPropertyNumberTypeString} + prop := rpc.UIElicitationSchemaProperty{Type: rpc.UIElicitationSchemaPropertyTypeString} if opts != nil { if opts.Title != "" { prop.Title = &opts.Title @@ -788,7 +788,7 @@ func (ui *SessionUI) Input(ctx context.Context, message string, opts *InputOptio rpcResult, err := ui.session.RPC.UI.Elicitation(ctx, &rpc.UIElicitationRequest{ Message: message, RequestedSchema: rpc.UIElicitationSchema{ - Type: rpc.RequestedSchemaTypeObject, + Type: rpc.UIElicitationSchemaTypeObject, Properties: map[string]rpc.UIElicitationSchemaProperty{ "value": prop, }, @@ -1029,7 +1029,7 @@ func (s *Session) executePermissionAndRespond(requestID string, permissionReques s.RPC.Permissions.HandlePendingPermissionRequest(context.Background(), &rpc.PermissionDecisionRequest{ RequestID: requestID, Result: rpc.PermissionDecision{ - Kind: rpc.KindDeniedNoApprovalRuleAndCouldNotRequestFromUser, + Kind: rpc.PermissionDecisionKindDeniedNoApprovalRuleAndCouldNotRequestFromUser, }, }) } @@ -1044,7 +1044,7 @@ func (s *Session) executePermissionAndRespond(requestID string, permissionReques s.RPC.Permissions.HandlePendingPermissionRequest(context.Background(), &rpc.PermissionDecisionRequest{ RequestID: requestID, Result: rpc.PermissionDecision{ - Kind: rpc.KindDeniedNoApprovalRuleAndCouldNotRequestFromUser, + Kind: rpc.PermissionDecisionKindDeniedNoApprovalRuleAndCouldNotRequestFromUser, }, }) return @@ -1056,7 +1056,7 @@ func (s *Session) executePermissionAndRespond(requestID string, permissionReques s.RPC.Permissions.HandlePendingPermissionRequest(context.Background(), &rpc.PermissionDecisionRequest{ RequestID: requestID, Result: rpc.PermissionDecision{ - Kind: rpc.Kind(result.Kind), + Kind: rpc.PermissionDecisionKind(result.Kind), Rules: result.Rules, Feedback: nil, }, @@ -1213,7 +1213,7 @@ func (s *Session) SetModel(ctx context.Context, model string, opts *SetModelOpti params := &rpc.ModelSwitchToRequest{ModelID: model} if opts != nil { params.ReasoningEffort = opts.ReasoningEffort - params.ModelCapabilities = convertModelCapabilitiesToClass(opts.ModelCapabilities) + params.ModelCapabilities = opts.ModelCapabilities } _, err := s.RPC.Model.SwitchTo(ctx, params) if err != nil { @@ -1223,34 +1223,6 @@ func (s *Session) SetModel(ctx context.Context, model string, opts *SetModelOpti return nil } -// convertModelCapabilitiesToClass converts from ModelCapabilitiesOverride -// (used in the public API) to ModelCapabilitiesClass (used internally by -// the ModelSwitchToRequest RPC). The two types are structurally identical -// but have different Go types due to code generation. -func convertModelCapabilitiesToClass(src *rpc.ModelCapabilitiesOverride) *rpc.ModelCapabilitiesClass { - if src == nil { - return nil - } - dst := &rpc.ModelCapabilitiesClass{ - Supports: src.Supports, - } - if src.Limits != nil { - dst.Limits = &rpc.ModelCapabilitiesLimitsClass{ - MaxContextWindowTokens: src.Limits.MaxContextWindowTokens, - MaxOutputTokens: src.Limits.MaxOutputTokens, - MaxPromptTokens: src.Limits.MaxPromptTokens, - } - if src.Limits.Vision != nil { - dst.Limits.Vision = &rpc.FluffyModelCapabilitiesOverrideLimitsVision{ - MaxPromptImageSize: src.Limits.Vision.MaxPromptImageSize, - MaxPromptImages: src.Limits.Vision.MaxPromptImages, - SupportedMediaTypes: src.Limits.Vision.SupportedMediaTypes, - } - } - } - return dst -} - type LogOptions struct { // Level sets the log severity. Valid values are [rpc.SessionLogLevelInfo] (default), // [rpc.SessionLogLevelWarning], and [rpc.SessionLogLevelError]. diff --git a/go/session_fs_provider.go b/go/session_fs_provider.go new file mode 100644 index 000000000..eb7107581 --- /dev/null +++ b/go/session_fs_provider.go @@ -0,0 +1,174 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package copilot + +import ( + "errors" + "os" + "time" + + "github.com/github/copilot-sdk/go/rpc" +) + +// SessionFsProvider is the interface that SDK users implement to provide +// a session filesystem. Methods use idiomatic Go error handling: return an +// error for failures (the adapter maps os.ErrNotExist → ENOENT automatically). +type SessionFsProvider interface { + // ReadFile reads the full content of a file. Return os.ErrNotExist (or wrap it) + // if the file does not exist. + ReadFile(path string) (string, error) + // WriteFile writes content to a file, creating it and parent directories if needed. + // mode is an optional POSIX-style permission mode. Pass nil to use the OS default. + WriteFile(path string, content string, mode *int) error + // AppendFile appends content to a file, creating it and parent directories if needed. + // mode is an optional POSIX-style permission mode. Pass nil to use the OS default. + AppendFile(path string, content string, mode *int) error + // Exists checks whether the given path exists. + Exists(path string) (bool, error) + // Stat returns metadata about a file or directory. + // Return os.ErrNotExist if the path does not exist. + Stat(path string) (*SessionFsFileInfo, error) + // Mkdir creates a directory. If recursive is true, create parent directories as needed. + // mode is an optional POSIX-style permission mode (e.g., 0o755). Pass nil to use the OS default. + Mkdir(path string, recursive bool, mode *int) error + // Readdir lists the names of entries in a directory. + // Return os.ErrNotExist if the directory does not exist. + Readdir(path string) ([]string, error) + // ReaddirWithTypes lists entries with type information. + // Return os.ErrNotExist if the directory does not exist. + ReaddirWithTypes(path string) ([]rpc.SessionFSReaddirWithTypesEntry, error) + // Rm removes a file or directory. If recursive is true, remove contents too. + // If force is true, do not return an error when the path does not exist. + Rm(path string, recursive bool, force bool) error + // Rename moves/renames a file or directory. + Rename(src string, dest string) error +} + +// SessionFsFileInfo holds file metadata returned by SessionFsProvider.Stat. +type SessionFsFileInfo struct { + IsFile bool + IsDirectory bool + Size int64 + Mtime time.Time + Birthtime time.Time +} + +// sessionFsAdapter wraps a SessionFsProvider to implement rpc.SessionFsHandler, +// converting idiomatic Go errors into SessionFSError results. +type sessionFsAdapter struct { + provider SessionFsProvider +} + +func newSessionFsAdapter(provider SessionFsProvider) rpc.SessionFsHandler { + return &sessionFsAdapter{provider: provider} +} + +func (a *sessionFsAdapter) ReadFile(request *rpc.SessionFSReadFileRequest) (*rpc.SessionFSReadFileResult, error) { + content, err := a.provider.ReadFile(request.Path) + if err != nil { + return &rpc.SessionFSReadFileResult{Error: toSessionFsError(err)}, nil + } + return &rpc.SessionFSReadFileResult{Content: content}, nil +} + +func (a *sessionFsAdapter) WriteFile(request *rpc.SessionFSWriteFileRequest) (*rpc.SessionFSError, error) { + var mode *int + if request.Mode != nil { + m := int(*request.Mode) + mode = &m + } + if err := a.provider.WriteFile(request.Path, request.Content, mode); err != nil { + return toSessionFsError(err), nil + } + return nil, nil +} + +func (a *sessionFsAdapter) AppendFile(request *rpc.SessionFSAppendFileRequest) (*rpc.SessionFSError, error) { + var mode *int + if request.Mode != nil { + m := int(*request.Mode) + mode = &m + } + if err := a.provider.AppendFile(request.Path, request.Content, mode); err != nil { + return toSessionFsError(err), nil + } + return nil, nil +} + +func (a *sessionFsAdapter) Exists(request *rpc.SessionFSExistsRequest) (*rpc.SessionFSExistsResult, error) { + exists, err := a.provider.Exists(request.Path) + if err != nil { + return &rpc.SessionFSExistsResult{Exists: false}, nil + } + return &rpc.SessionFSExistsResult{Exists: exists}, nil +} + +func (a *sessionFsAdapter) Stat(request *rpc.SessionFSStatRequest) (*rpc.SessionFSStatResult, error) { + info, err := a.provider.Stat(request.Path) + if err != nil { + return &rpc.SessionFSStatResult{Error: toSessionFsError(err)}, nil + } + return &rpc.SessionFSStatResult{ + IsFile: info.IsFile, + IsDirectory: info.IsDirectory, + Size: info.Size, + Mtime: info.Mtime, + Birthtime: info.Birthtime, + }, nil +} + +func (a *sessionFsAdapter) Mkdir(request *rpc.SessionFSMkdirRequest) (*rpc.SessionFSError, error) { + recursive := request.Recursive != nil && *request.Recursive + var mode *int + if request.Mode != nil { + m := int(*request.Mode) + mode = &m + } + if err := a.provider.Mkdir(request.Path, recursive, mode); err != nil { + return toSessionFsError(err), nil + } + return nil, nil +} + +func (a *sessionFsAdapter) Readdir(request *rpc.SessionFSReaddirRequest) (*rpc.SessionFSReaddirResult, error) { + entries, err := a.provider.Readdir(request.Path) + if err != nil { + return &rpc.SessionFSReaddirResult{Error: toSessionFsError(err)}, nil + } + return &rpc.SessionFSReaddirResult{Entries: entries}, nil +} + +func (a *sessionFsAdapter) ReaddirWithTypes(request *rpc.SessionFSReaddirWithTypesRequest) (*rpc.SessionFSReaddirWithTypesResult, error) { + entries, err := a.provider.ReaddirWithTypes(request.Path) + if err != nil { + return &rpc.SessionFSReaddirWithTypesResult{Error: toSessionFsError(err)}, nil + } + return &rpc.SessionFSReaddirWithTypesResult{Entries: entries}, nil +} + +func (a *sessionFsAdapter) Rm(request *rpc.SessionFSRmRequest) (*rpc.SessionFSError, error) { + recursive := request.Recursive != nil && *request.Recursive + force := request.Force != nil && *request.Force + if err := a.provider.Rm(request.Path, recursive, force); err != nil { + return toSessionFsError(err), nil + } + return nil, nil +} + +func (a *sessionFsAdapter) Rename(request *rpc.SessionFSRenameRequest) (*rpc.SessionFSError, error) { + if err := a.provider.Rename(request.Src, request.Dest); err != nil { + return toSessionFsError(err), nil + } + return nil, nil +} + +func toSessionFsError(err error) *rpc.SessionFSError { + code := rpc.SessionFSErrorCodeUNKNOWN + if errors.Is(err, os.ErrNotExist) { + code = rpc.SessionFSErrorCodeENOENT + } + msg := err.Error() + return &rpc.SessionFSError{Code: code, Message: &msg} +} diff --git a/go/types.go b/go/types.go index aa4fafc94..e3e21467e 100644 --- a/go/types.go +++ b/go/types.go @@ -561,7 +561,7 @@ type SessionConfig struct { OnEvent SessionEventHandler // CreateSessionFsHandler supplies a handler for session filesystem operations. // This takes effect only when ClientOptions.SessionFs is configured. - CreateSessionFsHandler func(session *Session) rpc.SessionFsHandler + CreateSessionFsHandler func(session *Session) SessionFsProvider // Commands registers slash-commands for this session. Each command appears as // /name in the CLI TUI for the user to invoke. The Handler is called when the // command is executed. @@ -775,7 +775,7 @@ type ResumeSessionConfig struct { OnEvent SessionEventHandler // CreateSessionFsHandler supplies a handler for session filesystem operations. // This takes effect only when ClientOptions.SessionFs is configured. - CreateSessionFsHandler func(session *Session) rpc.SessionFsHandler + CreateSessionFsHandler func(session *Session) SessionFsProvider // Commands registers slash-commands for this session. See SessionConfig.Commands. Commands []CommandDefinition // OnElicitationRequest is a handler for elicitation requests from the server. @@ -862,7 +862,7 @@ type ( ModelCapabilitiesOverride = rpc.ModelCapabilitiesOverride ModelCapabilitiesOverrideSupports = rpc.ModelCapabilitiesOverrideSupports ModelCapabilitiesOverrideLimits = rpc.ModelCapabilitiesOverrideLimits - ModelCapabilitiesOverrideLimitsVision = rpc.PurpleModelCapabilitiesOverrideLimitsVision + ModelCapabilitiesOverrideLimitsVision = rpc.ModelCapabilitiesOverrideLimitsVision ) // ModelPolicy contains model policy state diff --git a/nodejs/docs/agent-author.md b/nodejs/docs/agent-author.md index 8b3d93593..787bb6a32 100644 --- a/nodejs/docs/agent-author.md +++ b/nodejs/docs/agent-author.md @@ -18,6 +18,7 @@ For user-scoped extensions (persist across all repos), add `location: "user"`. ### Step 2: Edit the extension file Modify the generated `extension.mjs` using `edit` or `create` tools. The file must: + - Be named `extension.mjs` (only `.mjs` is supported) - Use ES module syntax (`import`/`export`) - Call `joinSession({ ... })` @@ -48,6 +49,7 @@ Check that the extension loaded successfully and isn't marked as "failed". ``` Discovery rules: + - The CLI scans `.github/extensions/` relative to the git root - It also scans the user's copilot config extensions directory - Only immediate subdirectories are checked (not recursive) @@ -62,8 +64,8 @@ Discovery rules: import { joinSession } from "@github/copilot-sdk/extension"; await joinSession({ - tools: [], // Optional — custom tools - hooks: {}, // Optional — lifecycle hooks + tools: [], // Optional — custom tools + hooks: {}, // Optional — lifecycle hooks }); ``` @@ -74,9 +76,10 @@ await joinSession({ ```js tools: [ { - name: "tool_name", // Required. Must be globally unique across all extensions. + name: "tool_name", // Required. Must be globally unique across all extensions. description: "What it does", // Required. Shown to the agent in tool descriptions. - parameters: { // Optional. JSON Schema for the arguments. + parameters: { + // Optional. JSON Schema for the arguments. type: "object", properties: { arg1: { type: "string", description: "..." }, @@ -96,10 +99,11 @@ tools: [ return `Result: ${args.arg1}`; }, }, -] +]; ``` **Constraints:** + - Tool names must be unique across ALL loaded extensions. Collisions cause the second extension to fail to load. - Handler must return a string or `{ textResultForLlm: string, resultType?: string }`. - Handler receives `(args, invocation)` — the second argument has `sessionId`, `toolCallId`, `toolName`. @@ -195,6 +199,7 @@ After `joinSession()`, the returned `session` provides: ### session.send(options) Send a message programmatically: + ```js await session.send({ prompt: "Analyze the test results." }); await session.send({ @@ -206,6 +211,7 @@ await session.send({ ### session.sendAndWait(options, timeout?) Send and block until the agent finishes (resolves on `session.idle`): + ```js const response = await session.sendAndWait({ prompt: "What is 2+2?" }); // response?.data.content contains the agent's reply @@ -214,6 +220,7 @@ const response = await session.sendAndWait({ prompt: "What is 2+2?" }); ### session.log(message, options?) Log to the CLI timeline: + ```js await session.log("Extension ready"); await session.log("Rate limit approaching", { level: "warning" }); @@ -224,6 +231,7 @@ await session.log("Processing...", { ephemeral: true }); // transient, not persi ### session.on(eventType, handler) Subscribe to session events. Returns an unsubscribe function. + ```js const unsub = session.on("tool.execution_complete", (event) => { // event.data.toolName, event.data.success, event.data.result @@ -232,16 +240,16 @@ const unsub = session.on("tool.execution_complete", (event) => { ### Key Event Types -| Event | Key Data Fields | -|-------|----------------| -| `assistant.message` | `content`, `messageId` | -| `tool.execution_start` | `toolCallId`, `toolName`, `arguments` | +| Event | Key Data Fields | +| ------------------------- | ------------------------------------------------------ | +| `assistant.message` | `content`, `messageId` | +| `tool.execution_start` | `toolCallId`, `toolName`, `arguments` | | `tool.execution_complete` | `toolCallId`, `toolName`, `success`, `result`, `error` | -| `user.message` | `content`, `attachments`, `source` | -| `session.idle` | `backgroundTasks` | -| `session.error` | `errorType`, `message`, `stack` | -| `permission.requested` | `requestId`, `permissionRequest.kind` | -| `session.shutdown` | `shutdownType`, `totalPremiumRequests` | +| `user.message` | `content`, `attachments`, `source` | +| `session.idle` | `backgroundTasks` | +| `session.error` | `errorType`, `message`, `stack` | +| `permission.requested` | `requestId`, `permissionRequest.kind` | +| `session.shutdown` | `shutdownType`, `totalPremiumRequests` | ### session.workspacePath diff --git a/nodejs/docs/examples.md b/nodejs/docs/examples.md index 1461a2f39..a3483d8d4 100644 --- a/nodejs/docs/examples.md +++ b/nodejs/docs/examples.md @@ -10,14 +10,19 @@ Every extension starts with the same boilerplate: import { joinSession } from "@github/copilot-sdk/extension"; const session = await joinSession({ - hooks: { /* ... */ }, - tools: [ /* ... */ ], + hooks: { + /* ... */ + }, + tools: [ + /* ... */ + ], }); ``` `joinSession` returns a `CopilotSession` object you can use to send messages and subscribe to events. > **Platform notes (Windows vs macOS/Linux):** +> > - Use `process.platform === "win32"` to detect Windows at runtime. > - Clipboard: `pbcopy` on macOS, `clip` on Windows. > - Use `exec()` instead of `execFile()` for `.cmd` scripts like `code`, `npx`, `npm` on Windows. @@ -71,7 +76,7 @@ tools: [ return `Processed: ${args.input}`; }, }, -] +]; ``` ### Tool that invokes an external shell command @@ -136,7 +141,7 @@ handler: async (args, invocation) => { // invocation.toolCallId — unique ID for this tool call // invocation.toolName — name of the tool being called return "done"; -} +}; ``` --- @@ -147,14 +152,14 @@ Hooks intercept and modify behavior at key lifecycle points. Register them in th ### Available Hooks -| Hook | Fires When | Can Modify | -|------|-----------|------------| -| `onUserPromptSubmitted` | User sends a message | The prompt text, add context | -| `onPreToolUse` | Before a tool executes | Tool args, permission decision, add context | -| `onPostToolUse` | After a tool executes | Tool result, add context | -| `onSessionStart` | Session starts or resumes | Add context, modify config | -| `onSessionEnd` | Session ends | Cleanup actions, summary | -| `onErrorOccurred` | An error occurs | Error handling strategy (retry/skip/abort) | +| Hook | Fires When | Can Modify | +| ----------------------- | ------------------------- | ------------------------------------------- | +| `onUserPromptSubmitted` | User sends a message | The prompt text, add context | +| `onPreToolUse` | Before a tool executes | Tool args, permission decision, add context | +| `onPostToolUse` | After a tool executes | Tool result, add context | +| `onSessionStart` | Session starts or resumes | Add context, modify config | +| `onSessionEnd` | Session ends | Cleanup actions, summary | +| `onErrorOccurred` | An error occurs | Error handling strategy (retry/skip/abort) | All hook inputs include `timestamp` (unix ms) and `cwd` (working directory). @@ -400,18 +405,18 @@ session.on("assistant.message", (event) => { ### Top 10 Most Useful Event Types -| Event Type | Description | Key Data Fields | -|-----------|-------------|-----------------| -| `assistant.message` | Agent's final response | `content`, `messageId`, `toolRequests` | -| `assistant.streaming_delta` | Token-by-token streaming (ephemeral) | `totalResponseSizeBytes` | -| `tool.execution_start` | A tool is about to run | `toolCallId`, `toolName`, `arguments` | -| `tool.execution_complete` | A tool finished running | `toolCallId`, `toolName`, `success`, `result`, `error` | -| `user.message` | User sent a message | `content`, `attachments`, `source` | -| `session.idle` | Session finished processing a turn | `backgroundTasks` | -| `session.error` | An error occurred | `errorType`, `message`, `stack` | -| `permission.requested` | Agent needs permission (shell, file write, etc.) | `requestId`, `permissionRequest.kind` | -| `session.shutdown` | Session is ending | `shutdownType`, `totalPremiumRequests`, `codeChanges` | -| `assistant.turn_start` | Agent begins a new thinking/response cycle | `turnId` | +| Event Type | Description | Key Data Fields | +| --------------------------- | ------------------------------------------------ | ------------------------------------------------------ | +| `assistant.message` | Agent's final response | `content`, `messageId`, `toolRequests` | +| `assistant.streaming_delta` | Token-by-token streaming (ephemeral) | `totalResponseSizeBytes` | +| `tool.execution_start` | A tool is about to run | `toolCallId`, `toolName`, `arguments` | +| `tool.execution_complete` | A tool finished running | `toolCallId`, `toolName`, `success`, `result`, `error` | +| `user.message` | User sent a message | `content`, `attachments`, `source` | +| `session.idle` | Session finished processing a turn | `backgroundTasks` | +| `session.error` | An error occurred | `errorType`, `message`, `stack` | +| `permission.requested` | Agent needs permission (shell, file write, etc.) | `requestId`, `permissionRequest.kind` | +| `session.shutdown` | Session is ending | `shutdownType`, `totalPremiumRequests`, `codeChanges` | +| `assistant.turn_start` | Agent begins a new thinking/response cycle | `turnId` | ### Example: Detecting when the plan file is created or edited @@ -435,8 +440,10 @@ if (workspace) { // Track agent edits to suppress false triggers session.on("tool.execution_start", (event) => { - if ((event.data.toolName === "edit" || event.data.toolName === "create") - && String(event.data.arguments?.path || "").endsWith("plan.md")) { + if ( + (event.data.toolName === "edit" || event.data.toolName === "create") && + String(event.data.arguments?.path || "").endsWith("plan.md") + ) { agentEdits.add(event.data.toolCallId); recentAgentPaths.add(planPath); } @@ -539,9 +546,7 @@ const response = await session.sendAndWait({ prompt: "What is 2 + 2?" }); ```js await session.send({ prompt: "Review this file", - attachments: [ - { type: "file", path: "./src/index.ts" }, - ], + attachments: [{ type: "file", path: "./src/index.ts" }], }); ``` @@ -617,7 +622,7 @@ const session = await joinSession({ onPreToolUse: async (input) => { if (input.toolName === "bash") { const cmd = String(input.toolArgs?.command || ""); - if (/rm\\s+-rf\\s+\\//i.test(cmd) || /Remove-Item\\s+.*-Recurse/i.test(cmd)) { + if (/rm\\s+-rf\\s+\\/ / i.test(cmd) || /Remove-Item\\s+.*-Recurse/i.test(cmd)) { return { permissionDecision: "deny" }; } } @@ -665,4 +670,3 @@ session.on("tool.execution_complete", (event) => { // event.data.success, event.data.toolName, event.data.result }); ``` - diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 4725ac205..574bc86a9 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,3646 +1,3646 @@ { - "name": "@github/copilot-sdk", - "version": "0.1.8", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@github/copilot-sdk", - "version": "0.1.8", - "license": "MIT", - "dependencies": { - "@github/copilot": "^1.0.32", - "vscode-jsonrpc": "^8.2.1", - "zod": "^4.3.6" - }, - "devDependencies": { - "@platformatic/vfs": "^0.3.0", - "@types/node": "^25.2.0", - "@typescript-eslint/eslint-plugin": "^8.54.0", - "@typescript-eslint/parser": "^8.54.0", - "esbuild": "^0.27.2", - "eslint": "^9.0.0", - "glob": "^13.0.1", - "json-schema": "^0.4.0", - "json-schema-to-typescript": "^15.0.4", - "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", - "rimraf": "^6.1.2", - "semver": "^7.7.3", - "tsx": "^4.20.6", - "typescript": "^5.0.0", - "vitest": "^4.0.18" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.9.3", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", - "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@github/copilot": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.32.tgz", - "integrity": "sha512-ydEYAztJQa1sLQw+WPmnkkt3Sf/k2Smn/7szzYvt1feUOdNIak1gHpQhKcgPr2w252gjVLRWjOiynoeLVW0Fbw==", - "license": "SEE LICENSE IN LICENSE.md", - "bin": { - "copilot": "npm-loader.js" - }, - "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.32", - "@github/copilot-darwin-x64": "1.0.32", - "@github/copilot-linux-arm64": "1.0.32", - "@github/copilot-linux-x64": "1.0.32", - "@github/copilot-win32-arm64": "1.0.32", - "@github/copilot-win32-x64": "1.0.32" - } - }, - "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.32.tgz", - "integrity": "sha512-RtGHpnrbP1eVtpzitLqC0jkBlo63PJiByv6W/NTtLw4ZAllumb5kMk8JaTtydKl9DCOHA0wfXbG5/JkGXuQ81g==", - "cpu": [ - "arm64" - ], - "license": "SEE LICENSE IN LICENSE.md", - "optional": true, - "os": [ - "darwin" - ], - "bin": { - "copilot-darwin-arm64": "copilot" - } - }, - "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.32.tgz", - "integrity": "sha512-eyF6uy8gcZ4m/0UdM9UoykMDotZ8hZPJ1xIg0iHy4wrNtkYOaAspAoVpOkm50ODOQAHJ5PVV+9LuT6IoeL+wHQ==", - "cpu": [ - "x64" - ], - "license": "SEE LICENSE IN LICENSE.md", - "optional": true, - "os": [ - "darwin" - ], - "bin": { - "copilot-darwin-x64": "copilot" - } - }, - "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.32.tgz", - "integrity": "sha512-acRAu5ehFPnw3hQSIxcmi7wzv8PAYd+nqdxZXizOi++en3QWgez7VEXiKLe9Ukf50iiGReg19yvWV4iDOGC0HQ==", - "cpu": [ - "arm64" - ], - "license": "SEE LICENSE IN LICENSE.md", - "optional": true, - "os": [ - "linux" - ], - "bin": { - "copilot-linux-arm64": "copilot" - } - }, - "node_modules/@github/copilot-linux-x64": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.32.tgz", - "integrity": "sha512-lw86YDwkTKwmeVpfnPErDe9DhemrOHN+l92xOU9wQSH5/d+HguXwRb3e4cQjlxsGLS+/fWRGtwf+u2fbQ37avw==", - "cpu": [ - "x64" - ], - "license": "SEE LICENSE IN LICENSE.md", - "optional": true, - "os": [ - "linux" - ], - "bin": { - "copilot-linux-x64": "copilot" - } - }, - "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.32.tgz", - "integrity": "sha512-+eZpuzgBbLHMIzltH541wfbbMy0HEdG91ISzRae3qPCssf3Ad85sat6k7FWTRBSZBFrN7z4yMQm5gROqDJYGSA==", - "cpu": [ - "arm64" - ], - "license": "SEE LICENSE IN LICENSE.md", - "optional": true, - "os": [ - "win32" - ], - "bin": { - "copilot-win32-arm64": "copilot.exe" - } - }, - "node_modules/@github/copilot-win32-x64": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.32.tgz", - "integrity": "sha512-R6SW1dsEVmPMhrN/WRTetS4gVxcuYcxi2zfDPOfcjW3W0iD0Vwpt3MlqwBaU2UL36j+rnTnmiOA+g82FIBCYVg==", - "cpu": [ - "x64" - ], - "license": "SEE LICENSE IN LICENSE.md", - "optional": true, - "os": [ - "win32" - ], - "bin": { - "copilot-win32-x64": "copilot.exe" - } - }, - "node_modules/@glideapps/ts-necessities": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.2.3.tgz", - "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@platformatic/vfs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@platformatic/vfs/-/vfs-0.3.0.tgz", - "integrity": "sha512-BGXVOAz59HYPZCgI9v/MtiTF/ng8YAWtkooxVwOPR3TatNgGy0WZ/t15ScqytiZi5NdSRqWNRfuAbXKeAlKDdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 22" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.3.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", - "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.0.18", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.18", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browser-or-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-3.0.0.tgz", - "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/collection-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", - "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-fetch": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-base64": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", - "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, - "node_modules/json-schema-to-typescript": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz", - "integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^11.5.5", - "@types/json-schema": "^7.0.15", - "@types/lodash": "^4.17.7", - "is-glob": "^4.0.3", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "prettier": "^3.2.5", - "tinyglobby": "^0.2.9" - }, - "bin": { - "json2ts": "dist/src/cli.js" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimatch/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/quicktype-core": { - "version": "23.2.6", - "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-23.2.6.tgz", - "integrity": "sha512-asfeSv7BKBNVb9WiYhFRBvBZHcRutPRBwJMxW0pefluK4kkKu4lv0IvZBwFKvw2XygLcL1Rl90zxWDHYgkwCmA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@glideapps/ts-necessities": "2.2.3", - "browser-or-node": "^3.0.0", - "collection-utils": "^1.0.1", - "cross-fetch": "^4.0.0", - "is-url": "^1.2.4", - "js-base64": "^3.7.7", - "lodash": "^4.17.21", - "pako": "^1.0.6", - "pluralize": "^8.0.0", - "readable-stream": "4.5.2", - "unicode-properties": "^1.4.1", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^2.4.1" - } - }, - "node_modules/readable-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicode-properties": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/unicode-trie/node_modules/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "dev": true, - "license": "MIT" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urijs": { - "version": "1.19.11", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^3.10.0", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true + "name": "@github/copilot-sdk", + "version": "0.1.8", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@github/copilot-sdk", + "version": "0.1.8", + "license": "MIT", + "dependencies": { + "@github/copilot": "^1.0.35-0", + "vscode-jsonrpc": "^8.2.1", + "zod": "^4.3.6" + }, + "devDependencies": { + "@platformatic/vfs": "^0.3.0", + "@types/node": "^25.2.0", + "@typescript-eslint/eslint-plugin": "^8.54.0", + "@typescript-eslint/parser": "^8.54.0", + "esbuild": "^0.27.2", + "eslint": "^9.0.0", + "glob": "^13.0.1", + "json-schema": "^0.4.0", + "json-schema-to-typescript": "^15.0.4", + "prettier": "^3.8.1", + "quicktype-core": "^23.2.6", + "rimraf": "^6.1.2", + "semver": "^7.7.3", + "tsx": "^4.20.6", + "typescript": "^5.0.0", + "vitest": "^4.0.18" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", + "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@github/copilot": { + "version": "1.0.35-0", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.35-0.tgz", + "integrity": "sha512-daPkiDXeXwsoEHy4XvZywVX3Voyaubir27qm/3uyifxeruMGOcUT/XC8tkJhE6VfSy3nvtjV4xXrZ43Wr0x2cg==", + "license": "SEE LICENSE IN LICENSE.md", + "bin": { + "copilot": "npm-loader.js" + }, + "optionalDependencies": { + "@github/copilot-darwin-arm64": "1.0.35-0", + "@github/copilot-darwin-x64": "1.0.35-0", + "@github/copilot-linux-arm64": "1.0.35-0", + "@github/copilot-linux-x64": "1.0.35-0", + "@github/copilot-win32-arm64": "1.0.35-0", + "@github/copilot-win32-x64": "1.0.35-0" + } + }, + "node_modules/@github/copilot-darwin-arm64": { + "version": "1.0.35-0", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.35-0.tgz", + "integrity": "sha512-Uc3PIw60y/9fk1F2JlLqBl0VkParTiCIxlLWKFs8N6TJwFafKmLt7B5r4nqoFhsYZOov6ww4nIxxaMiVdFF0YA==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "copilot-darwin-arm64": "copilot" + } + }, + "node_modules/@github/copilot-darwin-x64": { + "version": "1.0.35-0", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.35-0.tgz", + "integrity": "sha512-5R5hkZ4Z2CnHVdXnKMNjkFi00mdBYF9H9kkzQjmaN8cG4JwZFf209lo1bEzpXWKHl136LXNwLVhHCYfi3FgzXQ==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "copilot-darwin-x64": "copilot" + } + }, + "node_modules/@github/copilot-linux-arm64": { + "version": "1.0.35-0", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.35-0.tgz", + "integrity": "sha512-I+kDV2xhvq2t6ux2/ZmWoRkReq8fNlYgW1GfWRmp4c+vQKvH+WsQ5P0WWSt8BmmQGK9hUrTcXg2nvVAPQJ2D8Q==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "copilot-linux-arm64": "copilot" + } + }, + "node_modules/@github/copilot-linux-x64": { + "version": "1.0.35-0", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.35-0.tgz", + "integrity": "sha512-mnG6lpzmWvkasdYgmvotb2PQKW/GaCAdZbuv34iOT84Iz3VyEamcUNurw+KCrxitCYRa68cnCQFbGMf8p6Q22A==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "copilot-linux-x64": "copilot" + } + }, + "node_modules/@github/copilot-win32-arm64": { + "version": "1.0.35-0", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.35-0.tgz", + "integrity": "sha512-suB5kxHQtD5Hu7NUqH3bUkNBg6e0rPLSf54jCN8UjyxJBfV2mL7BZeqr77Du3UzHHkRKxqITiZ4LBZH8q0bOEg==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-arm64": "copilot.exe" + } + }, + "node_modules/@github/copilot-win32-x64": { + "version": "1.0.35-0", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.35-0.tgz", + "integrity": "sha512-KKuxw+rKpfEn/575l+3aef72/MiGlH8D9CIX6+3+qPQqojt7YBDlEqgL3/aAk9JUrQbiqSUXXKD3mMEHdgNoWQ==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-x64": "copilot.exe" + } + }, + "node_modules/@glideapps/ts-necessities": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.2.3.tgz", + "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@platformatic/vfs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@platformatic/vfs/-/vfs-0.3.0.tgz", + "integrity": "sha512-BGXVOAz59HYPZCgI9v/MtiTF/ng8YAWtkooxVwOPR3TatNgGy0WZ/t15ScqytiZi5NdSRqWNRfuAbXKeAlKDdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 22" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browser-or-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-3.0.0.tgz", + "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-to-typescript": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz", + "integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^11.5.5", + "@types/json-schema": "^7.0.15", + "@types/lodash": "^4.17.7", + "is-glob": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "prettier": "^3.2.5", + "tinyglobby": "^0.2.9" + }, + "bin": { + "json2ts": "dist/src/cli.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimatch/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quicktype-core": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-23.2.6.tgz", + "integrity": "sha512-asfeSv7BKBNVb9WiYhFRBvBZHcRutPRBwJMxW0pefluK4kkKu4lv0IvZBwFKvw2XygLcL1Rl90zxWDHYgkwCmA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@glideapps/ts-necessities": "2.2.3", + "browser-or-node": "^3.0.0", + "collection-utils": "^1.0.1", + "cross-fetch": "^4.0.0", + "is-url": "^1.2.4", + "js-base64": "^3.7.7", + "lodash": "^4.17.21", + "pako": "^1.0.6", + "pluralize": "^8.0.0", + "readable-stream": "4.5.2", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^2.4.1" + } + }, + "node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rimraf": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } - } - }, - "node_modules/vscode-jsonrpc": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", - "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } - } } diff --git a/nodejs/package.json b/nodejs/package.json index 220e76aef..c33b8cb2c 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -1,89 +1,89 @@ { - "name": "@github/copilot-sdk", - "repository": { - "type": "git", - "url": "https://github.com/github/copilot-sdk.git" - }, - "version": "0.1.8", - "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", - "main": "./dist/cjs/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/cjs/index.js" - } + "name": "@github/copilot-sdk", + "repository": { + "type": "git", + "url": "https://github.com/github/copilot-sdk.git" }, - "./extension": { - "import": { - "types": "./dist/extension.d.ts", - "default": "./dist/extension.js" - }, - "require": { - "types": "./dist/extension.d.ts", - "default": "./dist/cjs/extension.js" - } - } - }, - "type": "module", - "scripts": { - "clean": "rimraf --glob dist *.tgz", - "build": "tsx esbuild-copilotsdk-nodejs.ts", - "test": "vitest run", - "test:watch": "vitest", - "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" --ignore-path .prettierignore", - "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" --ignore-path .prettierignore", - "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"", - "lint:fix": "eslint --fix \"src/**/*.ts\" \"test/**/*.ts\"", - "typecheck": "tsc --noEmit", - "generate": "cd ../scripts/codegen && npm run generate", - "update:protocol-version": "tsx scripts/update-protocol-version.ts", - "prepublishOnly": "npm run build", - "package": "npm run clean && npm run build && node scripts/set-version.js && npm pack && npm version 0.1.0 --no-git-tag-version --allow-same-version" - }, - "keywords": [ - "github", - "copilot", - "sdk", - "jsonrpc", - "agent" - ], - "author": "GitHub", - "license": "MIT", - "dependencies": { - "@github/copilot": "^1.0.32", - "vscode-jsonrpc": "^8.2.1", - "zod": "^4.3.6" - }, - "devDependencies": { - "@platformatic/vfs": "^0.3.0", - "@types/node": "^25.2.0", - "@typescript-eslint/eslint-plugin": "^8.54.0", - "@typescript-eslint/parser": "^8.54.0", - "esbuild": "^0.27.2", - "eslint": "^9.0.0", - "glob": "^13.0.1", - "json-schema": "^0.4.0", - "json-schema-to-typescript": "^15.0.4", - "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", - "rimraf": "^6.1.2", - "semver": "^7.7.3", - "tsx": "^4.20.6", - "typescript": "^5.0.0", - "vitest": "^4.0.18" - }, - "engines": { - "node": ">=20.0.0" - }, - "files": [ - "dist/**/*", - "docs/**/*", - "README.md" - ] + "version": "0.1.8", + "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", + "main": "./dist/cjs/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "require": { + "types": "./dist/index.d.ts", + "default": "./dist/cjs/index.js" + } + }, + "./extension": { + "import": { + "types": "./dist/extension.d.ts", + "default": "./dist/extension.js" + }, + "require": { + "types": "./dist/extension.d.ts", + "default": "./dist/cjs/extension.js" + } + } + }, + "type": "module", + "scripts": { + "clean": "rimraf --glob dist *.tgz", + "build": "tsx esbuild-copilotsdk-nodejs.ts", + "test": "vitest run", + "test:watch": "vitest", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" --ignore-path .prettierignore", + "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" --ignore-path .prettierignore", + "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"", + "lint:fix": "eslint --fix \"src/**/*.ts\" \"test/**/*.ts\"", + "typecheck": "tsc --noEmit", + "generate": "cd ../scripts/codegen && npm run generate", + "update:protocol-version": "tsx scripts/update-protocol-version.ts", + "prepublishOnly": "npm run build", + "package": "npm run clean && npm run build && node scripts/set-version.js && npm pack && npm version 0.1.0 --no-git-tag-version --allow-same-version" + }, + "keywords": [ + "github", + "copilot", + "sdk", + "jsonrpc", + "agent" + ], + "author": "GitHub", + "license": "MIT", + "dependencies": { + "@github/copilot": "^1.0.35-0", + "vscode-jsonrpc": "^8.2.1", + "zod": "^4.3.6" + }, + "devDependencies": { + "@platformatic/vfs": "^0.3.0", + "@types/node": "^25.2.0", + "@typescript-eslint/eslint-plugin": "^8.54.0", + "@typescript-eslint/parser": "^8.54.0", + "esbuild": "^0.27.2", + "eslint": "^9.0.0", + "glob": "^13.0.1", + "json-schema": "^0.4.0", + "json-schema-to-typescript": "^15.0.4", + "prettier": "^3.8.1", + "quicktype-core": "^23.2.6", + "rimraf": "^6.1.2", + "semver": "^7.7.3", + "tsx": "^4.20.6", + "typescript": "^5.0.0", + "vitest": "^4.0.18" + }, + "engines": { + "node": ">=20.0.0" + }, + "files": [ + "dist/**/*", + "docs/**/*", + "README.md" + ] } diff --git a/nodejs/samples/package-lock.json b/nodejs/samples/package-lock.json index 37dda6dc4..32128f5e7 100644 --- a/nodejs/samples/package-lock.json +++ b/nodejs/samples/package-lock.json @@ -1,611 +1,611 @@ { - "name": "copilot-sdk-sample", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "copilot-sdk-sample", - "dependencies": { - "@github/copilot-sdk": "file:.." - }, - "devDependencies": { - "@types/node": "^22.0.0", - "tsx": "^4.20.6" - } - }, - "..": { - "name": "@github/copilot-sdk", - "version": "0.1.8", - "license": "MIT", - "dependencies": { - "@github/copilot": "^1.0.32", - "vscode-jsonrpc": "^8.2.1", - "zod": "^4.3.6" - }, - "devDependencies": { - "@platformatic/vfs": "^0.3.0", - "@types/node": "^25.2.0", - "@typescript-eslint/eslint-plugin": "^8.54.0", - "@typescript-eslint/parser": "^8.54.0", - "esbuild": "^0.27.2", - "eslint": "^9.0.0", - "glob": "^13.0.1", - "json-schema": "^0.4.0", - "json-schema-to-typescript": "^15.0.4", - "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", - "rimraf": "^6.1.2", - "semver": "^7.7.3", - "tsx": "^4.20.6", - "typescript": "^5.0.0", - "vitest": "^4.0.18" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@github/copilot-sdk": { - "resolved": "..", - "link": true - }, - "node_modules/@types/node": { - "version": "22.19.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", - "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-tsconfig": { - "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" + "name": "copilot-sdk-sample", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "copilot-sdk-sample", + "dependencies": { + "@github/copilot-sdk": "file:.." + }, + "devDependencies": { + "@types/node": "^22.0.0", + "tsx": "^4.20.6" + } + }, + "..": { + "name": "@github/copilot-sdk", + "version": "0.1.8", + "license": "MIT", + "dependencies": { + "@github/copilot": "^1.0.32", + "vscode-jsonrpc": "^8.2.1", + "zod": "^4.3.6" + }, + "devDependencies": { + "@platformatic/vfs": "^0.3.0", + "@types/node": "^25.2.0", + "@typescript-eslint/eslint-plugin": "^8.54.0", + "@typescript-eslint/parser": "^8.54.0", + "esbuild": "^0.27.2", + "eslint": "^9.0.0", + "glob": "^13.0.1", + "json-schema": "^0.4.0", + "json-schema-to-typescript": "^15.0.4", + "prettier": "^3.8.1", + "quicktype-core": "^23.2.6", + "rimraf": "^6.1.2", + "semver": "^7.7.3", + "tsx": "^4.20.6", + "typescript": "^5.0.0", + "vitest": "^4.0.18" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@github/copilot-sdk": { + "resolved": "..", + "link": true + }, + "node_modules/@types/node": { + "version": "22.19.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", + "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } } - } } diff --git a/nodejs/samples/package.json b/nodejs/samples/package.json index 7ff4cd9f5..f5e8147c2 100644 --- a/nodejs/samples/package.json +++ b/nodejs/samples/package.json @@ -1,14 +1,14 @@ { - "name": "copilot-sdk-sample", - "type": "module", - "scripts": { - "start": "npx tsx chat.ts" - }, - "dependencies": { - "@github/copilot-sdk": "file:.." - }, - "devDependencies": { - "tsx": "^4.20.6", - "@types/node": "^22.0.0" - } + "name": "copilot-sdk-sample", + "type": "module", + "scripts": { + "start": "npx tsx chat.ts" + }, + "dependencies": { + "@github/copilot-sdk": "file:.." + }, + "devDependencies": { + "tsx": "^4.20.6", + "@types/node": "^22.0.0" + } } diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index c8c137c3d..725fdf019 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -27,6 +27,7 @@ import { import { createServerRpc, registerClientSessionApiHandlers } from "./generated/rpc.js"; import { getSdkProtocolVersion } from "./sdkProtocolVersion.js"; import { CopilotSession, NO_RESULT_PERMISSION_V2_ERROR } from "./session.js"; +import { createSessionFsAdapter } from "./sessionFsProvider.js"; import { getTraceContext } from "./telemetry.js"; import type { ConnectionState, @@ -711,7 +712,9 @@ export class CopilotClient { this.sessions.set(sessionId, session); if (this.sessionFsConfig) { if (config.createSessionFsHandler) { - session.clientSessionApis.sessionFs = config.createSessionFsHandler(session); + session.clientSessionApis.sessionFs = createSessionFsAdapter( + config.createSessionFsHandler(session) + ); } else { throw new Error( "createSessionFsHandler is required in session config when sessionFs is enabled in client options." @@ -849,7 +852,9 @@ export class CopilotClient { this.sessions.set(sessionId, session); if (this.sessionFsConfig) { if (config.createSessionFsHandler) { - session.clientSessionApis.sessionFs = config.createSessionFsHandler(session); + session.clientSessionApis.sessionFs = createSessionFsAdapter( + config.createSessionFsHandler(session) + ); } else { throw new Error( "createSessionFsHandler is required in session config when sessionFs is enabled in client options." diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index dedfa8068..b40ffc701 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -6,137 +6,57 @@ import type { MessageConnection } from "vscode-jsonrpc/node.js"; /** - * MCP server configuration (local/stdio or remote/http) + * Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerConfig". + * via the `definition` "DiscoveredMcpServerType". */ -export type McpServerConfig = - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - type?: "local" | "stdio"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - command: string; - args: string[]; - cwd?: string; - env?: { - [k: string]: string; - }; - } - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - /** - * Remote transport type. Defaults to "http" when omitted. - */ - type?: "http" | "sse"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - url: string; - headers?: { - [k: string]: string; - }; - oauthClientId?: string; - oauthPublicClient?: boolean; - }; +export type DiscoveredMcpServerType = "stdio" | "http" | "sse" | "memory"; +/** + * Configuration source + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "DiscoveredMcpServerSource". + */ +export type DiscoveredMcpServerSource = "user" | "workspace" | "plugin" | "builtin"; +/** + * Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ExtensionSource". + */ +export type ExtensionSource = "project" | "user"; +/** + * Current status: running, disabled, failed, or starting + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ExtensionStatus". + */ +export type ExtensionStatus = "running" | "disabled" | "failed" | "starting"; export type FilterMapping = | { - [k: string]: "none" | "markdown" | "hidden_characters"; + [k: string]: FilterMappingValue; } - | ("none" | "markdown" | "hidden_characters"); + | FilterMappingString; + +export type FilterMappingValue = "none" | "markdown" | "hidden_characters"; + +export type FilterMappingString = "none" | "markdown" | "hidden_characters"; /** - * The agent mode. Valid values: "interactive", "plan", "autopilot". + * Category of instruction source — used for merge logic * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMode". + * via the `definition` "InstructionsSourcesType". */ -export type SessionMode = "interactive" | "plan" | "autopilot"; - -export type UIElicitationFieldValue = string | number | boolean | string[]; +export type InstructionsSourcesType = "home" | "repo" | "model" | "vscode" | "nested-agents" | "child-instructions"; /** - * The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + * Where this source lives — used for UI grouping * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResponseAction". + * via the `definition` "InstructionsSourcesLocation". */ -export type UIElicitationResponseAction = "accept" | "decline" | "cancel"; - -export type PermissionDecision = - | { - /** - * The permission request was approved - */ - kind: "approved"; - } - | { - /** - * Denied because approval rules explicitly blocked it - */ - kind: "denied-by-rules"; - /** - * Rules that denied the request - */ - rules: unknown[]; - } - | { - /** - * Denied because no approval rule matched and user confirmation was unavailable - */ - kind: "denied-no-approval-rule-and-could-not-request-from-user"; - } - | { - /** - * Denied by the user during an interactive prompt - */ - kind: "denied-interactively-by-user"; - /** - * Optional feedback from the user explaining the denial - */ - feedback?: string; - } - | { - /** - * Denied by the organization's content exclusion policy - */ - kind: "denied-by-content-exclusion-policy"; - /** - * File path that triggered the exclusion - */ - path: string; - /** - * Human-readable explanation of why the path was excluded - */ - message: string; - } - | { - /** - * Denied by a permission request hook registered by an extension or plugin - */ - kind: "denied-by-permission-request-hook"; - /** - * Optional message from the hook explaining the denial - */ - message?: string; - /** - * Whether to interrupt the current agent turn - */ - interrupt?: boolean; - }; +export type InstructionsSourcesLocation = "user" | "repository" | "working-directory"; /** * Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". * @@ -148,321 +68,155 @@ export type SessionLogLevel = "info" | "warning" | "error"; * MCP server configuration (local/stdio or remote/http) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_McpServerConfig". + * via the `definition` "McpServerConfig". */ -export type $Defs_McpServerConfig = - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - type?: "local" | "stdio"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - command: string; - args: string[]; - cwd?: string; - env?: { - [k: string]: string; - }; - } - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - /** - * Remote transport type. Defaults to "http" when omitted. - */ - type?: "http" | "sse"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - url: string; - headers?: { - [k: string]: string; - }; - oauthClientId?: string; - oauthPublicClient?: boolean; - }; +export type McpServerConfig = McpServerConfigLocal | McpServerConfigHttp; -export type $Defs_FilterMapping = - | { - [k: string]: "none" | "markdown" | "hidden_characters"; - } - | ("none" | "markdown" | "hidden_characters"); +export type McpServerConfigLocalType = "local" | "stdio"; /** - * The agent mode. Valid values: "interactive", "plan", "autopilot". + * Remote transport type. Defaults to "http" when omitted. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_SessionMode". + * via the `definition` "McpServerConfigHttpType". */ -export type $Defs_SessionMode = "interactive" | "plan" | "autopilot"; +export type McpServerConfigHttpType = "http" | "sse"; /** - * The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + * Connection status: connected, failed, needs-auth, pending, disabled, or not_configured * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_UIElicitationResponseAction". + * via the `definition` "McpServerStatus". */ -export type $Defs_UIElicitationResponseAction = "accept" | "decline" | "cancel"; - -export type $Defs_UIElicitationFieldValue = string | number | boolean | string[]; - -export type $Defs_PermissionDecision = - | { - /** - * The permission request was approved - */ - kind: "approved"; - } - | { - /** - * Denied because approval rules explicitly blocked it - */ - kind: "denied-by-rules"; - /** - * Rules that denied the request - */ - rules: unknown[]; - } - | { - /** - * Denied because no approval rule matched and user confirmation was unavailable - */ - kind: "denied-no-approval-rule-and-could-not-request-from-user"; - } - | { - /** - * Denied by the user during an interactive prompt - */ - kind: "denied-interactively-by-user"; - /** - * Optional feedback from the user explaining the denial - */ - feedback?: string; - } - | { - /** - * Denied by the organization's content exclusion policy - */ - kind: "denied-by-content-exclusion-policy"; - /** - * File path that triggered the exclusion - */ - path: string; - /** - * Human-readable explanation of why the path was excluded - */ - message: string; - } - | { - /** - * Denied by a permission request hook registered by an extension or plugin - */ - kind: "denied-by-permission-request-hook"; - /** - * Optional message from the hook explaining the denial - */ - message?: string; - /** - * Whether to interrupt the current agent turn - */ - interrupt?: boolean; - }; +export type McpServerStatus = "connected" | "failed" | "needs-auth" | "pending" | "disabled" | "not_configured"; /** - * Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". + * Configuration source: user, workspace, plugin, or builtin + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpServerSource". + */ +export type McpServerSource = "user" | "workspace" | "plugin" | "builtin"; +/** + * The agent mode. Valid values: "interactive", "plan", "autopilot". * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_SessionLogLevel". + * via the `definition` "SessionMode". */ -export type $Defs_SessionLogLevel = "info" | "warning" | "error"; +export type SessionMode = "interactive" | "plan" | "autopilot"; +export type PermissionDecision = + | PermissionDecisionApproved + | PermissionDecisionDeniedByRules + | PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser + | PermissionDecisionDeniedInteractivelyByUser + | PermissionDecisionDeniedByContentExclusionPolicy + | PermissionDecisionDeniedByPermissionRequestHook; /** - * Model capabilities and limits + * Error classification * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilities". + * via the `definition` "SessionFsErrorCode". */ -export interface ModelCapabilities { - /** - * Feature flags indicating what the model supports - */ - supports?: { - /** - * Whether this model supports vision/image input - */ - vision?: boolean; - /** - * Whether this model supports reasoning effort configuration - */ - reasoningEffort?: boolean; - }; - /** - * Token limits for prompts, outputs, and context window - */ - limits?: { - /** - * Maximum number of prompt/input tokens - */ - max_prompt_tokens?: number; - /** - * Maximum number of output/completion tokens - */ - max_output_tokens?: number; - /** - * Maximum total context window size in tokens - */ - max_context_window_tokens?: number; - vision?: ModelCapabilitiesLimitsVision; - }; -} +export type SessionFsErrorCode = "ENOENT" | "UNKNOWN"; /** - * Vision-specific limits + * Entry type + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirWithTypesEntryType". */ -export interface ModelCapabilitiesLimitsVision { - /** - * MIME types the model accepts - */ - supported_media_types: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images: number; - /** - * Maximum image size in bytes - */ - max_prompt_image_size: number; -} +export type SessionFsReaddirWithTypesEntryType = "file" | "directory"; /** - * Vision-specific limits + * Path conventions used by this filesystem * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesLimitsVision". + * via the `definition` "SessionFsSetProviderConventions". */ -export interface ModelCapabilitiesLimitsVision1 { - /** - * MIME types the model accepts - */ - supported_media_types: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images: number; - /** - * Maximum image size in bytes - */ - max_prompt_image_size: number; -} +export type SessionFsSetProviderConventions = "windows" | "posix"; +/** + * Signal to send (default: SIGTERM) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShellKillSignal". + */ +export type ShellKillSignal = "SIGTERM" | "SIGKILL" | "SIGINT"; +/** + * Tool call result (string or expanded result object) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ToolsHandlePendingToolCall". + */ +export type ToolsHandlePendingToolCall = string | ToolCallResult; -export interface DiscoveredMcpServer { - /** - * Server name (config key) - */ - name: string; - /** - * Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio) - */ - type?: "stdio" | "http" | "sse" | "memory"; - /** - * Configuration source - */ - source: "user" | "workspace" | "plugin" | "builtin"; - /** - * Whether the server is enabled (not in the disabled list) - */ - enabled: boolean; -} +export type UIElicitationFieldValue = string | number | boolean | string[]; -export interface ServerSkillList { +export type UIElicitationSchemaProperty = + | UIElicitationStringEnumField + | UIElicitationStringOneOfField + | UIElicitationArrayEnumField + | UIElicitationArrayAnyOfField + | UIElicitationSchemaPropertyBoolean + | UIElicitationSchemaPropertyString + | UIElicitationSchemaPropertyNumber; + +export type UIElicitationSchemaPropertyStringFormat = "email" | "uri" | "date" | "date-time"; + +export type UIElicitationSchemaPropertyNumberType = "number" | "integer"; +/** + * The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIElicitationResponseAction". + */ +export type UIElicitationResponseAction = "accept" | "decline" | "cancel"; + +export interface AccountGetQuotaResult { /** - * All discovered skills across all sources + * Quota snapshots keyed by type (e.g., chat, completions, premium_interactions) */ - skills: ServerSkill[]; + quotaSnapshots: { + [k: string]: AccountQuotaSnapshot; + }; } -export interface ServerSkill { +export interface AccountQuotaSnapshot { /** - * Unique identifier for the skill + * Whether the user has an unlimited usage entitlement */ - name: string; + isUnlimitedEntitlement: boolean; /** - * Description of what the skill does + * Number of requests included in the entitlement */ - description: string; + entitlementRequests: number; /** - * Source location type (e.g., project, personal-copilot, plugin, builtin) + * Number of requests used so far this period */ - source: string; + usedRequests: number; /** - * Whether the skill can be invoked by the user as a slash command + * Whether usage is still permitted after quota exhaustion */ - userInvocable: boolean; + usageAllowedWithExhaustedQuota: boolean; /** - * Whether the skill is currently enabled (based on global config) + * Percentage of entitlement remaining */ - enabled: boolean; + remainingPercentage: number; /** - * Absolute path to the skill file + * Number of overage requests made this period */ - path?: string; + overage: number; /** - * The project path this skill belongs to (only for project/inherited skills) + * Whether overage is allowed when quota is exhausted */ - projectPath?: string; -} - -export interface CurrentModel { + overageAllowedWithExhaustedQuota: boolean; /** - * Currently active model identifier + * Date when the quota resets (ISO 8601 string) */ - modelId?: string; + resetDate?: string; } -/** - * Override individual model capabilities resolved by the runtime - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesOverride". - */ -export interface ModelCapabilitiesOverride { + +/** @experimental */ +export interface AgentGetCurrentResult { /** - * Feature flags indicating what the model supports + * Currently selected custom agent, or null if using the default agent */ - supports?: { - vision?: boolean; - reasoningEffort?: boolean; - }; - /** - * Token limits for prompts, outputs, and context window - */ - limits?: { - max_prompt_tokens?: number; - max_output_tokens?: number; - /** - * Maximum total context window size in tokens - */ - max_context_window_tokens?: number; - vision?: { - /** - * MIME types the model accepts - */ - supported_media_types?: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images?: number; - /** - * Maximum image size in bytes - */ - max_prompt_image_size?: number; - }; - }; + agent?: AgentInfo | null; } export interface AgentInfo { @@ -481,342 +235,306 @@ export interface AgentInfo { } /** @experimental */ -export interface McpServerList { +export interface AgentList { /** - * Configured MCP servers + * Available custom agents */ - servers: { - /** - * Server name (config key) - */ - name: string; - /** - * Connection status: connected, failed, needs-auth, pending, disabled, or not_configured - */ - status: "connected" | "failed" | "needs-auth" | "pending" | "disabled" | "not_configured"; - /** - * Configuration source: user, workspace, plugin, or builtin - */ - source?: "user" | "workspace" | "plugin" | "builtin"; - /** - * Error message if the server failed to connect - */ - error?: string; - }[]; + agents: AgentInfo[]; } -export interface ToolCallResult { +/** @experimental */ +export interface AgentReloadResult { /** - * Text result to send back to the LLM + * Reloaded custom agents */ - textResultForLlm: string; + agents: AgentInfo[]; +} + +/** @experimental */ +export interface AgentSelectRequest { /** - * Type of the tool result + * Name of the custom agent to select */ - resultType?: string; + name: string; +} + +/** @experimental */ +export interface AgentSelectResult { + agent: AgentInfo; +} + +export interface CommandsHandlePendingCommandRequest { /** - * Error message if the tool call failed + * Request ID from the command invocation event */ - error?: string; + requestId: string; /** - * Telemetry data from tool execution + * Error message if the command handler failed */ - toolTelemetry?: { - [k: string]: unknown; - }; + error?: string; } -export interface HandleToolCallResult { +export interface CommandsHandlePendingCommandResult { /** - * Whether the tool call result was handled successfully + * Whether the command was handled successfully */ success: boolean; } -export interface UIElicitationStringEnumField { - type: "string"; - description?: string; - enum: string[]; - enumNames?: string[]; - default?: string; +export interface CurrentModel { + /** + * Currently active model identifier + */ + modelId?: string; } -export interface UIElicitationStringOneOfField { - type: "string"; - description?: string; - oneOf: { - const: string; - }[]; - default?: string; +export interface DiscoveredMcpServer { + /** + * Server name (config key) + */ + name: string; + type?: DiscoveredMcpServerType; + source: DiscoveredMcpServerSource; + /** + * Whether the server is enabled (not in the disabled list) + */ + enabled: boolean; } -export interface UIElicitationArrayEnumField { - type: "array"; - description?: string; - minItems?: number; - maxItems?: number; - items: { - type: "string"; - enum: string[]; - }; - default?: string[]; +export interface Extension { + /** + * Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper') + */ + id: string; + /** + * Extension name (directory name) + */ + name: string; + source: ExtensionSource; + status: ExtensionStatus; + /** + * Process ID if the extension is running + */ + pid?: number; } -export interface UIElicitationArrayAnyOfField { - type: "array"; - description?: string; - minItems?: number; - maxItems?: number; - items: { - anyOf: { - const: string; - }[]; - }; - default?: string[]; +/** @experimental */ +export interface ExtensionList { + /** + * Discovered extensions and their current status + */ + extensions: Extension[]; } -/** - * The elicitation response (accept with form values, decline, or cancel) - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResponse". - */ -export interface UIElicitationResponse { + +/** @experimental */ +export interface ExtensionsDisableRequest { /** - * The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + * Source-qualified extension ID to disable */ - action: "accept" | "decline" | "cancel"; - content?: UIElicitationResponseContent; + id: string; } -/** - * The form values submitted by the user (present when action is 'accept') - */ -export interface UIElicitationResponseContent { - [k: string]: UIElicitationFieldValue; + +/** @experimental */ +export interface ExtensionsEnableRequest { + /** + * Source-qualified extension ID to enable + */ + id: string; } -/** - * The form values submitted by the user (present when action is 'accept') - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResponseContent". - */ -export interface UIElicitationResponseContent1 { - [k: string]: UIElicitationFieldValue; + +/** @experimental */ +export interface FleetStartRequest { + /** + * Optional user prompt to combine with fleet instructions + */ + prompt?: string; } -export interface UIHandlePendingElicitationRequest { +/** @experimental */ +export interface FleetStartResult { /** - * The unique request ID from the elicitation.requested event + * Whether fleet mode was successfully activated */ - requestId: string; - result: UIElicitationResponse1; + started: boolean; +} + +export interface HandleToolCallResult { + /** + * Whether the tool call result was handled successfully + */ + success: boolean; } /** - * The elicitation response (accept with form values, decline, or cancel) + * Post-compaction context window usage breakdown + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HistoryCompactContextWindow". */ -export interface UIElicitationResponse1 { +export interface HistoryCompactContextWindow { /** - * The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + * Maximum token count for the model's context window */ - action: "accept" | "decline" | "cancel"; - content?: UIElicitationResponseContent; + tokenLimit: number; + /** + * Current total tokens in the context window (system + conversation + tool definitions) + */ + currentTokens: number; + /** + * Current number of messages in the conversation + */ + messagesLength: number; + /** + * Token count from system message(s) + */ + systemTokens?: number; + /** + * Token count from non-system messages (user, assistant, tool) + */ + conversationTokens?: number; + /** + * Token count from tool definitions + */ + toolDefinitionsTokens?: number; } -export interface UIElicitationResult { +/** @experimental */ +export interface HistoryCompactResult { /** - * Whether the response was accepted. False if the request was already resolved by another client. + * Whether compaction completed successfully */ success: boolean; + /** + * Number of tokens freed by compaction + */ + tokensRemoved: number; + /** + * Number of messages removed during compaction + */ + messagesRemoved: number; + contextWindow?: HistoryCompactContextWindow; } -export interface PermissionDecisionRequest { +/** @experimental */ +export interface HistoryTruncateRequest { /** - * Request ID of the pending permission request + * Event ID to truncate to. This event and all events after it are removed from the session. */ - requestId: string; - result: PermissionDecision; + eventId: string; } -export interface PermissionRequestResult { +/** @experimental */ +export interface HistoryTruncateResult { /** - * Whether the permission request was handled successfully + * Number of events that were removed */ - success: boolean; + eventsRemoved: number; } -export interface PingResult { +export interface InstructionsGetSourcesResult { /** - * Echoed message (or default greeting) + * Instruction sources for the session */ - message: string; + sources: InstructionsSources[]; +} + +export interface InstructionsSources { /** - * Server timestamp in milliseconds + * Unique identifier for this source (used for toggling) */ - timestamp: number; + id: string; /** - * Server protocol version number + * Human-readable label */ - protocolVersion: number; -} - -export interface PingRequest { + label: string; /** - * Optional message to echo back + * File path relative to repo or absolute for home */ - message?: string; + sourcePath: string; + /** + * Raw content of the instruction file + */ + content: string; + type: InstructionsSourcesType; + location: InstructionsSourcesLocation; + /** + * Glob pattern from frontmatter — when set, this instruction applies only to matching files + */ + applyTo?: string; + /** + * Short description (body after frontmatter) for use in instruction tables + */ + description?: string; } -export interface ModelList { +export interface LogRequest { /** - * List of available models with full metadata + * Human-readable message */ - models: { - /** - * Model identifier (e.g., "claude-sonnet-4.5") - */ - id: string; - /** - * Display name - */ - name: string; - capabilities: ModelCapabilities1; - /** - * Policy state (if applicable) - */ - policy?: { - /** - * Current policy state for this model - */ - state: string; - /** - * Usage terms or conditions for this model - */ - terms: string; - }; - /** - * Billing information - */ - billing?: { - /** - * Billing cost multiplier relative to the base rate - */ - multiplier: number; - }; - /** - * Supported reasoning effort levels (only present if model supports reasoning effort) - */ - supportedReasoningEfforts?: string[]; - /** - * Default reasoning effort level (only present if model supports reasoning effort) - */ - defaultReasoningEffort?: string; - }[]; + message: string; + level?: SessionLogLevel; + /** + * When true, the message is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Optional URL the user can open in their browser for more details + */ + url?: string; } -/** - * Model capabilities and limits - */ -export interface ModelCapabilities1 { - /** - * Feature flags indicating what the model supports - */ - supports?: { - /** - * Whether this model supports vision/image input - */ - vision?: boolean; - /** - * Whether this model supports reasoning effort configuration - */ - reasoningEffort?: boolean; - }; + +export interface LogResult { /** - * Token limits for prompts, outputs, and context window - */ - limits?: { - /** - * Maximum number of prompt/input tokens - */ - max_prompt_tokens?: number; - /** - * Maximum number of output/completion tokens - */ - max_output_tokens?: number; - /** - * Maximum total context window size in tokens - */ - max_context_window_tokens?: number; - vision?: ModelCapabilitiesLimitsVision; - }; + * The unique identifier of the emitted session event + */ + eventId: string; } -export interface ToolList { +export interface McpConfigAddRequest { /** - * List of available built-in tools with metadata + * Unique name for the MCP server */ - tools: { - /** - * Tool identifier (e.g., "bash", "grep", "str_replace_editor") - */ - name: string; - /** - * Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools) - */ - namespacedName?: string; - /** - * Description of what the tool does - */ - description: string; - /** - * JSON Schema for the tool's input parameters - */ - parameters?: { - [k: string]: unknown; - }; - /** - * Optional instructions for how to use this tool effectively - */ - instructions?: string; - }[]; + name: string; + config: McpServerConfig; } -export interface ToolsListRequest { +export interface McpServerConfigLocal { /** - * Optional model ID — when provided, the returned tool list reflects model-specific overrides + * Tools to include. Defaults to all tools if not specified. */ - model?: string; + tools?: string[]; + type?: McpServerConfigLocalType; + isDefaultServer?: boolean; + filterMapping?: FilterMapping; + /** + * Timeout in milliseconds for tool calls to this server. + */ + timeout?: number; + command: string; + args: string[]; + cwd?: string; + env?: { + [k: string]: string; + }; } -export interface AccountGetQuotaResult { +export interface McpServerConfigHttp { /** - * Quota snapshots keyed by type (e.g., chat, completions, premium_interactions) + * Tools to include. Defaults to all tools if not specified. */ - quotaSnapshots: { - [k: string]: { - /** - * Number of requests included in the entitlement - */ - entitlementRequests: number; - /** - * Number of requests used so far this period - */ - usedRequests: number; - /** - * Percentage of entitlement remaining - */ - remainingPercentage: number; - /** - * Number of overage requests made this period - */ - overage: number; - /** - * Whether pay-per-request usage is allowed when quota is exhausted - */ - overageAllowedWithExhaustedQuota: boolean; - /** - * Date when the quota resets (ISO 8601) - */ - resetDate?: string; - }; + tools?: string[]; + type?: McpServerConfigHttpType; + isDefaultServer?: boolean; + filterMapping?: FilterMapping; + /** + * Timeout in milliseconds for tool calls to this server. + */ + timeout?: number; + url: string; + headers?: { + [k: string]: string; }; + oauthClientId?: string; + oauthPublicClient?: boolean; } export interface McpConfigList { @@ -824,104 +542,15 @@ export interface McpConfigList { * All MCP servers from user config, keyed by name */ servers: { - /** - * MCP server configuration (local/stdio or remote/http) - */ - [k: string]: - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - type?: "local" | "stdio"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - command: string; - args: string[]; - cwd?: string; - env?: { - [k: string]: string; - }; - } - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - /** - * Remote transport type. Defaults to "http" when omitted. - */ - type?: "http" | "sse"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - url: string; - headers?: { - [k: string]: string; - }; - oauthClientId?: string; - oauthPublicClient?: boolean; - }; + [k: string]: McpServerConfig; }; } -export interface McpConfigAddRequest { +export interface McpConfigRemoveRequest { /** - * Unique name for the MCP server + * Name of the MCP server to remove */ name: string; - /** - * MCP server configuration (local/stdio or remote/http) - */ - config: - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - type?: "local" | "stdio"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - command: string; - args: string[]; - cwd?: string; - env?: { - [k: string]: string; - }; - } - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - /** - * Remote transport type. Defaults to "http" when omitted. - */ - type?: "http" | "sse"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - url: string; - headers?: { - [k: string]: string; - }; - oauthClientId?: string; - oauthPublicClient?: boolean; - }; } export interface McpConfigUpdateRequest { @@ -929,139 +558,232 @@ export interface McpConfigUpdateRequest { * Name of the MCP server to update */ name: string; - /** - * MCP server configuration (local/stdio or remote/http) - */ - config: - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - type?: "local" | "stdio"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - command: string; - args: string[]; - cwd?: string; - env?: { - [k: string]: string; - }; - } - | { - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - /** - * Remote transport type. Defaults to "http" when omitted. - */ - type?: "http" | "sse"; - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool calls to this server. - */ - timeout?: number; - url: string; - headers?: { - [k: string]: string; - }; - oauthClientId?: string; - oauthPublicClient?: boolean; - }; + config: McpServerConfig; } -export interface McpConfigRemoveRequest { +/** @experimental */ +export interface McpDisableRequest { /** - * Name of the MCP server to remove + * Name of the MCP server to disable */ - name: string; + serverName: string; } -export interface McpDiscoverResult { +export interface McpDiscoverRequest { /** - * MCP servers discovered from all sources + * Working directory used as context for discovery (e.g., plugin resolution) */ - servers: DiscoveredMcpServer[]; + workingDirectory?: string; } -export interface McpDiscoverRequest { +export interface McpDiscoverResult { /** - * Working directory used as context for discovery (e.g., plugin resolution) + * MCP servers discovered from all sources */ - workingDirectory?: string; + servers: DiscoveredMcpServer[]; } -export interface SkillsConfigSetDisabledSkillsRequest { +/** @experimental */ +export interface McpEnableRequest { /** - * List of skill names to disable + * Name of the MCP server to enable */ - disabledSkills: string[]; + serverName: string; } -export interface SkillsDiscoverRequest { +export interface McpServer { /** - * Optional list of project directory paths to scan for project-scoped skills + * Server name (config key) */ - projectPaths?: string[]; + name: string; + status: McpServerStatus; + source?: McpServerSource; /** - * Optional list of additional skill directory paths to include + * Error message if the server failed to connect */ - skillDirectories?: string[]; + error?: string; } -export interface SessionFsSetProviderResult { +/** @experimental */ +export interface McpServerList { /** - * Whether the provider was set successfully + * Configured MCP servers */ - success: boolean; + servers: McpServer[]; } -export interface SessionFsSetProviderRequest { +export interface Model { /** - * Initial working directory for sessions + * Model identifier (e.g., "claude-sonnet-4.5") */ - initialCwd: string; + id: string; /** - * Path within each session's SessionFs where the runtime stores files for that session + * Display name */ - sessionStatePath: string; + name: string; + capabilities: ModelCapabilities; + policy?: ModelPolicy; + billing?: ModelBilling; /** - * Path conventions used by this filesystem + * Supported reasoning effort levels (only present if model supports reasoning effort) */ - conventions: "windows" | "posix"; -} - -/** @experimental */ -export interface SessionsForkResult { + supportedReasoningEfforts?: string[]; /** - * The new forked session's ID + * Default reasoning effort level (only present if model supports reasoning effort) */ - sessionId: string; + defaultReasoningEffort?: string; } - -/** @experimental */ -export interface SessionsForkRequest { +/** + * Model capabilities and limits + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilities". + */ +export interface ModelCapabilities { + supports?: ModelCapabilitiesSupports; + limits?: ModelCapabilitiesLimits; +} +/** + * Feature flags indicating what the model supports + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesSupports". + */ +export interface ModelCapabilitiesSupports { /** - * Source session ID to fork from + * Whether this model supports vision/image input */ - sessionId: string; + vision?: boolean; /** - * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. + * Whether this model supports reasoning effort configuration */ - toEventId?: string; + reasoningEffort?: boolean; +} +/** + * Token limits for prompts, outputs, and context window + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesLimits". + */ +export interface ModelCapabilitiesLimits { + /** + * Maximum number of prompt/input tokens + */ + max_prompt_tokens?: number; + /** + * Maximum number of output/completion tokens + */ + max_output_tokens?: number; + /** + * Maximum total context window size in tokens + */ + max_context_window_tokens?: number; + vision?: ModelCapabilitiesLimitsVision; +} +/** + * Vision-specific limits + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesLimitsVision". + */ +export interface ModelCapabilitiesLimitsVision { + /** + * MIME types the model accepts + */ + supported_media_types: string[]; + /** + * Maximum number of images per prompt + */ + max_prompt_images: number; + /** + * Maximum image size in bytes + */ + max_prompt_image_size: number; +} +/** + * Policy state (if applicable) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelPolicy". + */ +export interface ModelPolicy { + /** + * Current policy state for this model + */ + state: string; + /** + * Usage terms or conditions for this model + */ + terms: string; +} +/** + * Billing information + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelBilling". + */ +export interface ModelBilling { + /** + * Billing cost multiplier relative to the base rate + */ + multiplier: number; +} +/** + * Override individual model capabilities resolved by the runtime + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesOverride". + */ +export interface ModelCapabilitiesOverride { + supports?: ModelCapabilitiesOverrideSupports; + limits?: ModelCapabilitiesOverrideLimits; +} +/** + * Feature flags indicating what the model supports + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesOverrideSupports". + */ +export interface ModelCapabilitiesOverrideSupports { + vision?: boolean; + reasoningEffort?: boolean; +} +/** + * Token limits for prompts, outputs, and context window + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesOverrideLimits". + */ +export interface ModelCapabilitiesOverrideLimits { + max_prompt_tokens?: number; + max_output_tokens?: number; + /** + * Maximum total context window size in tokens + */ + max_context_window_tokens?: number; + vision?: ModelCapabilitiesOverrideLimitsVision; } -export interface ModelSwitchToResult { +export interface ModelCapabilitiesOverrideLimitsVision { /** - * Currently active model identifier after the switch + * MIME types the model accepts */ - modelId?: string; + supported_media_types?: string[]; + /** + * Maximum number of images per prompt + */ + max_prompt_images?: number; + /** + * Maximum image size in bytes + */ + max_prompt_image_size?: number; +} + +export interface ModelList { + /** + * List of available models with full metadata + */ + models: Model[]; } export interface ModelSwitchToRequest { @@ -1073,51 +795,18 @@ export interface ModelSwitchToRequest { * Reasoning effort level to use for the model */ reasoningEffort?: string; - modelCapabilities?: ModelCapabilitiesOverride1; + modelCapabilities?: ModelCapabilitiesOverride; } -/** - * Override individual model capabilities resolved by the runtime - */ -export interface ModelCapabilitiesOverride1 { + +export interface ModelSwitchToResult { /** - * Feature flags indicating what the model supports + * Currently active model identifier after the switch */ - supports?: { - vision?: boolean; - reasoningEffort?: boolean; - }; - /** - * Token limits for prompts, outputs, and context window - */ - limits?: { - max_prompt_tokens?: number; - max_output_tokens?: number; - /** - * Maximum total context window size in tokens - */ - max_context_window_tokens?: number; - vision?: { - /** - * MIME types the model accepts - */ - supported_media_types?: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images?: number; - /** - * Maximum image size in bytes - */ - max_prompt_image_size?: number; - }; - }; + modelId?: string; } export interface ModeSetRequest { - /** - * The agent mode. Valid values: "interactive", "plan", "autopilot". - */ - mode: "interactive" | "plan" | "autopilot"; + mode: SessionMode; } export interface NameGetResult { @@ -1134,642 +823,384 @@ export interface NameSetRequest { name: string; } -export interface PlanReadResult { +export interface PermissionDecisionApproved { /** - * Whether the plan file exists in the workspace + * The permission request was approved */ - exists: boolean; + kind: "approved"; +} + +export interface PermissionDecisionDeniedByRules { /** - * The content of the plan file, or null if it does not exist + * Denied because approval rules explicitly blocked it */ - content: string | null; + kind: "denied-by-rules"; /** - * Absolute file path of the plan file, or null if workspace is not enabled + * Rules that denied the request */ - path: string | null; + rules: unknown[]; } -export interface PlanUpdateRequest { +export interface PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser { /** - * The new content for the plan file + * Denied because no approval rule matched and user confirmation was unavailable */ - content: string; + kind: "denied-no-approval-rule-and-could-not-request-from-user"; } -export interface WorkspacesGetWorkspaceResult { +export interface PermissionDecisionDeniedInteractivelyByUser { /** - * Current workspace metadata, or null if not available + * Denied by the user during an interactive prompt */ - workspace: { - id: string; - cwd?: string; - git_root?: string; - repository?: string; - host_type?: "github" | "ado"; - branch?: string; - summary?: string; - name?: string; - summary_count?: number; - created_at?: string; - updated_at?: string; - mc_task_id?: string; - mc_session_id?: string; - mc_last_event_id?: string; - session_sync_level?: "local" | "user" | "repo_and_user"; - pr_create_sync_dismissed?: boolean; - chronicle_sync_dismissed?: boolean; - } | null; -} - -export interface WorkspacesListFilesResult { + kind: "denied-interactively-by-user"; /** - * Relative file paths in the workspace files directory + * Optional feedback from the user explaining the denial */ - files: string[]; + feedback?: string; } -export interface WorkspacesReadFileResult { +export interface PermissionDecisionDeniedByContentExclusionPolicy { /** - * File content as a UTF-8 string + * Denied by the organization's content exclusion policy */ - content: string; -} - -export interface WorkspacesReadFileRequest { + kind: "denied-by-content-exclusion-policy"; /** - * Relative path within the workspace files directory + * File path that triggered the exclusion */ path: string; + /** + * Human-readable explanation of why the path was excluded + */ + message: string; } -export interface WorkspacesCreateFileRequest { +export interface PermissionDecisionDeniedByPermissionRequestHook { /** - * Relative path within the workspace files directory + * Denied by a permission request hook registered by an extension or plugin */ - path: string; + kind: "denied-by-permission-request-hook"; /** - * File content to write as a UTF-8 string + * Optional message from the hook explaining the denial */ - content: string; -} - -export interface InstructionsGetSourcesResult { + message?: string; /** - * Instruction sources for the session + * Whether to interrupt the current agent turn */ - sources: { - /** - * Unique identifier for this source (used for toggling) - */ - id: string; - /** - * Human-readable label - */ - label: string; - /** - * File path relative to repo or absolute for home - */ - sourcePath: string; - /** - * Raw content of the instruction file - */ - content: string; - /** - * Category of instruction source — used for merge logic - */ - type: "home" | "repo" | "model" | "vscode" | "nested-agents" | "child-instructions"; - /** - * Where this source lives — used for UI grouping - */ - location: "user" | "repository" | "working-directory"; - /** - * Glob pattern from frontmatter — when set, this instruction applies only to matching files - */ - applyTo?: string; - /** - * Short description (body after frontmatter) for use in instruction tables - */ - description?: string; - }[]; + interrupt?: boolean; } -/** @experimental */ -export interface FleetStartResult { +export interface PermissionDecisionRequest { /** - * Whether fleet mode was successfully activated + * Request ID of the pending permission request */ - started: boolean; + requestId: string; + result: PermissionDecision; } -/** @experimental */ -export interface FleetStartRequest { +export interface PermissionRequestResult { /** - * Optional user prompt to combine with fleet instructions + * Whether the permission request was handled successfully */ - prompt?: string; + success: boolean; } -/** @experimental */ -export interface AgentList { +export interface PingRequest { /** - * Available custom agents + * Optional message to echo back */ - agents: AgentInfo[]; + message?: string; } -/** @experimental */ -export interface AgentGetCurrentResult { +export interface PingResult { /** - * Currently selected custom agent, or null if using the default agent + * Echoed message (or default greeting) */ - agent?: AgentInfo | null; + message: string; + /** + * Server timestamp in milliseconds + */ + timestamp: number; + /** + * Server protocol version number + */ + protocolVersion: number; } -/** @experimental */ -export interface AgentSelectResult { - agent: AgentInfo1; -} -/** - * The newly selected custom agent - */ -export interface AgentInfo1 { +export interface PlanReadResult { /** - * Unique identifier of the custom agent + * Whether the plan file exists in the workspace */ - name: string; + exists: boolean; /** - * Human-readable display name + * The content of the plan file, or null if it does not exist */ - displayName: string; + content: string | null; /** - * Description of the agent's purpose + * Absolute file path of the plan file, or null if workspace is not enabled */ - description: string; + path: string | null; } -/** @experimental */ -export interface AgentSelectRequest { +export interface PlanUpdateRequest { /** - * Name of the custom agent to select + * The new content for the plan file */ - name: string; + content: string; } -/** @experimental */ -export interface AgentReloadResult { +export interface Plugin { /** - * Reloaded custom agents + * Plugin name */ - agents: AgentInfo[]; -} - -/** @experimental */ -export interface SkillList { + name: string; /** - * Available skills + * Marketplace the plugin came from + */ + marketplace: string; + /** + * Installed version + */ + version?: string; + /** + * Whether the plugin is currently enabled */ - skills: { - /** - * Unique identifier for the skill - */ - name: string; - /** - * Description of what the skill does - */ - description: string; - /** - * Source location type (e.g., project, personal, plugin) - */ - source: string; - /** - * Whether the skill can be invoked by the user as a slash command - */ - userInvocable: boolean; - /** - * Whether the skill is currently enabled - */ - enabled: boolean; - /** - * Absolute path to the skill file - */ - path?: string; - }[]; + enabled: boolean; } /** @experimental */ -export interface SkillsEnableRequest { +export interface PluginList { /** - * Name of the skill to enable + * Installed plugins */ - name: string; + plugins: Plugin[]; } -/** @experimental */ -export interface SkillsDisableRequest { +export interface ServerSkill { /** - * Name of the skill to disable + * Unique identifier for the skill */ name: string; -} - -/** @experimental */ -export interface McpEnableRequest { /** - * Name of the MCP server to enable + * Description of what the skill does */ - serverName: string; -} - -/** @experimental */ -export interface McpDisableRequest { + description: string; /** - * Name of the MCP server to disable + * Source location type (e.g., project, personal-copilot, plugin, builtin) */ - serverName: string; -} - -/** @experimental */ -export interface PluginList { + source: string; /** - * Installed plugins + * Whether the skill can be invoked by the user as a slash command */ - plugins: { - /** - * Plugin name - */ - name: string; - /** - * Marketplace the plugin came from - */ - marketplace: string; - /** - * Installed version - */ - version?: string; - /** - * Whether the plugin is currently enabled - */ - enabled: boolean; - }[]; -} - -/** @experimental */ -export interface ExtensionList { + userInvocable: boolean; /** - * Discovered extensions and their current status + * Whether the skill is currently enabled (based on global config) */ - extensions: { - /** - * Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper') - */ - id: string; - /** - * Extension name (directory name) - */ - name: string; - /** - * Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) - */ - source: "project" | "user"; - /** - * Current status: running, disabled, failed, or starting - */ - status: "running" | "disabled" | "failed" | "starting"; - /** - * Process ID if the extension is running - */ - pid?: number; - }[]; -} - -/** @experimental */ -export interface ExtensionsEnableRequest { + enabled: boolean; /** - * Source-qualified extension ID to enable + * Absolute path to the skill file */ - id: string; + path?: string; + /** + * The project path this skill belongs to (only for project/inherited skills) + */ + projectPath?: string; } -/** @experimental */ -export interface ExtensionsDisableRequest { +export interface ServerSkillList { /** - * Source-qualified extension ID to disable + * All discovered skills across all sources */ - id: string; + skills: ServerSkill[]; } -export interface ToolsHandlePendingToolCallRequest { +export interface SessionFsAppendFileRequest { /** - * Request ID of the pending tool call + * Target session identifier */ - requestId: string; + sessionId: string; /** - * Tool call result (string or expanded result object) + * Path using SessionFs conventions */ - result?: string | ToolCallResult; + path: string; /** - * Error message if the tool call failed + * Content to append */ - error?: string; -} - -export interface CommandsHandlePendingCommandResult { + content: string; /** - * Whether the command was handled successfully + * Optional POSIX-style mode for newly created files */ - success: boolean; + mode?: number; } - -export interface CommandsHandlePendingCommandRequest { - /** - * Request ID from the command invocation event - */ - requestId: string; +/** + * Describes a filesystem error. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsError". + */ +export interface SessionFsError { + code: SessionFsErrorCode; /** - * Error message if the command handler failed + * Free-form detail about the error, for logging/diagnostics */ - error?: string; + message?: string; } -export interface UIElicitationRequest { +export interface SessionFsExistsRequest { /** - * Message describing what information is needed from the user + * Target session identifier */ - message: string; + sessionId: string; /** - * JSON Schema describing the form fields to present to the user - */ - requestedSchema: { - /** - * Schema type indicator (always 'object') - */ - type: "object"; - /** - * Form field definitions, keyed by field name - */ - properties: { - [k: string]: - | UIElicitationStringEnumField - | UIElicitationStringOneOfField - | UIElicitationArrayEnumField - | UIElicitationArrayAnyOfField - | { - type: "boolean"; - description?: string; - default?: boolean; - } - | { - type: "string"; - description?: string; - minLength?: number; - maxLength?: number; - format?: "email" | "uri" | "date" | "date-time"; - default?: string; - } - | { - type: "number" | "integer"; - description?: string; - minimum?: number; - maximum?: number; - default?: number; - }; - }; - /** - * List of required field names - */ - required?: string[]; - }; + * Path using SessionFs conventions + */ + path: string; } -export interface LogResult { +export interface SessionFsExistsResult { /** - * The unique identifier of the emitted session event + * Whether the path exists */ - eventId: string; + exists: boolean; } -export interface LogRequest { - /** - * Human-readable message - */ - message: string; +export interface SessionFsMkdirRequest { /** - * Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". + * Target session identifier */ - level?: "info" | "warning" | "error"; + sessionId: string; /** - * When true, the message is transient and not persisted to the session event log on disk + * Path using SessionFs conventions */ - ephemeral?: boolean; + path: string; /** - * Optional URL the user can open in their browser for more details + * Create parent directories as needed */ - url?: string; -} - -export interface ShellExecResult { + recursive?: boolean; /** - * Unique identifier for tracking streamed output + * Optional POSIX-style mode for newly created directories */ - processId: string; + mode?: number; } -export interface ShellExecRequest { +export interface SessionFsReaddirRequest { /** - * Shell command to execute + * Target session identifier */ - command: string; + sessionId: string; /** - * Working directory (defaults to session working directory) + * Path using SessionFs conventions */ - cwd?: string; + path: string; +} + +export interface SessionFsReaddirResult { /** - * Timeout in milliseconds (default: 30000) + * Entry names in the directory */ - timeout?: number; + entries: string[]; + error?: SessionFsError; } -export interface ShellKillResult { +export interface SessionFsReaddirWithTypesEntry { /** - * Whether the signal was sent successfully + * Entry name */ - killed: boolean; + name: string; + type: SessionFsReaddirWithTypesEntryType; } -export interface ShellKillRequest { +export interface SessionFsReaddirWithTypesRequest { /** - * Process identifier returned by shell.exec + * Target session identifier */ - processId: string; + sessionId: string; /** - * Signal to send (default: SIGTERM) + * Path using SessionFs conventions */ - signal?: "SIGTERM" | "SIGKILL" | "SIGINT"; + path: string; } -/** @experimental */ -export interface HistoryCompactResult { +export interface SessionFsReaddirWithTypesResult { /** - * Whether compaction completed successfully + * Directory entries with type information */ - success: boolean; + entries: SessionFsReaddirWithTypesEntry[]; + error?: SessionFsError; +} + +export interface SessionFsReadFileRequest { /** - * Number of tokens freed by compaction + * Target session identifier */ - tokensRemoved: number; + sessionId: string; /** - * Number of messages removed during compaction + * Path using SessionFs conventions */ - messagesRemoved: number; - /** - * Post-compaction context window usage breakdown - */ - contextWindow?: { - /** - * Maximum token count for the model's context window - */ - tokenLimit: number; - /** - * Current total tokens in the context window (system + conversation + tool definitions) - */ - currentTokens: number; - /** - * Current number of messages in the conversation - */ - messagesLength: number; - /** - * Token count from system message(s) - */ - systemTokens?: number; - /** - * Token count from non-system messages (user, assistant, tool) - */ - conversationTokens?: number; - /** - * Token count from tool definitions - */ - toolDefinitionsTokens?: number; - }; + path: string; } -/** @experimental */ -export interface HistoryTruncateResult { +export interface SessionFsReadFileResult { /** - * Number of events that were removed + * File content as UTF-8 string */ - eventsRemoved: number; + content: string; + error?: SessionFsError; } -/** @experimental */ -export interface HistoryTruncateRequest { +export interface SessionFsRenameRequest { /** - * Event ID to truncate to. This event and all events after it are removed from the session. + * Target session identifier */ - eventId: string; -} - -/** @experimental */ -export interface UsageGetMetricsResult { + sessionId: string; /** - * Total user-initiated premium request cost across all models (may be fractional due to multipliers) + * Source path using SessionFs conventions */ - totalPremiumRequestCost: number; + src: string; /** - * Raw count of user-initiated API requests + * Destination path using SessionFs conventions */ - totalUserRequests: number; + dest: string; +} + +export interface SessionFsRmRequest { /** - * Total time spent in model API calls (milliseconds) + * Target session identifier */ - totalApiDurationMs: number; + sessionId: string; /** - * Session start timestamp (epoch milliseconds) + * Path using SessionFs conventions */ - sessionStartTime: number; - /** - * Aggregated code change metrics - */ - codeChanges: { - /** - * Total lines of code added - */ - linesAdded: number; - /** - * Total lines of code removed - */ - linesRemoved: number; - /** - * Number of distinct files modified - */ - filesModifiedCount: number; - }; + path: string; /** - * Per-model token and request metrics, keyed by model identifier + * Remove directories and their contents recursively */ - modelMetrics: { - [k: string]: { - /** - * Request count and cost metrics for this model - */ - requests: { - /** - * Number of API requests made with this model - */ - count: number; - /** - * User-initiated premium request cost (with multiplier applied) - */ - cost: number; - }; - /** - * Token usage metrics for this model - */ - usage: { - /** - * Total input tokens consumed - */ - inputTokens: number; - /** - * Total output tokens produced - */ - outputTokens: number; - /** - * Total tokens read from prompt cache - */ - cacheReadTokens: number; - /** - * Total tokens written to prompt cache - */ - cacheWriteTokens: number; - /** - * Total output tokens used for reasoning - */ - reasoningTokens?: number; - }; - }; - }; + recursive?: boolean; /** - * Currently active model identifier + * Ignore errors if the path does not exist */ - currentModel?: string; + force?: boolean; +} + +export interface SessionFsSetProviderRequest { /** - * Input tokens from the most recent main-agent API call + * Initial working directory for sessions */ - lastCallInputTokens: number; + initialCwd: string; /** - * Output tokens from the most recent main-agent API call + * Path within each session's SessionFs where the runtime stores files for that session */ - lastCallOutputTokens: number; + sessionStatePath: string; + conventions: SessionFsSetProviderConventions; } -export interface SessionFsReadFileResult { +export interface SessionFsSetProviderResult { /** - * File content as UTF-8 string + * Whether the provider was set successfully */ - content: string; + success: boolean; } -export interface SessionFsReadFileRequest { +export interface SessionFsStatRequest { /** * Target session identifier */ @@ -1780,26 +1211,31 @@ export interface SessionFsReadFileRequest { path: string; } -export interface SessionFsWriteFileRequest { +export interface SessionFsStatResult { /** - * Target session identifier + * Whether the path is a file */ - sessionId: string; + isFile: boolean; /** - * Path using SessionFs conventions + * Whether the path is a directory */ - path: string; + isDirectory: boolean; /** - * Content to write + * File size in bytes */ - content: string; + size: number; /** - * Optional POSIX-style mode for newly created files + * ISO 8601 timestamp of last modification */ - mode?: number; + mtime: string; + /** + * ISO 8601 timestamp of creation + */ + birthtime: string; + error?: SessionFsError; } -export interface SessionFsAppendFileRequest { +export interface SessionFsWriteFileRequest { /** * Target session identifier */ @@ -1809,7 +1245,7 @@ export interface SessionFsAppendFileRequest { */ path: string; /** - * Content to append + * Content to write */ content: string; /** @@ -1818,511 +1254,513 @@ export interface SessionFsAppendFileRequest { mode?: number; } -export interface SessionFsExistsResult { - /** - * Whether the path exists - */ - exists: boolean; -} - -export interface SessionFsExistsRequest { +/** @experimental */ +export interface SessionsForkRequest { /** - * Target session identifier + * Source session ID to fork from */ sessionId: string; /** - * Path using SessionFs conventions - */ - path: string; -} - -export interface SessionFsStatResult { - /** - * Whether the path is a file - */ - isFile: boolean; - /** - * Whether the path is a directory - */ - isDirectory: boolean; - /** - * File size in bytes - */ - size: number; - /** - * ISO 8601 timestamp of last modification - */ - mtime: string; - /** - * ISO 8601 timestamp of creation + * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. */ - birthtime: string; + toEventId?: string; } -export interface SessionFsStatRequest { +/** @experimental */ +export interface SessionsForkResult { /** - * Target session identifier + * The new forked session's ID */ sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; } -export interface SessionFsMkdirRequest { - /** - * Target session identifier - */ - sessionId: string; +export interface ShellExecRequest { /** - * Path using SessionFs conventions + * Shell command to execute */ - path: string; + command: string; /** - * Create parent directories as needed + * Working directory (defaults to session working directory) */ - recursive?: boolean; + cwd?: string; /** - * Optional POSIX-style mode for newly created directories + * Timeout in milliseconds (default: 30000) */ - mode?: number; + timeout?: number; } -export interface SessionFsReaddirResult { +export interface ShellExecResult { /** - * Entry names in the directory + * Unique identifier for tracking streamed output */ - entries: string[]; + processId: string; } -export interface SessionFsReaddirRequest { - /** - * Target session identifier - */ - sessionId: string; +export interface ShellKillRequest { /** - * Path using SessionFs conventions + * Process identifier returned by shell.exec */ - path: string; + processId: string; + signal?: ShellKillSignal; } -export interface SessionFsReaddirWithTypesResult { +export interface ShellKillResult { /** - * Directory entries with type information + * Whether the signal was sent successfully */ - entries: { - /** - * Entry name - */ - name: string; - /** - * Entry type - */ - type: "file" | "directory"; - }[]; + killed: boolean; } -export interface SessionFsReaddirWithTypesRequest { +export interface Skill { /** - * Target session identifier + * Unique identifier for the skill */ - sessionId: string; + name: string; /** - * Path using SessionFs conventions + * Description of what the skill does */ - path: string; -} - -export interface SessionFsRmRequest { + description: string; /** - * Target session identifier + * Source location type (e.g., project, personal, plugin) */ - sessionId: string; + source: string; /** - * Path using SessionFs conventions + * Whether the skill can be invoked by the user as a slash command */ - path: string; + userInvocable: boolean; /** - * Remove directories and their contents recursively + * Whether the skill is currently enabled */ - recursive?: boolean; + enabled: boolean; /** - * Ignore errors if the path does not exist + * Absolute path to the skill file */ - force?: boolean; + path?: string; } -export interface SessionFsRenameRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Source path using SessionFs conventions - */ - src: string; - /** - * Destination path using SessionFs conventions - */ - dest: string; -} -/** - * Model capabilities and limits - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_ModelCapabilities". - */ -export interface $Defs_ModelCapabilities { - /** - * Feature flags indicating what the model supports - */ - supports?: { - /** - * Whether this model supports vision/image input - */ - vision?: boolean; - /** - * Whether this model supports reasoning effort configuration - */ - reasoningEffort?: boolean; - }; - /** - * Token limits for prompts, outputs, and context window - */ - limits?: { - /** - * Maximum number of prompt/input tokens - */ - max_prompt_tokens?: number; - /** - * Maximum number of output/completion tokens - */ - max_output_tokens?: number; - /** - * Maximum total context window size in tokens - */ - max_context_window_tokens?: number; - vision?: ModelCapabilitiesLimitsVision2; - }; -} -/** - * Vision-specific limits - */ -export interface ModelCapabilitiesLimitsVision2 { - /** - * MIME types the model accepts - */ - supported_media_types: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images: number; +/** @experimental */ +export interface SkillList { /** - * Maximum image size in bytes + * Available skills */ - max_prompt_image_size: number; + skills: Skill[]; } -/** - * Vision-specific limits - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_ModelCapabilitiesLimitsVision". - */ -export interface $Defs_ModelCapabilitiesLimitsVision { - /** - * MIME types the model accepts - */ - supported_media_types: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images: number; + +export interface SkillsConfigSetDisabledSkillsRequest { /** - * Maximum image size in bytes + * List of skill names to disable */ - max_prompt_image_size: number; + disabledSkills: string[]; } -export interface $Defs_DiscoveredMcpServer { +/** @experimental */ +export interface SkillsDisableRequest { /** - * Server name (config key) + * Name of the skill to disable */ name: string; +} + +export interface SkillsDiscoverRequest { /** - * Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio) - */ - type?: "stdio" | "http" | "sse" | "memory"; - /** - * Configuration source + * Optional list of project directory paths to scan for project-scoped skills */ - source: "user" | "workspace" | "plugin" | "builtin"; + projectPaths?: string[]; /** - * Whether the server is enabled (not in the disabled list) + * Optional list of additional skill directory paths to include */ - enabled: boolean; + skillDirectories?: string[]; } -export interface $Defs_ServerSkillList { +/** @experimental */ +export interface SkillsEnableRequest { /** - * All discovered skills across all sources + * Name of the skill to enable */ - skills: ServerSkill[]; + name: string; } -export interface $Defs_ServerSkill { +export interface Tool { /** - * Unique identifier for the skill + * Tool identifier (e.g., "bash", "grep", "str_replace_editor") */ name: string; /** - * Description of what the skill does + * Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools) */ - description: string; + namespacedName?: string; /** - * Source location type (e.g., project, personal-copilot, plugin, builtin) + * Description of what the tool does */ - source: string; + description: string; /** - * Whether the skill can be invoked by the user as a slash command + * JSON Schema for the tool's input parameters */ - userInvocable: boolean; + parameters?: { + [k: string]: unknown; + }; /** - * Whether the skill is currently enabled (based on global config) + * Optional instructions for how to use this tool effectively */ - enabled: boolean; + instructions?: string; +} + +export interface ToolCallResult { /** - * Absolute path to the skill file + * Text result to send back to the LLM */ - path?: string; + textResultForLlm: string; /** - * The project path this skill belongs to (only for project/inherited skills) + * Type of the tool result */ - projectPath?: string; -} - -export interface $Defs_CurrentModel { + resultType?: string; /** - * Currently active model identifier + * Error message if the tool call failed */ - modelId?: string; -} -/** - * Override individual model capabilities resolved by the runtime - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_ModelCapabilitiesOverride". - */ -export interface $Defs_ModelCapabilitiesOverride { + error?: string; /** - * Feature flags indicating what the model supports + * Telemetry data from tool execution */ - supports?: { - vision?: boolean; - reasoningEffort?: boolean; - }; - /** - * Token limits for prompts, outputs, and context window - */ - limits?: { - max_prompt_tokens?: number; - max_output_tokens?: number; - /** - * Maximum total context window size in tokens - */ - max_context_window_tokens?: number; - vision?: { - /** - * MIME types the model accepts - */ - supported_media_types?: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images?: number; - /** - * Maximum image size in bytes - */ - max_prompt_image_size?: number; - }; + toolTelemetry?: { + [k: string]: unknown; }; } -export interface $Defs_AgentInfo { +export interface ToolList { /** - * Unique identifier of the custom agent + * List of available built-in tools with metadata */ - name: string; + tools: Tool[]; +} + +export interface ToolsHandlePendingToolCallRequest { /** - * Human-readable display name + * Request ID of the pending tool call */ - displayName: string; + requestId: string; + result?: ToolsHandlePendingToolCall; /** - * Description of the agent's purpose + * Error message if the tool call failed */ - description: string; + error?: string; } -export interface $Defs_McpServerList { - /** - * Configured MCP servers - */ - servers: { - /** - * Server name (config key) - */ - name: string; - /** - * Connection status: connected, failed, needs-auth, pending, disabled, or not_configured - */ - status: "connected" | "failed" | "needs-auth" | "pending" | "disabled" | "not_configured"; - /** - * Configuration source: user, workspace, plugin, or builtin - */ - source?: "user" | "workspace" | "plugin" | "builtin"; - /** - * Error message if the server failed to connect - */ - error?: string; - }[]; -} - -export interface $Defs_ToolCallResult { +export interface ToolsListRequest { /** - * Text result to send back to the LLM + * Optional model ID — when provided, the returned tool list reflects model-specific overrides */ - textResultForLlm: string; + model?: string; +} + +export interface UIElicitationArrayAnyOfField { + type: "array"; + title?: string; + description?: string; + minItems?: number; + maxItems?: number; + items: UIElicitationArrayAnyOfFieldItems; + default?: string[]; +} + +export interface UIElicitationArrayAnyOfFieldItems { + anyOf: UIElicitationArrayAnyOfFieldItemsAnyOf[]; +} + +export interface UIElicitationArrayAnyOfFieldItemsAnyOf { + const: string; + title: string; +} + +export interface UIElicitationArrayEnumField { + type: "array"; + title?: string; + description?: string; + minItems?: number; + maxItems?: number; + items: UIElicitationArrayEnumFieldItems; + default?: string[]; +} + +export interface UIElicitationArrayEnumFieldItems { + type: "string"; + enum: string[]; +} + +export interface UIElicitationRequest { /** - * Type of the tool result + * Message describing what information is needed from the user */ - resultType?: string; + message: string; + requestedSchema: UIElicitationSchema; +} +/** + * JSON Schema describing the form fields to present to the user + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIElicitationSchema". + */ +export interface UIElicitationSchema { /** - * Error message if the tool call failed + * Schema type indicator (always 'object') */ - error?: string; + type: "object"; /** - * Telemetry data from tool execution + * Form field definitions, keyed by field name */ - toolTelemetry?: { - [k: string]: unknown; + properties: { + [k: string]: UIElicitationSchemaProperty; }; -} - -export interface $Defs_HandleToolCallResult { /** - * Whether the tool call result was handled successfully + * List of required field names */ - success: boolean; + required?: string[]; } -export interface $Defs_UIElicitationStringEnumField { +export interface UIElicitationStringEnumField { type: "string"; + title?: string; description?: string; enum: string[]; enumNames?: string[]; default?: string; } -export interface $Defs_UIElicitationStringOneOfField { +export interface UIElicitationStringOneOfField { type: "string"; + title?: string; description?: string; - oneOf: { - const: string; - }[]; + oneOf: UIElicitationStringOneOfFieldOneOf[]; default?: string; } -export interface $Defs_UIElicitationArrayEnumField { - type: "array"; +export interface UIElicitationStringOneOfFieldOneOf { + const: string; + title: string; +} + +export interface UIElicitationSchemaPropertyBoolean { + type: "boolean"; + title?: string; description?: string; - minItems?: number; - maxItems?: number; - items: { - type: "string"; - enum: string[]; - }; - default?: string[]; + default?: boolean; } -export interface $Defs_UIElicitationArrayAnyOfField { - type: "array"; +export interface UIElicitationSchemaPropertyString { + type: "string"; + title?: string; description?: string; - minItems?: number; - maxItems?: number; - items: { - anyOf: { - const: string; - }[]; - }; - default?: string[]; + minLength?: number; + maxLength?: number; + format?: UIElicitationSchemaPropertyStringFormat; + default?: string; +} + +export interface UIElicitationSchemaPropertyNumber { + type: UIElicitationSchemaPropertyNumberType; + title?: string; + description?: string; + minimum?: number; + maximum?: number; + default?: number; } /** * The elicitation response (accept with form values, decline, or cancel) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_UIElicitationResponse". + * via the `definition` "UIElicitationResponse". */ -export interface $Defs_UIElicitationResponse { - /** - * The user's response: accept (submitted), decline (rejected), or cancel (dismissed) - */ - action: "accept" | "decline" | "cancel"; - content?: UIElicitationResponseContent2; +export interface UIElicitationResponse { + action: UIElicitationResponseAction; + content?: UIElicitationResponseContent; } /** * The form values submitted by the user (present when action is 'accept') + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIElicitationResponseContent". */ -export interface UIElicitationResponseContent2 { +export interface UIElicitationResponseContent { [k: string]: UIElicitationFieldValue; } + +export interface UIElicitationResult { + /** + * Whether the response was accepted. False if the request was already resolved by another client. + */ + success: boolean; +} + +export interface UIHandlePendingElicitationRequest { + /** + * The unique request ID from the elicitation.requested event + */ + requestId: string; + result: UIElicitationResponse; +} + +/** @experimental */ +export interface UsageGetMetricsResult { + /** + * Total user-initiated premium request cost across all models (may be fractional due to multipliers) + */ + totalPremiumRequestCost: number; + /** + * Raw count of user-initiated API requests + */ + totalUserRequests: number; + /** + * Total time spent in model API calls (milliseconds) + */ + totalApiDurationMs: number; + /** + * Session start timestamp (epoch milliseconds) + */ + sessionStartTime: number; + codeChanges: UsageMetricsCodeChanges; + /** + * Per-model token and request metrics, keyed by model identifier + */ + modelMetrics: { + [k: string]: UsageMetricsModelMetric; + }; + /** + * Currently active model identifier + */ + currentModel?: string; + /** + * Input tokens from the most recent main-agent API call + */ + lastCallInputTokens: number; + /** + * Output tokens from the most recent main-agent API call + */ + lastCallOutputTokens: number; +} /** - * The form values submitted by the user (present when action is 'accept') + * Aggregated code change metrics * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "$defs_UIElicitationResponseContent". + * via the `definition` "UsageMetricsCodeChanges". */ -export interface $Defs_UIElicitationResponseContent { - [k: string]: UIElicitationFieldValue; +export interface UsageMetricsCodeChanges { + /** + * Total lines of code added + */ + linesAdded: number; + /** + * Total lines of code removed + */ + linesRemoved: number; + /** + * Number of distinct files modified + */ + filesModifiedCount: number; } -export interface $Defs_UIHandlePendingElicitationRequest { +export interface UsageMetricsModelMetric { + requests: UsageMetricsModelMetricRequests; + usage: UsageMetricsModelMetricUsage; +} +/** + * Request count and cost metrics for this model + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UsageMetricsModelMetricRequests". + */ +export interface UsageMetricsModelMetricRequests { /** - * The unique request ID from the elicitation.requested event + * Number of API requests made with this model */ - requestId: string; - result: UIElicitationResponse2; + count: number; + /** + * User-initiated premium request cost (with multiplier applied) + */ + cost: number; } /** - * The elicitation response (accept with form values, decline, or cancel) + * Token usage metrics for this model + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UsageMetricsModelMetricUsage". */ -export interface UIElicitationResponse2 { +export interface UsageMetricsModelMetricUsage { /** - * The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + * Total input tokens consumed */ - action: "accept" | "decline" | "cancel"; - content?: UIElicitationResponseContent; + inputTokens: number; + /** + * Total output tokens produced + */ + outputTokens: number; + /** + * Total tokens read from prompt cache + */ + cacheReadTokens: number; + /** + * Total tokens written to prompt cache + */ + cacheWriteTokens: number; + /** + * Total output tokens used for reasoning + */ + reasoningTokens?: number; } -export interface $Defs_UIElicitationResult { +export interface WorkspacesCreateFileRequest { /** - * Whether the response was accepted. False if the request was already resolved by another client. + * Relative path within the workspace files directory */ - success: boolean; + path: string; + /** + * File content to write as a UTF-8 string + */ + content: string; } -export interface $Defs_PermissionDecisionRequest { +export interface WorkspacesGetWorkspaceResult { /** - * Request ID of the pending permission request + * Current workspace metadata, or null if not available */ - requestId: string; - result: PermissionDecision; + workspace: { + id: string; + cwd?: string; + git_root?: string; + repository?: string; + host_type?: "github" | "ado"; + branch?: string; + summary?: string; + name?: string; + summary_count?: number; + created_at?: string; + updated_at?: string; + remote_steerable?: boolean; + mc_task_id?: string; + mc_session_id?: string; + mc_last_event_id?: string; + session_sync_level?: "local" | "user" | "repo_and_user"; + chronicle_sync_dismissed?: boolean; + } | null; } -export interface $Defs_PermissionRequestResult { +export interface WorkspacesListFilesResult { /** - * Whether the permission request was handled successfully + * Relative file paths in the workspace files directory */ - success: boolean; + files: string[]; +} + +export interface WorkspacesReadFileRequest { + /** + * Relative path within the workspace files directory + */ + path: string; +} + +export interface WorkspacesReadFileResult { + /** + * File content as a UTF-8 string + */ + content: string; } /** Create typed server-scoped RPC methods (no session required). */ @@ -2519,15 +1957,15 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin /** Handler for `sessionFs` client session API methods. */ export interface SessionFsHandler { readFile(params: SessionFsReadFileRequest): Promise; - writeFile(params: SessionFsWriteFileRequest): Promise; - appendFile(params: SessionFsAppendFileRequest): Promise; + writeFile(params: SessionFsWriteFileRequest): Promise; + appendFile(params: SessionFsAppendFileRequest): Promise; exists(params: SessionFsExistsRequest): Promise; stat(params: SessionFsStatRequest): Promise; - mkdir(params: SessionFsMkdirRequest): Promise; + mkdir(params: SessionFsMkdirRequest): Promise; readdir(params: SessionFsReaddirRequest): Promise; readdirWithTypes(params: SessionFsReaddirWithTypesRequest): Promise; - rm(params: SessionFsRmRequest): Promise; - rename(params: SessionFsRenameRequest): Promise; + rm(params: SessionFsRmRequest): Promise; + rename(params: SessionFsRenameRequest): Promise; } /** All client session API handler groups. */ diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index d2de8d250..b35ab7c59 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -4,3955 +4,302 @@ */ export type SessionEvent = - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.start"; - /** - * Session initialization metadata including context and configuration - */ - data: { - /** - * Unique identifier for the session - */ - sessionId: string; - /** - * Schema version number for the session event format - */ - version: number; - /** - * Identifier of the software producing the events (e.g., "copilot-agent") - */ - producer: string; - /** - * Version string of the Copilot application - */ - copilotVersion: string; - /** - * ISO 8601 timestamp when the session was created - */ - startTime: string; - /** - * Model selected at session creation time, if any - */ - selectedModel?: string; - /** - * Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") - */ - reasoningEffort?: string; - context?: WorkingDirectoryContext; - /** - * Whether the session was already in use by another client at start time - */ - alreadyInUse?: boolean; - /** - * Whether this session supports remote steering via Mission Control - */ - remoteSteerable?: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.resume"; - /** - * Session resume metadata including current context and event count - */ - data: { - /** - * ISO 8601 timestamp when the session was resumed - */ - resumeTime: string; - /** - * Total number of persisted events in the session at the time of resume - */ - eventCount: number; - /** - * Model currently selected at resume time - */ - selectedModel?: string; - /** - * Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") - */ - reasoningEffort?: string; - context?: WorkingDirectoryContext1; - /** - * Whether the session was already in use by another client at resume time - */ - alreadyInUse?: boolean; - /** - * Whether this session supports remote steering via Mission Control - */ - remoteSteerable?: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.remote_steerable_changed"; - /** - * Notifies Mission Control that the session's remote steering capability has changed - */ - data: { - /** - * Whether this session now supports remote steering via Mission Control - */ - remoteSteerable: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.error"; - /** - * Error details for timeline display including message and optional diagnostic information - */ - data: { - /** - * Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") - */ - errorType: string; - /** - * Human-readable error message - */ - message: string; - /** - * Error stack trace, when available - */ - stack?: string; - /** - * HTTP status code from the upstream request, if applicable - */ - statusCode?: number; - /** - * GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs - */ - providerCallId?: string; - /** - * Optional URL associated with this error that the user can open in a browser - */ - url?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.idle"; - /** - * Payload indicating the session is idle with no background agents in flight - */ - data: { - /** - * True when the preceding agentic loop was cancelled via abort signal - */ - aborted?: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.title_changed"; - /** - * Session title change payload containing the new display title - */ - data: {}; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.info"; - /** - * Informational message for timeline display with categorization - */ - data: { - /** - * Category of informational message (e.g., "notification", "timing", "context_window", "mcp", "snapshot", "configuration", "authentication", "model") - */ - infoType: string; - /** - * Human-readable informational message for display in the timeline - */ - message: string; - /** - * Optional URL associated with this message that the user can open in a browser - */ - url?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.warning"; - /** - * Warning message for timeline display with categorization - */ - data: { - /** - * Category of warning (e.g., "subscription", "policy", "mcp") - */ - warningType: string; - /** - * Human-readable warning message for display in the timeline - */ - message: string; - /** - * Optional URL associated with this warning that the user can open in a browser - */ - url?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.model_change"; - /** - * Model change details including previous and new model identifiers - */ - data: { - /** - * Model that was previously selected, if any - */ - previousModel?: string; - /** - * Newly selected model identifier - */ - newModel: string; - /** - * Reasoning effort level before the model change, if applicable - */ - previousReasoningEffort?: string; - /** - * Reasoning effort level after the model change, if applicable - */ - reasoningEffort?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.mode_changed"; - /** - * Agent mode change details including previous and new modes - */ - data: { - /** - * Agent mode before the change (e.g., "interactive", "plan", "autopilot") - */ - previousMode: string; - /** - * Agent mode after the change (e.g., "interactive", "plan", "autopilot") - */ - newMode: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.plan_changed"; - /** - * Plan file operation details indicating what changed - */ - data: { - /** - * The type of operation performed on the plan file - */ - operation: "create" | "update" | "delete"; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.workspace_file_changed"; - /** - * Workspace file change details including path and operation type - */ - data: { - /** - * Relative path within the session workspace files directory - */ - path: string; - /** - * Whether the file was newly created or updated - */ - operation: "create" | "update"; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.handoff"; - /** - * Session handoff metadata including source, context, and repository information - */ - data: { - /** - * ISO 8601 timestamp when the handoff occurred - */ - handoffTime: string; - /** - * Origin type of the session being handed off - */ - sourceType: "remote" | "local"; - /** - * Repository context for the handed-off session - */ - repository?: { - /** - * Repository owner (user or organization) - */ - owner: string; - /** - * Repository name - */ - name: string; - /** - * Git branch name, if applicable - */ - branch?: string; - }; - /** - * Additional context information for the handoff - */ - context?: string; - /** - * Summary of the work done in the source session - */ - summary?: string; - /** - * Session ID of the remote session being handed off - */ - remoteSessionId?: string; - /** - * GitHub host URL for the source session (e.g., https://github.com or https://tenant.ghe.com) - */ - host?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.truncation"; - /** - * Conversation truncation statistics including token counts and removed content metrics - */ - data: { - /** - * Maximum token count for the model's context window - */ - tokenLimit: number; - /** - * Total tokens in conversation messages before truncation - */ - preTruncationTokensInMessages: number; - /** - * Number of conversation messages before truncation - */ - preTruncationMessagesLength: number; - /** - * Total tokens in conversation messages after truncation - */ - postTruncationTokensInMessages: number; - /** - * Number of conversation messages after truncation - */ - postTruncationMessagesLength: number; - /** - * Number of tokens removed by truncation - */ - tokensRemovedDuringTruncation: number; - /** - * Number of messages removed by truncation - */ - messagesRemovedDuringTruncation: number; - /** - * Identifier of the component that performed truncation (e.g., "BasicTruncator") - */ - performedBy: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.snapshot_rewind"; - /** - * Session rewind details including target event and count of removed events - */ - data: { - /** - * Event ID that was rewound to; this event and all after it were removed - */ - upToEventId: string; - /** - * Number of events that were removed by the rewind - */ - eventsRemoved: number; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.shutdown"; - /** - * Session termination metrics including usage statistics, code changes, and shutdown reason - */ - data: { - /** - * Whether the session ended normally ("routine") or due to a crash/fatal error ("error") - */ - shutdownType: "routine" | "error"; - /** - * Error description when shutdownType is "error" - */ - errorReason?: string; - /** - * Total number of premium API requests used during the session - */ - totalPremiumRequests: number; - /** - * Cumulative time spent in API calls during the session, in milliseconds - */ - totalApiDurationMs: number; - /** - * Unix timestamp (milliseconds) when the session started - */ - sessionStartTime: number; - /** - * Aggregate code change metrics for the session - */ - codeChanges: { - /** - * Total number of lines added during the session - */ - linesAdded: number; - /** - * Total number of lines removed during the session - */ - linesRemoved: number; - /** - * List of file paths that were modified during the session - */ - filesModified: string[]; - }; - /** - * Per-model usage breakdown, keyed by model identifier - */ - modelMetrics: { - [k: string]: { - /** - * Request count and cost metrics - */ - requests: { - /** - * Total number of API requests made to this model - */ - count: number; - /** - * Cumulative cost multiplier for requests to this model - */ - cost: number; - }; - /** - * Token usage breakdown - */ - usage: { - /** - * Total input tokens consumed across all requests to this model - */ - inputTokens: number; - /** - * Total output tokens produced across all requests to this model - */ - outputTokens: number; - /** - * Total tokens read from prompt cache across all requests - */ - cacheReadTokens: number; - /** - * Total tokens written to prompt cache across all requests - */ - cacheWriteTokens: number; - /** - * Total reasoning tokens produced across all requests to this model - */ - reasoningTokens?: number; - }; - }; - }; - /** - * Model that was selected at the time of shutdown - */ - currentModel?: string; - /** - * Total tokens in context window at shutdown - */ - currentTokens?: number; - /** - * System message token count at shutdown - */ - systemTokens?: number; - /** - * Non-system message token count at shutdown - */ - conversationTokens?: number; - /** - * Tool definitions token count at shutdown - */ - toolDefinitionsTokens?: number; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.context_changed"; - data: WorkingDirectoryContext2; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.usage_info"; - /** - * Current context window usage statistics including token and message counts - */ - data: { - /** - * Maximum token count for the model's context window - */ - tokenLimit: number; - /** - * Current number of tokens in the context window - */ - currentTokens: number; - /** - * Current number of messages in the conversation - */ - messagesLength: number; - /** - * Token count from system message(s) - */ - systemTokens?: number; - /** - * Token count from non-system messages (user, assistant, tool) - */ - conversationTokens?: number; - /** - * Token count from tool definitions - */ - toolDefinitionsTokens?: number; - /** - * Whether this is the first usage_info event emitted in this session - */ - isInitial?: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.compaction_start"; - /** - * Context window breakdown at the start of LLM-powered conversation compaction - */ - data: { - /** - * Token count from system message(s) at compaction start - */ - systemTokens?: number; - /** - * Token count from non-system messages (user, assistant, tool) at compaction start - */ - conversationTokens?: number; - /** - * Token count from tool definitions at compaction start - */ - toolDefinitionsTokens?: number; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.compaction_complete"; - /** - * Conversation compaction results including success status, metrics, and optional error details - */ - data: { - /** - * Whether compaction completed successfully - */ - success: boolean; - /** - * Error message if compaction failed - */ - error?: string; - /** - * Total tokens in conversation before compaction - */ - preCompactionTokens?: number; - /** - * Total tokens in conversation after compaction - */ - postCompactionTokens?: number; - /** - * Number of messages before compaction - */ - preCompactionMessagesLength?: number; - /** - * Number of messages removed during compaction - */ - messagesRemoved?: number; - /** - * Number of tokens removed during compaction - */ - tokensRemoved?: number; - /** - * LLM-generated summary of the compacted conversation history - */ - summaryContent?: string; - /** - * Checkpoint snapshot number created for recovery - */ - checkpointNumber?: number; - /** - * File path where the checkpoint was stored - */ - checkpointPath?: string; - /** - * Token usage breakdown for the compaction LLM call - */ - compactionTokensUsed?: { - /** - * Input tokens consumed by the compaction LLM call - */ - input: number; - /** - * Output tokens produced by the compaction LLM call - */ - output: number; - /** - * Cached input tokens reused in the compaction LLM call - */ - cachedInput: number; - }; - /** - * GitHub request tracing ID (x-github-request-id header) for the compaction LLM call - */ - requestId?: string; - /** - * Token count from system message(s) after compaction - */ - systemTokens?: number; - /** - * Token count from non-system messages (user, assistant, tool) after compaction - */ - conversationTokens?: number; - /** - * Token count from tool definitions after compaction - */ - toolDefinitionsTokens?: number; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.task_complete"; - /** - * Task completion notification with summary from the agent - */ - data: { - /** - * Summary of the completed task, provided by the agent - */ - summary?: string; - /** - * Whether the tool call succeeded. False when validation failed (e.g., invalid arguments) - */ - success?: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "user.message"; - data: { - /** - * The user's message text as displayed in the timeline - */ - content: string; - /** - * Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching - */ - transformedContent?: string; - /** - * Files, selections, or GitHub references attached to the message - */ - attachments?: ( - | { - /** - * Attachment type discriminator - */ - type: "file"; - /** - * Absolute file path - */ - path: string; - /** - * User-facing display name for the attachment - */ - displayName: string; - /** - * Optional line range to scope the attachment to a specific section of the file - */ - lineRange?: { - /** - * Start line number (1-based) - */ - start: number; - /** - * End line number (1-based, inclusive) - */ - end: number; - }; - } - | { - /** - * Attachment type discriminator - */ - type: "directory"; - /** - * Absolute directory path - */ - path: string; - /** - * User-facing display name for the attachment - */ - displayName: string; - } - | { - /** - * Attachment type discriminator - */ - type: "selection"; - /** - * Absolute path to the file containing the selection - */ - filePath: string; - /** - * User-facing display name for the selection - */ - displayName: string; - /** - * The selected text content - */ - text: string; - /** - * Position range of the selection within the file - */ - selection: { - /** - * Start position of the selection - */ - start: { - /** - * Start line number (0-based) - */ - line: number; - /** - * Start character offset within the line (0-based) - */ - character: number; - }; - /** - * End position of the selection - */ - end: { - /** - * End line number (0-based) - */ - line: number; - /** - * End character offset within the line (0-based) - */ - character: number; - }; - }; - } - | { - /** - * Attachment type discriminator - */ - type: "github_reference"; - /** - * Issue, pull request, or discussion number - */ - number: number; - /** - * Type of GitHub reference - */ - referenceType: "issue" | "pr" | "discussion"; - /** - * Current state of the referenced item (e.g., open, closed, merged) - */ - state: string; - /** - * URL to the referenced item on GitHub - */ - url: string; - } - | { - /** - * Attachment type discriminator - */ - type: "blob"; - /** - * Base64-encoded content - */ - data: string; - /** - * MIME type of the inline data - */ - mimeType: string; - /** - * User-facing display name for the attachment - */ - displayName?: string; - } - )[]; - /** - * Normalized document MIME types that were sent natively instead of through tagged_files XML - */ - supportedNativeDocumentMimeTypes?: string[]; - /** - * Path-backed native document attachments that stayed on the tagged_files path flow because native upload would exceed the request size limit - */ - nativeDocumentPathFallbackPaths?: string[]; - /** - * Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user) - */ - source?: string; - /** - * The agent mode that was active when this message was sent - */ - agentMode?: "interactive" | "plan" | "autopilot" | "shell"; - /** - * CAPI interaction ID for correlating this user message with its turn - */ - interactionId?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "pending_messages.modified"; - /** - * Empty payload; the event signals that the pending message queue has changed - */ - data: {}; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.turn_start"; - /** - * Turn initialization metadata including identifier and interaction tracking - */ - data: { - /** - * Identifier for this turn within the agentic loop, typically a stringified turn number - */ - turnId: string; - /** - * CAPI interaction ID for correlating this turn with upstream telemetry - */ - interactionId?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.intent"; - /** - * Agent intent description for current activity or plan - */ - data: { - /** - * Short description of what the agent is currently doing or planning to do - */ - intent: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.reasoning"; - /** - * Assistant reasoning content for timeline display with complete thinking text - */ - data: { - /** - * Unique identifier for this reasoning block - */ - reasoningId: string; - /** - * The complete extended thinking text from the model - */ - content: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.reasoning_delta"; - /** - * Streaming reasoning delta for incremental extended thinking updates - */ - data: { - /** - * Reasoning block ID this delta belongs to, matching the corresponding assistant.reasoning event - */ - reasoningId: string; - /** - * Incremental text chunk to append to the reasoning content - */ - deltaContent: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.streaming_delta"; - /** - * Streaming response progress with cumulative byte count - */ - data: { - /** - * Cumulative total bytes received from the streaming response so far - */ - totalResponseSizeBytes: number; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.message"; - /** - * Assistant response containing text content, optional tool requests, and interaction metadata - */ - data: { - /** - * Unique identifier for this assistant message - */ - messageId: string; - /** - * The assistant's text response content - */ - content: string; - /** - * Tool invocations requested by the assistant in this message - */ - toolRequests?: { - /** - * Unique identifier for this tool call - */ - toolCallId: string; - /** - * Name of the tool being invoked - */ - name: string; - /** - * Arguments to pass to the tool, format depends on the tool - */ - arguments?: { - [k: string]: unknown; - }; - /** - * Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. - */ - type?: "function" | "custom"; - /** - * Human-readable display title for the tool - */ - toolTitle?: string; - /** - * Name of the MCP server hosting this tool, when the tool is an MCP tool - */ - mcpServerName?: string; - /** - * Resolved intention summary describing what this specific call does - */ - intentionSummary?: string | null; - }[]; - /** - * Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. - */ - reasoningOpaque?: string; - /** - * Readable reasoning text from the model's extended thinking - */ - reasoningText?: string; - /** - * Encrypted reasoning content from OpenAI models. Session-bound and stripped on resume. - */ - encryptedContent?: string; - /** - * Generation phase for phased-output models (e.g., thinking vs. response phases) - */ - phase?: string; - /** - * Actual output token count from the API response (completion_tokens), used for accurate token accounting - */ - outputTokens?: number; - /** - * CAPI interaction ID for correlating this message with upstream telemetry - */ - interactionId?: string; - /** - * GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs - */ - requestId?: string; - /** - * @deprecated - * Tool call ID of the parent tool invocation when this event originates from a sub-agent - */ - parentToolCallId?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.message_delta"; - /** - * Streaming assistant message delta for incremental response updates - */ - data: { - /** - * Message ID this delta belongs to, matching the corresponding assistant.message event - */ - messageId: string; - /** - * Incremental text chunk to append to the message content - */ - deltaContent: string; - /** - * @deprecated - * Tool call ID of the parent tool invocation when this event originates from a sub-agent - */ - parentToolCallId?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.turn_end"; - /** - * Turn completion metadata including the turn identifier - */ - data: { - /** - * Identifier of the turn that has ended, matching the corresponding assistant.turn_start event - */ - turnId: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "assistant.usage"; - /** - * LLM API call usage metrics including tokens, costs, quotas, and billing information - */ - data: { - /** - * Model identifier used for this API call - */ - model: string; - /** - * Number of input tokens consumed - */ - inputTokens?: number; - /** - * Number of output tokens produced - */ - outputTokens?: number; - /** - * Number of tokens read from prompt cache - */ - cacheReadTokens?: number; - /** - * Number of tokens written to prompt cache - */ - cacheWriteTokens?: number; - /** - * Number of output tokens used for reasoning (e.g., chain-of-thought) - */ - reasoningTokens?: number; - /** - * Model multiplier cost for billing purposes - */ - cost?: number; - /** - * Duration of the API call in milliseconds - */ - duration?: number; - /** - * Time to first token in milliseconds. Only available for streaming requests - */ - ttftMs?: number; - /** - * Average inter-token latency in milliseconds. Only available for streaming requests - */ - interTokenLatencyMs?: number; - /** - * What initiated this API call (e.g., "sub-agent", "mcp-sampling"); absent for user-initiated calls - */ - initiator?: string; - /** - * Completion ID from the model provider (e.g., chatcmpl-abc123) - */ - apiCallId?: string; - /** - * GitHub request tracing ID (x-github-request-id header) for server-side log correlation - */ - providerCallId?: string; - /** - * @deprecated - * Parent tool call ID when this usage originates from a sub-agent - */ - parentToolCallId?: string; - /** - * Per-quota resource usage snapshots, keyed by quota identifier - */ - quotaSnapshots?: { - [k: string]: { - /** - * Whether the user has an unlimited usage entitlement - */ - isUnlimitedEntitlement: boolean; - /** - * Total requests allowed by the entitlement - */ - entitlementRequests: number; - /** - * Number of requests already consumed - */ - usedRequests: number; - /** - * Whether usage is still permitted after quota exhaustion - */ - usageAllowedWithExhaustedQuota: boolean; - /** - * Number of requests over the entitlement limit - */ - overage: number; - /** - * Whether overage is allowed when quota is exhausted - */ - overageAllowedWithExhaustedQuota: boolean; - /** - * Percentage of quota remaining (0.0 to 1.0) - */ - remainingPercentage: number; - /** - * Date when the quota resets - */ - resetDate?: string; - }; - }; - /** - * Per-request cost and usage data from the CAPI copilot_usage response field - */ - copilotUsage?: { - /** - * Itemized token usage breakdown - */ - tokenDetails: { - /** - * Number of tokens in this billing batch - */ - batchSize: number; - /** - * Cost per batch of tokens - */ - costPerBatch: number; - /** - * Total token count for this entry - */ - tokenCount: number; - /** - * Token category (e.g., "input", "output") - */ - tokenType: string; - }[]; - /** - * Total cost in nano-AIU (AI Units) for this request - */ - totalNanoAiu: number; - }; - /** - * Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") - */ - reasoningEffort?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "abort"; - /** - * Turn abort information including the reason for termination - */ - data: { - /** - * Reason the current turn was aborted (e.g., "user initiated") - */ - reason: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "tool.user_requested"; - /** - * User-initiated tool invocation request with tool name and arguments - */ - data: { - /** - * Unique identifier for this tool call - */ - toolCallId: string; - /** - * Name of the tool the user wants to invoke - */ - toolName: string; - /** - * Arguments for the tool invocation - */ - arguments?: { - [k: string]: unknown; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "tool.execution_start"; - /** - * Tool execution startup details including MCP server information when applicable - */ - data: { - /** - * Unique identifier for this tool call - */ - toolCallId: string; - /** - * Name of the tool being executed - */ - toolName: string; - /** - * Arguments passed to the tool - */ - arguments?: { - [k: string]: unknown; - }; - /** - * Name of the MCP server hosting this tool, when the tool is an MCP tool - */ - mcpServerName?: string; - /** - * Original tool name on the MCP server, when the tool is an MCP tool - */ - mcpToolName?: string; - /** - * @deprecated - * Tool call ID of the parent tool invocation when this event originates from a sub-agent - */ - parentToolCallId?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "tool.execution_partial_result"; - /** - * Streaming tool execution output for incremental result display - */ - data: { - /** - * Tool call ID this partial result belongs to - */ - toolCallId: string; - /** - * Incremental output chunk from the running tool - */ - partialOutput: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "tool.execution_progress"; - /** - * Tool execution progress notification with status message - */ - data: { - /** - * Tool call ID this progress notification belongs to - */ - toolCallId: string; - /** - * Human-readable progress status message (e.g., from an MCP server) - */ - progressMessage: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "tool.execution_complete"; - /** - * Tool execution completion results including success status, detailed output, and error information - */ - data: { - /** - * Unique identifier for the completed tool call - */ - toolCallId: string; - /** - * Whether the tool execution completed successfully - */ - success: boolean; - /** - * Model identifier that generated this tool call - */ - model?: string; - /** - * CAPI interaction ID for correlating this tool execution with upstream telemetry - */ - interactionId?: string; - /** - * Whether this tool call was explicitly requested by the user rather than the assistant - */ - isUserRequested?: boolean; - /** - * Tool execution result on success - */ - result?: { - /** - * Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency - */ - content: string; - /** - * Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. - */ - detailedContent?: string; - /** - * Structured content blocks (text, images, audio, resources) returned by the tool in their native format - */ - contents?: ( - | { - /** - * Content block type discriminator - */ - type: "text"; - /** - * The text content - */ - text: string; - } - | { - /** - * Content block type discriminator - */ - type: "terminal"; - /** - * Terminal/shell output text - */ - text: string; - /** - * Process exit code, if the command has completed - */ - exitCode?: number; - /** - * Working directory where the command was executed - */ - cwd?: string; - } - | { - /** - * Content block type discriminator - */ - type: "image"; - /** - * Base64-encoded image data - */ - data: string; - /** - * MIME type of the image (e.g., image/png, image/jpeg) - */ - mimeType: string; - } - | { - /** - * Content block type discriminator - */ - type: "audio"; - /** - * Base64-encoded audio data - */ - data: string; - /** - * MIME type of the audio (e.g., audio/wav, audio/mpeg) - */ - mimeType: string; - } - | { - /** - * Icons associated with this resource - */ - icons?: { - /** - * URL or path to the icon image - */ - src: string; - /** - * MIME type of the icon image - */ - mimeType?: string; - /** - * Available icon sizes (e.g., ['16x16', '32x32']) - */ - sizes?: string[]; - /** - * Theme variant this icon is intended for - */ - theme?: "light" | "dark"; - }[]; - /** - * Resource name identifier - */ - name: string; - /** - * URI identifying the resource - */ - uri: string; - /** - * Human-readable description of the resource - */ - description?: string; - /** - * MIME type of the resource content - */ - mimeType?: string; - /** - * Size of the resource in bytes - */ - size?: number; - /** - * Content block type discriminator - */ - type: "resource_link"; - } - | { - /** - * Content block type discriminator - */ - type: "resource"; - /** - * The embedded resource contents, either text or base64-encoded binary - */ - resource: EmbeddedTextResourceContents | EmbeddedBlobResourceContents; - } - )[]; - }; - /** - * Error details when the tool execution failed - */ - error?: { - /** - * Human-readable error message - */ - message: string; - /** - * Machine-readable error code - */ - code?: string; - }; - /** - * Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts) - */ - toolTelemetry?: { - [k: string]: unknown; - }; - /** - * @deprecated - * Tool call ID of the parent tool invocation when this event originates from a sub-agent - */ - parentToolCallId?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "skill.invoked"; - /** - * Skill invocation details including content, allowed tools, and plugin metadata - */ - data: { - /** - * Name of the invoked skill - */ - name: string; - /** - * File path to the SKILL.md definition - */ - path: string; - /** - * Full content of the skill file, injected into the conversation for the model - */ - content: string; - /** - * Tool names that should be auto-approved when this skill is active - */ - allowedTools?: string[]; - /** - * Name of the plugin this skill originated from, when applicable - */ - pluginName?: string; - /** - * Version of the plugin this skill originated from, when applicable - */ - pluginVersion?: string; - /** - * Description of the skill from its SKILL.md frontmatter - */ - description?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "subagent.started"; - /** - * Sub-agent startup details including parent tool call and agent information - */ - data: { - /** - * Tool call ID of the parent tool invocation that spawned this sub-agent - */ - toolCallId: string; - /** - * Internal name of the sub-agent - */ - agentName: string; - /** - * Human-readable display name of the sub-agent - */ - agentDisplayName: string; - /** - * Description of what the sub-agent does - */ - agentDescription: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "subagent.completed"; - /** - * Sub-agent completion details for successful execution - */ - data: { - /** - * Tool call ID of the parent tool invocation that spawned this sub-agent - */ - toolCallId: string; - /** - * Internal name of the sub-agent - */ - agentName: string; - /** - * Human-readable display name of the sub-agent - */ - agentDisplayName: string; - /** - * Model used by the sub-agent - */ - model?: string; - /** - * Total number of tool calls made by the sub-agent - */ - totalToolCalls?: number; - /** - * Total tokens (input + output) consumed by the sub-agent - */ - totalTokens?: number; - /** - * Wall-clock duration of the sub-agent execution in milliseconds - */ - durationMs?: number; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "subagent.failed"; - /** - * Sub-agent failure details including error message and agent information - */ - data: { - /** - * Tool call ID of the parent tool invocation that spawned this sub-agent - */ - toolCallId: string; - /** - * Internal name of the sub-agent - */ - agentName: string; - /** - * Human-readable display name of the sub-agent - */ - agentDisplayName: string; - /** - * Error message describing why the sub-agent failed - */ - error: string; - /** - * Model used by the sub-agent (if any model calls succeeded before failure) - */ - model?: string; - /** - * Total number of tool calls made before the sub-agent failed - */ - totalToolCalls?: number; - /** - * Total tokens (input + output) consumed before the sub-agent failed - */ - totalTokens?: number; - /** - * Wall-clock duration of the sub-agent execution in milliseconds - */ - durationMs?: number; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "subagent.selected"; - /** - * Custom agent selection details including name and available tools - */ - data: { - /** - * Internal name of the selected custom agent - */ - agentName: string; - /** - * Human-readable display name of the selected custom agent - */ - agentDisplayName: string; - /** - * List of tool names available to this agent, or null for all tools - */ - tools: string[] | null; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "subagent.deselected"; - /** - * Empty payload; the event signals that the custom agent was deselected, returning to the default agent - */ - data: {}; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "hook.start"; - /** - * Hook invocation start details including type and input data - */ - data: { - /** - * Unique identifier for this hook invocation - */ - hookInvocationId: string; - /** - * Type of hook being invoked (e.g., "preToolUse", "postToolUse", "sessionStart") - */ - hookType: string; - /** - * Input data passed to the hook - */ - input?: { - [k: string]: unknown; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "hook.end"; - /** - * Hook invocation completion details including output, success status, and error information - */ - data: { - /** - * Identifier matching the corresponding hook.start event - */ - hookInvocationId: string; - /** - * Type of hook that was invoked (e.g., "preToolUse", "postToolUse", "sessionStart") - */ - hookType: string; - /** - * Output data produced by the hook - */ - output?: { - [k: string]: unknown; - }; - /** - * Whether the hook completed successfully - */ - success: boolean; - /** - * Error details when the hook failed - */ - error?: { - /** - * Human-readable error message - */ - message: string; - /** - * Error stack trace, when available - */ - stack?: string; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "system.message"; - /** - * System/developer instruction content with role and optional template metadata - */ - data: { - /** - * The system or developer prompt text sent as model input - */ - content: string; - /** - * Message role: "system" for system prompts, "developer" for developer-injected instructions - */ - role: "system" | "developer"; - /** - * Optional name identifier for the message source - */ - name?: string; - /** - * Metadata about the prompt template and its construction - */ - metadata?: { - /** - * Version identifier of the prompt template used - */ - promptVersion?: string; - /** - * Template variables used when constructing the prompt - */ - variables?: { - [k: string]: unknown; - }; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - /** - * When true, the event is transient and not persisted to the session event log on disk - */ - ephemeral?: boolean; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "system.notification"; - /** - * System-generated notification for runtime events like background task completion - */ - data: { - /** - * The notification text, typically wrapped in XML tags - */ - content: string; - /** - * Structured metadata identifying what triggered this notification - */ - kind: - | { - type: "agent_completed"; - /** - * Unique identifier of the background agent - */ - agentId: string; - /** - * Type of the agent (e.g., explore, task, general-purpose) - */ - agentType: string; - /** - * Whether the agent completed successfully or failed - */ - status: "completed" | "failed"; - /** - * Human-readable description of the agent task - */ - description?: string; - /** - * The full prompt given to the background agent - */ - prompt?: string; - } - | { - type: "agent_idle"; - /** - * Unique identifier of the background agent - */ - agentId: string; - /** - * Type of the agent (e.g., explore, task, general-purpose) - */ - agentType: string; - /** - * Human-readable description of the agent task - */ - description?: string; - } - | { - type: "shell_completed"; - /** - * Unique identifier of the shell session - */ - shellId: string; - /** - * Exit code of the shell command, if available - */ - exitCode?: number; - /** - * Human-readable description of the command - */ - description?: string; - } - | { - type: "shell_detached_completed"; - /** - * Unique identifier of the detached shell session - */ - shellId: string; - /** - * Human-readable description of the command - */ - description?: string; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "permission.requested"; - /** - * Permission request notification requiring client approval with request details - */ - data: { - /** - * Unique identifier for this permission request; used to respond via session.respondToPermission() - */ - requestId: string; - /** - * Details of the permission being requested - */ - permissionRequest: - | { - /** - * Permission kind discriminator - */ - kind: "shell"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * The complete shell command text to be executed - */ - fullCommandText: string; - /** - * Human-readable description of what the command intends to do - */ - intention: string; - /** - * Parsed command identifiers found in the command text - */ - commands: { - /** - * Command identifier (e.g., executable name) - */ - identifier: string; - /** - * Whether this command is read-only (no side effects) - */ - readOnly: boolean; - }[]; - /** - * File paths that may be read or written by the command - */ - possiblePaths: string[]; - /** - * URLs that may be accessed by the command - */ - possibleUrls: { - /** - * URL that may be accessed by the command - */ - url: string; - }[]; - /** - * Whether the command includes a file write redirection (e.g., > or >>) - */ - hasWriteFileRedirection: boolean; - /** - * Whether the UI can offer session-wide approval for this command pattern - */ - canOfferSessionApproval: boolean; - /** - * Optional warning message about risks of running this command - */ - warning?: string; - } - | { - /** - * Permission kind discriminator - */ - kind: "write"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * Human-readable description of the intended file change - */ - intention: string; - /** - * Path of the file being written to - */ - fileName: string; - /** - * Unified diff showing the proposed changes - */ - diff: string; - /** - * Complete new file contents for newly created files - */ - newFileContents?: string; - /** - * Whether the UI can offer session-wide approval for file write operations - */ - canOfferSessionApproval: boolean; - } - | { - /** - * Permission kind discriminator - */ - kind: "read"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * Human-readable description of why the file is being read - */ - intention: string; - /** - * Path of the file or directory being read - */ - path: string; - } - | { - /** - * Permission kind discriminator - */ - kind: "mcp"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * Name of the MCP server providing the tool - */ - serverName: string; - /** - * Internal name of the MCP tool - */ - toolName: string; - /** - * Human-readable title of the MCP tool - */ - toolTitle: string; - /** - * Arguments to pass to the MCP tool - */ - args?: { - [k: string]: unknown; - }; - /** - * Whether this MCP tool is read-only (no side effects) - */ - readOnly: boolean; - } - | { - /** - * Permission kind discriminator - */ - kind: "url"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * Human-readable description of why the URL is being accessed - */ - intention: string; - /** - * URL to be fetched - */ - url: string; - } - | { - /** - * Permission kind discriminator - */ - kind: "memory"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * Whether this is a store or vote memory operation - */ - action?: "store" | "vote"; - /** - * Topic or subject of the memory (store only) - */ - subject?: string; - /** - * The fact being stored or voted on - */ - fact: string; - /** - * Source references for the stored fact (store only) - */ - citations?: string; - /** - * Vote direction (vote only) - */ - direction?: "upvote" | "downvote"; - /** - * Reason for the vote (vote only) - */ - reason?: string; - } - | { - /** - * Permission kind discriminator - */ - kind: "custom-tool"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * Name of the custom tool - */ - toolName: string; - /** - * Description of what the custom tool does - */ - toolDescription: string; - /** - * Arguments to pass to the custom tool - */ - args?: { - [k: string]: unknown; - }; - } - | { - /** - * Permission kind discriminator - */ - kind: "hook"; - /** - * Tool call ID that triggered this permission request - */ - toolCallId?: string; - /** - * Name of the tool the hook is gating - */ - toolName: string; - /** - * Arguments of the tool call being gated - */ - toolArgs?: { - [k: string]: unknown; - }; - /** - * Optional message from the hook explaining why confirmation is needed - */ - hookMessage?: string; - }; - /** - * When true, this permission was already resolved by a permissionRequest hook and requires no client action - */ - resolvedByHook?: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "permission.completed"; - /** - * Permission request completion notification signaling UI dismissal - */ - data: { - /** - * Request ID of the resolved permission request; clients should dismiss any UI for this request - */ - requestId: string; - /** - * The result of the permission request - */ - result: { - /** - * The outcome of the permission request - */ - kind: - | "approved" - | "denied-by-rules" - | "denied-no-approval-rule-and-could-not-request-from-user" - | "denied-interactively-by-user" - | "denied-by-content-exclusion-policy" - | "denied-by-permission-request-hook"; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "user_input.requested"; - /** - * User input request notification with question and optional predefined choices - */ - data: { - /** - * Unique identifier for this input request; used to respond via session.respondToUserInput() - */ - requestId: string; - /** - * The question or prompt to present to the user - */ - question: string; - /** - * Predefined choices for the user to select from, if applicable - */ - choices?: string[]; - /** - * Whether the user can provide a free-form text response in addition to predefined choices - */ - allowFreeform?: boolean; - /** - * The LLM-assigned tool call ID that triggered this request; used by remote UIs to correlate responses - */ - toolCallId?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "user_input.completed"; - /** - * User input request completion with the user's response - */ - data: { - /** - * Request ID of the resolved user input request; clients should dismiss any UI for this request - */ - requestId: string; - /** - * The user's answer to the input request - */ - answer?: string; - /** - * Whether the answer was typed as free-form text rather than selected from choices - */ - wasFreeform?: boolean; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "elicitation.requested"; - /** - * Elicitation request; may be form-based (structured input) or URL-based (browser redirect) - */ - data: { - /** - * Unique identifier for this elicitation request; used to respond via session.respondToElicitation() - */ - requestId: string; - /** - * Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id for remote UIs - */ - toolCallId?: string; - /** - * The source that initiated the request (MCP server name, or absent for agent-initiated) - */ - elicitationSource?: string; - /** - * Message describing what information is needed from the user - */ - message: string; - /** - * Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. - */ - mode?: "form" | "url"; - /** - * JSON Schema describing the form fields to present to the user (form mode only) - */ - requestedSchema?: { - /** - * Schema type indicator (always 'object') - */ - type: "object"; - /** - * Form field definitions, keyed by field name - */ - properties: { - [k: string]: unknown; - }; - /** - * List of required field names - */ - required?: string[]; - }; - /** - * URL to open in the user's browser (url mode only) - */ - url?: string; - [k: string]: unknown; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "elicitation.completed"; - /** - * Elicitation request completion with the user's response - */ - data: { - /** - * Request ID of the resolved elicitation request; clients should dismiss any UI for this request - */ - requestId: string; - /** - * The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) - */ - action?: "accept" | "decline" | "cancel"; - /** - * The submitted form data when action is 'accept'; keys match the requested schema fields - */ - content?: { - [k: string]: string | number | boolean | string[]; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "sampling.requested"; - /** - * Sampling request from an MCP server; contains the server name and a requestId for correlation - */ - data: { - /** - * Unique identifier for this sampling request; used to respond via session.respondToSampling() - */ - requestId: string; - /** - * Name of the MCP server that initiated the sampling request - */ - serverName: string; - /** - * The JSON-RPC request ID from the MCP protocol - */ - mcpRequestId: string | number; - [k: string]: unknown; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "sampling.completed"; - /** - * Sampling request completion notification signaling UI dismissal - */ - data: { - /** - * Request ID of the resolved sampling request; clients should dismiss any UI for this request - */ - requestId: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "mcp.oauth_required"; - /** - * OAuth authentication request for an MCP server - */ - data: { - /** - * Unique identifier for this OAuth request; used to respond via session.respondToMcpOAuth() - */ - requestId: string; - /** - * Display name of the MCP server that requires OAuth - */ - serverName: string; - /** - * URL of the MCP server that requires OAuth - */ - serverUrl: string; - /** - * Static OAuth client configuration, if the server specifies one - */ - staticClientConfig?: { - /** - * OAuth client ID for the server - */ - clientId: string; - /** - * Whether this is a public OAuth client - */ - publicClient?: boolean; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "mcp.oauth_completed"; - /** - * MCP OAuth request completion notification - */ - data: { - /** - * Request ID of the resolved OAuth request - */ - requestId: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "external_tool.requested"; - /** - * External tool invocation request for client-side tool execution - */ - data: { - /** - * Unique identifier for this request; used to respond via session.respondToExternalTool() - */ - requestId: string; - /** - * Session ID that this external tool request belongs to - */ - sessionId: string; - /** - * Tool call ID assigned to this external tool invocation - */ - toolCallId: string; - /** - * Name of the external tool to invoke - */ - toolName: string; - /** - * Arguments to pass to the external tool - */ - arguments?: { - [k: string]: unknown; - }; - /** - * W3C Trace Context traceparent header for the execute_tool span - */ - traceparent?: string; - /** - * W3C Trace Context tracestate header for the execute_tool span - */ - tracestate?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "external_tool.completed"; - /** - * External tool completion notification signaling UI dismissal - */ - data: { - /** - * Request ID of the resolved external tool request; clients should dismiss any UI for this request - */ - requestId: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "command.queued"; - /** - * Queued slash command dispatch request for client execution - */ - data: { - /** - * Unique identifier for this request; used to respond via session.respondToQueuedCommand() - */ - requestId: string; - /** - * The slash command text to be executed (e.g., /help, /clear) - */ - command: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "command.execute"; - /** - * Registered command dispatch request routed to the owning client - */ - data: { - /** - * Unique identifier; used to respond via session.commands.handlePendingCommand() - */ - requestId: string; - /** - * The full command text (e.g., /deploy production) - */ - command: string; - /** - * Command name without leading / - */ - commandName: string; - /** - * Raw argument string after the command name - */ - args: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "command.completed"; - /** - * Queued command completion notification signaling UI dismissal - */ - data: { - /** - * Request ID of the resolved command request; clients should dismiss any UI for this request - */ - requestId: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "commands.changed"; - /** - * SDK command registration change notification - */ - data: { - /** - * Current list of registered SDK commands - */ - commands: { - name: string; - description?: string; - }[]; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "capabilities.changed"; - /** - * Session capability change notification - */ - data: { - /** - * UI capability changes - */ - ui?: { - /** - * Whether elicitation is now supported - */ - elicitation?: boolean; - }; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "exit_plan_mode.requested"; - /** - * Plan approval request with plan content and available user actions - */ - data: { - /** - * Unique identifier for this request; used to respond via session.respondToExitPlanMode() - */ - requestId: string; - /** - * Summary of the plan that was created - */ - summary: string; - /** - * Full content of the plan file - */ - planContent: string; - /** - * Available actions the user can take (e.g., approve, edit, reject) - */ - actions: string[]; - /** - * The recommended action for the user to take - */ - recommendedAction: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "exit_plan_mode.completed"; - /** - * Plan mode exit completion with the user's approval decision and optional feedback - */ - data: { - /** - * Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request - */ - requestId: string; - /** - * Whether the plan was approved by the user - */ - approved?: boolean; - /** - * Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only') - */ - selectedAction?: string; - /** - * Whether edits should be auto-approved without confirmation - */ - autoApproveEdits?: boolean; - /** - * Free-form feedback from the user if they requested changes to the plan - */ - feedback?: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.tools_updated"; - data: { - model: string; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.background_tasks_changed"; - data: {}; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.skills_loaded"; - data: { - /** - * Array of resolved skill metadata - */ - skills: { - /** - * Unique identifier for the skill - */ - name: string; - /** - * Description of what the skill does - */ - description: string; - /** - * Source location type of the skill (e.g., project, personal, plugin) - */ - source: string; - /** - * Whether the skill can be invoked by the user as a slash command - */ - userInvocable: boolean; - /** - * Whether the skill is currently enabled - */ - enabled: boolean; - /** - * Absolute path to the skill file, if available - */ - path?: string; - }[]; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.custom_agents_updated"; - data: { - /** - * Array of loaded custom agent metadata - */ - agents: { - /** - * Unique identifier for the agent - */ - id: string; - /** - * Internal name of the agent - */ - name: string; - /** - * Human-readable display name - */ - displayName: string; - /** - * Description of what the agent does - */ - description: string; - /** - * Source location: user, project, inherited, remote, or plugin - */ - source: string; - /** - * List of tool names available to this agent - */ - tools: string[]; - /** - * Whether the agent can be selected by the user - */ - userInvocable: boolean; - /** - * Model override for this agent, if set - */ - model?: string; - }[]; - /** - * Non-fatal warnings from agent loading - */ - warnings: string[]; - /** - * Fatal errors from agent loading - */ - errors: string[]; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.mcp_servers_loaded"; - data: { - /** - * Array of MCP server status summaries - */ - servers: { - /** - * Server name (config key) - */ - name: string; - /** - * Connection status: connected, failed, needs-auth, pending, disabled, or not_configured - */ - status: "connected" | "failed" | "needs-auth" | "pending" | "disabled" | "not_configured"; - /** - * Configuration source: user, workspace, plugin, or builtin - */ - source?: string; - /** - * Error message if the server failed to connect - */ - error?: string; - }[]; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.mcp_server_status_changed"; - data: { - /** - * Name of the MCP server whose status changed - */ - serverName: string; - /** - * New connection status: connected, failed, needs-auth, pending, disabled, or not_configured - */ - status: "connected" | "failed" | "needs-auth" | "pending" | "disabled" | "not_configured"; - }; - } - | { - /** - * Unique event identifier (UUID v4), generated when the event is emitted - */ - id: string; - /** - * ISO 8601 timestamp when the event was created - */ - timestamp: string; - /** - * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. - */ - parentId: string | null; - ephemeral: true; - /** - * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. - */ - agentId?: string; - type: "session.extensions_loaded"; - data: { - /** - * Array of discovered extensions and their status - */ - extensions: { - /** - * Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper') - */ - id: string; - /** - * Extension name (directory name) - */ - name: string; - /** - * Discovery source - */ - source: "project" | "user"; - /** - * Current status: running, disabled, failed, or starting - */ - status: "running" | "disabled" | "failed" | "starting"; - }[]; - }; - }; + | StartEvent + | ResumeEvent + | RemoteSteerableChangedEvent + | ErrorEvent + | IdleEvent + | TitleChangedEvent + | InfoEvent + | WarningEvent + | ModelChangeEvent + | ModeChangedEvent + | PlanChangedEvent + | WorkspaceFileChangedEvent + | HandoffEvent + | TruncationEvent + | SnapshotRewindEvent + | ShutdownEvent + | ContextChangedEvent + | UsageInfoEvent + | CompactionStartEvent + | CompactionCompleteEvent + | TaskCompleteEvent + | UserMessageEvent + | PendingMessagesModifiedEvent + | AssistantTurnStartEvent + | AssistantIntentEvent + | AssistantReasoningEvent + | AssistantReasoningDeltaEvent + | AssistantStreamingDeltaEvent + | AssistantMessageEvent + | AssistantMessageDeltaEvent + | AssistantTurnEndEvent + | AssistantUsageEvent + | AbortEvent + | ToolUserRequestedEvent + | ToolExecutionStartEvent + | ToolExecutionPartialResultEvent + | ToolExecutionProgressEvent + | ToolExecutionCompleteEvent + | SkillInvokedEvent + | SubagentStartedEvent + | SubagentCompletedEvent + | SubagentFailedEvent + | SubagentSelectedEvent + | SubagentDeselectedEvent + | HookStartEvent + | HookEndEvent + | SystemMessageEvent + | SystemNotificationEvent + | PermissionRequestedEvent + | PermissionCompletedEvent + | UserInputRequestedEvent + | UserInputCompletedEvent + | ElicitationRequestedEvent + | ElicitationCompletedEvent + | SamplingRequestedEvent + | SamplingCompletedEvent + | McpOauthRequiredEvent + | McpOauthCompletedEvent + | ExternalToolRequestedEvent + | ExternalToolCompletedEvent + | CommandQueuedEvent + | CommandExecuteEvent + | CommandCompletedEvent + | CommandsChangedEvent + | CapabilitiesChangedEvent + | ExitPlanModeRequestedEvent + | ExitPlanModeCompletedEvent + | ToolsUpdatedEvent + | BackgroundTasksChangedEvent + | SkillsLoadedEvent + | CustomAgentsUpdatedEvent + | McpServersLoadedEvent + | McpServerStatusChangedEvent + | ExtensionsLoadedEvent; +/** + * Hosting platform type of the repository (github or ado) + */ +export type WorkingDirectoryContextHostType = "github" | "ado"; +/** + * The type of operation performed on the plan file + */ +export type PlanChangedOperation = "create" | "update" | "delete"; +/** + * Whether the file was newly created or updated + */ +export type WorkspaceFileChangedOperation = "create" | "update"; +/** + * Origin type of the session being handed off + */ +export type HandoffSourceType = "remote" | "local"; +/** + * Whether the session ended normally ("routine") or due to a crash/fatal error ("error") + */ +export type ShutdownType = "routine" | "error"; +/** + * The agent mode that was active when this message was sent + */ +export type UserMessageAgentMode = "interactive" | "plan" | "autopilot" | "shell"; +/** + * A user message attachment — a file, directory, code selection, blob, or GitHub reference + */ +export type UserMessageAttachment = + | UserMessageAttachmentFile + | UserMessageAttachmentDirectory + | UserMessageAttachmentSelection + | UserMessageAttachmentGithubReference + | UserMessageAttachmentBlob; +/** + * Type of GitHub reference + */ +export type UserMessageAttachmentGithubReferenceType = "issue" | "pr" | "discussion"; +/** + * Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. + */ +export type AssistantMessageToolRequestType = "function" | "custom"; +/** + * A content block within a tool result, which may be text, terminal output, image, audio, or a resource + */ +export type ToolExecutionCompleteContent = + | ToolExecutionCompleteContentText + | ToolExecutionCompleteContentTerminal + | ToolExecutionCompleteContentImage + | ToolExecutionCompleteContentAudio + | ToolExecutionCompleteContentResourceLink + | ToolExecutionCompleteContentResource; +/** + * Theme variant this icon is intended for + */ +export type ToolExecutionCompleteContentResourceLinkIconTheme = "light" | "dark"; +/** + * The embedded resource contents, either text or base64-encoded binary + */ +export type ToolExecutionCompleteContentResourceDetails = EmbeddedTextResourceContents | EmbeddedBlobResourceContents; +/** + * Message role: "system" for system prompts, "developer" for developer-injected instructions + */ +export type SystemMessageRole = "system" | "developer"; +/** + * Structured metadata identifying what triggered this notification + */ +export type SystemNotification = + | SystemNotificationAgentCompleted + | SystemNotificationAgentIdle + | SystemNotificationNewInboxMessage + | SystemNotificationShellCompleted + | SystemNotificationShellDetachedCompleted; +/** + * Whether the agent completed successfully or failed + */ +export type SystemNotificationAgentCompletedStatus = "completed" | "failed"; +/** + * Details of the permission being requested + */ +export type PermissionRequest = + | PermissionRequestShell + | PermissionRequestWrite + | PermissionRequestRead + | PermissionRequestMcp + | PermissionRequestUrl + | PermissionRequestMemory + | PermissionRequestCustomTool + | PermissionRequestHook; +/** + * Whether this is a store or vote memory operation + */ +export type PermissionRequestMemoryAction = "store" | "vote"; +/** + * Vote direction (vote only) + */ +export type PermissionRequestMemoryDirection = "upvote" | "downvote"; +/** + * The outcome of the permission request + */ +export type PermissionCompletedKind = + | "approved" + | "denied-by-rules" + | "denied-no-approval-rule-and-could-not-request-from-user" + | "denied-interactively-by-user" + | "denied-by-content-exclusion-policy" + | "denied-by-permission-request-hook"; +/** + * Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. + */ +export type ElicitationRequestedMode = "form" | "url"; +/** + * The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) + */ +export type ElicitationCompletedAction = "accept" | "decline" | "cancel"; +export type ElicitationCompletedContent = string | number | boolean | string[]; +/** + * Connection status: connected, failed, needs-auth, pending, disabled, or not_configured + */ +export type McpServersLoadedServerStatus = + | "connected" + | "failed" + | "needs-auth" + | "pending" + | "disabled" + | "not_configured"; +/** + * New connection status: connected, failed, needs-auth, pending, disabled, or not_configured + */ +export type McpServerStatusChangedStatus = + | "connected" + | "failed" + | "needs-auth" + | "pending" + | "disabled" + | "not_configured"; +/** + * Discovery source + */ +export type ExtensionsLoadedExtensionSource = "project" | "user"; +/** + * Current status: running, disabled, failed, or starting + */ +export type ExtensionsLoadedExtensionStatus = "running" | "disabled" | "failed" | "starting"; +export interface StartEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: StartData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.start"; +} +/** + * Session initialization metadata including context and configuration + */ +export interface StartData { + /** + * Whether the session was already in use by another client at start time + */ + alreadyInUse?: boolean; + context?: WorkingDirectoryContext; + /** + * Version string of the Copilot application + */ + copilotVersion: string; + /** + * Identifier of the software producing the events (e.g., "copilot-agent") + */ + producer: string; + /** + * Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") + */ + reasoningEffort?: string; + /** + * Whether this session supports remote steering via Mission Control + */ + remoteSteerable?: boolean; + /** + * Model selected at session creation time, if any + */ + selectedModel?: string; + /** + * Unique identifier for the session + */ + sessionId: string; + /** + * ISO 8601 timestamp when the session was created + */ + startTime: string; + /** + * Schema version number for the session event format + */ + version: number; +} /** * Working directory and git context at session start */ export interface WorkingDirectoryContext { + /** + * Base commit of current git branch at session start time + */ + baseCommit?: string; + /** + * Current git branch name + */ + branch?: string; /** * Current working directory path */ @@ -3961,118 +308,4050 @@ export interface WorkingDirectoryContext { * Root directory of the git repository, resolved via git rev-parse */ gitRoot?: string; + /** + * Head commit of current git branch at session start time + */ + headCommit?: string; + hostType?: WorkingDirectoryContextHostType; /** * Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) */ repository?: string; /** - * Hosting platform type of the repository (github or ado) + * Raw host string from the git remote URL (e.g. "github.com", "mycompany.ghe.com", "dev.azure.com") */ - hostType?: "github" | "ado"; + repositoryHost?: string; +} +export interface ResumeEvent { /** - * Current git branch name + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. */ - branch?: string; + agentId?: string; + data: ResumeData; /** - * Head commit of current git branch at session start time + * When true, the event is transient and not persisted to the session event log on disk */ - headCommit?: string; + ephemeral?: boolean; /** - * Base commit of current git branch at session start time + * Unique event identifier (UUID v4), generated when the event is emitted */ - baseCommit?: string; + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.resume"; } /** - * Updated working directory and git context at resume time + * Session resume metadata including current context and event count */ -export interface WorkingDirectoryContext1 { +export interface ResumeData { /** - * Current working directory path + * Whether the session was already in use by another client at resume time */ - cwd: string; + alreadyInUse?: boolean; + context?: WorkingDirectoryContext; /** - * Root directory of the git repository, resolved via git rev-parse + * Total number of persisted events in the session at the time of resume */ - gitRoot?: string; + eventCount: number; /** - * Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) + * Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") */ - repository?: string; + reasoningEffort?: string; /** - * Hosting platform type of the repository (github or ado) + * Whether this session supports remote steering via Mission Control */ - hostType?: "github" | "ado"; + remoteSteerable?: boolean; /** - * Current git branch name + * ISO 8601 timestamp when the session was resumed */ - branch?: string; + resumeTime: string; /** - * Head commit of current git branch at session start time + * Model currently selected at resume time */ - headCommit?: string; + selectedModel?: string; +} +export interface RemoteSteerableChangedEvent { /** - * Base commit of current git branch at session start time + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. */ - baseCommit?: string; + agentId?: string; + data: RemoteSteerableChangedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.remote_steerable_changed"; } /** - * Updated working directory and git context after the change + * Notifies Mission Control that the session's remote steering capability has changed */ -export interface WorkingDirectoryContext2 { +export interface RemoteSteerableChangedData { /** - * Current working directory path + * Whether this session now supports remote steering via Mission Control */ - cwd: string; + remoteSteerable: boolean; +} +export interface ErrorEvent { /** - * Root directory of the git repository, resolved via git rev-parse + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. */ - gitRoot?: string; + agentId?: string; + data: ErrorData; /** - * Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) + * When true, the event is transient and not persisted to the session event log on disk */ - repository?: string; + ephemeral?: boolean; /** - * Hosting platform type of the repository (github or ado) + * Unique event identifier (UUID v4), generated when the event is emitted */ - hostType?: "github" | "ado"; + id: string; /** - * Current git branch name + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. */ - branch?: string; + parentId: string | null; /** - * Head commit of current git branch at session start time + * ISO 8601 timestamp when the event was created */ - headCommit?: string; + timestamp: string; + type: "session.error"; +} +/** + * Error details for timeline display including message and optional diagnostic information + */ +export interface ErrorData { /** - * Base commit of current git branch at session start time + * Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") */ - baseCommit?: string; + errorType: string; + /** + * Human-readable error message + */ + message: string; + /** + * GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs + */ + providerCallId?: string; + /** + * Error stack trace, when available + */ + stack?: string; + /** + * HTTP status code from the upstream request, if applicable + */ + statusCode?: number; + /** + * Optional URL associated with this error that the user can open in a browser + */ + url?: string; } -export interface EmbeddedTextResourceContents { +export interface IdleEvent { /** - * URI identifying the resource + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. */ - uri: string; + agentId?: string; + data: IdleData; + ephemeral: true; /** - * MIME type of the text content + * Unique event identifier (UUID v4), generated when the event is emitted */ - mimeType?: string; + id: string; /** - * Text content of the resource + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. */ - text: string; + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.idle"; } -export interface EmbeddedBlobResourceContents { +/** + * Payload indicating the session is idle with no background agents in flight + */ +export interface IdleData { /** - * URI identifying the resource + * True when the preceding agentic loop was cancelled via abort signal */ - uri: string; + aborted?: boolean; +} +export interface TitleChangedEvent { /** - * MIME type of the blob content + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. */ - mimeType?: string; + agentId?: string; + data: TitleChangedData; + ephemeral: true; /** - * Base64-encoded binary content of the resource + * Unique event identifier (UUID v4), generated when the event is emitted */ - blob: string; + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.title_changed"; +} +/** + * Session title change payload containing the new display title + */ +export interface TitleChangedData { + /** + * The new display title for the session + */ + title: string; +} +export interface InfoEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: InfoData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.info"; +} +/** + * Informational message for timeline display with categorization + */ +export interface InfoData { + /** + * Category of informational message (e.g., "notification", "timing", "context_window", "mcp", "snapshot", "configuration", "authentication", "model") + */ + infoType: string; + /** + * Human-readable informational message for display in the timeline + */ + message: string; + /** + * Optional URL associated with this message that the user can open in a browser + */ + url?: string; +} +export interface WarningEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: WarningData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.warning"; +} +/** + * Warning message for timeline display with categorization + */ +export interface WarningData { + /** + * Human-readable warning message for display in the timeline + */ + message: string; + /** + * Optional URL associated with this warning that the user can open in a browser + */ + url?: string; + /** + * Category of warning (e.g., "subscription", "policy", "mcp") + */ + warningType: string; +} +export interface ModelChangeEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ModelChangeData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.model_change"; +} +/** + * Model change details including previous and new model identifiers + */ +export interface ModelChangeData { + /** + * Newly selected model identifier + */ + newModel: string; + /** + * Model that was previously selected, if any + */ + previousModel?: string; + /** + * Reasoning effort level before the model change, if applicable + */ + previousReasoningEffort?: string; + /** + * Reasoning effort level after the model change, if applicable + */ + reasoningEffort?: string; +} +export interface ModeChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ModeChangedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.mode_changed"; +} +/** + * Agent mode change details including previous and new modes + */ +export interface ModeChangedData { + /** + * Agent mode after the change (e.g., "interactive", "plan", "autopilot") + */ + newMode: string; + /** + * Agent mode before the change (e.g., "interactive", "plan", "autopilot") + */ + previousMode: string; +} +export interface PlanChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: PlanChangedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.plan_changed"; +} +/** + * Plan file operation details indicating what changed + */ +export interface PlanChangedData { + operation: PlanChangedOperation; +} +export interface WorkspaceFileChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: WorkspaceFileChangedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.workspace_file_changed"; +} +/** + * Workspace file change details including path and operation type + */ +export interface WorkspaceFileChangedData { + operation: WorkspaceFileChangedOperation; + /** + * Relative path within the session workspace files directory + */ + path: string; +} +export interface HandoffEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: HandoffData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.handoff"; +} +/** + * Session handoff metadata including source, context, and repository information + */ +export interface HandoffData { + /** + * Additional context information for the handoff + */ + context?: string; + /** + * ISO 8601 timestamp when the handoff occurred + */ + handoffTime: string; + /** + * GitHub host URL for the source session (e.g., https://github.com or https://tenant.ghe.com) + */ + host?: string; + /** + * Session ID of the remote session being handed off + */ + remoteSessionId?: string; + repository?: HandoffRepository; + sourceType: HandoffSourceType; + /** + * Summary of the work done in the source session + */ + summary?: string; +} +/** + * Repository context for the handed-off session + */ +export interface HandoffRepository { + /** + * Git branch name, if applicable + */ + branch?: string; + /** + * Repository name + */ + name: string; + /** + * Repository owner (user or organization) + */ + owner: string; +} +export interface TruncationEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: TruncationData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.truncation"; +} +/** + * Conversation truncation statistics including token counts and removed content metrics + */ +export interface TruncationData { + /** + * Number of messages removed by truncation + */ + messagesRemovedDuringTruncation: number; + /** + * Identifier of the component that performed truncation (e.g., "BasicTruncator") + */ + performedBy: string; + /** + * Number of conversation messages after truncation + */ + postTruncationMessagesLength: number; + /** + * Total tokens in conversation messages after truncation + */ + postTruncationTokensInMessages: number; + /** + * Number of conversation messages before truncation + */ + preTruncationMessagesLength: number; + /** + * Total tokens in conversation messages before truncation + */ + preTruncationTokensInMessages: number; + /** + * Maximum token count for the model's context window + */ + tokenLimit: number; + /** + * Number of tokens removed by truncation + */ + tokensRemovedDuringTruncation: number; +} +export interface SnapshotRewindEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SnapshotRewindData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.snapshot_rewind"; +} +/** + * Session rewind details including target event and count of removed events + */ +export interface SnapshotRewindData { + /** + * Number of events that were removed by the rewind + */ + eventsRemoved: number; + /** + * Event ID that was rewound to; this event and all after it were removed + */ + upToEventId: string; +} +export interface ShutdownEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ShutdownData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.shutdown"; +} +/** + * Session termination metrics including usage statistics, code changes, and shutdown reason + */ +export interface ShutdownData { + codeChanges: ShutdownCodeChanges; + /** + * Non-system message token count at shutdown + */ + conversationTokens?: number; + /** + * Model that was selected at the time of shutdown + */ + currentModel?: string; + /** + * Total tokens in context window at shutdown + */ + currentTokens?: number; + /** + * Error description when shutdownType is "error" + */ + errorReason?: string; + /** + * Per-model usage breakdown, keyed by model identifier + */ + modelMetrics: { + [k: string]: ShutdownModelMetric; + }; + /** + * Unix timestamp (milliseconds) when the session started + */ + sessionStartTime: number; + shutdownType: ShutdownType; + /** + * System message token count at shutdown + */ + systemTokens?: number; + /** + * Tool definitions token count at shutdown + */ + toolDefinitionsTokens?: number; + /** + * Cumulative time spent in API calls during the session, in milliseconds + */ + totalApiDurationMs: number; + /** + * Total number of premium API requests used during the session + */ + totalPremiumRequests: number; +} +/** + * Aggregate code change metrics for the session + */ +export interface ShutdownCodeChanges { + /** + * List of file paths that were modified during the session + */ + filesModified: string[]; + /** + * Total number of lines added during the session + */ + linesAdded: number; + /** + * Total number of lines removed during the session + */ + linesRemoved: number; +} +export interface ShutdownModelMetric { + requests: ShutdownModelMetricRequests; + usage: ShutdownModelMetricUsage; +} +/** + * Request count and cost metrics + */ +export interface ShutdownModelMetricRequests { + /** + * Cumulative cost multiplier for requests to this model + */ + cost: number; + /** + * Total number of API requests made to this model + */ + count: number; +} +/** + * Token usage breakdown + */ +export interface ShutdownModelMetricUsage { + /** + * Total tokens read from prompt cache across all requests + */ + cacheReadTokens: number; + /** + * Total tokens written to prompt cache across all requests + */ + cacheWriteTokens: number; + /** + * Total input tokens consumed across all requests to this model + */ + inputTokens: number; + /** + * Total output tokens produced across all requests to this model + */ + outputTokens: number; + /** + * Total reasoning tokens produced across all requests to this model + */ + reasoningTokens?: number; +} +export interface ContextChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: WorkingDirectoryContext; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.context_changed"; +} +export interface UsageInfoEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: UsageInfoData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.usage_info"; +} +/** + * Current context window usage statistics including token and message counts + */ +export interface UsageInfoData { + /** + * Token count from non-system messages (user, assistant, tool) + */ + conversationTokens?: number; + /** + * Current number of tokens in the context window + */ + currentTokens: number; + /** + * Whether this is the first usage_info event emitted in this session + */ + isInitial?: boolean; + /** + * Current number of messages in the conversation + */ + messagesLength: number; + /** + * Token count from system message(s) + */ + systemTokens?: number; + /** + * Maximum token count for the model's context window + */ + tokenLimit: number; + /** + * Token count from tool definitions + */ + toolDefinitionsTokens?: number; +} +export interface CompactionStartEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CompactionStartData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.compaction_start"; +} +/** + * Context window breakdown at the start of LLM-powered conversation compaction + */ +export interface CompactionStartData { + /** + * Token count from non-system messages (user, assistant, tool) at compaction start + */ + conversationTokens?: number; + /** + * Token count from system message(s) at compaction start + */ + systemTokens?: number; + /** + * Token count from tool definitions at compaction start + */ + toolDefinitionsTokens?: number; +} +export interface CompactionCompleteEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CompactionCompleteData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.compaction_complete"; +} +/** + * Conversation compaction results including success status, metrics, and optional error details + */ +export interface CompactionCompleteData { + /** + * Checkpoint snapshot number created for recovery + */ + checkpointNumber?: number; + /** + * File path where the checkpoint was stored + */ + checkpointPath?: string; + compactionTokensUsed?: CompactionCompleteCompactionTokensUsed; + /** + * Token count from non-system messages (user, assistant, tool) after compaction + */ + conversationTokens?: number; + /** + * Error message if compaction failed + */ + error?: string; + /** + * Number of messages removed during compaction + */ + messagesRemoved?: number; + /** + * Total tokens in conversation after compaction + */ + postCompactionTokens?: number; + /** + * Number of messages before compaction + */ + preCompactionMessagesLength?: number; + /** + * Total tokens in conversation before compaction + */ + preCompactionTokens?: number; + /** + * GitHub request tracing ID (x-github-request-id header) for the compaction LLM call + */ + requestId?: string; + /** + * Whether compaction completed successfully + */ + success: boolean; + /** + * LLM-generated summary of the compacted conversation history + */ + summaryContent?: string; + /** + * Token count from system message(s) after compaction + */ + systemTokens?: number; + /** + * Number of tokens removed during compaction + */ + tokensRemoved?: number; + /** + * Token count from tool definitions after compaction + */ + toolDefinitionsTokens?: number; +} +/** + * Token usage breakdown for the compaction LLM call + */ +export interface CompactionCompleteCompactionTokensUsed { + /** + * Cached input tokens reused in the compaction LLM call + */ + cachedInput: number; + /** + * Input tokens consumed by the compaction LLM call + */ + input: number; + /** + * Output tokens produced by the compaction LLM call + */ + output: number; +} +export interface TaskCompleteEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: TaskCompleteData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.task_complete"; +} +/** + * Task completion notification with summary from the agent + */ +export interface TaskCompleteData { + /** + * Whether the tool call succeeded. False when validation failed (e.g., invalid arguments) + */ + success?: boolean; + /** + * Summary of the completed task, provided by the agent + */ + summary?: string; +} +export interface UserMessageEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: UserMessageData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "user.message"; +} +export interface UserMessageData { + agentMode?: UserMessageAgentMode; + /** + * Files, selections, or GitHub references attached to the message + */ + attachments?: UserMessageAttachment[]; + /** + * The user's message text as displayed in the timeline + */ + content: string; + /** + * CAPI interaction ID for correlating this user message with its turn + */ + interactionId?: string; + /** + * Path-backed native document attachments that stayed on the tagged_files path flow because native upload would exceed the request size limit + */ + nativeDocumentPathFallbackPaths?: string[]; + /** + * Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user) + */ + source?: string; + /** + * Normalized document MIME types that were sent natively instead of through tagged_files XML + */ + supportedNativeDocumentMimeTypes?: string[]; + /** + * Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching + */ + transformedContent?: string; +} +/** + * File attachment + */ +export interface UserMessageAttachmentFile { + /** + * User-facing display name for the attachment + */ + displayName: string; + lineRange?: UserMessageAttachmentFileLineRange; + /** + * Absolute file path + */ + path: string; + /** + * Attachment type discriminator + */ + type: "file"; +} +/** + * Optional line range to scope the attachment to a specific section of the file + */ +export interface UserMessageAttachmentFileLineRange { + /** + * End line number (1-based, inclusive) + */ + end: number; + /** + * Start line number (1-based) + */ + start: number; +} +/** + * Directory attachment + */ +export interface UserMessageAttachmentDirectory { + /** + * User-facing display name for the attachment + */ + displayName: string; + /** + * Absolute directory path + */ + path: string; + /** + * Attachment type discriminator + */ + type: "directory"; +} +/** + * Code selection attachment from an editor + */ +export interface UserMessageAttachmentSelection { + /** + * User-facing display name for the selection + */ + displayName: string; + /** + * Absolute path to the file containing the selection + */ + filePath: string; + selection: UserMessageAttachmentSelectionDetails; + /** + * The selected text content + */ + text: string; + /** + * Attachment type discriminator + */ + type: "selection"; +} +/** + * Position range of the selection within the file + */ +export interface UserMessageAttachmentSelectionDetails { + end: UserMessageAttachmentSelectionDetailsEnd; + start: UserMessageAttachmentSelectionDetailsStart; +} +/** + * End position of the selection + */ +export interface UserMessageAttachmentSelectionDetailsEnd { + /** + * End character offset within the line (0-based) + */ + character: number; + /** + * End line number (0-based) + */ + line: number; +} +/** + * Start position of the selection + */ +export interface UserMessageAttachmentSelectionDetailsStart { + /** + * Start character offset within the line (0-based) + */ + character: number; + /** + * Start line number (0-based) + */ + line: number; +} +/** + * GitHub issue, pull request, or discussion reference + */ +export interface UserMessageAttachmentGithubReference { + /** + * Issue, pull request, or discussion number + */ + number: number; + referenceType: UserMessageAttachmentGithubReferenceType; + /** + * Current state of the referenced item (e.g., open, closed, merged) + */ + state: string; + /** + * Title of the referenced item + */ + title: string; + /** + * Attachment type discriminator + */ + type: "github_reference"; + /** + * URL to the referenced item on GitHub + */ + url: string; +} +/** + * Blob attachment with inline base64-encoded data + */ +export interface UserMessageAttachmentBlob { + /** + * Base64-encoded content + */ + data: string; + /** + * User-facing display name for the attachment + */ + displayName?: string; + /** + * MIME type of the inline data + */ + mimeType: string; + /** + * Attachment type discriminator + */ + type: "blob"; +} +export interface PendingMessagesModifiedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: PendingMessagesModifiedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "pending_messages.modified"; +} +/** + * Empty payload; the event signals that the pending message queue has changed + */ +export interface PendingMessagesModifiedData {} +export interface AssistantTurnStartEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantTurnStartData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.turn_start"; +} +/** + * Turn initialization metadata including identifier and interaction tracking + */ +export interface AssistantTurnStartData { + /** + * CAPI interaction ID for correlating this turn with upstream telemetry + */ + interactionId?: string; + /** + * Identifier for this turn within the agentic loop, typically a stringified turn number + */ + turnId: string; +} +export interface AssistantIntentEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantIntentData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.intent"; +} +/** + * Agent intent description for current activity or plan + */ +export interface AssistantIntentData { + /** + * Short description of what the agent is currently doing or planning to do + */ + intent: string; +} +export interface AssistantReasoningEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantReasoningData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.reasoning"; +} +/** + * Assistant reasoning content for timeline display with complete thinking text + */ +export interface AssistantReasoningData { + /** + * The complete extended thinking text from the model + */ + content: string; + /** + * Unique identifier for this reasoning block + */ + reasoningId: string; +} +export interface AssistantReasoningDeltaEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantReasoningDeltaData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.reasoning_delta"; +} +/** + * Streaming reasoning delta for incremental extended thinking updates + */ +export interface AssistantReasoningDeltaData { + /** + * Incremental text chunk to append to the reasoning content + */ + deltaContent: string; + /** + * Reasoning block ID this delta belongs to, matching the corresponding assistant.reasoning event + */ + reasoningId: string; +} +export interface AssistantStreamingDeltaEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantStreamingDeltaData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.streaming_delta"; +} +/** + * Streaming response progress with cumulative byte count + */ +export interface AssistantStreamingDeltaData { + /** + * Cumulative total bytes received from the streaming response so far + */ + totalResponseSizeBytes: number; +} +export interface AssistantMessageEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantMessageData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.message"; +} +/** + * Assistant response containing text content, optional tool requests, and interaction metadata + */ +export interface AssistantMessageData { + /** + * The assistant's text response content + */ + content: string; + /** + * Encrypted reasoning content from OpenAI models. Session-bound and stripped on resume. + */ + encryptedContent?: string; + /** + * CAPI interaction ID for correlating this message with upstream telemetry + */ + interactionId?: string; + /** + * Unique identifier for this assistant message + */ + messageId: string; + /** + * Actual output token count from the API response (completion_tokens), used for accurate token accounting + */ + outputTokens?: number; + /** + * @deprecated + * Tool call ID of the parent tool invocation when this event originates from a sub-agent + */ + parentToolCallId?: string; + /** + * Generation phase for phased-output models (e.g., thinking vs. response phases) + */ + phase?: string; + /** + * Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. + */ + reasoningOpaque?: string; + /** + * Readable reasoning text from the model's extended thinking + */ + reasoningText?: string; + /** + * GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs + */ + requestId?: string; + /** + * Tool invocations requested by the assistant in this message + */ + toolRequests?: AssistantMessageToolRequest[]; +} +/** + * A tool invocation request from the assistant + */ +export interface AssistantMessageToolRequest { + /** + * Arguments to pass to the tool, format depends on the tool + */ + arguments?: { + [k: string]: unknown; + }; + /** + * Resolved intention summary describing what this specific call does + */ + intentionSummary?: string | null; + /** + * Name of the MCP server hosting this tool, when the tool is an MCP tool + */ + mcpServerName?: string; + /** + * Name of the tool being invoked + */ + name: string; + /** + * Unique identifier for this tool call + */ + toolCallId: string; + /** + * Human-readable display title for the tool + */ + toolTitle?: string; + type?: AssistantMessageToolRequestType; +} +export interface AssistantMessageDeltaEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantMessageDeltaData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.message_delta"; +} +/** + * Streaming assistant message delta for incremental response updates + */ +export interface AssistantMessageDeltaData { + /** + * Incremental text chunk to append to the message content + */ + deltaContent: string; + /** + * Message ID this delta belongs to, matching the corresponding assistant.message event + */ + messageId: string; + /** + * @deprecated + * Tool call ID of the parent tool invocation when this event originates from a sub-agent + */ + parentToolCallId?: string; +} +export interface AssistantTurnEndEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantTurnEndData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.turn_end"; +} +/** + * Turn completion metadata including the turn identifier + */ +export interface AssistantTurnEndData { + /** + * Identifier of the turn that has ended, matching the corresponding assistant.turn_start event + */ + turnId: string; +} +export interface AssistantUsageEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AssistantUsageData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "assistant.usage"; +} +/** + * LLM API call usage metrics including tokens, costs, quotas, and billing information + */ +export interface AssistantUsageData { + /** + * Completion ID from the model provider (e.g., chatcmpl-abc123) + */ + apiCallId?: string; + /** + * Number of tokens read from prompt cache + */ + cacheReadTokens?: number; + /** + * Number of tokens written to prompt cache + */ + cacheWriteTokens?: number; + copilotUsage?: AssistantUsageCopilotUsage; + /** + * Model multiplier cost for billing purposes + */ + cost?: number; + /** + * Duration of the API call in milliseconds + */ + duration?: number; + /** + * What initiated this API call (e.g., "sub-agent", "mcp-sampling"); absent for user-initiated calls + */ + initiator?: string; + /** + * Number of input tokens consumed + */ + inputTokens?: number; + /** + * Average inter-token latency in milliseconds. Only available for streaming requests + */ + interTokenLatencyMs?: number; + /** + * Model identifier used for this API call + */ + model: string; + /** + * Number of output tokens produced + */ + outputTokens?: number; + /** + * @deprecated + * Parent tool call ID when this usage originates from a sub-agent + */ + parentToolCallId?: string; + /** + * GitHub request tracing ID (x-github-request-id header) for server-side log correlation + */ + providerCallId?: string; + /** + * Per-quota resource usage snapshots, keyed by quota identifier + */ + quotaSnapshots?: { + [k: string]: AssistantUsageQuotaSnapshot; + }; + /** + * Reasoning effort level used for model calls, if applicable (e.g. "low", "medium", "high", "xhigh") + */ + reasoningEffort?: string; + /** + * Number of output tokens used for reasoning (e.g., chain-of-thought) + */ + reasoningTokens?: number; + /** + * Time to first token in milliseconds. Only available for streaming requests + */ + ttftMs?: number; +} +/** + * Per-request cost and usage data from the CAPI copilot_usage response field + */ +export interface AssistantUsageCopilotUsage { + /** + * Itemized token usage breakdown + */ + tokenDetails: AssistantUsageCopilotUsageTokenDetail[]; + /** + * Total cost in nano-AIU (AI Units) for this request + */ + totalNanoAiu: number; +} +/** + * Token usage detail for a single billing category + */ +export interface AssistantUsageCopilotUsageTokenDetail { + /** + * Number of tokens in this billing batch + */ + batchSize: number; + /** + * Cost per batch of tokens + */ + costPerBatch: number; + /** + * Total token count for this entry + */ + tokenCount: number; + /** + * Token category (e.g., "input", "output") + */ + tokenType: string; +} +export interface AssistantUsageQuotaSnapshot { + /** + * Total requests allowed by the entitlement + */ + entitlementRequests: number; + /** + * Whether the user has an unlimited usage entitlement + */ + isUnlimitedEntitlement: boolean; + /** + * Number of requests over the entitlement limit + */ + overage: number; + /** + * Whether overage is allowed when quota is exhausted + */ + overageAllowedWithExhaustedQuota: boolean; + /** + * Percentage of quota remaining (0.0 to 1.0) + */ + remainingPercentage: number; + /** + * Date when the quota resets + */ + resetDate?: string; + /** + * Whether usage is still permitted after quota exhaustion + */ + usageAllowedWithExhaustedQuota: boolean; + /** + * Number of requests already consumed + */ + usedRequests: number; +} +export interface AbortEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: AbortData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "abort"; +} +/** + * Turn abort information including the reason for termination + */ +export interface AbortData { + /** + * Reason the current turn was aborted (e.g., "user initiated") + */ + reason: string; +} +export interface ToolUserRequestedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ToolUserRequestedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "tool.user_requested"; +} +/** + * User-initiated tool invocation request with tool name and arguments + */ +export interface ToolUserRequestedData { + /** + * Arguments for the tool invocation + */ + arguments?: { + [k: string]: unknown; + }; + /** + * Unique identifier for this tool call + */ + toolCallId: string; + /** + * Name of the tool the user wants to invoke + */ + toolName: string; +} +export interface ToolExecutionStartEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ToolExecutionStartData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "tool.execution_start"; +} +/** + * Tool execution startup details including MCP server information when applicable + */ +export interface ToolExecutionStartData { + /** + * Arguments passed to the tool + */ + arguments?: { + [k: string]: unknown; + }; + /** + * Name of the MCP server hosting this tool, when the tool is an MCP tool + */ + mcpServerName?: string; + /** + * Original tool name on the MCP server, when the tool is an MCP tool + */ + mcpToolName?: string; + /** + * @deprecated + * Tool call ID of the parent tool invocation when this event originates from a sub-agent + */ + parentToolCallId?: string; + /** + * Unique identifier for this tool call + */ + toolCallId: string; + /** + * Name of the tool being executed + */ + toolName: string; +} +export interface ToolExecutionPartialResultEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ToolExecutionPartialData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "tool.execution_partial_result"; +} +/** + * Streaming tool execution output for incremental result display + */ +export interface ToolExecutionPartialData { + /** + * Incremental output chunk from the running tool + */ + partialOutput: string; + /** + * Tool call ID this partial result belongs to + */ + toolCallId: string; +} +export interface ToolExecutionProgressEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ToolExecutionProgressData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "tool.execution_progress"; +} +/** + * Tool execution progress notification with status message + */ +export interface ToolExecutionProgressData { + /** + * Human-readable progress status message (e.g., from an MCP server) + */ + progressMessage: string; + /** + * Tool call ID this progress notification belongs to + */ + toolCallId: string; +} +export interface ToolExecutionCompleteEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ToolExecutionCompleteData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "tool.execution_complete"; +} +/** + * Tool execution completion results including success status, detailed output, and error information + */ +export interface ToolExecutionCompleteData { + error?: ToolExecutionCompleteError; + /** + * CAPI interaction ID for correlating this tool execution with upstream telemetry + */ + interactionId?: string; + /** + * Whether this tool call was explicitly requested by the user rather than the assistant + */ + isUserRequested?: boolean; + /** + * Model identifier that generated this tool call + */ + model?: string; + /** + * @deprecated + * Tool call ID of the parent tool invocation when this event originates from a sub-agent + */ + parentToolCallId?: string; + result?: ToolExecutionCompleteResult; + /** + * Whether the tool execution completed successfully + */ + success: boolean; + /** + * Unique identifier for the completed tool call + */ + toolCallId: string; + /** + * Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts) + */ + toolTelemetry?: { + [k: string]: unknown; + }; +} +/** + * Error details when the tool execution failed + */ +export interface ToolExecutionCompleteError { + /** + * Machine-readable error code + */ + code?: string; + /** + * Human-readable error message + */ + message: string; +} +/** + * Tool execution result on success + */ +export interface ToolExecutionCompleteResult { + /** + * Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency + */ + content: string; + /** + * Structured content blocks (text, images, audio, resources) returned by the tool in their native format + */ + contents?: ToolExecutionCompleteContent[]; + /** + * Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. + */ + detailedContent?: string; +} +/** + * Plain text content block + */ +export interface ToolExecutionCompleteContentText { + /** + * The text content + */ + text: string; + /** + * Content block type discriminator + */ + type: "text"; +} +/** + * Terminal/shell output content block with optional exit code and working directory + */ +export interface ToolExecutionCompleteContentTerminal { + /** + * Working directory where the command was executed + */ + cwd?: string; + /** + * Process exit code, if the command has completed + */ + exitCode?: number; + /** + * Terminal/shell output text + */ + text: string; + /** + * Content block type discriminator + */ + type: "terminal"; +} +/** + * Image content block with base64-encoded data + */ +export interface ToolExecutionCompleteContentImage { + /** + * Base64-encoded image data + */ + data: string; + /** + * MIME type of the image (e.g., image/png, image/jpeg) + */ + mimeType: string; + /** + * Content block type discriminator + */ + type: "image"; +} +/** + * Audio content block with base64-encoded data + */ +export interface ToolExecutionCompleteContentAudio { + /** + * Base64-encoded audio data + */ + data: string; + /** + * MIME type of the audio (e.g., audio/wav, audio/mpeg) + */ + mimeType: string; + /** + * Content block type discriminator + */ + type: "audio"; +} +/** + * Resource link content block referencing an external resource + */ +export interface ToolExecutionCompleteContentResourceLink { + /** + * Human-readable description of the resource + */ + description?: string; + /** + * Icons associated with this resource + */ + icons?: ToolExecutionCompleteContentResourceLinkIcon[]; + /** + * MIME type of the resource content + */ + mimeType?: string; + /** + * Resource name identifier + */ + name: string; + /** + * Size of the resource in bytes + */ + size?: number; + /** + * Human-readable display title for the resource + */ + title?: string; + /** + * Content block type discriminator + */ + type: "resource_link"; + /** + * URI identifying the resource + */ + uri: string; +} +/** + * Icon image for a resource + */ +export interface ToolExecutionCompleteContentResourceLinkIcon { + /** + * MIME type of the icon image + */ + mimeType?: string; + /** + * Available icon sizes (e.g., ['16x16', '32x32']) + */ + sizes?: string[]; + /** + * URL or path to the icon image + */ + src: string; + theme?: ToolExecutionCompleteContentResourceLinkIconTheme; +} +/** + * Embedded resource content block with inline text or binary data + */ +export interface ToolExecutionCompleteContentResource { + resource: ToolExecutionCompleteContentResourceDetails; + /** + * Content block type discriminator + */ + type: "resource"; +} +export interface EmbeddedTextResourceContents { + /** + * MIME type of the text content + */ + mimeType?: string; + /** + * Text content of the resource + */ + text: string; + /** + * URI identifying the resource + */ + uri: string; +} +export interface EmbeddedBlobResourceContents { + /** + * Base64-encoded binary content of the resource + */ + blob: string; + /** + * MIME type of the blob content + */ + mimeType?: string; + /** + * URI identifying the resource + */ + uri: string; +} +export interface SkillInvokedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SkillInvokedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "skill.invoked"; +} +/** + * Skill invocation details including content, allowed tools, and plugin metadata + */ +export interface SkillInvokedData { + /** + * Tool names that should be auto-approved when this skill is active + */ + allowedTools?: string[]; + /** + * Full content of the skill file, injected into the conversation for the model + */ + content: string; + /** + * Description of the skill from its SKILL.md frontmatter + */ + description?: string; + /** + * Name of the invoked skill + */ + name: string; + /** + * File path to the SKILL.md definition + */ + path: string; + /** + * Name of the plugin this skill originated from, when applicable + */ + pluginName?: string; + /** + * Version of the plugin this skill originated from, when applicable + */ + pluginVersion?: string; +} +export interface SubagentStartedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SubagentStartedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "subagent.started"; +} +/** + * Sub-agent startup details including parent tool call and agent information + */ +export interface SubagentStartedData { + /** + * Description of what the sub-agent does + */ + agentDescription: string; + /** + * Human-readable display name of the sub-agent + */ + agentDisplayName: string; + /** + * Internal name of the sub-agent + */ + agentName: string; + /** + * Tool call ID of the parent tool invocation that spawned this sub-agent + */ + toolCallId: string; +} +export interface SubagentCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SubagentCompletedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "subagent.completed"; +} +/** + * Sub-agent completion details for successful execution + */ +export interface SubagentCompletedData { + /** + * Human-readable display name of the sub-agent + */ + agentDisplayName: string; + /** + * Internal name of the sub-agent + */ + agentName: string; + /** + * Wall-clock duration of the sub-agent execution in milliseconds + */ + durationMs?: number; + /** + * Model used by the sub-agent + */ + model?: string; + /** + * Tool call ID of the parent tool invocation that spawned this sub-agent + */ + toolCallId: string; + /** + * Total tokens (input + output) consumed by the sub-agent + */ + totalTokens?: number; + /** + * Total number of tool calls made by the sub-agent + */ + totalToolCalls?: number; +} +export interface SubagentFailedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SubagentFailedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "subagent.failed"; +} +/** + * Sub-agent failure details including error message and agent information + */ +export interface SubagentFailedData { + /** + * Human-readable display name of the sub-agent + */ + agentDisplayName: string; + /** + * Internal name of the sub-agent + */ + agentName: string; + /** + * Wall-clock duration of the sub-agent execution in milliseconds + */ + durationMs?: number; + /** + * Error message describing why the sub-agent failed + */ + error: string; + /** + * Model used by the sub-agent (if any model calls succeeded before failure) + */ + model?: string; + /** + * Tool call ID of the parent tool invocation that spawned this sub-agent + */ + toolCallId: string; + /** + * Total tokens (input + output) consumed before the sub-agent failed + */ + totalTokens?: number; + /** + * Total number of tool calls made before the sub-agent failed + */ + totalToolCalls?: number; +} +export interface SubagentSelectedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SubagentSelectedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "subagent.selected"; +} +/** + * Custom agent selection details including name and available tools + */ +export interface SubagentSelectedData { + /** + * Human-readable display name of the selected custom agent + */ + agentDisplayName: string; + /** + * Internal name of the selected custom agent + */ + agentName: string; + /** + * List of tool names available to this agent, or null for all tools + */ + tools: string[] | null; +} +export interface SubagentDeselectedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SubagentDeselectedData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "subagent.deselected"; +} +/** + * Empty payload; the event signals that the custom agent was deselected, returning to the default agent + */ +export interface SubagentDeselectedData {} +export interface HookStartEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: HookStartData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "hook.start"; +} +/** + * Hook invocation start details including type and input data + */ +export interface HookStartData { + /** + * Unique identifier for this hook invocation + */ + hookInvocationId: string; + /** + * Type of hook being invoked (e.g., "preToolUse", "postToolUse", "sessionStart") + */ + hookType: string; + /** + * Input data passed to the hook + */ + input?: { + [k: string]: unknown; + }; +} +export interface HookEndEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: HookEndData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "hook.end"; +} +/** + * Hook invocation completion details including output, success status, and error information + */ +export interface HookEndData { + error?: HookEndError; + /** + * Identifier matching the corresponding hook.start event + */ + hookInvocationId: string; + /** + * Type of hook that was invoked (e.g., "preToolUse", "postToolUse", "sessionStart") + */ + hookType: string; + /** + * Output data produced by the hook + */ + output?: { + [k: string]: unknown; + }; + /** + * Whether the hook completed successfully + */ + success: boolean; +} +/** + * Error details when the hook failed + */ +export interface HookEndError { + /** + * Human-readable error message + */ + message: string; + /** + * Error stack trace, when available + */ + stack?: string; +} +export interface SystemMessageEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SystemMessageData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "system.message"; +} +/** + * System/developer instruction content with role and optional template metadata + */ +export interface SystemMessageData { + /** + * The system or developer prompt text sent as model input + */ + content: string; + metadata?: SystemMessageMetadata; + /** + * Optional name identifier for the message source + */ + name?: string; + role: SystemMessageRole; +} +/** + * Metadata about the prompt template and its construction + */ +export interface SystemMessageMetadata { + /** + * Version identifier of the prompt template used + */ + promptVersion?: string; + /** + * Template variables used when constructing the prompt + */ + variables?: { + [k: string]: unknown; + }; +} +export interface SystemNotificationEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SystemNotificationData; + /** + * When true, the event is transient and not persisted to the session event log on disk + */ + ephemeral?: boolean; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "system.notification"; +} +/** + * System-generated notification for runtime events like background task completion + */ +export interface SystemNotificationData { + /** + * The notification text, typically wrapped in XML tags + */ + content: string; + kind: SystemNotification; +} +export interface SystemNotificationAgentCompleted { + /** + * Unique identifier of the background agent + */ + agentId: string; + /** + * Type of the agent (e.g., explore, task, general-purpose) + */ + agentType: string; + /** + * Human-readable description of the agent task + */ + description?: string; + /** + * The full prompt given to the background agent + */ + prompt?: string; + status: SystemNotificationAgentCompletedStatus; + type: "agent_completed"; +} +export interface SystemNotificationAgentIdle { + /** + * Unique identifier of the background agent + */ + agentId: string; + /** + * Type of the agent (e.g., explore, task, general-purpose) + */ + agentType: string; + /** + * Human-readable description of the agent task + */ + description?: string; + type: "agent_idle"; +} +export interface SystemNotificationNewInboxMessage { + /** + * Unique identifier of the inbox entry + */ + entryId: string; + /** + * Human-readable name of the sender + */ + senderName: string; + /** + * Category of the sender (e.g., ambient-agent, plugin, hook) + */ + senderType: string; + /** + * Short summary shown before the agent decides whether to read the inbox + */ + summary: string; + type: "new_inbox_message"; +} +export interface SystemNotificationShellCompleted { + /** + * Human-readable description of the command + */ + description?: string; + /** + * Exit code of the shell command, if available + */ + exitCode?: number; + /** + * Unique identifier of the shell session + */ + shellId: string; + type: "shell_completed"; +} +export interface SystemNotificationShellDetachedCompleted { + /** + * Human-readable description of the command + */ + description?: string; + /** + * Unique identifier of the detached shell session + */ + shellId: string; + type: "shell_detached_completed"; +} +export interface PermissionRequestedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: PermissionRequestedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "permission.requested"; +} +/** + * Permission request notification requiring client approval with request details + */ +export interface PermissionRequestedData { + permissionRequest: PermissionRequest; + /** + * Unique identifier for this permission request; used to respond via session.respondToPermission() + */ + requestId: string; + /** + * When true, this permission was already resolved by a permissionRequest hook and requires no client action + */ + resolvedByHook?: boolean; +} +/** + * Shell command permission request + */ +export interface PermissionRequestShell { + /** + * Whether the UI can offer session-wide approval for this command pattern + */ + canOfferSessionApproval: boolean; + /** + * Parsed command identifiers found in the command text + */ + commands: PermissionRequestShellCommand[]; + /** + * The complete shell command text to be executed + */ + fullCommandText: string; + /** + * Whether the command includes a file write redirection (e.g., > or >>) + */ + hasWriteFileRedirection: boolean; + /** + * Human-readable description of what the command intends to do + */ + intention: string; + /** + * Permission kind discriminator + */ + kind: "shell"; + /** + * File paths that may be read or written by the command + */ + possiblePaths: string[]; + /** + * URLs that may be accessed by the command + */ + possibleUrls: PermissionRequestShellPossibleUrl[]; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; + /** + * Optional warning message about risks of running this command + */ + warning?: string; +} +export interface PermissionRequestShellCommand { + /** + * Command identifier (e.g., executable name) + */ + identifier: string; + /** + * Whether this command is read-only (no side effects) + */ + readOnly: boolean; +} +export interface PermissionRequestShellPossibleUrl { + /** + * URL that may be accessed by the command + */ + url: string; +} +/** + * File write permission request + */ +export interface PermissionRequestWrite { + /** + * Whether the UI can offer session-wide approval for file write operations + */ + canOfferSessionApproval: boolean; + /** + * Unified diff showing the proposed changes + */ + diff: string; + /** + * Path of the file being written to + */ + fileName: string; + /** + * Human-readable description of the intended file change + */ + intention: string; + /** + * Permission kind discriminator + */ + kind: "write"; + /** + * Complete new file contents for newly created files + */ + newFileContents?: string; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; +} +/** + * File or directory read permission request + */ +export interface PermissionRequestRead { + /** + * Human-readable description of why the file is being read + */ + intention: string; + /** + * Permission kind discriminator + */ + kind: "read"; + /** + * Path of the file or directory being read + */ + path: string; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; +} +/** + * MCP tool invocation permission request + */ +export interface PermissionRequestMcp { + /** + * Arguments to pass to the MCP tool + */ + args?: { + [k: string]: unknown; + }; + /** + * Permission kind discriminator + */ + kind: "mcp"; + /** + * Whether this MCP tool is read-only (no side effects) + */ + readOnly: boolean; + /** + * Name of the MCP server providing the tool + */ + serverName: string; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; + /** + * Internal name of the MCP tool + */ + toolName: string; + /** + * Human-readable title of the MCP tool + */ + toolTitle: string; +} +/** + * URL access permission request + */ +export interface PermissionRequestUrl { + /** + * Human-readable description of why the URL is being accessed + */ + intention: string; + /** + * Permission kind discriminator + */ + kind: "url"; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; + /** + * URL to be fetched + */ + url: string; +} +/** + * Memory operation permission request + */ +export interface PermissionRequestMemory { + action?: PermissionRequestMemoryAction; + /** + * Source references for the stored fact (store only) + */ + citations?: string; + direction?: PermissionRequestMemoryDirection; + /** + * The fact being stored or voted on + */ + fact: string; + /** + * Permission kind discriminator + */ + kind: "memory"; + /** + * Reason for the vote (vote only) + */ + reason?: string; + /** + * Topic or subject of the memory (store only) + */ + subject?: string; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; +} +/** + * Custom tool invocation permission request + */ +export interface PermissionRequestCustomTool { + /** + * Arguments to pass to the custom tool + */ + args?: { + [k: string]: unknown; + }; + /** + * Permission kind discriminator + */ + kind: "custom-tool"; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; + /** + * Description of what the custom tool does + */ + toolDescription: string; + /** + * Name of the custom tool + */ + toolName: string; +} +/** + * Hook confirmation permission request + */ +export interface PermissionRequestHook { + /** + * Optional message from the hook explaining why confirmation is needed + */ + hookMessage?: string; + /** + * Permission kind discriminator + */ + kind: "hook"; + /** + * Arguments of the tool call being gated + */ + toolArgs?: { + [k: string]: unknown; + }; + /** + * Tool call ID that triggered this permission request + */ + toolCallId?: string; + /** + * Name of the tool the hook is gating + */ + toolName: string; +} +export interface PermissionCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: PermissionCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "permission.completed"; +} +/** + * Permission request completion notification signaling UI dismissal + */ +export interface PermissionCompletedData { + /** + * Request ID of the resolved permission request; clients should dismiss any UI for this request + */ + requestId: string; + result: PermissionCompletedResult; +} +/** + * The result of the permission request + */ +export interface PermissionCompletedResult { + kind: PermissionCompletedKind; +} +export interface UserInputRequestedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: UserInputRequestedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "user_input.requested"; +} +/** + * User input request notification with question and optional predefined choices + */ +export interface UserInputRequestedData { + /** + * Whether the user can provide a free-form text response in addition to predefined choices + */ + allowFreeform?: boolean; + /** + * Predefined choices for the user to select from, if applicable + */ + choices?: string[]; + /** + * The question or prompt to present to the user + */ + question: string; + /** + * Unique identifier for this input request; used to respond via session.respondToUserInput() + */ + requestId: string; + /** + * The LLM-assigned tool call ID that triggered this request; used by remote UIs to correlate responses + */ + toolCallId?: string; +} +export interface UserInputCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: UserInputCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "user_input.completed"; +} +/** + * User input request completion with the user's response + */ +export interface UserInputCompletedData { + /** + * The user's answer to the input request + */ + answer?: string; + /** + * Request ID of the resolved user input request; clients should dismiss any UI for this request + */ + requestId: string; + /** + * Whether the answer was typed as free-form text rather than selected from choices + */ + wasFreeform?: boolean; +} +export interface ElicitationRequestedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ElicitationRequestedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "elicitation.requested"; +} +/** + * Elicitation request; may be form-based (structured input) or URL-based (browser redirect) + */ +export interface ElicitationRequestedData { + /** + * The source that initiated the request (MCP server name, or absent for agent-initiated) + */ + elicitationSource?: string; + /** + * Message describing what information is needed from the user + */ + message: string; + mode?: ElicitationRequestedMode; + requestedSchema?: ElicitationRequestedSchema; + /** + * Unique identifier for this elicitation request; used to respond via session.respondToElicitation() + */ + requestId: string; + /** + * Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id for remote UIs + */ + toolCallId?: string; + /** + * URL to open in the user's browser (url mode only) + */ + url?: string; + [k: string]: unknown; +} +/** + * JSON Schema describing the form fields to present to the user (form mode only) + */ +export interface ElicitationRequestedSchema { + /** + * Form field definitions, keyed by field name + */ + properties: { + [k: string]: unknown; + }; + /** + * List of required field names + */ + required?: string[]; + /** + * Schema type indicator (always 'object') + */ + type: "object"; +} +export interface ElicitationCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ElicitationCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "elicitation.completed"; +} +/** + * Elicitation request completion with the user's response + */ +export interface ElicitationCompletedData { + action?: ElicitationCompletedAction; + /** + * The submitted form data when action is 'accept'; keys match the requested schema fields + */ + content?: { + [k: string]: ElicitationCompletedContent; + }; + /** + * Request ID of the resolved elicitation request; clients should dismiss any UI for this request + */ + requestId: string; +} +export interface SamplingRequestedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SamplingRequestedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "sampling.requested"; +} +/** + * Sampling request from an MCP server; contains the server name and a requestId for correlation + */ +export interface SamplingRequestedData { + /** + * The JSON-RPC request ID from the MCP protocol + */ + mcpRequestId: string | number; + /** + * Unique identifier for this sampling request; used to respond via session.respondToSampling() + */ + requestId: string; + /** + * Name of the MCP server that initiated the sampling request + */ + serverName: string; + [k: string]: unknown; +} +export interface SamplingCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SamplingCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "sampling.completed"; +} +/** + * Sampling request completion notification signaling UI dismissal + */ +export interface SamplingCompletedData { + /** + * Request ID of the resolved sampling request; clients should dismiss any UI for this request + */ + requestId: string; +} +export interface McpOauthRequiredEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: McpOauthRequiredData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "mcp.oauth_required"; +} +/** + * OAuth authentication request for an MCP server + */ +export interface McpOauthRequiredData { + /** + * Unique identifier for this OAuth request; used to respond via session.respondToMcpOAuth() + */ + requestId: string; + /** + * Display name of the MCP server that requires OAuth + */ + serverName: string; + /** + * URL of the MCP server that requires OAuth + */ + serverUrl: string; + staticClientConfig?: McpOauthRequiredStaticClientConfig; +} +/** + * Static OAuth client configuration, if the server specifies one + */ +export interface McpOauthRequiredStaticClientConfig { + /** + * OAuth client ID for the server + */ + clientId: string; + /** + * Whether this is a public OAuth client + */ + publicClient?: boolean; +} +export interface McpOauthCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: McpOauthCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "mcp.oauth_completed"; +} +/** + * MCP OAuth request completion notification + */ +export interface McpOauthCompletedData { + /** + * Request ID of the resolved OAuth request + */ + requestId: string; +} +export interface ExternalToolRequestedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ExternalToolRequestedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "external_tool.requested"; +} +/** + * External tool invocation request for client-side tool execution + */ +export interface ExternalToolRequestedData { + /** + * Arguments to pass to the external tool + */ + arguments?: { + [k: string]: unknown; + }; + /** + * Unique identifier for this request; used to respond via session.respondToExternalTool() + */ + requestId: string; + /** + * Session ID that this external tool request belongs to + */ + sessionId: string; + /** + * Tool call ID assigned to this external tool invocation + */ + toolCallId: string; + /** + * Name of the external tool to invoke + */ + toolName: string; + /** + * W3C Trace Context traceparent header for the execute_tool span + */ + traceparent?: string; + /** + * W3C Trace Context tracestate header for the execute_tool span + */ + tracestate?: string; +} +export interface ExternalToolCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ExternalToolCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "external_tool.completed"; +} +/** + * External tool completion notification signaling UI dismissal + */ +export interface ExternalToolCompletedData { + /** + * Request ID of the resolved external tool request; clients should dismiss any UI for this request + */ + requestId: string; +} +export interface CommandQueuedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CommandQueuedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "command.queued"; +} +/** + * Queued slash command dispatch request for client execution + */ +export interface CommandQueuedData { + /** + * The slash command text to be executed (e.g., /help, /clear) + */ + command: string; + /** + * Unique identifier for this request; used to respond via session.respondToQueuedCommand() + */ + requestId: string; +} +export interface CommandExecuteEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CommandExecuteData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "command.execute"; +} +/** + * Registered command dispatch request routed to the owning client + */ +export interface CommandExecuteData { + /** + * Raw argument string after the command name + */ + args: string; + /** + * The full command text (e.g., /deploy production) + */ + command: string; + /** + * Command name without leading / + */ + commandName: string; + /** + * Unique identifier; used to respond via session.commands.handlePendingCommand() + */ + requestId: string; +} +export interface CommandCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CommandCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "command.completed"; +} +/** + * Queued command completion notification signaling UI dismissal + */ +export interface CommandCompletedData { + /** + * Request ID of the resolved command request; clients should dismiss any UI for this request + */ + requestId: string; +} +export interface CommandsChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CommandsChangedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "commands.changed"; +} +/** + * SDK command registration change notification + */ +export interface CommandsChangedData { + /** + * Current list of registered SDK commands + */ + commands: CommandsChangedCommand[]; +} +export interface CommandsChangedCommand { + description?: string; + name: string; +} +export interface CapabilitiesChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CapabilitiesChangedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "capabilities.changed"; +} +/** + * Session capability change notification + */ +export interface CapabilitiesChangedData { + ui?: CapabilitiesChangedUI; +} +/** + * UI capability changes + */ +export interface CapabilitiesChangedUI { + /** + * Whether elicitation is now supported + */ + elicitation?: boolean; +} +export interface ExitPlanModeRequestedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ExitPlanModeRequestedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "exit_plan_mode.requested"; +} +/** + * Plan approval request with plan content and available user actions + */ +export interface ExitPlanModeRequestedData { + /** + * Available actions the user can take (e.g., approve, edit, reject) + */ + actions: string[]; + /** + * Full content of the plan file + */ + planContent: string; + /** + * The recommended action for the user to take + */ + recommendedAction: string; + /** + * Unique identifier for this request; used to respond via session.respondToExitPlanMode() + */ + requestId: string; + /** + * Summary of the plan that was created + */ + summary: string; +} +export interface ExitPlanModeCompletedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ExitPlanModeCompletedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "exit_plan_mode.completed"; +} +/** + * Plan mode exit completion with the user's approval decision and optional feedback + */ +export interface ExitPlanModeCompletedData { + /** + * Whether the plan was approved by the user + */ + approved?: boolean; + /** + * Whether edits should be auto-approved without confirmation + */ + autoApproveEdits?: boolean; + /** + * Free-form feedback from the user if they requested changes to the plan + */ + feedback?: string; + /** + * Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request + */ + requestId: string; + /** + * Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only') + */ + selectedAction?: string; +} +export interface ToolsUpdatedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ToolsUpdatedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.tools_updated"; +} +export interface ToolsUpdatedData { + model: string; +} +export interface BackgroundTasksChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: BackgroundTasksChangedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.background_tasks_changed"; +} +export interface BackgroundTasksChangedData {} +export interface SkillsLoadedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: SkillsLoadedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.skills_loaded"; +} +export interface SkillsLoadedData { + /** + * Array of resolved skill metadata + */ + skills: SkillsLoadedSkill[]; +} +export interface SkillsLoadedSkill { + /** + * Description of what the skill does + */ + description: string; + /** + * Whether the skill is currently enabled + */ + enabled: boolean; + /** + * Unique identifier for the skill + */ + name: string; + /** + * Absolute path to the skill file, if available + */ + path?: string; + /** + * Source location type of the skill (e.g., project, personal, plugin) + */ + source: string; + /** + * Whether the skill can be invoked by the user as a slash command + */ + userInvocable: boolean; +} +export interface CustomAgentsUpdatedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: CustomAgentsUpdatedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.custom_agents_updated"; +} +export interface CustomAgentsUpdatedData { + /** + * Array of loaded custom agent metadata + */ + agents: CustomAgentsUpdatedAgent[]; + /** + * Fatal errors from agent loading + */ + errors: string[]; + /** + * Non-fatal warnings from agent loading + */ + warnings: string[]; +} +export interface CustomAgentsUpdatedAgent { + /** + * Description of what the agent does + */ + description: string; + /** + * Human-readable display name + */ + displayName: string; + /** + * Unique identifier for the agent + */ + id: string; + /** + * Model override for this agent, if set + */ + model?: string; + /** + * Internal name of the agent + */ + name: string; + /** + * Source location: user, project, inherited, remote, or plugin + */ + source: string; + /** + * List of tool names available to this agent + */ + tools: string[]; + /** + * Whether the agent can be selected by the user + */ + userInvocable: boolean; +} +export interface McpServersLoadedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: McpServersLoadedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.mcp_servers_loaded"; +} +export interface McpServersLoadedData { + /** + * Array of MCP server status summaries + */ + servers: McpServersLoadedServer[]; +} +export interface McpServersLoadedServer { + /** + * Error message if the server failed to connect + */ + error?: string; + /** + * Server name (config key) + */ + name: string; + /** + * Configuration source: user, workspace, plugin, or builtin + */ + source?: string; + status: McpServersLoadedServerStatus; +} +export interface McpServerStatusChangedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: McpServerStatusChangedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.mcp_server_status_changed"; +} +export interface McpServerStatusChangedData { + /** + * Name of the MCP server whose status changed + */ + serverName: string; + status: McpServerStatusChangedStatus; +} +export interface ExtensionsLoadedEvent { + /** + * Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. + */ + agentId?: string; + data: ExtensionsLoadedData; + ephemeral: true; + /** + * Unique event identifier (UUID v4), generated when the event is emitted + */ + id: string; + /** + * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event. + */ + parentId: string | null; + /** + * ISO 8601 timestamp when the event was created + */ + timestamp: string; + type: "session.extensions_loaded"; +} +export interface ExtensionsLoadedData { + /** + * Array of discovered extensions and their status + */ + extensions: ExtensionsLoadedExtension[]; +} +export interface ExtensionsLoadedExtension { + /** + * Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper') + */ + id: string; + /** + * Extension name (directory name) + */ + name: string; + source: ExtensionsLoadedExtensionSource; + status: ExtensionsLoadedExtensionStatus; } diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index e2942998a..2c80cad69 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -14,6 +14,7 @@ export { defineTool, approveAll, convertMcpCallToolResult, + createSessionFsAdapter, SYSTEM_PROMPT_SECTIONS, } from "./types.js"; export type { @@ -66,7 +67,8 @@ export type { SessionMetadata, SessionUiApi, SessionFsConfig, - SessionFsHandler, + SessionFsProvider, + SessionFsFileInfo, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, diff --git a/nodejs/src/sessionFsProvider.ts b/nodejs/src/sessionFsProvider.ts new file mode 100644 index 000000000..721a990ec --- /dev/null +++ b/nodejs/src/sessionFsProvider.ts @@ -0,0 +1,159 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import type { + SessionFsHandler, + SessionFsError, + SessionFsStatResult, + SessionFsReaddirWithTypesEntry, +} from "./generated/rpc.js"; + +/** + * File metadata returned by {@link SessionFsProvider.stat}. + * Same shape as the generated {@link SessionFsStatResult} but without the + * `error` field, since providers signal errors by throwing. + */ +export type SessionFsFileInfo = Omit; + +/** + * Interface for session filesystem providers. Implementors use idiomatic + * TypeScript patterns: throw on error, return values directly. Use + * {@link createSessionFsAdapter} to convert a provider into the + * {@link SessionFsHandler} expected by the SDK. + * + * Errors with a `code` property of `"ENOENT"` are mapped to the ENOENT + * error code; all others map to UNKNOWN. + */ +export interface SessionFsProvider { + /** Reads the full content of a file. Throw if the file does not exist. */ + readFile(path: string): Promise; + + /** Writes content to a file, creating parent directories if needed. */ + writeFile(path: string, content: string, mode?: number): Promise; + + /** Appends content to a file, creating parent directories if needed. */ + appendFile(path: string, content: string, mode?: number): Promise; + + /** Checks whether a path exists. */ + exists(path: string): Promise; + + /** Gets metadata about a file or directory. Throw if it does not exist. */ + stat(path: string): Promise; + + /** Creates a directory. If recursive is true, creates parents as needed. */ + mkdir(path: string, recursive: boolean, mode?: number): Promise; + + /** Lists entry names in a directory. Throw if it does not exist. */ + readdir(path: string): Promise; + + /** Lists entries with type info. Throw if the directory does not exist. */ + readdirWithTypes(path: string): Promise; + + /** Removes a file or directory. If force is true, do not throw on ENOENT. */ + rm(path: string, recursive: boolean, force: boolean): Promise; + + /** Renames/moves a file or directory. */ + rename(src: string, dest: string): Promise; +} + +/** + * Wraps a {@link SessionFsProvider} into the {@link SessionFsHandler} + * interface expected by the SDK, converting thrown errors into + * {@link SessionFsError} results. + */ +export function createSessionFsAdapter(provider: SessionFsProvider): SessionFsHandler { + return { + readFile: async ({ path }) => { + try { + const content = await provider.readFile(path); + return { content }; + } catch (err) { + return { content: "", error: toSessionFsError(err) }; + } + }, + writeFile: async ({ path, content, mode }) => { + try { + await provider.writeFile(path, content, mode); + return undefined; + } catch (err) { + return toSessionFsError(err); + } + }, + appendFile: async ({ path, content, mode }) => { + try { + await provider.appendFile(path, content, mode); + return undefined; + } catch (err) { + return toSessionFsError(err); + } + }, + exists: async ({ path }) => { + try { + return { exists: await provider.exists(path) }; + } catch { + return { exists: false }; + } + }, + stat: async ({ path }) => { + try { + return await provider.stat(path); + } catch (err) { + return { + isFile: false, + isDirectory: false, + size: 0, + mtime: new Date().toISOString(), + birthtime: new Date().toISOString(), + error: toSessionFsError(err), + }; + } + }, + mkdir: async ({ path, recursive, mode }) => { + try { + await provider.mkdir(path, recursive ?? false, mode); + return undefined; + } catch (err) { + return toSessionFsError(err); + } + }, + readdir: async ({ path }) => { + try { + const entries = await provider.readdir(path); + return { entries }; + } catch (err) { + return { entries: [], error: toSessionFsError(err) }; + } + }, + readdirWithTypes: async ({ path }) => { + try { + const entries = await provider.readdirWithTypes(path); + return { entries }; + } catch (err) { + return { entries: [], error: toSessionFsError(err) }; + } + }, + rm: async ({ path, recursive, force }) => { + try { + await provider.rm(path, recursive ?? false, force ?? false); + return undefined; + } catch (err) { + return toSessionFsError(err); + } + }, + rename: async ({ src, dest }) => { + try { + await provider.rename(src, dest); + return undefined; + } catch (err) { + return toSessionFsError(err); + } + }, + }; +} + +function toSessionFsError(err: unknown): SessionFsError { + const e = err as NodeJS.ErrnoException; + const code = e.code === "ENOENT" ? "ENOENT" : "UNKNOWN"; + return { code, message: e.message ?? String(err) }; +} diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 9b2df4193..fb46635ae 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -7,11 +7,13 @@ */ // Import and re-export generated session event types -import type { SessionFsHandler } from "./generated/rpc.js"; +import type { SessionFsProvider } from "./sessionFsProvider.js"; import type { SessionEvent as GeneratedSessionEvent } from "./generated/session-events.js"; import type { CopilotSession } from "./session.js"; export type SessionEvent = GeneratedSessionEvent; -export type { SessionFsHandler } from "./generated/rpc.js"; +export type { SessionFsProvider } from "./sessionFsProvider.js"; +export { createSessionFsAdapter } from "./sessionFsProvider.js"; +export type { SessionFsFileInfo } from "./sessionFsProvider.js"; /** * Options for creating a CopilotClient @@ -739,9 +741,8 @@ export type SystemMessageConfig = * Permission request types from the server */ export interface PermissionRequest { - kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool"; + kind: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "memory" | "hook"; toolCallId?: string; - [key: string]: unknown; } import type { PermissionDecisionRequest } from "./generated/rpc.js"; @@ -1331,7 +1332,7 @@ export interface SessionConfig { * Supplies a handler for session filesystem operations. This takes effect * only if {@link CopilotClientOptions.sessionFs} is configured. */ - createSessionFsHandler?: (session: CopilotSession) => SessionFsHandler; + createSessionFsHandler?: (session: CopilotSession) => SessionFsProvider; } /** diff --git a/nodejs/test/e2e/session_fs.test.ts b/nodejs/test/e2e/session_fs.test.ts index 8185a55be..f455ffcd1 100644 --- a/nodejs/test/e2e/session_fs.test.ts +++ b/nodejs/test/e2e/session_fs.test.ts @@ -6,13 +6,15 @@ import { SessionCompactionCompleteEvent } from "@github/copilot/sdk"; import { MemoryProvider, VirtualProvider } from "@platformatic/vfs"; import { describe, expect, it, onTestFinished } from "vitest"; import { CopilotClient } from "../../src/client.js"; -import { SessionFsHandler } from "../../src/generated/rpc.js"; +import type { SessionFsReaddirWithTypesEntry } from "../../src/generated/rpc.js"; import { approveAll, CopilotSession, defineTool, SessionEvent, type SessionFsConfig, + type SessionFsProvider, + type SessionFsFileInfo, } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; @@ -123,6 +125,46 @@ describe("Session Fs", async () => { expect(fileContent).toBe(suppliedFileContent); }); + it("should write workspace metadata via sessionFs", async () => { + const session = await client.createSession({ + onPermissionRequest: approveAll, + createSessionFsHandler, + }); + + const msg = await session.sendAndWait({ prompt: "What is 7 * 8?" }); + expect(msg?.data.content).toContain("56"); + + // WorkspaceManager should have created workspace.yaml via sessionFs + const workspaceYamlPath = p(session.sessionId, "/session-state/workspace.yaml"); + await expect.poll(() => provider.exists(workspaceYamlPath)).toBe(true); + const yaml = await provider.readFile(workspaceYamlPath, "utf8"); + expect(yaml).toContain("id:"); + + // Checkpoint index should also exist + const indexPath = p(session.sessionId, "/session-state/checkpoints/index.md"); + await expect.poll(() => provider.exists(indexPath)).toBe(true); + + await session.disconnect(); + }); + + it("should persist plan.md via sessionFs", async () => { + const session = await client.createSession({ + onPermissionRequest: approveAll, + createSessionFsHandler, + }); + + // Write a plan via the session RPC + await session.sendAndWait({ prompt: "What is 2 + 3?" }); + await session.rpc.plan.update({ content: "# Test Plan\n\nThis is a test." }); + + const planPath = p(session.sessionId, "/session-state/plan.md"); + await expect.poll(() => provider.exists(planPath)).toBe(true); + const content = await provider.readFile(planPath, "utf8"); + expect(content).toContain("# Test Plan"); + + await session.disconnect(); + }); + it("should succeed with compaction while using sessionFs", async () => { const session = await client.createSession({ onPermissionRequest: approveAll, @@ -177,26 +219,24 @@ const sessionFsConfig: SessionFsConfig = { function createTestSessionFsHandler( session: CopilotSession, provider: VirtualProvider -): SessionFsHandler { - const sp = (sessionId: string, path: string) => - `/${sessionId}${path.startsWith("/") ? path : "/" + path}`; +): SessionFsProvider { + const sp = (path: string) => `/${session.sessionId}${path.startsWith("/") ? path : "/" + path}`; return { - readFile: async ({ path }) => { - const content = await provider.readFile(sp(session.sessionId, path), "utf8"); - return { content: content as string }; + async readFile(path: string): Promise { + return (await provider.readFile(sp(path), "utf8")) as string; }, - writeFile: async ({ path, content }) => { - await provider.writeFile(sp(session.sessionId, path), content); + async writeFile(path: string, content: string): Promise { + await provider.writeFile(sp(path), content); }, - appendFile: async ({ path, content }) => { - await provider.appendFile(sp(session.sessionId, path), content); + async appendFile(path: string, content: string): Promise { + await provider.appendFile(sp(path), content); }, - exists: async ({ path }) => { - return { exists: await provider.exists(sp(session.sessionId, path)) }; + async exists(path: string): Promise { + return provider.exists(sp(path)); }, - stat: async ({ path }) => { - const st = await provider.stat(sp(session.sessionId, path)); + async stat(path: string): Promise { + const st = await provider.stat(sp(path)); return { isFile: st.isFile(), isDirectory: st.isDirectory(), @@ -205,34 +245,29 @@ function createTestSessionFsHandler( birthtime: new Date(st.birthtimeMs).toISOString(), }; }, - mkdir: async ({ path, recursive, mode }) => { - await provider.mkdir(sp(session.sessionId, path), { - recursive: recursive ?? false, - mode, - }); + async mkdir(path: string, recursive: boolean, mode?: number): Promise { + await provider.mkdir(sp(path), { recursive, mode }); }, - readdir: async ({ path }) => { - const entries = await provider.readdir(sp(session.sessionId, path)); - return { entries: entries as string[] }; + async readdir(path: string): Promise { + return (await provider.readdir(sp(path))) as string[]; }, - readdirWithTypes: async ({ path }) => { - const names = (await provider.readdir(sp(session.sessionId, path))) as string[]; - const entries = await Promise.all( + async readdirWithTypes(path: string): Promise { + const names = (await provider.readdir(sp(path))) as string[]; + return Promise.all( names.map(async (name) => { - const st = await provider.stat(sp(session.sessionId, `${path}/${name}`)); + const st = await provider.stat(sp(`${path}/${name}`)); return { name, type: st.isDirectory() ? ("directory" as const) : ("file" as const), }; }) ); - return { entries }; }, - rm: async ({ path }) => { - await provider.unlink(sp(session.sessionId, path)); + async rm(path: string): Promise { + await provider.unlink(sp(path)); }, - rename: async ({ src, dest }) => { - await provider.rename(sp(session.sessionId, src), sp(session.sessionId, dest)); + async rename(src: string, dest: string): Promise { + await provider.rename(sp(src), sp(dest)); }, }; } diff --git a/python/copilot/__init__.py b/python/copilot/__init__.py index 190c058a0..ad9e28803 100644 --- a/python/copilot/__init__.py +++ b/python/copilot/__init__.py @@ -26,10 +26,14 @@ ProviderConfig, SessionCapabilities, SessionFsConfig, - SessionFsHandler, SessionUiApi, SessionUiCapabilities, ) +from .session_fs_provider import ( + SessionFsFileInfo, + SessionFsProvider, + create_session_fs_adapter, +) from .tools import convert_mcp_call_tool_result, define_tool __version__ = "0.1.0" @@ -53,7 +57,9 @@ "ProviderConfig", "SessionCapabilities", "SessionFsConfig", - "SessionFsHandler", + "SessionFsFileInfo", + "SessionFsProvider", + "create_session_fs_adapter", "SessionUiApi", "SessionUiCapabilities", "SubprocessConfig", diff --git a/python/copilot/_jsonrpc.py b/python/copilot/_jsonrpc.py index 287f1b965..8a200cc8d 100644 --- a/python/copilot/_jsonrpc.py +++ b/python/copilot/_jsonrpc.py @@ -328,7 +328,8 @@ def _handle_message(self, message: dict): self._handle_request(message) def _handle_request(self, message: dict): - handler = self.request_handlers.get(message["method"]) + method = message.get("method", "") + handler = self.request_handlers.get(method) if not handler: if self._loop: asyncio.run_coroutine_threadsafe( @@ -351,17 +352,17 @@ async def _dispatch_request(self, message: dict, handler: RequestHandler): outcome = handler(params) if inspect.isawaitable(outcome): outcome = await outcome - if outcome is None: - outcome = {} - if not isinstance(outcome, dict): - raise ValueError("Request handler must return a dict") + if outcome is not None and not isinstance(outcome, dict): + raise ValueError( + f"Request handler must return a dict, got {type(outcome).__name__}" + ) await self._send_response(message["id"], outcome) except JsonRpcError as exc: await self._send_error_response(message["id"], exc.code, exc.message, exc.data) except Exception as exc: # pylint: disable=broad-except await self._send_error_response(message["id"], -32603, str(exc), None) - async def _send_response(self, request_id: str, result: dict): + async def _send_response(self, request_id: str, result: dict | None): response = { "jsonrpc": "2.0", "id": request_id, diff --git a/python/copilot/client.py b/python/copilot/client.py index 4c1186f23..5f70e0b62 100644 --- a/python/copilot/client.py +++ b/python/copilot/client.py @@ -59,6 +59,7 @@ UserInputHandler, _PermissionHandlerFn, ) +from .session_fs_provider import create_session_fs_adapter from .tools import Tool, ToolInvocation, ToolResult # ============================================================================ @@ -1427,7 +1428,9 @@ async def create_session( "create_session_fs_handler is required in session config when " "session_fs is enabled in client options." ) - session._client_session_apis.session_fs = create_session_fs_handler(session) + session._client_session_apis.session_fs = create_session_fs_adapter( + create_session_fs_handler(session) + ) session._register_tools(tools) session._register_commands(commands) session._register_permission_handler(on_permission_request) @@ -1682,7 +1685,9 @@ async def resume_session( "create_session_fs_handler is required in session config when " "session_fs is enabled in client options." ) - session._client_session_apis.session_fs = create_session_fs_handler(session) + session._client_session_apis.session_fs = create_session_fs_adapter( + create_session_fs_handler(session) + ) session._register_tools(tools) session._register_commands(commands) session._register_permission_handler(on_permission_request) diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 1aa658823..67c41fc96 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -25,9 +25,13 @@ def from_int(x: Any) -> int: assert isinstance(x, int) and not isinstance(x, bool) return x -def from_list(f: Callable[[Any], T], x: Any) -> list[T]: - assert isinstance(x, list) - return [f(y) for y in x] +def from_bool(x: Any) -> bool: + assert isinstance(x, bool) + return x + +def from_float(x: Any) -> float: + assert isinstance(x, (float, int)) and not isinstance(x, bool) + return float(x) def from_str(x: Any) -> str: assert isinstance(x, str) @@ -45,126 +49,180 @@ def from_union(fs, x): pass assert False -def to_class(c: type[T], x: Any) -> dict: - assert isinstance(x, c) - return cast(Any, x).to_dict() - -def from_bool(x: Any) -> bool: - assert isinstance(x, bool) +def to_float(x: Any) -> float: + assert isinstance(x, (int, float)) return x def from_dict(f: Callable[[Any], T], x: Any) -> dict[str, T]: assert isinstance(x, dict) return { k: f(v) for (k, v) in x.items() } -def to_enum(c: type[EnumT], x: Any) -> EnumT: +def to_class(c: type[T], x: Any) -> dict: assert isinstance(x, c) - return x.value + return cast(Any, x).to_dict() -def from_float(x: Any) -> float: - assert isinstance(x, (float, int)) and not isinstance(x, bool) - return float(x) +def from_list(f: Callable[[Any], T], x: Any) -> list[T]: + assert isinstance(x, list) + return [f(y) for y in x] -def to_float(x: Any) -> float: - assert isinstance(x, (int, float)) - return x +def to_enum(c: type[EnumT], x: Any) -> EnumT: + assert isinstance(x, c) + return x.value def from_datetime(x: Any) -> datetime: return dateutil.parser.parse(x) @dataclass -class PurpleModelCapabilitiesLimitsVision: - """Vision-specific limits""" +class AccountQuotaSnapshot: + entitlement_requests: int + """Number of requests included in the entitlement""" - max_prompt_image_size: int - """Maximum image size in bytes""" + is_unlimited_entitlement: bool + """Whether the user has an unlimited usage entitlement""" - max_prompt_images: int - """Maximum number of images per prompt""" + overage: float + """Number of overage requests made this period""" - supported_media_types: list[str] - """MIME types the model accepts""" + overage_allowed_with_exhausted_quota: bool + """Whether overage is allowed when quota is exhausted""" + + remaining_percentage: float + """Percentage of entitlement remaining""" + + usage_allowed_with_exhausted_quota: bool + """Whether usage is still permitted after quota exhaustion""" + + used_requests: int + """Number of requests used so far this period""" + + reset_date: str | None = None + """Date when the quota resets (ISO 8601 string)""" @staticmethod - def from_dict(obj: Any) -> 'PurpleModelCapabilitiesLimitsVision': + def from_dict(obj: Any) -> 'AccountQuotaSnapshot': assert isinstance(obj, dict) - max_prompt_image_size = from_int(obj.get("max_prompt_image_size")) - max_prompt_images = from_int(obj.get("max_prompt_images")) - supported_media_types = from_list(from_str, obj.get("supported_media_types")) - return PurpleModelCapabilitiesLimitsVision(max_prompt_image_size, max_prompt_images, supported_media_types) + entitlement_requests = from_int(obj.get("entitlementRequests")) + is_unlimited_entitlement = from_bool(obj.get("isUnlimitedEntitlement")) + overage = from_float(obj.get("overage")) + overage_allowed_with_exhausted_quota = from_bool(obj.get("overageAllowedWithExhaustedQuota")) + remaining_percentage = from_float(obj.get("remainingPercentage")) + usage_allowed_with_exhausted_quota = from_bool(obj.get("usageAllowedWithExhaustedQuota")) + used_requests = from_int(obj.get("usedRequests")) + reset_date = from_union([from_str, from_none], obj.get("resetDate")) + return AccountQuotaSnapshot(entitlement_requests, is_unlimited_entitlement, overage, overage_allowed_with_exhausted_quota, remaining_percentage, usage_allowed_with_exhausted_quota, used_requests, reset_date) def to_dict(self) -> dict: result: dict = {} - result["max_prompt_image_size"] = from_int(self.max_prompt_image_size) - result["max_prompt_images"] = from_int(self.max_prompt_images) - result["supported_media_types"] = from_list(from_str, self.supported_media_types) + result["entitlementRequests"] = from_int(self.entitlement_requests) + result["isUnlimitedEntitlement"] = from_bool(self.is_unlimited_entitlement) + result["overage"] = to_float(self.overage) + result["overageAllowedWithExhaustedQuota"] = from_bool(self.overage_allowed_with_exhausted_quota) + result["remainingPercentage"] = to_float(self.remaining_percentage) + result["usageAllowedWithExhaustedQuota"] = from_bool(self.usage_allowed_with_exhausted_quota) + result["usedRequests"] = from_int(self.used_requests) + if self.reset_date is not None: + result["resetDate"] = from_union([from_str, from_none], self.reset_date) return result @dataclass -class ModelCapabilitiesSupports: - """Feature flags indicating what the model supports""" +class AgentInfo: + """The newly selected custom agent""" - reasoning_effort: bool | None = None - """Whether this model supports reasoning effort configuration""" + description: str + """Description of the agent's purpose""" - vision: bool | None = None - """Whether this model supports vision/image input""" + display_name: str + """Human-readable display name""" + + name: str + """Unique identifier of the custom agent""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesSupports': + def from_dict(obj: Any) -> 'AgentInfo': assert isinstance(obj, dict) - reasoning_effort = from_union([from_bool, from_none], obj.get("reasoningEffort")) - vision = from_union([from_bool, from_none], obj.get("vision")) - return ModelCapabilitiesSupports(reasoning_effort, vision) + description = from_str(obj.get("description")) + display_name = from_str(obj.get("displayName")) + name = from_str(obj.get("name")) + return AgentInfo(description, display_name, name) def to_dict(self) -> dict: result: dict = {} - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_bool, from_none], self.reasoning_effort) - if self.vision is not None: - result["vision"] = from_union([from_bool, from_none], self.vision) + result["description"] = from_str(self.description) + result["displayName"] = from_str(self.display_name) + result["name"] = from_str(self.name) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ModelCapabilitiesLimitsVision: - """Vision-specific limits""" +class AgentSelectRequest: + name: str + """Name of the custom agent to select""" - max_prompt_image_size: int - """Maximum image size in bytes""" + @staticmethod + def from_dict(obj: Any) -> 'AgentSelectRequest': + assert isinstance(obj, dict) + name = from_str(obj.get("name")) + return AgentSelectRequest(name) - max_prompt_images: int - """Maximum number of images per prompt""" + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_str(self.name) + return result - supported_media_types: list[str] - """MIME types the model accepts""" +@dataclass +class CommandsHandlePendingCommandRequest: + request_id: str + """Request ID from the command invocation event""" + + error: str | None = None + """Error message if the command handler failed""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesLimitsVision': + def from_dict(obj: Any) -> 'CommandsHandlePendingCommandRequest': assert isinstance(obj, dict) - max_prompt_image_size = from_int(obj.get("max_prompt_image_size")) - max_prompt_images = from_int(obj.get("max_prompt_images")) - supported_media_types = from_list(from_str, obj.get("supported_media_types")) - return ModelCapabilitiesLimitsVision(max_prompt_image_size, max_prompt_images, supported_media_types) + request_id = from_str(obj.get("requestId")) + error = from_union([from_str, from_none], obj.get("error")) + return CommandsHandlePendingCommandRequest(request_id, error) def to_dict(self) -> dict: result: dict = {} - result["max_prompt_image_size"] = from_int(self.max_prompt_image_size) - result["max_prompt_images"] = from_int(self.max_prompt_images) - result["supported_media_types"] = from_list(from_str, self.supported_media_types) + result["requestId"] = from_str(self.request_id) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) return result -class FilterMappingString(Enum): - HIDDEN_CHARACTERS = "hidden_characters" - MARKDOWN = "markdown" - NONE = "none" +@dataclass +class CommandsHandlePendingCommandResult: + success: bool + """Whether the command was handled successfully""" -class MCPServerConfigType(Enum): - """Remote transport type. Defaults to "http" when omitted.""" + @staticmethod + def from_dict(obj: Any) -> 'CommandsHandlePendingCommandResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + return CommandsHandlePendingCommandResult(success) - HTTP = "http" - LOCAL = "local" - SSE = "sse" - STDIO = "stdio" + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + return result + +@dataclass +class CurrentModel: + model_id: str | None = None + """Currently active model identifier""" + + @staticmethod + def from_dict(obj: Any) -> 'CurrentModel': + assert isinstance(obj, dict) + model_id = from_union([from_str, from_none], obj.get("modelId")) + return CurrentModel(model_id) + + def to_dict(self) -> dict: + result: dict = {} + if self.model_id is not None: + result["modelId"] = from_union([from_str, from_none], self.model_id) + return result class MCPServerSource(Enum): """Configuration source @@ -184,390 +242,331 @@ class DiscoveredMCPServerType(Enum): SSE = "sse" STDIO = "stdio" -@dataclass -class SkillElement: - description: str - """Description of what the skill does""" - - enabled: bool - """Whether the skill is currently enabled (based on global config)""" - - name: str - """Unique identifier for the skill""" +class ExtensionSource(Enum): + """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" - source: str - """Source location type (e.g., project, personal-copilot, plugin, builtin)""" + PROJECT = "project" + USER = "user" - user_invocable: bool - """Whether the skill can be invoked by the user as a slash command""" +class ExtensionStatus(Enum): + """Current status: running, disabled, failed, or starting""" - path: str | None = None - """Absolute path to the skill file""" + DISABLED = "disabled" + FAILED = "failed" + RUNNING = "running" + STARTING = "starting" - project_path: str | None = None - """The project path this skill belongs to (only for project/inherited skills)""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ExtensionsDisableRequest: + id: str + """Source-qualified extension ID to disable""" @staticmethod - def from_dict(obj: Any) -> 'SkillElement': + def from_dict(obj: Any) -> 'ExtensionsDisableRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = from_str(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - path = from_union([from_str, from_none], obj.get("path")) - project_path = from_union([from_str, from_none], obj.get("projectPath")) - return SkillElement(description, enabled, name, source, user_invocable, path, project_path) + id = from_str(obj.get("id")) + return ExtensionsDisableRequest(id) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = from_str(self.source) - result["userInvocable"] = from_bool(self.user_invocable) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.project_path is not None: - result["projectPath"] = from_union([from_str, from_none], self.project_path) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ServerSkill: - description: str - """Description of what the skill does""" +class ExtensionsEnableRequest: + id: str + """Source-qualified extension ID to enable""" - enabled: bool - """Whether the skill is currently enabled (based on global config)""" + @staticmethod + def from_dict(obj: Any) -> 'ExtensionsEnableRequest': + assert isinstance(obj, dict) + id = from_str(obj.get("id")) + return ExtensionsEnableRequest(id) - name: str - """Unique identifier for the skill""" + def to_dict(self) -> dict: + result: dict = {} + result["id"] = from_str(self.id) + return result - source: str - """Source location type (e.g., project, personal-copilot, plugin, builtin)""" - - user_invocable: bool - """Whether the skill can be invoked by the user as a slash command""" - - path: str | None = None - """Absolute path to the skill file""" +class FilterMappingString(Enum): + HIDDEN_CHARACTERS = "hidden_characters" + MARKDOWN = "markdown" + NONE = "none" - project_path: str | None = None - """The project path this skill belongs to (only for project/inherited skills)""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class FleetStartRequest: + prompt: str | None = None + """Optional user prompt to combine with fleet instructions""" @staticmethod - def from_dict(obj: Any) -> 'ServerSkill': + def from_dict(obj: Any) -> 'FleetStartRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = from_str(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - path = from_union([from_str, from_none], obj.get("path")) - project_path = from_union([from_str, from_none], obj.get("projectPath")) - return ServerSkill(description, enabled, name, source, user_invocable, path, project_path) + prompt = from_union([from_str, from_none], obj.get("prompt")) + return FleetStartRequest(prompt) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = from_str(self.source) - result["userInvocable"] = from_bool(self.user_invocable) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.project_path is not None: - result["projectPath"] = from_union([from_str, from_none], self.project_path) + if self.prompt is not None: + result["prompt"] = from_union([from_str, from_none], self.prompt) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class CurrentModel: - model_id: str | None = None - """Currently active model identifier""" +class FleetStartResult: + started: bool + """Whether fleet mode was successfully activated""" @staticmethod - def from_dict(obj: Any) -> 'CurrentModel': + def from_dict(obj: Any) -> 'FleetStartResult': assert isinstance(obj, dict) - model_id = from_union([from_str, from_none], obj.get("modelId")) - return CurrentModel(model_id) + started = from_bool(obj.get("started")) + return FleetStartResult(started) def to_dict(self) -> dict: result: dict = {} - if self.model_id is not None: - result["modelId"] = from_union([from_str, from_none], self.model_id) + result["started"] = from_bool(self.started) return result @dataclass -class PurpleModelCapabilitiesOverrideLimitsVision: - max_prompt_image_size: int | None = None - """Maximum image size in bytes""" - - max_prompt_images: int | None = None - """Maximum number of images per prompt""" - - supported_media_types: list[str] | None = None - """MIME types the model accepts""" +class HandleToolCallResult: + success: bool + """Whether the tool call result was handled successfully""" @staticmethod - def from_dict(obj: Any) -> 'PurpleModelCapabilitiesOverrideLimitsVision': + def from_dict(obj: Any) -> 'HandleToolCallResult': assert isinstance(obj, dict) - max_prompt_image_size = from_union([from_int, from_none], obj.get("max_prompt_image_size")) - max_prompt_images = from_union([from_int, from_none], obj.get("max_prompt_images")) - supported_media_types = from_union([lambda x: from_list(from_str, x), from_none], obj.get("supported_media_types")) - return PurpleModelCapabilitiesOverrideLimitsVision(max_prompt_image_size, max_prompt_images, supported_media_types) + success = from_bool(obj.get("success")) + return HandleToolCallResult(success) def to_dict(self) -> dict: result: dict = {} - if self.max_prompt_image_size is not None: - result["max_prompt_image_size"] = from_union([from_int, from_none], self.max_prompt_image_size) - if self.max_prompt_images is not None: - result["max_prompt_images"] = from_union([from_int, from_none], self.max_prompt_images) - if self.supported_media_types is not None: - result["supported_media_types"] = from_union([lambda x: from_list(from_str, x), from_none], self.supported_media_types) + result["success"] = from_bool(self.success) return result @dataclass -class ModelCapabilitiesOverrideSupports: - """Feature flags indicating what the model supports""" +class HistoryCompactContextWindow: + """Post-compaction context window usage breakdown""" - reasoning_effort: bool | None = None - vision: bool | None = None + current_tokens: int + """Current total tokens in the context window (system + conversation + tool definitions)""" - @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideSupports': - assert isinstance(obj, dict) - reasoning_effort = from_union([from_bool, from_none], obj.get("reasoningEffort")) - vision = from_union([from_bool, from_none], obj.get("vision")) - return ModelCapabilitiesOverrideSupports(reasoning_effort, vision) + messages_length: int + """Current number of messages in the conversation""" - def to_dict(self) -> dict: - result: dict = {} - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_bool, from_none], self.reasoning_effort) - if self.vision is not None: - result["vision"] = from_union([from_bool, from_none], self.vision) - return result + token_limit: int + """Maximum token count for the model's context window""" -@dataclass -class AgentInfo: - description: str - """Description of the agent's purpose""" + conversation_tokens: int | None = None + """Token count from non-system messages (user, assistant, tool)""" - display_name: str - """Human-readable display name""" + system_tokens: int | None = None + """Token count from system message(s)""" - name: str - """Unique identifier of the custom agent""" + tool_definitions_tokens: int | None = None + """Token count from tool definitions""" @staticmethod - def from_dict(obj: Any) -> 'AgentInfo': + def from_dict(obj: Any) -> 'HistoryCompactContextWindow': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - display_name = from_str(obj.get("displayName")) - name = from_str(obj.get("name")) - return AgentInfo(description, display_name, name) + current_tokens = from_int(obj.get("currentTokens")) + messages_length = from_int(obj.get("messagesLength")) + token_limit = from_int(obj.get("tokenLimit")) + conversation_tokens = from_union([from_int, from_none], obj.get("conversationTokens")) + system_tokens = from_union([from_int, from_none], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_int, from_none], obj.get("toolDefinitionsTokens")) + return HistoryCompactContextWindow(current_tokens, messages_length, token_limit, conversation_tokens, system_tokens, tool_definitions_tokens) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["displayName"] = from_str(self.display_name) - result["name"] = from_str(self.name) + result["currentTokens"] = from_int(self.current_tokens) + result["messagesLength"] = from_int(self.messages_length) + result["tokenLimit"] = from_int(self.token_limit) + if self.conversation_tokens is not None: + result["conversationTokens"] = from_union([from_int, from_none], self.conversation_tokens) + if self.system_tokens is not None: + result["systemTokens"] = from_union([from_int, from_none], self.system_tokens) + if self.tool_definitions_tokens is not None: + result["toolDefinitionsTokens"] = from_union([from_int, from_none], self.tool_definitions_tokens) return result -class MCPServerStatus(Enum): - """Connection status: connected, failed, needs-auth, pending, disabled, or not_configured""" - - CONNECTED = "connected" - DISABLED = "disabled" - FAILED = "failed" - NEEDS_AUTH = "needs-auth" - NOT_CONFIGURED = "not_configured" - PENDING = "pending" - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ToolCallResult: - text_result_for_llm: str - """Text result to send back to the LLM""" - - error: str | None = None - """Error message if the tool call failed""" - - result_type: str | None = None - """Type of the tool result""" - - tool_telemetry: dict[str, Any] | None = None - """Telemetry data from tool execution""" +class HistoryTruncateRequest: + event_id: str + """Event ID to truncate to. This event and all events after it are removed from the session.""" @staticmethod - def from_dict(obj: Any) -> 'ToolCallResult': + def from_dict(obj: Any) -> 'HistoryTruncateRequest': assert isinstance(obj, dict) - text_result_for_llm = from_str(obj.get("textResultForLlm")) - error = from_union([from_str, from_none], obj.get("error")) - result_type = from_union([from_str, from_none], obj.get("resultType")) - tool_telemetry = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("toolTelemetry")) - return ToolCallResult(text_result_for_llm, error, result_type, tool_telemetry) + event_id = from_str(obj.get("eventId")) + return HistoryTruncateRequest(event_id) def to_dict(self) -> dict: result: dict = {} - result["textResultForLlm"] = from_str(self.text_result_for_llm) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.result_type is not None: - result["resultType"] = from_union([from_str, from_none], self.result_type) - if self.tool_telemetry is not None: - result["toolTelemetry"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.tool_telemetry) + result["eventId"] = from_str(self.event_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class HandleToolCallResult: - success: bool - """Whether the tool call result was handled successfully""" +class HistoryTruncateResult: + events_removed: int + """Number of events that were removed""" @staticmethod - def from_dict(obj: Any) -> 'HandleToolCallResult': + def from_dict(obj: Any) -> 'HistoryTruncateResult': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return HandleToolCallResult(success) + events_removed = from_int(obj.get("eventsRemoved")) + return HistoryTruncateResult(events_removed) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["eventsRemoved"] = from_int(self.events_removed) return result -class UIElicitationStringEnumFieldType(Enum): - STRING = "string" +class InstructionsSourcesLocation(Enum): + """Where this source lives — used for UI grouping""" -@dataclass -class UIElicitationStringOneOfFieldOneOf: - const: str - title: str + REPOSITORY = "repository" + USER = "user" + WORKING_DIRECTORY = "working-directory" - @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringOneOfFieldOneOf': - assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return UIElicitationStringOneOfFieldOneOf(const, title) +class InstructionsSourcesType(Enum): + """Category of instruction source — used for merge logic""" - def to_dict(self) -> dict: - result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) - return result + CHILD_INSTRUCTIONS = "child-instructions" + HOME = "home" + MODEL = "model" + NESTED_AGENTS = "nested-agents" + REPO = "repo" + VSCODE = "vscode" -class UIElicitationArrayEnumFieldType(Enum): - ARRAY = "array" +class SessionLogLevel(Enum): + """Log severity level. Determines how the message is displayed in the timeline. Defaults to + "info". + """ + ERROR = "error" + INFO = "info" + WARNING = "warning" @dataclass -class PurpleUIElicitationArrayAnyOfFieldItemsAnyOf: - const: str - title: str +class LogResult: + event_id: UUID + """The unique identifier of the emitted session event""" @staticmethod - def from_dict(obj: Any) -> 'PurpleUIElicitationArrayAnyOfFieldItemsAnyOf': + def from_dict(obj: Any) -> 'LogResult': assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return PurpleUIElicitationArrayAnyOfFieldItemsAnyOf(const, title) + event_id = UUID(obj.get("eventId")) + return LogResult(event_id) def to_dict(self) -> dict: result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) + result["eventId"] = str(self.event_id) return result -class UIElicitationResponseAction(Enum): - """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" +class MCPServerConfigType(Enum): + """Remote transport type. Defaults to "http" when omitted.""" - ACCEPT = "accept" - CANCEL = "cancel" - DECLINE = "decline" + HTTP = "http" + LOCAL = "local" + SSE = "sse" + STDIO = "stdio" @dataclass -class UIElicitationResult: - success: bool - """Whether the response was accepted. False if the request was already resolved by another - client. - """ +class MCPConfigRemoveRequest: + name: str + """Name of the MCP server to remove""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationResult': + def from_dict(obj: Any) -> 'MCPConfigRemoveRequest': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return UIElicitationResult(success) + name = from_str(obj.get("name")) + return MCPConfigRemoveRequest(name) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["name"] = from_str(self.name) return result -class Kind(Enum): - APPROVED = "approved" - DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" - DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" - DENIED_BY_RULES = "denied-by-rules" - DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" - DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" - @dataclass -class PermissionRequestResult: - success: bool - """Whether the permission request was handled successfully""" +class MCPDisableRequest: + server_name: str + """Name of the MCP server to disable""" @staticmethod - def from_dict(obj: Any) -> 'PermissionRequestResult': + def from_dict(obj: Any) -> 'MCPDisableRequest': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionRequestResult(success) + server_name = from_str(obj.get("serverName")) + return MCPDisableRequest(server_name) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["serverName"] = from_str(self.server_name) return result @dataclass -class PingResult: - message: str - """Echoed message (or default greeting)""" - - protocol_version: int - """Server protocol version number""" - - timestamp: int - """Server timestamp in milliseconds""" +class MCPDiscoverRequest: + working_directory: str | None = None + """Working directory used as context for discovery (e.g., plugin resolution)""" @staticmethod - def from_dict(obj: Any) -> 'PingResult': + def from_dict(obj: Any) -> 'MCPDiscoverRequest': assert isinstance(obj, dict) - message = from_str(obj.get("message")) - protocol_version = from_int(obj.get("protocolVersion")) - timestamp = from_int(obj.get("timestamp")) - return PingResult(message, protocol_version, timestamp) + working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) + return MCPDiscoverRequest(working_directory) def to_dict(self) -> dict: result: dict = {} - result["message"] = from_str(self.message) - result["protocolVersion"] = from_int(self.protocol_version) - result["timestamp"] = from_int(self.timestamp) + if self.working_directory is not None: + result["workingDirectory"] = from_union([from_str, from_none], self.working_directory) return result @dataclass -class PingRequest: - message: str | None = None - """Optional message to echo back""" +class MCPEnableRequest: + server_name: str + """Name of the MCP server to enable""" @staticmethod - def from_dict(obj: Any) -> 'PingRequest': + def from_dict(obj: Any) -> 'MCPEnableRequest': assert isinstance(obj, dict) - message = from_union([from_str, from_none], obj.get("message")) - return PingRequest(message) + server_name = from_str(obj.get("serverName")) + return MCPEnableRequest(server_name) def to_dict(self) -> dict: result: dict = {} - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) + result["serverName"] = from_str(self.server_name) return result +class MCPServerStatus(Enum): + """Connection status: connected, failed, needs-auth, pending, disabled, or not_configured""" + + CONNECTED = "connected" + DISABLED = "disabled" + FAILED = "failed" + NEEDS_AUTH = "needs-auth" + NOT_CONFIGURED = "not_configured" + PENDING = "pending" + +class MCPServerConfigHTTPType(Enum): + """Remote transport type. Defaults to "http" when omitted.""" + + HTTP = "http" + SSE = "sse" + +class MCPServerConfigLocalType(Enum): + LOCAL = "local" + STDIO = "stdio" + +class SessionMode(Enum): + """The agent mode. Valid values: "interactive", "plan", "autopilot".""" + + AUTOPILOT = "autopilot" + INTERACTIVE = "interactive" + PLAN = "plan" + @dataclass class ModelBilling: """Billing information""" @@ -587,7 +586,7 @@ def to_dict(self) -> dict: return result @dataclass -class FluffyModelCapabilitiesLimitsVision: +class ModelCapabilitiesLimitsVision: """Vision-specific limits""" max_prompt_image_size: int @@ -600,12 +599,12 @@ class FluffyModelCapabilitiesLimitsVision: """MIME types the model accepts""" @staticmethod - def from_dict(obj: Any) -> 'FluffyModelCapabilitiesLimitsVision': + def from_dict(obj: Any) -> 'ModelCapabilitiesLimitsVision': assert isinstance(obj, dict) max_prompt_image_size = from_int(obj.get("max_prompt_image_size")) max_prompt_images = from_int(obj.get("max_prompt_images")) supported_media_types = from_list(from_str, obj.get("supported_media_types")) - return FluffyModelCapabilitiesLimitsVision(max_prompt_image_size, max_prompt_images, supported_media_types) + return ModelCapabilitiesLimitsVision(max_prompt_image_size, max_prompt_images, supported_media_types) def to_dict(self) -> dict: result: dict = {} @@ -615,7 +614,7 @@ def to_dict(self) -> dict: return result @dataclass -class CapabilitiesSupports: +class ModelCapabilitiesSupports: """Feature flags indicating what the model supports""" reasoning_effort: bool | None = None @@ -625,11 +624,11 @@ class CapabilitiesSupports: """Whether this model supports vision/image input""" @staticmethod - def from_dict(obj: Any) -> 'CapabilitiesSupports': + def from_dict(obj: Any) -> 'ModelCapabilitiesSupports': assert isinstance(obj, dict) reasoning_effort = from_union([from_bool, from_none], obj.get("reasoningEffort")) vision = from_union([from_bool, from_none], obj.get("vision")) - return CapabilitiesSupports(reasoning_effort, vision) + return ModelCapabilitiesSupports(reasoning_effort, vision) def to_dict(self) -> dict: result: dict = {} @@ -663,325 +662,188 @@ def to_dict(self) -> dict: return result @dataclass -class Tool: - description: str - """Description of what the tool does""" - - name: str - """Tool identifier (e.g., "bash", "grep", "str_replace_editor")""" +class ModelCapabilitiesOverrideLimitsVision: + max_prompt_image_size: int | None = None + """Maximum image size in bytes""" - instructions: str | None = None - """Optional instructions for how to use this tool effectively""" + max_prompt_images: int | None = None + """Maximum number of images per prompt""" - namespaced_name: str | None = None - """Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP - tools) - """ - parameters: dict[str, Any] | None = None - """JSON Schema for the tool's input parameters""" + supported_media_types: list[str] | None = None + """MIME types the model accepts""" @staticmethod - def from_dict(obj: Any) -> 'Tool': + def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideLimitsVision': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - name = from_str(obj.get("name")) - instructions = from_union([from_str, from_none], obj.get("instructions")) - namespaced_name = from_union([from_str, from_none], obj.get("namespacedName")) - parameters = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("parameters")) - return Tool(description, name, instructions, namespaced_name, parameters) + max_prompt_image_size = from_union([from_int, from_none], obj.get("max_prompt_image_size")) + max_prompt_images = from_union([from_int, from_none], obj.get("max_prompt_images")) + supported_media_types = from_union([lambda x: from_list(from_str, x), from_none], obj.get("supported_media_types")) + return ModelCapabilitiesOverrideLimitsVision(max_prompt_image_size, max_prompt_images, supported_media_types) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["name"] = from_str(self.name) - if self.instructions is not None: - result["instructions"] = from_union([from_str, from_none], self.instructions) - if self.namespaced_name is not None: - result["namespacedName"] = from_union([from_str, from_none], self.namespaced_name) - if self.parameters is not None: - result["parameters"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.parameters) + if self.max_prompt_image_size is not None: + result["max_prompt_image_size"] = from_union([from_int, from_none], self.max_prompt_image_size) + if self.max_prompt_images is not None: + result["max_prompt_images"] = from_union([from_int, from_none], self.max_prompt_images) + if self.supported_media_types is not None: + result["supported_media_types"] = from_union([lambda x: from_list(from_str, x), from_none], self.supported_media_types) return result @dataclass -class ToolsListRequest: - model: str | None = None - """Optional model ID — when provided, the returned tool list reflects model-specific - overrides - """ +class ModelCapabilitiesOverrideSupports: + """Feature flags indicating what the model supports""" + + reasoning_effort: bool | None = None + vision: bool | None = None @staticmethod - def from_dict(obj: Any) -> 'ToolsListRequest': + def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideSupports': assert isinstance(obj, dict) - model = from_union([from_str, from_none], obj.get("model")) - return ToolsListRequest(model) + reasoning_effort = from_union([from_bool, from_none], obj.get("reasoningEffort")) + vision = from_union([from_bool, from_none], obj.get("vision")) + return ModelCapabilitiesOverrideSupports(reasoning_effort, vision) def to_dict(self) -> dict: result: dict = {} - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_bool, from_none], self.reasoning_effort) + if self.vision is not None: + result["vision"] = from_union([from_bool, from_none], self.vision) return result @dataclass -class AccountQuotaSnapshot: - entitlement_requests: int - """Number of requests included in the entitlement""" - - overage: int - """Number of overage requests made this period""" - - overage_allowed_with_exhausted_quota: bool - """Whether pay-per-request usage is allowed when quota is exhausted""" - - remaining_percentage: float - """Percentage of entitlement remaining""" - - used_requests: int - """Number of requests used so far this period""" - - reset_date: datetime | None = None - """Date when the quota resets (ISO 8601)""" +class ModelSwitchToResult: + model_id: str | None = None + """Currently active model identifier after the switch""" @staticmethod - def from_dict(obj: Any) -> 'AccountQuotaSnapshot': + def from_dict(obj: Any) -> 'ModelSwitchToResult': assert isinstance(obj, dict) - entitlement_requests = from_int(obj.get("entitlementRequests")) - overage = from_int(obj.get("overage")) - overage_allowed_with_exhausted_quota = from_bool(obj.get("overageAllowedWithExhaustedQuota")) - remaining_percentage = from_float(obj.get("remainingPercentage")) - used_requests = from_int(obj.get("usedRequests")) - reset_date = from_union([from_datetime, from_none], obj.get("resetDate")) - return AccountQuotaSnapshot(entitlement_requests, overage, overage_allowed_with_exhausted_quota, remaining_percentage, used_requests, reset_date) + model_id = from_union([from_str, from_none], obj.get("modelId")) + return ModelSwitchToResult(model_id) def to_dict(self) -> dict: result: dict = {} - result["entitlementRequests"] = from_int(self.entitlement_requests) - result["overage"] = from_int(self.overage) - result["overageAllowedWithExhaustedQuota"] = from_bool(self.overage_allowed_with_exhausted_quota) - result["remainingPercentage"] = to_float(self.remaining_percentage) - result["usedRequests"] = from_int(self.used_requests) - if self.reset_date is not None: - result["resetDate"] = from_union([lambda x: x.isoformat(), from_none], self.reset_date) + if self.model_id is not None: + result["modelId"] = from_union([from_str, from_none], self.model_id) return result @dataclass -class MCPConfigRemoveRequest: - name: str - """Name of the MCP server to remove""" +class NameGetResult: + name: str | None = None + """The session name, falling back to the auto-generated summary, or null if neither exists""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigRemoveRequest': + def from_dict(obj: Any) -> 'NameGetResult': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return MCPConfigRemoveRequest(name) + name = from_union([from_none, from_str], obj.get("name")) + return NameGetResult(name) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + result["name"] = from_union([from_none, from_str], self.name) return result @dataclass -class MCPDiscoverRequest: - working_directory: str | None = None - """Working directory used as context for discovery (e.g., plugin resolution)""" +class NameSetRequest: + name: str + """New session name (1–100 characters, trimmed of leading/trailing whitespace)""" @staticmethod - def from_dict(obj: Any) -> 'MCPDiscoverRequest': + def from_dict(obj: Any) -> 'NameSetRequest': assert isinstance(obj, dict) - working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) - return MCPDiscoverRequest(working_directory) + name = from_str(obj.get("name")) + return NameSetRequest(name) def to_dict(self) -> dict: result: dict = {} - if self.working_directory is not None: - result["workingDirectory"] = from_union([from_str, from_none], self.working_directory) + result["name"] = from_str(self.name) return result -@dataclass -class SkillsConfigSetDisabledSkillsRequest: - disabled_skills: list[str] - """List of skill names to disable""" +class PermissionDecisionKind(Enum): + APPROVED = "approved" + DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" + DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" + DENIED_BY_RULES = "denied-by-rules" + DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" + DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" - @staticmethod - def from_dict(obj: Any) -> 'SkillsConfigSetDisabledSkillsRequest': - assert isinstance(obj, dict) - disabled_skills = from_list(from_str, obj.get("disabledSkills")) - return SkillsConfigSetDisabledSkillsRequest(disabled_skills) +class PermissionDecisionApprovedKind(Enum): + APPROVED = "approved" - def to_dict(self) -> dict: - result: dict = {} - result["disabledSkills"] = from_list(from_str, self.disabled_skills) - return result +class PermissionDecisionDeniedByContentExclusionPolicyKind(Enum): + DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" -@dataclass -class SkillsDiscoverRequest: - project_paths: list[str] | None = None - """Optional list of project directory paths to scan for project-scoped skills""" +class PermissionDecisionDeniedByPermissionRequestHookKind(Enum): + DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" - skill_directories: list[str] | None = None - """Optional list of additional skill directory paths to include""" +class PermissionDecisionDeniedByRulesKind(Enum): + DENIED_BY_RULES = "denied-by-rules" - @staticmethod - def from_dict(obj: Any) -> 'SkillsDiscoverRequest': - assert isinstance(obj, dict) - project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) - return SkillsDiscoverRequest(project_paths, skill_directories) +class PermissionDecisionDeniedInteractivelyByUserKind(Enum): + DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" - def to_dict(self) -> dict: - result: dict = {} - if self.project_paths is not None: - result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) - if self.skill_directories is not None: - result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) - return result +class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind(Enum): + DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" @dataclass -class SessionFSSetProviderResult: +class PermissionRequestResult: success: bool - """Whether the provider was set successfully""" + """Whether the permission request was handled successfully""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderResult': + def from_dict(obj: Any) -> 'PermissionRequestResult': assert isinstance(obj, dict) success = from_bool(obj.get("success")) - return SessionFSSetProviderResult(success) + return PermissionRequestResult(success) def to_dict(self) -> dict: result: dict = {} result["success"] = from_bool(self.success) return result -class SessionFSSetProviderConventions(Enum): - """Path conventions used by this filesystem""" - - POSIX = "posix" - WINDOWS = "windows" - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsForkResult: - session_id: str - """The new forked session's ID""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionsForkResult': - assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionsForkResult(session_id) - - def to_dict(self) -> dict: - result: dict = {} - result["sessionId"] = from_str(self.session_id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsForkRequest: - session_id: str - """Source session ID to fork from""" - - to_event_id: str | None = None - """Optional event ID boundary. When provided, the fork includes only events before this ID - (exclusive). When omitted, all events are included. - """ - - @staticmethod - def from_dict(obj: Any) -> 'SessionsForkRequest': - assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - to_event_id = from_union([from_str, from_none], obj.get("toEventId")) - return SessionsForkRequest(session_id, to_event_id) - - def to_dict(self) -> dict: - result: dict = {} - result["sessionId"] = from_str(self.session_id) - if self.to_event_id is not None: - result["toEventId"] = from_union([from_str, from_none], self.to_event_id) - return result - -@dataclass -class ModelSwitchToResult: - model_id: str | None = None - """Currently active model identifier after the switch""" - - @staticmethod - def from_dict(obj: Any) -> 'ModelSwitchToResult': - assert isinstance(obj, dict) - model_id = from_union([from_str, from_none], obj.get("modelId")) - return ModelSwitchToResult(model_id) - - def to_dict(self) -> dict: - result: dict = {} - if self.model_id is not None: - result["modelId"] = from_union([from_str, from_none], self.model_id) - return result - @dataclass -class FluffyModelCapabilitiesOverrideLimitsVision: - max_prompt_image_size: int | None = None - """Maximum image size in bytes""" - - max_prompt_images: int | None = None - """Maximum number of images per prompt""" - - supported_media_types: list[str] | None = None - """MIME types the model accepts""" +class PingRequest: + message: str | None = None + """Optional message to echo back""" @staticmethod - def from_dict(obj: Any) -> 'FluffyModelCapabilitiesOverrideLimitsVision': + def from_dict(obj: Any) -> 'PingRequest': assert isinstance(obj, dict) - max_prompt_image_size = from_union([from_int, from_none], obj.get("max_prompt_image_size")) - max_prompt_images = from_union([from_int, from_none], obj.get("max_prompt_images")) - supported_media_types = from_union([lambda x: from_list(from_str, x), from_none], obj.get("supported_media_types")) - return FluffyModelCapabilitiesOverrideLimitsVision(max_prompt_image_size, max_prompt_images, supported_media_types) + message = from_union([from_str, from_none], obj.get("message")) + return PingRequest(message) def to_dict(self) -> dict: result: dict = {} - if self.max_prompt_image_size is not None: - result["max_prompt_image_size"] = from_union([from_int, from_none], self.max_prompt_image_size) - if self.max_prompt_images is not None: - result["max_prompt_images"] = from_union([from_int, from_none], self.max_prompt_images) - if self.supported_media_types is not None: - result["supported_media_types"] = from_union([lambda x: from_list(from_str, x), from_none], self.supported_media_types) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) return result -class SessionMode(Enum): - """The agent mode. Valid values: "interactive", "plan", "autopilot".""" - - AUTOPILOT = "autopilot" - INTERACTIVE = "interactive" - PLAN = "plan" - @dataclass -class NameGetResult: - name: str | None = None - """The session name, falling back to the auto-generated summary, or null if neither exists""" - - @staticmethod - def from_dict(obj: Any) -> 'NameGetResult': - assert isinstance(obj, dict) - name = from_union([from_none, from_str], obj.get("name")) - return NameGetResult(name) +class PingResult: + message: str + """Echoed message (or default greeting)""" - def to_dict(self) -> dict: - result: dict = {} - result["name"] = from_union([from_none, from_str], self.name) - return result + protocol_version: int + """Server protocol version number""" -@dataclass -class NameSetRequest: - name: str - """New session name (1–100 characters, trimmed of leading/trailing whitespace)""" + timestamp: int + """Server timestamp in milliseconds""" @staticmethod - def from_dict(obj: Any) -> 'NameSetRequest': + def from_dict(obj: Any) -> 'PingResult': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return NameSetRequest(name) + message = from_str(obj.get("message")) + protocol_version = from_int(obj.get("protocolVersion")) + timestamp = from_int(obj.get("timestamp")) + return PingResult(message, protocol_version, timestamp) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + result["message"] = from_str(self.message) + result["protocolVersion"] = from_int(self.protocol_version) + result["timestamp"] = from_int(self.timestamp) return result @dataclass @@ -1026,697 +888,819 @@ def to_dict(self) -> dict: result["content"] = from_str(self.content) return result -class HostType(Enum): - ADO = "ado" - GITHUB = "github" - -class SessionSyncLevel(Enum): - LOCAL = "local" - REPO_AND_USER = "repo_and_user" - USER = "user" - @dataclass -class WorkspacesListFilesResult: - files: list[str] - """Relative file paths in the workspace files directory""" +class Plugin: + enabled: bool + """Whether the plugin is currently enabled""" - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesListFilesResult': - assert isinstance(obj, dict) - files = from_list(from_str, obj.get("files")) - return WorkspacesListFilesResult(files) + marketplace: str + """Marketplace the plugin came from""" - def to_dict(self) -> dict: - result: dict = {} - result["files"] = from_list(from_str, self.files) - return result + name: str + """Plugin name""" -@dataclass -class WorkspacesReadFileResult: - content: str - """File content as a UTF-8 string""" + version: str | None = None + """Installed version""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadFileResult': + def from_dict(obj: Any) -> 'Plugin': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - return WorkspacesReadFileResult(content) + enabled = from_bool(obj.get("enabled")) + marketplace = from_str(obj.get("marketplace")) + name = from_str(obj.get("name")) + version = from_union([from_str, from_none], obj.get("version")) + return Plugin(enabled, marketplace, name, version) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) + result["enabled"] = from_bool(self.enabled) + result["marketplace"] = from_str(self.marketplace) + result["name"] = from_str(self.name) + if self.version is not None: + result["version"] = from_union([from_str, from_none], self.version) return result @dataclass -class WorkspacesReadFileRequest: - path: str - """Relative path within the workspace files directory""" +class ServerSkill: + description: str + """Description of what the skill does""" - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadFileRequest': - assert isinstance(obj, dict) - path = from_str(obj.get("path")) - return WorkspacesReadFileRequest(path) + enabled: bool + """Whether the skill is currently enabled (based on global config)""" - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - return result + name: str + """Unique identifier for the skill""" -@dataclass -class WorkspacesCreateFileRequest: - content: str - """File content to write as a UTF-8 string""" + source: str + """Source location type (e.g., project, personal-copilot, plugin, builtin)""" - path: str - """Relative path within the workspace files directory""" + user_invocable: bool + """Whether the skill can be invoked by the user as a slash command""" - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesCreateFileRequest': - assert isinstance(obj, dict) - content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - return WorkspacesCreateFileRequest(content, path) + path: str | None = None + """Absolute path to the skill file""" + + project_path: str | None = None + """The project path this skill belongs to (only for project/inherited skills)""" + + @staticmethod + def from_dict(obj: Any) -> 'ServerSkill': + assert isinstance(obj, dict) + description = from_str(obj.get("description")) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = from_str(obj.get("source")) + user_invocable = from_bool(obj.get("userInvocable")) + path = from_union([from_str, from_none], obj.get("path")) + project_path = from_union([from_str, from_none], obj.get("projectPath")) + return ServerSkill(description, enabled, name, source, user_invocable, path, project_path) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["path"] = from_str(self.path) + result["description"] = from_str(self.description) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = from_str(self.source) + result["userInvocable"] = from_bool(self.user_invocable) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.project_path is not None: + result["projectPath"] = from_union([from_str, from_none], self.project_path) return result -class InstructionsSourcesLocation(Enum): - """Where this source lives — used for UI grouping""" - - REPOSITORY = "repository" - USER = "user" - WORKING_DIRECTORY = "working-directory" +@dataclass +class SessionFSAppendFileRequest: + content: str + """Content to append""" -class InstructionsSourcesType(Enum): - """Category of instruction source — used for merge logic""" + path: str + """Path using SessionFs conventions""" - CHILD_INSTRUCTIONS = "child-instructions" - HOME = "home" - MODEL = "model" - NESTED_AGENTS = "nested-agents" - REPO = "repo" - VSCODE = "vscode" + session_id: str + """Target session identifier""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class FleetStartResult: - started: bool - """Whether fleet mode was successfully activated""" + mode: int | None = None + """Optional POSIX-style mode for newly created files""" @staticmethod - def from_dict(obj: Any) -> 'FleetStartResult': + def from_dict(obj: Any) -> 'SessionFSAppendFileRequest': assert isinstance(obj, dict) - started = from_bool(obj.get("started")) - return FleetStartResult(started) + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + return SessionFSAppendFileRequest(content, path, session_id, mode) def to_dict(self) -> dict: result: dict = {} - result["started"] = from_bool(self.started) + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) return result -# Experimental: this type is part of an experimental API and may change or be removed. +class SessionFSErrorCode(Enum): + """Error classification""" + + ENOENT = "ENOENT" + UNKNOWN = "UNKNOWN" + @dataclass -class FleetStartRequest: - prompt: str | None = None - """Optional user prompt to combine with fleet instructions""" +class SessionFSExistsRequest: + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'FleetStartRequest': + def from_dict(obj: Any) -> 'SessionFSExistsRequest': assert isinstance(obj, dict) - prompt = from_union([from_str, from_none], obj.get("prompt")) - return FleetStartRequest(prompt) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSExistsRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - if self.prompt is not None: - result["prompt"] = from_union([from_str, from_none], self.prompt) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class AgentListAgent: - description: str - """Description of the agent's purpose""" - - display_name: str - """Human-readable display name""" - - name: str - """Unique identifier of the custom agent""" +class SessionFSExistsResult: + exists: bool + """Whether the path exists""" @staticmethod - def from_dict(obj: Any) -> 'AgentListAgent': + def from_dict(obj: Any) -> 'SessionFSExistsResult': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - display_name = from_str(obj.get("displayName")) - name = from_str(obj.get("name")) - return AgentListAgent(description, display_name, name) + exists = from_bool(obj.get("exists")) + return SessionFSExistsResult(exists) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["displayName"] = from_str(self.display_name) - result["name"] = from_str(self.name) + result["exists"] = from_bool(self.exists) return result @dataclass -class AgentSelectResultAgent: - """The newly selected custom agent""" +class SessionFSMkdirRequest: + path: str + """Path using SessionFs conventions""" - description: str - """Description of the agent's purpose""" + session_id: str + """Target session identifier""" - display_name: str - """Human-readable display name""" + mode: int | None = None + """Optional POSIX-style mode for newly created directories""" - name: str - """Unique identifier of the custom agent""" + recursive: bool | None = None + """Create parent directories as needed""" @staticmethod - def from_dict(obj: Any) -> 'AgentSelectResultAgent': + def from_dict(obj: Any) -> 'SessionFSMkdirRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - display_name = from_str(obj.get("displayName")) - name = from_str(obj.get("name")) - return AgentSelectResultAgent(description, display_name, name) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + recursive = from_union([from_bool, from_none], obj.get("recursive")) + return SessionFSMkdirRequest(path, session_id, mode, recursive) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["displayName"] = from_str(self.display_name) - result["name"] = from_str(self.name) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) + if self.recursive is not None: + result["recursive"] = from_union([from_bool, from_none], self.recursive) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentSelectRequest: - name: str - """Name of the custom agent to select""" +class SessionFSReadFileRequest: + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'AgentSelectRequest': + def from_dict(obj: Any) -> 'SessionFSReadFileRequest': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return AgentSelectRequest(name) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReadFileRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class AgentReloadResultAgent: - description: str - """Description of the agent's purpose""" - - display_name: str - """Human-readable display name""" +class SessionFSReaddirRequest: + path: str + """Path using SessionFs conventions""" - name: str - """Unique identifier of the custom agent""" + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'AgentReloadResultAgent': + def from_dict(obj: Any) -> 'SessionFSReaddirRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - display_name = from_str(obj.get("displayName")) - name = from_str(obj.get("name")) - return AgentReloadResultAgent(description, display_name, name) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReaddirRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["displayName"] = from_str(self.display_name) - result["name"] = from_str(self.name) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result -@dataclass -class Skill: - description: str - """Description of what the skill does""" - - enabled: bool - """Whether the skill is currently enabled""" - - name: str - """Unique identifier for the skill""" +class SessionFSReaddirWithTypesEntryType(Enum): + """Entry type""" - source: str - """Source location type (e.g., project, personal, plugin)""" + DIRECTORY = "directory" + FILE = "file" - user_invocable: bool - """Whether the skill can be invoked by the user as a slash command""" +@dataclass +class SessionFSReaddirWithTypesRequest: + path: str + """Path using SessionFs conventions""" - path: str | None = None - """Absolute path to the skill file""" + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'Skill': + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = from_str(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - path = from_union([from_str, from_none], obj.get("path")) - return Skill(description, enabled, name, source, user_invocable, path) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReaddirWithTypesRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = from_str(self.source) - result["userInvocable"] = from_bool(self.user_invocable) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SkillsEnableRequest: - name: str - """Name of the skill to enable""" +class SessionFSRenameRequest: + dest: str + """Destination path using SessionFs conventions""" + + session_id: str + """Target session identifier""" + + src: str + """Source path using SessionFs conventions""" @staticmethod - def from_dict(obj: Any) -> 'SkillsEnableRequest': + def from_dict(obj: Any) -> 'SessionFSRenameRequest': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return SkillsEnableRequest(name) + dest = from_str(obj.get("dest")) + session_id = from_str(obj.get("sessionId")) + src = from_str(obj.get("src")) + return SessionFSRenameRequest(dest, session_id, src) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + result["dest"] = from_str(self.dest) + result["sessionId"] = from_str(self.session_id) + result["src"] = from_str(self.src) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SkillsDisableRequest: - name: str - """Name of the skill to disable""" +class SessionFSRmRequest: + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" + + force: bool | None = None + """Ignore errors if the path does not exist""" + + recursive: bool | None = None + """Remove directories and their contents recursively""" @staticmethod - def from_dict(obj: Any) -> 'SkillsDisableRequest': + def from_dict(obj: Any) -> 'SessionFSRmRequest': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return SkillsDisableRequest(name) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + force = from_union([from_bool, from_none], obj.get("force")) + recursive = from_union([from_bool, from_none], obj.get("recursive")) + return SessionFSRmRequest(path, session_id, force, recursive) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.force is not None: + result["force"] = from_union([from_bool, from_none], self.force) + if self.recursive is not None: + result["recursive"] = from_union([from_bool, from_none], self.recursive) return result +class SessionFSSetProviderConventions(Enum): + """Path conventions used by this filesystem""" + + POSIX = "posix" + WINDOWS = "windows" + @dataclass -class MCPEnableRequest: - server_name: str - """Name of the MCP server to enable""" +class SessionFSSetProviderResult: + success: bool + """Whether the provider was set successfully""" @staticmethod - def from_dict(obj: Any) -> 'MCPEnableRequest': + def from_dict(obj: Any) -> 'SessionFSSetProviderResult': assert isinstance(obj, dict) - server_name = from_str(obj.get("serverName")) - return MCPEnableRequest(server_name) + success = from_bool(obj.get("success")) + return SessionFSSetProviderResult(success) def to_dict(self) -> dict: result: dict = {} - result["serverName"] = from_str(self.server_name) + result["success"] = from_bool(self.success) return result @dataclass -class MCPDisableRequest: - server_name: str - """Name of the MCP server to disable""" +class SessionFSStatRequest: + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'MCPDisableRequest': + def from_dict(obj: Any) -> 'SessionFSStatRequest': assert isinstance(obj, dict) - server_name = from_str(obj.get("serverName")) - return MCPDisableRequest(server_name) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSStatRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["serverName"] = from_str(self.server_name) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class Plugin: - enabled: bool - """Whether the plugin is currently enabled""" +class SessionFSWriteFileRequest: + content: str + """Content to write""" - marketplace: str - """Marketplace the plugin came from""" + path: str + """Path using SessionFs conventions""" - name: str - """Plugin name""" + session_id: str + """Target session identifier""" - version: str | None = None - """Installed version""" + mode: int | None = None + """Optional POSIX-style mode for newly created files""" @staticmethod - def from_dict(obj: Any) -> 'Plugin': + def from_dict(obj: Any) -> 'SessionFSWriteFileRequest': assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - marketplace = from_str(obj.get("marketplace")) - name = from_str(obj.get("name")) - version = from_union([from_str, from_none], obj.get("version")) - return Plugin(enabled, marketplace, name, version) + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + return SessionFSWriteFileRequest(content, path, session_id, mode) def to_dict(self) -> dict: result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["marketplace"] = from_str(self.marketplace) - result["name"] = from_str(self.name) - if self.version is not None: - result["version"] = from_union([from_str, from_none], self.version) + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) return result -class ExtensionSource(Enum): - """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" - - PROJECT = "project" - USER = "user" - -class ExtensionStatus(Enum): - """Current status: running, disabled, failed, or starting""" - - DISABLED = "disabled" - FAILED = "failed" - RUNNING = "running" - STARTING = "starting" - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExtensionsEnableRequest: - id: str - """Source-qualified extension ID to enable""" +class SessionsForkRequest: + session_id: str + """Source session ID to fork from""" + + to_event_id: str | None = None + """Optional event ID boundary. When provided, the fork includes only events before this ID + (exclusive). When omitted, all events are included. + """ @staticmethod - def from_dict(obj: Any) -> 'ExtensionsEnableRequest': + def from_dict(obj: Any) -> 'SessionsForkRequest': assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return ExtensionsEnableRequest(id) + session_id = from_str(obj.get("sessionId")) + to_event_id = from_union([from_str, from_none], obj.get("toEventId")) + return SessionsForkRequest(session_id, to_event_id) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) + result["sessionId"] = from_str(self.session_id) + if self.to_event_id is not None: + result["toEventId"] = from_union([from_str, from_none], self.to_event_id) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExtensionsDisableRequest: - id: str - """Source-qualified extension ID to disable""" +class SessionsForkResult: + session_id: str + """The new forked session's ID""" @staticmethod - def from_dict(obj: Any) -> 'ExtensionsDisableRequest': + def from_dict(obj: Any) -> 'SessionsForkResult': assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return ExtensionsDisableRequest(id) + session_id = from_str(obj.get("sessionId")) + return SessionsForkResult(session_id) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class CommandsHandlePendingCommandResult: - success: bool - """Whether the command was handled successfully""" +class ShellExecRequest: + command: str + """Shell command to execute""" + + cwd: str | None = None + """Working directory (defaults to session working directory)""" + + timeout: int | None = None + """Timeout in milliseconds (default: 30000)""" @staticmethod - def from_dict(obj: Any) -> 'CommandsHandlePendingCommandResult': + def from_dict(obj: Any) -> 'ShellExecRequest': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return CommandsHandlePendingCommandResult(success) + command = from_str(obj.get("command")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + return ShellExecRequest(command, cwd, timeout) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["command"] = from_str(self.command) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) return result @dataclass -class CommandsHandlePendingCommandRequest: - request_id: str - """Request ID from the command invocation event""" - - error: str | None = None - """Error message if the command handler failed""" +class ShellExecResult: + process_id: str + """Unique identifier for tracking streamed output""" @staticmethod - def from_dict(obj: Any) -> 'CommandsHandlePendingCommandRequest': + def from_dict(obj: Any) -> 'ShellExecResult': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - error = from_union([from_str, from_none], obj.get("error")) - return CommandsHandlePendingCommandRequest(request_id, error) + process_id = from_str(obj.get("processId")) + return ShellExecResult(process_id) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) + result["processId"] = from_str(self.process_id) return result -class UIElicitationSchemaPropertyStringFormat(Enum): - DATE = "date" - DATE_TIME = "date-time" - EMAIL = "email" - URI = "uri" +class ShellKillSignal(Enum): + """Signal to send (default: SIGTERM)""" + + SIGINT = "SIGINT" + SIGKILL = "SIGKILL" + SIGTERM = "SIGTERM" @dataclass -class FluffyUIElicitationArrayAnyOfFieldItemsAnyOf: - const: str - title: str +class ShellKillResult: + killed: bool + """Whether the signal was sent successfully""" @staticmethod - def from_dict(obj: Any) -> 'FluffyUIElicitationArrayAnyOfFieldItemsAnyOf': + def from_dict(obj: Any) -> 'ShellKillResult': assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return FluffyUIElicitationArrayAnyOfFieldItemsAnyOf(const, title) + killed = from_bool(obj.get("killed")) + return ShellKillResult(killed) def to_dict(self) -> dict: result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) + result["killed"] = from_bool(self.killed) return result @dataclass -class UIElicitationSchemaPropertyOneOf: - const: str - title: str +class Skill: + description: str + """Description of what the skill does""" - @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyOneOf': - assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return UIElicitationSchemaPropertyOneOf(const, title) + enabled: bool + """Whether the skill is currently enabled""" - def to_dict(self) -> dict: - result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) - return result + name: str + """Unique identifier for the skill""" -class UIElicitationSchemaPropertyNumberType(Enum): - ARRAY = "array" - BOOLEAN = "boolean" - INTEGER = "integer" - NUMBER = "number" - STRING = "string" + source: str + """Source location type (e.g., project, personal, plugin)""" -class RequestedSchemaType(Enum): - OBJECT = "object" + user_invocable: bool + """Whether the skill can be invoked by the user as a slash command""" -@dataclass -class LogResult: - event_id: UUID - """The unique identifier of the emitted session event""" + path: str | None = None + """Absolute path to the skill file""" @staticmethod - def from_dict(obj: Any) -> 'LogResult': + def from_dict(obj: Any) -> 'Skill': assert isinstance(obj, dict) - event_id = UUID(obj.get("eventId")) - return LogResult(event_id) + description = from_str(obj.get("description")) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = from_str(obj.get("source")) + user_invocable = from_bool(obj.get("userInvocable")) + path = from_union([from_str, from_none], obj.get("path")) + return Skill(description, enabled, name, source, user_invocable, path) def to_dict(self) -> dict: result: dict = {} - result["eventId"] = str(self.event_id) + result["description"] = from_str(self.description) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = from_str(self.source) + result["userInvocable"] = from_bool(self.user_invocable) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) return result -class SessionLogLevel(Enum): - """Log severity level. Determines how the message is displayed in the timeline. Defaults to - "info". - """ - ERROR = "error" - INFO = "info" - WARNING = "warning" - @dataclass -class ShellExecResult: - process_id: str - """Unique identifier for tracking streamed output""" +class SkillsConfigSetDisabledSkillsRequest: + disabled_skills: list[str] + """List of skill names to disable""" @staticmethod - def from_dict(obj: Any) -> 'ShellExecResult': + def from_dict(obj: Any) -> 'SkillsConfigSetDisabledSkillsRequest': assert isinstance(obj, dict) - process_id = from_str(obj.get("processId")) - return ShellExecResult(process_id) + disabled_skills = from_list(from_str, obj.get("disabledSkills")) + return SkillsConfigSetDisabledSkillsRequest(disabled_skills) def to_dict(self) -> dict: result: dict = {} - result["processId"] = from_str(self.process_id) + result["disabledSkills"] = from_list(from_str, self.disabled_skills) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ShellExecRequest: - command: str - """Shell command to execute""" - - cwd: str | None = None - """Working directory (defaults to session working directory)""" - - timeout: int | None = None - """Timeout in milliseconds (default: 30000)""" +class SkillsDisableRequest: + name: str + """Name of the skill to disable""" @staticmethod - def from_dict(obj: Any) -> 'ShellExecRequest': + def from_dict(obj: Any) -> 'SkillsDisableRequest': assert isinstance(obj, dict) - command = from_str(obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - return ShellExecRequest(command, cwd, timeout) + name = from_str(obj.get("name")) + return SkillsDisableRequest(name) def to_dict(self) -> dict: result: dict = {} - result["command"] = from_str(self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) + result["name"] = from_str(self.name) return result @dataclass -class ShellKillResult: - killed: bool - """Whether the signal was sent successfully""" +class SkillsDiscoverRequest: + project_paths: list[str] | None = None + """Optional list of project directory paths to scan for project-scoped skills""" + + skill_directories: list[str] | None = None + """Optional list of additional skill directory paths to include""" @staticmethod - def from_dict(obj: Any) -> 'ShellKillResult': + def from_dict(obj: Any) -> 'SkillsDiscoverRequest': assert isinstance(obj, dict) - killed = from_bool(obj.get("killed")) - return ShellKillResult(killed) + project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) + skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) + return SkillsDiscoverRequest(project_paths, skill_directories) def to_dict(self) -> dict: result: dict = {} - result["killed"] = from_bool(self.killed) + if self.project_paths is not None: + result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) + if self.skill_directories is not None: + result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) return result -class ShellKillSignal(Enum): - """Signal to send (default: SIGTERM)""" - - SIGINT = "SIGINT" - SIGKILL = "SIGKILL" - SIGTERM = "SIGTERM" - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class HistoryCompactContextWindow: - """Post-compaction context window usage breakdown""" +class SkillsEnableRequest: + name: str + """Name of the skill to enable""" - current_tokens: int - """Current total tokens in the context window (system + conversation + tool definitions)""" + @staticmethod + def from_dict(obj: Any) -> 'SkillsEnableRequest': + assert isinstance(obj, dict) + name = from_str(obj.get("name")) + return SkillsEnableRequest(name) - messages_length: int - """Current number of messages in the conversation""" + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_str(self.name) + return result - token_limit: int - """Maximum token count for the model's context window""" +@dataclass +class Tool: + description: str + """Description of what the tool does""" - conversation_tokens: int | None = None - """Token count from non-system messages (user, assistant, tool)""" + name: str + """Tool identifier (e.g., "bash", "grep", "str_replace_editor")""" - system_tokens: int | None = None - """Token count from system message(s)""" + instructions: str | None = None + """Optional instructions for how to use this tool effectively""" - tool_definitions_tokens: int | None = None - """Token count from tool definitions""" + namespaced_name: str | None = None + """Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP + tools) + """ + parameters: dict[str, Any] | None = None + """JSON Schema for the tool's input parameters""" @staticmethod - def from_dict(obj: Any) -> 'HistoryCompactContextWindow': + def from_dict(obj: Any) -> 'Tool': assert isinstance(obj, dict) - current_tokens = from_int(obj.get("currentTokens")) - messages_length = from_int(obj.get("messagesLength")) - token_limit = from_int(obj.get("tokenLimit")) - conversation_tokens = from_union([from_int, from_none], obj.get("conversationTokens")) - system_tokens = from_union([from_int, from_none], obj.get("systemTokens")) - tool_definitions_tokens = from_union([from_int, from_none], obj.get("toolDefinitionsTokens")) - return HistoryCompactContextWindow(current_tokens, messages_length, token_limit, conversation_tokens, system_tokens, tool_definitions_tokens) + description = from_str(obj.get("description")) + name = from_str(obj.get("name")) + instructions = from_union([from_str, from_none], obj.get("instructions")) + namespaced_name = from_union([from_str, from_none], obj.get("namespacedName")) + parameters = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("parameters")) + return Tool(description, name, instructions, namespaced_name, parameters) def to_dict(self) -> dict: result: dict = {} - result["currentTokens"] = from_int(self.current_tokens) - result["messagesLength"] = from_int(self.messages_length) - result["tokenLimit"] = from_int(self.token_limit) - if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_int, from_none], self.conversation_tokens) - if self.system_tokens is not None: - result["systemTokens"] = from_union([from_int, from_none], self.system_tokens) - if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_int, from_none], self.tool_definitions_tokens) + result["description"] = from_str(self.description) + result["name"] = from_str(self.name) + if self.instructions is not None: + result["instructions"] = from_union([from_str, from_none], self.instructions) + if self.namespaced_name is not None: + result["namespacedName"] = from_union([from_str, from_none], self.namespaced_name) + if self.parameters is not None: + result["parameters"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.parameters) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class HistoryTruncateResult: - events_removed: int - """Number of events that were removed""" +class ToolCallResult: + text_result_for_llm: str + """Text result to send back to the LLM""" + + error: str | None = None + """Error message if the tool call failed""" + + result_type: str | None = None + """Type of the tool result""" + + tool_telemetry: dict[str, Any] | None = None + """Telemetry data from tool execution""" @staticmethod - def from_dict(obj: Any) -> 'HistoryTruncateResult': + def from_dict(obj: Any) -> 'ToolCallResult': assert isinstance(obj, dict) - events_removed = from_int(obj.get("eventsRemoved")) - return HistoryTruncateResult(events_removed) + text_result_for_llm = from_str(obj.get("textResultForLlm")) + error = from_union([from_str, from_none], obj.get("error")) + result_type = from_union([from_str, from_none], obj.get("resultType")) + tool_telemetry = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("toolTelemetry")) + return ToolCallResult(text_result_for_llm, error, result_type, tool_telemetry) def to_dict(self) -> dict: result: dict = {} - result["eventsRemoved"] = from_int(self.events_removed) + result["textResultForLlm"] = from_str(self.text_result_for_llm) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.result_type is not None: + result["resultType"] = from_union([from_str, from_none], self.result_type) + if self.tool_telemetry is not None: + result["toolTelemetry"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.tool_telemetry) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class HistoryTruncateRequest: - event_id: str - """Event ID to truncate to. This event and all events after it are removed from the session.""" +class ToolsListRequest: + model: str | None = None + """Optional model ID — when provided, the returned tool list reflects model-specific + overrides + """ @staticmethod - def from_dict(obj: Any) -> 'HistoryTruncateRequest': + def from_dict(obj: Any) -> 'ToolsListRequest': assert isinstance(obj, dict) - event_id = from_str(obj.get("eventId")) - return HistoryTruncateRequest(event_id) + model = from_union([from_str, from_none], obj.get("model")) + return ToolsListRequest(model) def to_dict(self) -> dict: result: dict = {} - result["eventId"] = from_str(self.event_id) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) return result @dataclass -class UsageMetricsCodeChanges: - """Aggregated code change metrics""" - - files_modified_count: int - """Number of distinct files modified""" - - lines_added: int - """Total lines of code added""" - - lines_removed: int - """Total lines of code removed""" +class UIElicitationArrayAnyOfFieldItemsAnyOf: + const: str + title: str @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsCodeChanges': + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItemsAnyOf': + assert isinstance(obj, dict) + const = from_str(obj.get("const")) + title = from_str(obj.get("title")) + return UIElicitationArrayAnyOfFieldItemsAnyOf(const, title) + + def to_dict(self) -> dict: + result: dict = {} + result["const"] = from_str(self.const) + result["title"] = from_str(self.title) + return result + +class UIElicitationArrayAnyOfFieldType(Enum): + ARRAY = "array" + +class UIElicitationArrayEnumFieldItemsType(Enum): + STRING = "string" + +class UIElicitationSchemaPropertyStringFormat(Enum): + DATE = "date" + DATE_TIME = "date-time" + EMAIL = "email" + URI = "uri" + +@dataclass +class UIElicitationStringOneOfFieldOneOf: + const: str + title: str + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationStringOneOfFieldOneOf': + assert isinstance(obj, dict) + const = from_str(obj.get("const")) + title = from_str(obj.get("title")) + return UIElicitationStringOneOfFieldOneOf(const, title) + + def to_dict(self) -> dict: + result: dict = {} + result["const"] = from_str(self.const) + result["title"] = from_str(self.title) + return result + +class UIElicitationSchemaPropertyType(Enum): + ARRAY = "array" + BOOLEAN = "boolean" + INTEGER = "integer" + NUMBER = "number" + STRING = "string" + +class UIElicitationSchemaType(Enum): + OBJECT = "object" + +class UIElicitationResponseAction(Enum): + """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" + + ACCEPT = "accept" + CANCEL = "cancel" + DECLINE = "decline" + +@dataclass +class UIElicitationResult: + success: bool + """Whether the response was accepted. False if the request was already resolved by another + client. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + return UIElicitationResult(success) + + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + return result + +class UIElicitationSchemaPropertyBooleanType(Enum): + BOOLEAN = "boolean" + +class UIElicitationSchemaPropertyNumberType(Enum): + INTEGER = "integer" + NUMBER = "number" + +@dataclass +class UsageMetricsCodeChanges: + """Aggregated code change metrics""" + + files_modified_count: int + """Number of distinct files modified""" + + lines_added: int + """Total lines of code added""" + + lines_removed: int + """Total lines of code removed""" + + @staticmethod + def from_dict(obj: Any) -> 'UsageMetricsCodeChanges': assert isinstance(obj, dict) files_modified_count = from_int(obj.get("filesModifiedCount")) lines_added = from_int(obj.get("linesAdded")) @@ -1793,611 +1777,360 @@ def to_dict(self) -> dict: return result @dataclass -class SessionFSReadFileResult: +class WorkspacesCreateFileRequest: content: str - """File content as UTF-8 string""" + """File content to write as a UTF-8 string""" + + path: str + """Relative path within the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReadFileResult': + def from_dict(obj: Any) -> 'WorkspacesCreateFileRequest': assert isinstance(obj, dict) content = from_str(obj.get("content")) - return SessionFSReadFileResult(content) + path = from_str(obj.get("path")) + return WorkspacesCreateFileRequest(content, path) def to_dict(self) -> dict: result: dict = {} result["content"] = from_str(self.content) + result["path"] = from_str(self.path) return result -@dataclass -class SessionFSReadFileRequest: - path: str - """Path using SessionFs conventions""" +class HostType(Enum): + ADO = "ado" + GITHUB = "github" - session_id: str - """Target session identifier""" +class SessionSyncLevel(Enum): + LOCAL = "local" + REPO_AND_USER = "repo_and_user" + USER = "user" + +@dataclass +class WorkspacesListFilesResult: + files: list[str] + """Relative file paths in the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReadFileRequest': + def from_dict(obj: Any) -> 'WorkspacesListFilesResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReadFileRequest(path, session_id) + files = from_list(from_str, obj.get("files")) + return WorkspacesListFilesResult(files) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["files"] = from_list(from_str, self.files) return result @dataclass -class SessionFSWriteFileRequest: - content: str - """Content to write""" - +class WorkspacesReadFileRequest: path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" - - mode: int | None = None - """Optional POSIX-style mode for newly created files""" + """Relative path within the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSWriteFileRequest': + def from_dict(obj: Any) -> 'WorkspacesReadFileRequest': assert isinstance(obj, dict) - content = from_str(obj.get("content")) path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - return SessionFSWriteFileRequest(content, path, session_id, mode) + return WorkspacesReadFileRequest(path) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) return result @dataclass -class SessionFSAppendFileRequest: +class WorkspacesReadFileResult: content: str - """Content to append""" - - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" - - mode: int | None = None - """Optional POSIX-style mode for newly created files""" + """File content as a UTF-8 string""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSAppendFileRequest': + def from_dict(obj: Any) -> 'WorkspacesReadFileResult': assert isinstance(obj, dict) content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - return SessionFSAppendFileRequest(content, path, session_id, mode) + return WorkspacesReadFileResult(content) def to_dict(self) -> dict: result: dict = {} result["content"] = from_str(self.content) - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) return result @dataclass -class SessionFSExistsResult: - exists: bool - """Whether the path exists""" +class AccountGetQuotaResult: + quota_snapshots: dict[str, AccountQuotaSnapshot] + """Quota snapshots keyed by type (e.g., chat, completions, premium_interactions)""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSExistsResult': + def from_dict(obj: Any) -> 'AccountGetQuotaResult': assert isinstance(obj, dict) - exists = from_bool(obj.get("exists")) - return SessionFSExistsResult(exists) + quota_snapshots = from_dict(AccountQuotaSnapshot.from_dict, obj.get("quotaSnapshots")) + return AccountGetQuotaResult(quota_snapshots) def to_dict(self) -> dict: result: dict = {} - result["exists"] = from_bool(self.exists) + result["quotaSnapshots"] = from_dict(lambda x: to_class(AccountQuotaSnapshot, x), self.quota_snapshots) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSExistsRequest: - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" +class AgentGetCurrentResult: + agent: AgentInfo | None = None + """Currently selected custom agent, or null if using the default agent""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSExistsRequest': + def from_dict(obj: Any) -> 'AgentGetCurrentResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSExistsRequest(path, session_id) + agent = from_union([AgentInfo.from_dict, from_none], obj.get("agent")) + return AgentGetCurrentResult(agent) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + if self.agent is not None: + result["agent"] = from_union([lambda x: to_class(AgentInfo, x), from_none], self.agent) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSStatResult: - birthtime: datetime - """ISO 8601 timestamp of creation""" - - is_directory: bool - """Whether the path is a directory""" - - is_file: bool - """Whether the path is a file""" - - mtime: datetime - """ISO 8601 timestamp of last modification""" - - size: int - """File size in bytes""" +class AgentList: + agents: list[AgentInfo] + """Available custom agents""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSStatResult': + def from_dict(obj: Any) -> 'AgentList': assert isinstance(obj, dict) - birthtime = from_datetime(obj.get("birthtime")) - is_directory = from_bool(obj.get("isDirectory")) - is_file = from_bool(obj.get("isFile")) - mtime = from_datetime(obj.get("mtime")) - size = from_int(obj.get("size")) - return SessionFSStatResult(birthtime, is_directory, is_file, mtime, size) + agents = from_list(AgentInfo.from_dict, obj.get("agents")) + return AgentList(agents) def to_dict(self) -> dict: result: dict = {} - result["birthtime"] = self.birthtime.isoformat() - result["isDirectory"] = from_bool(self.is_directory) - result["isFile"] = from_bool(self.is_file) - result["mtime"] = self.mtime.isoformat() - result["size"] = from_int(self.size) + result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSStatRequest: - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" +class AgentReloadResult: + agents: list[AgentInfo] + """Reloaded custom agents""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSStatRequest': + def from_dict(obj: Any) -> 'AgentReloadResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSStatRequest(path, session_id) - - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - return result - -@dataclass -class SessionFSMkdirRequest: - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" - - mode: int | None = None - """Optional POSIX-style mode for newly created directories""" - - recursive: bool | None = None - """Create parent directories as needed""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionFSMkdirRequest': - assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - recursive = from_union([from_bool, from_none], obj.get("recursive")) - return SessionFSMkdirRequest(path, session_id, mode, recursive) + agents = from_list(AgentInfo.from_dict, obj.get("agents")) + return AgentReloadResult(agents) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) - if self.recursive is not None: - result["recursive"] = from_union([from_bool, from_none], self.recursive) + result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSReaddirResult: - entries: list[str] - """Entry names in the directory""" +class AgentSelectResult: + agent: AgentInfo + """The newly selected custom agent""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirResult': + def from_dict(obj: Any) -> 'AgentSelectResult': assert isinstance(obj, dict) - entries = from_list(from_str, obj.get("entries")) - return SessionFSReaddirResult(entries) + agent = AgentInfo.from_dict(obj.get("agent")) + return AgentSelectResult(agent) def to_dict(self) -> dict: result: dict = {} - result["entries"] = from_list(from_str, self.entries) + result["agent"] = to_class(AgentInfo, self.agent) return result @dataclass -class SessionFSReaddirRequest: - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirRequest': - assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReaddirRequest(path, session_id) - - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - return result - -class SessionFSReaddirWithTypesEntryType(Enum): - """Entry type""" +class DiscoveredMCPServer: + enabled: bool + """Whether the server is enabled (not in the disabled list)""" - DIRECTORY = "directory" - FILE = "file" + name: str + """Server name (config key)""" -@dataclass -class SessionFSReaddirWithTypesRequest: - path: str - """Path using SessionFs conventions""" + source: MCPServerSource + """Configuration source""" - session_id: str - """Target session identifier""" + type: DiscoveredMCPServerType | None = None + """Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio)""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesRequest': + def from_dict(obj: Any) -> 'DiscoveredMCPServer': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReaddirWithTypesRequest(path, session_id) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = MCPServerSource(obj.get("source")) + type = from_union([DiscoveredMCPServerType, from_none], obj.get("type")) + return DiscoveredMCPServer(enabled, name, source, type) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = to_enum(MCPServerSource, self.source) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(DiscoveredMCPServerType, x), from_none], self.type) return result @dataclass -class SessionFSRmRequest: - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" - - force: bool | None = None - """Ignore errors if the path does not exist""" - - recursive: bool | None = None - """Remove directories and their contents recursively""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionFSRmRequest': - assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - force = from_union([from_bool, from_none], obj.get("force")) - recursive = from_union([from_bool, from_none], obj.get("recursive")) - return SessionFSRmRequest(path, session_id, force, recursive) +class Extension: + id: str + """Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper')""" - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.force is not None: - result["force"] = from_union([from_bool, from_none], self.force) - if self.recursive is not None: - result["recursive"] = from_union([from_bool, from_none], self.recursive) - return result + name: str + """Extension name (directory name)""" -@dataclass -class SessionFSRenameRequest: - dest: str - """Destination path using SessionFs conventions""" + source: ExtensionSource + """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" - session_id: str - """Target session identifier""" + status: ExtensionStatus + """Current status: running, disabled, failed, or starting""" - src: str - """Source path using SessionFs conventions""" + pid: int | None = None + """Process ID if the extension is running""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSRenameRequest': + def from_dict(obj: Any) -> 'Extension': assert isinstance(obj, dict) - dest = from_str(obj.get("dest")) - session_id = from_str(obj.get("sessionId")) - src = from_str(obj.get("src")) - return SessionFSRenameRequest(dest, session_id, src) + id = from_str(obj.get("id")) + name = from_str(obj.get("name")) + source = ExtensionSource(obj.get("source")) + status = ExtensionStatus(obj.get("status")) + pid = from_union([from_int, from_none], obj.get("pid")) + return Extension(id, name, source, status, pid) def to_dict(self) -> dict: result: dict = {} - result["dest"] = from_str(self.dest) - result["sessionId"] = from_str(self.session_id) - result["src"] = from_str(self.src) + result["id"] = from_str(self.id) + result["name"] = from_str(self.name) + result["source"] = to_enum(ExtensionSource, self.source) + result["status"] = to_enum(ExtensionStatus, self.status) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ModelCapabilitiesLimits: - """Token limits for prompts, outputs, and context window""" - - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" +class HistoryCompactResult: + messages_removed: int + """Number of messages removed during compaction""" - max_output_tokens: int | None = None - """Maximum number of output/completion tokens""" + success: bool + """Whether compaction completed successfully""" - max_prompt_tokens: int | None = None - """Maximum number of prompt/input tokens""" + tokens_removed: int + """Number of tokens freed by compaction""" - vision: PurpleModelCapabilitiesLimitsVision | None = None - """Vision-specific limits""" + context_window: HistoryCompactContextWindow | None = None + """Post-compaction context window usage breakdown""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesLimits': + def from_dict(obj: Any) -> 'HistoryCompactResult': assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([PurpleModelCapabilitiesLimitsVision.from_dict, from_none], obj.get("vision")) - return ModelCapabilitiesLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) + messages_removed = from_int(obj.get("messagesRemoved")) + success = from_bool(obj.get("success")) + tokens_removed = from_int(obj.get("tokensRemoved")) + context_window = from_union([HistoryCompactContextWindow.from_dict, from_none], obj.get("contextWindow")) + return HistoryCompactResult(messages_removed, success, tokens_removed, context_window) def to_dict(self) -> dict: result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(PurpleModelCapabilitiesLimitsVision, x), from_none], self.vision) + result["messagesRemoved"] = from_int(self.messages_removed) + result["success"] = from_bool(self.success) + result["tokensRemoved"] = from_int(self.tokens_removed) + if self.context_window is not None: + result["contextWindow"] = from_union([lambda x: to_class(HistoryCompactContextWindow, x), from_none], self.context_window) return result @dataclass -class MCPServerConfig: - """MCP server configuration (local/stdio or remote/http)""" - - args: list[str] | None = None - command: str | None = None - cwd: str | None = None - env: dict[str, str] | None = None - filter_mapping: dict[str, FilterMappingString] | FilterMappingString | None = None - is_default_server: bool | None = None - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" - - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" - - type: MCPServerConfigType | None = None - """Remote transport type. Defaults to "http" when omitted.""" - - headers: dict[str, str] | None = None - oauth_client_id: str | None = None - oauth_public_client: bool | None = None - url: str | None = None +class InstructionsSources: + content: str + """Raw content of the instruction file""" - @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfig': - assert isinstance(obj, dict) - args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) - command = from_union([from_str, from_none], obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) - filter_mapping = from_union([lambda x: from_dict(FilterMappingString, x), FilterMappingString, from_none], obj.get("filterMapping")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - type = from_union([MCPServerConfigType, from_none], obj.get("type")) - headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) - oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) - oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) - url = from_union([from_str, from_none], obj.get("url")) - return MCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, type, headers, oauth_client_id, oauth_public_client, url) + id: str + """Unique identifier for this source (used for toggling)""" - def to_dict(self) -> dict: - result: dict = {} - if self.args is not None: - result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) - if self.command is not None: - result["command"] = from_union([from_str, from_none], self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.env is not None: - result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(FilterMappingString, x), x), lambda x: to_enum(FilterMappingString, x), from_none], self.filter_mapping) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(MCPServerConfigType, x), from_none], self.type) - if self.headers is not None: - result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) - if self.oauth_client_id is not None: - result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) - if self.oauth_public_client is not None: - result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) - return result + label: str + """Human-readable label""" -@dataclass -class MCPServerConfigValue: - """MCP server configuration (local/stdio or remote/http)""" + location: InstructionsSourcesLocation + """Where this source lives — used for UI grouping""" - args: list[str] | None = None - command: str | None = None - cwd: str | None = None - env: dict[str, str] | None = None - filter_mapping: dict[str, FilterMappingString] | FilterMappingString | None = None - is_default_server: bool | None = None - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" + source_path: str + """File path relative to repo or absolute for home""" - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" + type: InstructionsSourcesType + """Category of instruction source — used for merge logic""" - type: MCPServerConfigType | None = None - """Remote transport type. Defaults to "http" when omitted.""" + apply_to: str | None = None + """Glob pattern from frontmatter — when set, this instruction applies only to matching files""" - headers: dict[str, str] | None = None - oauth_client_id: str | None = None - oauth_public_client: bool | None = None - url: str | None = None + description: str | None = None + """Short description (body after frontmatter) for use in instruction tables""" @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfigValue': + def from_dict(obj: Any) -> 'InstructionsSources': assert isinstance(obj, dict) - args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) - command = from_union([from_str, from_none], obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) - filter_mapping = from_union([lambda x: from_dict(FilterMappingString, x), FilterMappingString, from_none], obj.get("filterMapping")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - type = from_union([MCPServerConfigType, from_none], obj.get("type")) - headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) - oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) - oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) - url = from_union([from_str, from_none], obj.get("url")) - return MCPServerConfigValue(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, type, headers, oauth_client_id, oauth_public_client, url) + content = from_str(obj.get("content")) + id = from_str(obj.get("id")) + label = from_str(obj.get("label")) + location = InstructionsSourcesLocation(obj.get("location")) + source_path = from_str(obj.get("sourcePath")) + type = InstructionsSourcesType(obj.get("type")) + apply_to = from_union([from_str, from_none], obj.get("applyTo")) + description = from_union([from_str, from_none], obj.get("description")) + return InstructionsSources(content, id, label, location, source_path, type, apply_to, description) def to_dict(self) -> dict: result: dict = {} - if self.args is not None: - result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) - if self.command is not None: - result["command"] = from_union([from_str, from_none], self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.env is not None: - result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(FilterMappingString, x), x), lambda x: to_enum(FilterMappingString, x), from_none], self.filter_mapping) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(MCPServerConfigType, x), from_none], self.type) - if self.headers is not None: - result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) - if self.oauth_client_id is not None: - result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) - if self.oauth_public_client is not None: - result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["content"] = from_str(self.content) + result["id"] = from_str(self.id) + result["label"] = from_str(self.label) + result["location"] = to_enum(InstructionsSourcesLocation, self.location) + result["sourcePath"] = from_str(self.source_path) + result["type"] = to_enum(InstructionsSourcesType, self.type) + if self.apply_to is not None: + result["applyTo"] = from_union([from_str, from_none], self.apply_to) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) return result @dataclass -class MCPConfigAddRequestMCPServerConfig: - """MCP server configuration (local/stdio or remote/http)""" - - args: list[str] | None = None - command: str | None = None - cwd: str | None = None - env: dict[str, str] | None = None - filter_mapping: dict[str, FilterMappingString] | FilterMappingString | None = None - is_default_server: bool | None = None - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" - - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" +class LogRequest: + message: str + """Human-readable message""" - type: MCPServerConfigType | None = None - """Remote transport type. Defaults to "http" when omitted.""" + ephemeral: bool | None = None + """When true, the message is transient and not persisted to the session event log on disk""" - headers: dict[str, str] | None = None - oauth_client_id: str | None = None - oauth_public_client: bool | None = None + level: SessionLogLevel | None = None + """Log severity level. Determines how the message is displayed in the timeline. Defaults to + "info". + """ url: str | None = None + """Optional URL the user can open in their browser for more details""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigAddRequestMCPServerConfig': + def from_dict(obj: Any) -> 'LogRequest': assert isinstance(obj, dict) - args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) - command = from_union([from_str, from_none], obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) - filter_mapping = from_union([lambda x: from_dict(FilterMappingString, x), FilterMappingString, from_none], obj.get("filterMapping")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - type = from_union([MCPServerConfigType, from_none], obj.get("type")) - headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) - oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) - oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) + message = from_str(obj.get("message")) + ephemeral = from_union([from_bool, from_none], obj.get("ephemeral")) + level = from_union([SessionLogLevel, from_none], obj.get("level")) url = from_union([from_str, from_none], obj.get("url")) - return MCPConfigAddRequestMCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, type, headers, oauth_client_id, oauth_public_client, url) + return LogRequest(message, ephemeral, level, url) def to_dict(self) -> dict: - result: dict = {} - if self.args is not None: - result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) - if self.command is not None: - result["command"] = from_union([from_str, from_none], self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.env is not None: - result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(FilterMappingString, x), x), lambda x: to_enum(FilterMappingString, x), from_none], self.filter_mapping) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(MCPServerConfigType, x), from_none], self.type) - if self.headers is not None: - result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) - if self.oauth_client_id is not None: - result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) - if self.oauth_public_client is not None: - result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) + result: dict = {} + result["message"] = from_str(self.message) + if self.ephemeral is not None: + result["ephemeral"] = from_union([from_bool, from_none], self.ephemeral) + if self.level is not None: + result["level"] = from_union([lambda x: to_enum(SessionLogLevel, x), from_none], self.level) if self.url is not None: result["url"] = from_union([from_str, from_none], self.url) return result @dataclass -class MCPConfigUpdateRequestMCPServerConfig: +class MCPServerConfig: """MCP server configuration (local/stdio or remote/http)""" args: list[str] | None = None @@ -2421,7 +2154,7 @@ class MCPConfigUpdateRequestMCPServerConfig: url: str | None = None @staticmethod - def from_dict(obj: Any) -> 'MCPConfigUpdateRequestMCPServerConfig': + def from_dict(obj: Any) -> 'MCPServerConfig': assert isinstance(obj, dict) args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) command = from_union([from_str, from_none], obj.get("command")) @@ -2436,7 +2169,7 @@ def from_dict(obj: Any) -> 'MCPConfigUpdateRequestMCPServerConfig': oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) url = from_union([from_str, from_none], obj.get("url")) - return MCPConfigUpdateRequestMCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, type, headers, oauth_client_id, oauth_public_client, url) + return MCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, type, headers, oauth_client_id, oauth_public_client, url) def to_dict(self) -> dict: result: dict = {} @@ -2468,118 +2201,6 @@ def to_dict(self) -> dict: result["url"] = from_union([from_str, from_none], self.url) return result -@dataclass -class DiscoveredMCPServer: - enabled: bool - """Whether the server is enabled (not in the disabled list)""" - - name: str - """Server name (config key)""" - - source: MCPServerSource - """Configuration source""" - - type: DiscoveredMCPServerType | None = None - """Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio)""" - - @staticmethod - def from_dict(obj: Any) -> 'DiscoveredMCPServer': - assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = MCPServerSource(obj.get("source")) - type = from_union([DiscoveredMCPServerType, from_none], obj.get("type")) - return DiscoveredMCPServer(enabled, name, source, type) - - def to_dict(self) -> dict: - result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(MCPServerSource, self.source) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(DiscoveredMCPServerType, x), from_none], self.type) - return result - -@dataclass -class ServerElement: - enabled: bool - """Whether the server is enabled (not in the disabled list)""" - - name: str - """Server name (config key)""" - - source: MCPServerSource - """Configuration source""" - - type: DiscoveredMCPServerType | None = None - """Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio)""" - - @staticmethod - def from_dict(obj: Any) -> 'ServerElement': - assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = MCPServerSource(obj.get("source")) - type = from_union([DiscoveredMCPServerType, from_none], obj.get("type")) - return ServerElement(enabled, name, source, type) - - def to_dict(self) -> dict: - result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(MCPServerSource, self.source) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(DiscoveredMCPServerType, x), from_none], self.type) - return result - -@dataclass -class ServerSkillList: - skills: list[SkillElement] - """All discovered skills across all sources""" - - @staticmethod - def from_dict(obj: Any) -> 'ServerSkillList': - assert isinstance(obj, dict) - skills = from_list(SkillElement.from_dict, obj.get("skills")) - return ServerSkillList(skills) - - def to_dict(self) -> dict: - result: dict = {} - result["skills"] = from_list(lambda x: to_class(SkillElement, x), self.skills) - return result - -@dataclass -class ModelCapabilitiesOverrideLimits: - """Token limits for prompts, outputs, and context window""" - - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" - - max_output_tokens: int | None = None - max_prompt_tokens: int | None = None - vision: PurpleModelCapabilitiesOverrideLimitsVision | None = None - - @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideLimits': - assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([PurpleModelCapabilitiesOverrideLimitsVision.from_dict, from_none], obj.get("vision")) - return ModelCapabilitiesOverrideLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) - - def to_dict(self) -> dict: - result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(PurpleModelCapabilitiesOverrideLimitsVision, x), from_none], self.vision) - return result - @dataclass class MCPServer: name: str @@ -2614,129 +2235,195 @@ def to_dict(self) -> dict: return result @dataclass -class UIElicitationStringEnumField: - enum: list[str] - type: UIElicitationStringEnumFieldType - default: str | None = None - description: str | None = None - enum_names: list[str] | None = None - title: str | None = None +class MCPServerConfigHTTP: + url: str + filter_mapping: dict[str, FilterMappingString] | FilterMappingString | None = None + headers: dict[str, str] | None = None + is_default_server: bool | None = None + oauth_client_id: str | None = None + oauth_public_client: bool | None = None + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" + + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" + + type: MCPServerConfigHTTPType | None = None + """Remote transport type. Defaults to "http" when omitted.""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringEnumField': + def from_dict(obj: Any) -> 'MCPServerConfigHTTP': assert isinstance(obj, dict) - enum = from_list(from_str, obj.get("enum")) - type = UIElicitationStringEnumFieldType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationStringEnumField(enum, type, default, description, enum_names, title) + url = from_str(obj.get("url")) + filter_mapping = from_union([lambda x: from_dict(FilterMappingString, x), FilterMappingString, from_none], obj.get("filterMapping")) + headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) + oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) + return MCPServerConfigHTTP(url, filter_mapping, headers, is_default_server, oauth_client_id, oauth_public_client, timeout, tools, type) def to_dict(self) -> dict: result: dict = {} - result["enum"] = from_list(from_str, self.enum) - result["type"] = to_enum(UIElicitationStringEnumFieldType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.enum_names is not None: - result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["url"] = from_str(self.url) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(FilterMappingString, x), x), lambda x: to_enum(FilterMappingString, x), from_none], self.filter_mapping) + if self.headers is not None: + result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.oauth_client_id is not None: + result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) + if self.oauth_public_client is not None: + result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) return result @dataclass -class UIElicitationArrayEnumFieldItems: - enum: list[str] - type: UIElicitationStringEnumFieldType +class MCPServerConfigLocal: + args: list[str] + command: str + cwd: str | None = None + env: dict[str, str] | None = None + filter_mapping: dict[str, FilterMappingString] | FilterMappingString | None = None + is_default_server: bool | None = None + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" + + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" + + type: MCPServerConfigLocalType | None = None @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayEnumFieldItems': + def from_dict(obj: Any) -> 'MCPServerConfigLocal': assert isinstance(obj, dict) - enum = from_list(from_str, obj.get("enum")) - type = UIElicitationStringEnumFieldType(obj.get("type")) - return UIElicitationArrayEnumFieldItems(enum, type) + args = from_list(from_str, obj.get("args")) + command = from_str(obj.get("command")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) + filter_mapping = from_union([lambda x: from_dict(FilterMappingString, x), FilterMappingString, from_none], obj.get("filterMapping")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + type = from_union([MCPServerConfigLocalType, from_none], obj.get("type")) + return MCPServerConfigLocal(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, type) def to_dict(self) -> dict: result: dict = {} - result["enum"] = from_list(from_str, self.enum) - result["type"] = to_enum(UIElicitationStringEnumFieldType, self.type) + result["args"] = from_list(from_str, self.args) + result["command"] = from_str(self.command) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.env is not None: + result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(FilterMappingString, x), x), lambda x: to_enum(FilterMappingString, x), from_none], self.filter_mapping) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(MCPServerConfigLocalType, x), from_none], self.type) return result @dataclass -class UIElicitationStringOneOfField: - one_of: list[UIElicitationStringOneOfFieldOneOf] - type: UIElicitationStringEnumFieldType - default: str | None = None - description: str | None = None - title: str | None = None +class ModeSetRequest: + mode: SessionMode + """The agent mode. Valid values: "interactive", "plan", "autopilot".""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringOneOfField': + def from_dict(obj: Any) -> 'ModeSetRequest': assert isinstance(obj, dict) - one_of = from_list(UIElicitationStringOneOfFieldOneOf.from_dict, obj.get("oneOf")) - type = UIElicitationStringEnumFieldType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationStringOneOfField(one_of, type, default, description, title) + mode = SessionMode(obj.get("mode")) + return ModeSetRequest(mode) def to_dict(self) -> dict: result: dict = {} - result["oneOf"] = from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), self.one_of) - result["type"] = to_enum(UIElicitationStringEnumFieldType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["mode"] = to_enum(SessionMode, self.mode) return result @dataclass -class UIElicitationArrayAnyOfFieldItems: - any_of: list[PurpleUIElicitationArrayAnyOfFieldItemsAnyOf] +class ModelCapabilitiesLimits: + """Token limits for prompts, outputs, and context window""" + + max_context_window_tokens: int | None = None + """Maximum total context window size in tokens""" + + max_output_tokens: int | None = None + """Maximum number of output/completion tokens""" + + max_prompt_tokens: int | None = None + """Maximum number of prompt/input tokens""" + + vision: ModelCapabilitiesLimitsVision | None = None + """Vision-specific limits""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItems': + def from_dict(obj: Any) -> 'ModelCapabilitiesLimits': assert isinstance(obj, dict) - any_of = from_list(PurpleUIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, obj.get("anyOf")) - return UIElicitationArrayAnyOfFieldItems(any_of) + max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) + max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) + max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) + vision = from_union([ModelCapabilitiesLimitsVision.from_dict, from_none], obj.get("vision")) + return ModelCapabilitiesLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) def to_dict(self) -> dict: result: dict = {} - result["anyOf"] = from_list(lambda x: to_class(PurpleUIElicitationArrayAnyOfFieldItemsAnyOf, x), self.any_of) + if self.max_context_window_tokens is not None: + result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) + if self.max_output_tokens is not None: + result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) + if self.max_prompt_tokens is not None: + result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) + if self.vision is not None: + result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesLimitsVision, x), from_none], self.vision) return result @dataclass -class UIElicitationResponse: - """The elicitation response (accept with form values, decline, or cancel)""" +class ModelCapabilitiesOverrideLimits: + """Token limits for prompts, outputs, and context window""" - action: UIElicitationResponseAction - """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" + max_context_window_tokens: int | None = None + """Maximum total context window size in tokens""" - content: dict[str, float | bool | list[str] | str] | None = None - """The form values submitted by the user (present when action is 'accept')""" + max_output_tokens: int | None = None + max_prompt_tokens: int | None = None + vision: ModelCapabilitiesOverrideLimitsVision | None = None @staticmethod - def from_dict(obj: Any) -> 'UIElicitationResponse': + def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideLimits': assert isinstance(obj, dict) - action = UIElicitationResponseAction(obj.get("action")) - content = from_union([lambda x: from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], obj.get("content")) - return UIElicitationResponse(action, content) + max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) + max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) + max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) + vision = from_union([ModelCapabilitiesOverrideLimitsVision.from_dict, from_none], obj.get("vision")) + return ModelCapabilitiesOverrideLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) def to_dict(self) -> dict: result: dict = {} - result["action"] = to_enum(UIElicitationResponseAction, self.action) - if self.content is not None: - result["content"] = from_union([lambda x: from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], self.content) + if self.max_context_window_tokens is not None: + result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) + if self.max_output_tokens is not None: + result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) + if self.max_prompt_tokens is not None: + result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) + if self.vision is not None: + result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimitsVision, x), from_none], self.vision) return result @dataclass class PermissionDecision: - kind: Kind + kind: PermissionDecisionKind """The permission request was approved Denied because approval rules explicitly blocked it @@ -2769,7 +2456,7 @@ class PermissionDecision: @staticmethod def from_dict(obj: Any) -> 'PermissionDecision': assert isinstance(obj, dict) - kind = Kind(obj.get("kind")) + kind = PermissionDecisionKind(obj.get("kind")) rules = from_union([lambda x: from_list(lambda x: x, x), from_none], obj.get("rules")) feedback = from_union([from_str, from_none], obj.get("feedback")) message = from_union([from_str, from_none], obj.get("message")) @@ -2779,7 +2466,7 @@ def from_dict(obj: Any) -> 'PermissionDecision': def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(Kind, self.kind) + result["kind"] = to_enum(PermissionDecisionKind, self.kind) if self.rules is not None: result["rules"] = from_union([lambda x: from_list(lambda x: x, x), from_none], self.rules) if self.feedback is not None: @@ -2793,375 +2480,258 @@ def to_dict(self) -> dict: return result @dataclass -class CapabilitiesLimits: - """Token limits for prompts, outputs, and context window""" - - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" - - max_output_tokens: int | None = None - """Maximum number of output/completion tokens""" - - max_prompt_tokens: int | None = None - """Maximum number of prompt/input tokens""" - - vision: FluffyModelCapabilitiesLimitsVision | None = None - """Vision-specific limits""" - - @staticmethod - def from_dict(obj: Any) -> 'CapabilitiesLimits': - assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([FluffyModelCapabilitiesLimitsVision.from_dict, from_none], obj.get("vision")) - return CapabilitiesLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) - - def to_dict(self) -> dict: - result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(FluffyModelCapabilitiesLimitsVision, x), from_none], self.vision) - return result - -@dataclass -class ToolList: - tools: list[Tool] - """List of available built-in tools with metadata""" +class PermissionDecisionApproved: + kind: PermissionDecisionApprovedKind + """The permission request was approved""" @staticmethod - def from_dict(obj: Any) -> 'ToolList': + def from_dict(obj: Any) -> 'PermissionDecisionApproved': assert isinstance(obj, dict) - tools = from_list(Tool.from_dict, obj.get("tools")) - return ToolList(tools) + kind = PermissionDecisionApprovedKind(obj.get("kind")) + return PermissionDecisionApproved(kind) def to_dict(self) -> dict: result: dict = {} - result["tools"] = from_list(lambda x: to_class(Tool, x), self.tools) + result["kind"] = to_enum(PermissionDecisionApprovedKind, self.kind) return result @dataclass -class ToolsHandlePendingToolCallRequest: - request_id: str - """Request ID of the pending tool call""" +class PermissionDecisionDeniedByContentExclusionPolicy: + kind: PermissionDecisionDeniedByContentExclusionPolicyKind + """Denied by the organization's content exclusion policy""" - error: str | None = None - """Error message if the tool call failed""" + message: str + """Human-readable explanation of why the path was excluded""" - result: ToolCallResult | str | None = None - """Tool call result (string or expanded result object)""" + path: str + """File path that triggered the exclusion""" @staticmethod - def from_dict(obj: Any) -> 'ToolsHandlePendingToolCallRequest': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedByContentExclusionPolicy': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - error = from_union([from_str, from_none], obj.get("error")) - result = from_union([ToolCallResult.from_dict, from_str, from_none], obj.get("result")) - return ToolsHandlePendingToolCallRequest(request_id, error, result) + kind = PermissionDecisionDeniedByContentExclusionPolicyKind(obj.get("kind")) + message = from_str(obj.get("message")) + path = from_str(obj.get("path")) + return PermissionDecisionDeniedByContentExclusionPolicy(kind, message, path) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.result is not None: - result["result"] = from_union([lambda x: to_class(ToolCallResult, x), from_str, from_none], self.result) + result["kind"] = to_enum(PermissionDecisionDeniedByContentExclusionPolicyKind, self.kind) + result["message"] = from_str(self.message) + result["path"] = from_str(self.path) return result @dataclass -class AccountGetQuotaResult: - quota_snapshots: dict[str, AccountQuotaSnapshot] - """Quota snapshots keyed by type (e.g., chat, completions, premium_interactions)""" +class PermissionDecisionDeniedByPermissionRequestHook: + kind: PermissionDecisionDeniedByPermissionRequestHookKind + """Denied by a permission request hook registered by an extension or plugin""" + + interrupt: bool | None = None + """Whether to interrupt the current agent turn""" + + message: str | None = None + """Optional message from the hook explaining the denial""" @staticmethod - def from_dict(obj: Any) -> 'AccountGetQuotaResult': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedByPermissionRequestHook': assert isinstance(obj, dict) - quota_snapshots = from_dict(AccountQuotaSnapshot.from_dict, obj.get("quotaSnapshots")) - return AccountGetQuotaResult(quota_snapshots) + kind = PermissionDecisionDeniedByPermissionRequestHookKind(obj.get("kind")) + interrupt = from_union([from_bool, from_none], obj.get("interrupt")) + message = from_union([from_str, from_none], obj.get("message")) + return PermissionDecisionDeniedByPermissionRequestHook(kind, interrupt, message) def to_dict(self) -> dict: result: dict = {} - result["quotaSnapshots"] = from_dict(lambda x: to_class(AccountQuotaSnapshot, x), self.quota_snapshots) + result["kind"] = to_enum(PermissionDecisionDeniedByPermissionRequestHookKind, self.kind) + if self.interrupt is not None: + result["interrupt"] = from_union([from_bool, from_none], self.interrupt) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) return result @dataclass -class SessionFSSetProviderRequest: - conventions: SessionFSSetProviderConventions - """Path conventions used by this filesystem""" - - initial_cwd: str - """Initial working directory for sessions""" +class PermissionDecisionDeniedByRules: + kind: PermissionDecisionDeniedByRulesKind + """Denied because approval rules explicitly blocked it""" - session_state_path: str - """Path within each session's SessionFs where the runtime stores files for that session""" + rules: list[Any] + """Rules that denied the request""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderRequest': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedByRules': assert isinstance(obj, dict) - conventions = SessionFSSetProviderConventions(obj.get("conventions")) - initial_cwd = from_str(obj.get("initialCwd")) - session_state_path = from_str(obj.get("sessionStatePath")) - return SessionFSSetProviderRequest(conventions, initial_cwd, session_state_path) + kind = PermissionDecisionDeniedByRulesKind(obj.get("kind")) + rules = from_list(lambda x: x, obj.get("rules")) + return PermissionDecisionDeniedByRules(kind, rules) def to_dict(self) -> dict: result: dict = {} - result["conventions"] = to_enum(SessionFSSetProviderConventions, self.conventions) - result["initialCwd"] = from_str(self.initial_cwd) - result["sessionStatePath"] = from_str(self.session_state_path) + result["kind"] = to_enum(PermissionDecisionDeniedByRulesKind, self.kind) + result["rules"] = from_list(lambda x: x, self.rules) return result @dataclass -class ModelCapabilitiesLimitsClass: - """Token limits for prompts, outputs, and context window""" +class PermissionDecisionDeniedInteractivelyByUser: + kind: PermissionDecisionDeniedInteractivelyByUserKind + """Denied by the user during an interactive prompt""" - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" - - max_output_tokens: int | None = None - max_prompt_tokens: int | None = None - vision: FluffyModelCapabilitiesOverrideLimitsVision | None = None + feedback: str | None = None + """Optional feedback from the user explaining the denial""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesLimitsClass': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedInteractivelyByUser': assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([FluffyModelCapabilitiesOverrideLimitsVision.from_dict, from_none], obj.get("vision")) - return ModelCapabilitiesLimitsClass(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) + kind = PermissionDecisionDeniedInteractivelyByUserKind(obj.get("kind")) + feedback = from_union([from_str, from_none], obj.get("feedback")) + return PermissionDecisionDeniedInteractivelyByUser(kind, feedback) def to_dict(self) -> dict: result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(FluffyModelCapabilitiesOverrideLimitsVision, x), from_none], self.vision) + result["kind"] = to_enum(PermissionDecisionDeniedInteractivelyByUserKind, self.kind) + if self.feedback is not None: + result["feedback"] = from_union([from_str, from_none], self.feedback) return result @dataclass -class ModeSetRequest: - mode: SessionMode - """The agent mode. Valid values: "interactive", "plan", "autopilot".""" +class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser: + kind: PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind + """Denied because no approval rule matched and user confirmation was unavailable""" @staticmethod - def from_dict(obj: Any) -> 'ModeSetRequest': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser': assert isinstance(obj, dict) - mode = SessionMode(obj.get("mode")) - return ModeSetRequest(mode) + kind = PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind(obj.get("kind")) + return PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser(kind) def to_dict(self) -> dict: result: dict = {} - result["mode"] = to_enum(SessionMode, self.mode) + result["kind"] = to_enum(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind, self.kind) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class Workspace: - id: UUID - branch: str | None = None - chronicle_sync_dismissed: bool | None = None - created_at: datetime | None = None - cwd: str | None = None - git_root: str | None = None - host_type: HostType | None = None - mc_last_event_id: str | None = None - mc_session_id: str | None = None - mc_task_id: str | None = None - name: str | None = None - pr_create_sync_dismissed: bool | None = None - repository: str | None = None - session_sync_level: SessionSyncLevel | None = None - summary: str | None = None - summary_count: int | None = None - updated_at: datetime | None = None +class PluginList: + plugins: list[Plugin] + """Installed plugins""" @staticmethod - def from_dict(obj: Any) -> 'Workspace': + def from_dict(obj: Any) -> 'PluginList': assert isinstance(obj, dict) - id = UUID(obj.get("id")) - branch = from_union([from_str, from_none], obj.get("branch")) - chronicle_sync_dismissed = from_union([from_bool, from_none], obj.get("chronicle_sync_dismissed")) - created_at = from_union([from_datetime, from_none], obj.get("created_at")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - git_root = from_union([from_str, from_none], obj.get("git_root")) - host_type = from_union([HostType, from_none], obj.get("host_type")) - mc_last_event_id = from_union([from_str, from_none], obj.get("mc_last_event_id")) - mc_session_id = from_union([from_str, from_none], obj.get("mc_session_id")) - mc_task_id = from_union([from_str, from_none], obj.get("mc_task_id")) - name = from_union([from_str, from_none], obj.get("name")) - pr_create_sync_dismissed = from_union([from_bool, from_none], obj.get("pr_create_sync_dismissed")) - repository = from_union([from_str, from_none], obj.get("repository")) - session_sync_level = from_union([SessionSyncLevel, from_none], obj.get("session_sync_level")) - summary = from_union([from_str, from_none], obj.get("summary")) - summary_count = from_union([from_int, from_none], obj.get("summary_count")) - updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) - return Workspace(id, branch, chronicle_sync_dismissed, created_at, cwd, git_root, host_type, mc_last_event_id, mc_session_id, mc_task_id, name, pr_create_sync_dismissed, repository, session_sync_level, summary, summary_count, updated_at) + plugins = from_list(Plugin.from_dict, obj.get("plugins")) + return PluginList(plugins) def to_dict(self) -> dict: result: dict = {} - result["id"] = str(self.id) - if self.branch is not None: - result["branch"] = from_union([from_str, from_none], self.branch) - if self.chronicle_sync_dismissed is not None: - result["chronicle_sync_dismissed"] = from_union([from_bool, from_none], self.chronicle_sync_dismissed) - if self.created_at is not None: - result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.git_root is not None: - result["git_root"] = from_union([from_str, from_none], self.git_root) - if self.host_type is not None: - result["host_type"] = from_union([lambda x: to_enum(HostType, x), from_none], self.host_type) - if self.mc_last_event_id is not None: - result["mc_last_event_id"] = from_union([from_str, from_none], self.mc_last_event_id) - if self.mc_session_id is not None: - result["mc_session_id"] = from_union([from_str, from_none], self.mc_session_id) - if self.mc_task_id is not None: - result["mc_task_id"] = from_union([from_str, from_none], self.mc_task_id) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.pr_create_sync_dismissed is not None: - result["pr_create_sync_dismissed"] = from_union([from_bool, from_none], self.pr_create_sync_dismissed) - if self.repository is not None: - result["repository"] = from_union([from_str, from_none], self.repository) - if self.session_sync_level is not None: - result["session_sync_level"] = from_union([lambda x: to_enum(SessionSyncLevel, x), from_none], self.session_sync_level) - if self.summary is not None: - result["summary"] = from_union([from_str, from_none], self.summary) - if self.summary_count is not None: - result["summary_count"] = from_union([from_int, from_none], self.summary_count) - if self.updated_at is not None: - result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) + result["plugins"] = from_list(lambda x: to_class(Plugin, x), self.plugins) return result @dataclass -class InstructionsSources: - content: str - """Raw content of the instruction file""" - - id: str - """Unique identifier for this source (used for toggling)""" - - label: str - """Human-readable label""" - - location: InstructionsSourcesLocation - """Where this source lives — used for UI grouping""" - - source_path: str - """File path relative to repo or absolute for home""" - - type: InstructionsSourcesType - """Category of instruction source — used for merge logic""" - - apply_to: str | None = None - """Glob pattern from frontmatter — when set, this instruction applies only to matching files""" - - description: str | None = None - """Short description (body after frontmatter) for use in instruction tables""" +class ServerSkillList: + skills: list[ServerSkill] + """All discovered skills across all sources""" @staticmethod - def from_dict(obj: Any) -> 'InstructionsSources': + def from_dict(obj: Any) -> 'ServerSkillList': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - id = from_str(obj.get("id")) - label = from_str(obj.get("label")) - location = InstructionsSourcesLocation(obj.get("location")) - source_path = from_str(obj.get("sourcePath")) - type = InstructionsSourcesType(obj.get("type")) - apply_to = from_union([from_str, from_none], obj.get("applyTo")) - description = from_union([from_str, from_none], obj.get("description")) - return InstructionsSources(content, id, label, location, source_path, type, apply_to, description) + skills = from_list(ServerSkill.from_dict, obj.get("skills")) + return ServerSkillList(skills) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["id"] = from_str(self.id) - result["label"] = from_str(self.label) - result["location"] = to_enum(InstructionsSourcesLocation, self.location) - result["sourcePath"] = from_str(self.source_path) - result["type"] = to_enum(InstructionsSourcesType, self.type) - if self.apply_to is not None: - result["applyTo"] = from_union([from_str, from_none], self.apply_to) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) + result["skills"] = from_list(lambda x: to_class(ServerSkill, x), self.skills) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentList: - agents: list[AgentListAgent] - """Available custom agents""" +class SessionFSError: + """Describes a filesystem error.""" + + code: SessionFSErrorCode + """Error classification""" + + message: str | None = None + """Free-form detail about the error, for logging/diagnostics""" @staticmethod - def from_dict(obj: Any) -> 'AgentList': + def from_dict(obj: Any) -> 'SessionFSError': assert isinstance(obj, dict) - agents = from_list(AgentListAgent.from_dict, obj.get("agents")) - return AgentList(agents) + code = SessionFSErrorCode(obj.get("code")) + message = from_union([from_str, from_none], obj.get("message")) + return SessionFSError(code, message) def to_dict(self) -> dict: result: dict = {} - result["agents"] = from_list(lambda x: to_class(AgentListAgent, x), self.agents) + result["code"] = to_enum(SessionFSErrorCode, self.code) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentSelectResult: - agent: AgentSelectResultAgent - """The newly selected custom agent""" +class SessionFSReaddirWithTypesEntry: + name: str + """Entry name""" + + type: SessionFSReaddirWithTypesEntryType + """Entry type""" @staticmethod - def from_dict(obj: Any) -> 'AgentSelectResult': + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesEntry': assert isinstance(obj, dict) - agent = AgentSelectResultAgent.from_dict(obj.get("agent")) - return AgentSelectResult(agent) + name = from_str(obj.get("name")) + type = SessionFSReaddirWithTypesEntryType(obj.get("type")) + return SessionFSReaddirWithTypesEntry(name, type) def to_dict(self) -> dict: result: dict = {} - result["agent"] = to_class(AgentSelectResultAgent, self.agent) + result["name"] = from_str(self.name) + result["type"] = to_enum(SessionFSReaddirWithTypesEntryType, self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentGetCurrentResult: - agent: AgentReloadResultAgent | None = None - """Currently selected custom agent, or null if using the default agent""" +class SessionFSSetProviderRequest: + conventions: SessionFSSetProviderConventions + """Path conventions used by this filesystem""" + + initial_cwd: str + """Initial working directory for sessions""" + + session_state_path: str + """Path within each session's SessionFs where the runtime stores files for that session""" @staticmethod - def from_dict(obj: Any) -> 'AgentGetCurrentResult': + def from_dict(obj: Any) -> 'SessionFSSetProviderRequest': assert isinstance(obj, dict) - agent = from_union([AgentReloadResultAgent.from_dict, from_none], obj.get("agent")) - return AgentGetCurrentResult(agent) + conventions = SessionFSSetProviderConventions(obj.get("conventions")) + initial_cwd = from_str(obj.get("initialCwd")) + session_state_path = from_str(obj.get("sessionStatePath")) + return SessionFSSetProviderRequest(conventions, initial_cwd, session_state_path) def to_dict(self) -> dict: result: dict = {} - if self.agent is not None: - result["agent"] = from_union([lambda x: to_class(AgentReloadResultAgent, x), from_none], self.agent) + result["conventions"] = to_enum(SessionFSSetProviderConventions, self.conventions) + result["initialCwd"] = from_str(self.initial_cwd) + result["sessionStatePath"] = from_str(self.session_state_path) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentReloadResult: - agents: list[AgentReloadResultAgent] - """Reloaded custom agents""" +class ShellKillRequest: + process_id: str + """Process identifier returned by shell.exec""" + + signal: ShellKillSignal | None = None + """Signal to send (default: SIGTERM)""" @staticmethod - def from_dict(obj: Any) -> 'AgentReloadResult': + def from_dict(obj: Any) -> 'ShellKillRequest': assert isinstance(obj, dict) - agents = from_list(AgentReloadResultAgent.from_dict, obj.get("agents")) - return AgentReloadResult(agents) + process_id = from_str(obj.get("processId")) + signal = from_union([ShellKillSignal, from_none], obj.get("signal")) + return ShellKillRequest(process_id, signal) def to_dict(self) -> dict: result: dict = {} - result["agents"] = from_list(lambda x: to_class(AgentReloadResultAgent, x), self.agents) + result["processId"] = from_str(self.process_id) + if self.signal is not None: + result["signal"] = from_union([lambda x: to_enum(ShellKillSignal, x), from_none], self.signal) return result # Experimental: this type is part of an experimental API and may change or be removed. @@ -3181,172 +2751,294 @@ def to_dict(self) -> dict: result["skills"] = from_list(lambda x: to_class(Skill, x), self.skills) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PluginList: - plugins: list[Plugin] - """Installed plugins""" +class ToolList: + tools: list[Tool] + """List of available built-in tools with metadata""" @staticmethod - def from_dict(obj: Any) -> 'PluginList': + def from_dict(obj: Any) -> 'ToolList': assert isinstance(obj, dict) - plugins = from_list(Plugin.from_dict, obj.get("plugins")) - return PluginList(plugins) + tools = from_list(Tool.from_dict, obj.get("tools")) + return ToolList(tools) def to_dict(self) -> dict: result: dict = {} - result["plugins"] = from_list(lambda x: to_class(Plugin, x), self.plugins) + result["tools"] = from_list(lambda x: to_class(Tool, x), self.tools) return result @dataclass -class Extension: - id: str - """Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper')""" +class ToolsHandlePendingToolCallRequest: + request_id: str + """Request ID of the pending tool call""" - name: str - """Extension name (directory name)""" + error: str | None = None + """Error message if the tool call failed""" - source: ExtensionSource - """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" + result: ToolCallResult | str | None = None + """Tool call result (string or expanded result object)""" - status: ExtensionStatus - """Current status: running, disabled, failed, or starting""" + @staticmethod + def from_dict(obj: Any) -> 'ToolsHandlePendingToolCallRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + error = from_union([from_str, from_none], obj.get("error")) + result = from_union([ToolCallResult.from_dict, from_str, from_none], obj.get("result")) + return ToolsHandlePendingToolCallRequest(request_id, error, result) - pid: int | None = None - """Process ID if the extension is running""" + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.result is not None: + result["result"] = from_union([lambda x: to_class(ToolCallResult, x), from_str, from_none], self.result) + return result + +@dataclass +class UIElicitationArrayAnyOfFieldItems: + any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] @staticmethod - def from_dict(obj: Any) -> 'Extension': + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItems': assert isinstance(obj, dict) - id = from_str(obj.get("id")) - name = from_str(obj.get("name")) - source = ExtensionSource(obj.get("source")) - status = ExtensionStatus(obj.get("status")) - pid = from_union([from_int, from_none], obj.get("pid")) - return Extension(id, name, source, status, pid) + any_of = from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, obj.get("anyOf")) + return UIElicitationArrayAnyOfFieldItems(any_of) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) - result["name"] = from_str(self.name) - result["source"] = to_enum(ExtensionSource, self.source) - result["status"] = to_enum(ExtensionStatus, self.status) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) + result["anyOf"] = from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), self.any_of) + return result + +@dataclass +class UIElicitationArrayEnumFieldItems: + enum: list[str] + type: UIElicitationArrayEnumFieldItemsType + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationArrayEnumFieldItems': + assert isinstance(obj, dict) + enum = from_list(from_str, obj.get("enum")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + return UIElicitationArrayEnumFieldItems(enum, type) + + def to_dict(self) -> dict: + result: dict = {} + result["enum"] = from_list(from_str, self.enum) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) return result @dataclass class UIElicitationArrayFieldItems: enum: list[str] | None = None - type: UIElicitationStringEnumFieldType | None = None - any_of: list[FluffyUIElicitationArrayAnyOfFieldItemsAnyOf] | None = None + type: UIElicitationArrayEnumFieldItemsType | None = None + any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] | None = None + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationArrayFieldItems': + assert isinstance(obj, dict) + enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) + type = from_union([UIElicitationArrayEnumFieldItemsType, from_none], obj.get("type")) + any_of = from_union([lambda x: from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, x), from_none], obj.get("anyOf")) + return UIElicitationArrayFieldItems(enum, type, any_of) + + def to_dict(self) -> dict: + result: dict = {} + if self.enum is not None: + result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(UIElicitationArrayEnumFieldItemsType, x), from_none], self.type) + if self.any_of is not None: + result["anyOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), x), from_none], self.any_of) + return result + +@dataclass +class UIElicitationStringEnumField: + enum: list[str] + type: UIElicitationArrayEnumFieldItemsType + default: str | None = None + description: str | None = None + enum_names: list[str] | None = None + title: str | None = None + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationStringEnumField': + assert isinstance(obj, dict) + enum = from_list(from_str, obj.get("enum")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationStringEnumField(enum, type, default, description, enum_names, title) + + def to_dict(self) -> dict: + result: dict = {} + result["enum"] = from_list(from_str, self.enum) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.enum_names is not None: + result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationSchemaPropertyString: + type: UIElicitationArrayEnumFieldItemsType + default: str | None = None + description: str | None = None + format: UIElicitationSchemaPropertyStringFormat | None = None + max_length: float | None = None + min_length: float | None = None + title: str | None = None + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyString': + assert isinstance(obj, dict) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) + max_length = from_union([from_float, from_none], obj.get("maxLength")) + min_length = from_union([from_float, from_none], obj.get("minLength")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationSchemaPropertyString(type, default, description, format, max_length, min_length, title) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.format is not None: + result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) + if self.max_length is not None: + result["maxLength"] = from_union([to_float, from_none], self.max_length) + if self.min_length is not None: + result["minLength"] = from_union([to_float, from_none], self.min_length) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationStringOneOfField: + one_of: list[UIElicitationStringOneOfFieldOneOf] + type: UIElicitationArrayEnumFieldItemsType + default: str | None = None + description: str | None = None + title: str | None = None @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayFieldItems': + def from_dict(obj: Any) -> 'UIElicitationStringOneOfField': assert isinstance(obj, dict) - enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) - type = from_union([UIElicitationStringEnumFieldType, from_none], obj.get("type")) - any_of = from_union([lambda x: from_list(FluffyUIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, x), from_none], obj.get("anyOf")) - return UIElicitationArrayFieldItems(enum, type, any_of) + one_of = from_list(UIElicitationStringOneOfFieldOneOf.from_dict, obj.get("oneOf")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationStringOneOfField(one_of, type, default, description, title) def to_dict(self) -> dict: result: dict = {} - if self.enum is not None: - result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(UIElicitationStringEnumFieldType, x), from_none], self.type) - if self.any_of is not None: - result["anyOf"] = from_union([lambda x: from_list(lambda x: to_class(FluffyUIElicitationArrayAnyOfFieldItemsAnyOf, x), x), from_none], self.any_of) + result["oneOf"] = from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), self.one_of) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result @dataclass -class LogRequest: - message: str - """Human-readable message""" +class UIElicitationResponse: + """The elicitation response (accept with form values, decline, or cancel)""" - ephemeral: bool | None = None - """When true, the message is transient and not persisted to the session event log on disk""" + action: UIElicitationResponseAction + """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" - level: SessionLogLevel | None = None - """Log severity level. Determines how the message is displayed in the timeline. Defaults to - "info". - """ - url: str | None = None - """Optional URL the user can open in their browser for more details""" + content: dict[str, float | bool | list[str] | str] | None = None + """The form values submitted by the user (present when action is 'accept')""" @staticmethod - def from_dict(obj: Any) -> 'LogRequest': + def from_dict(obj: Any) -> 'UIElicitationResponse': assert isinstance(obj, dict) - message = from_str(obj.get("message")) - ephemeral = from_union([from_bool, from_none], obj.get("ephemeral")) - level = from_union([SessionLogLevel, from_none], obj.get("level")) - url = from_union([from_str, from_none], obj.get("url")) - return LogRequest(message, ephemeral, level, url) + action = UIElicitationResponseAction(obj.get("action")) + content = from_union([lambda x: from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], obj.get("content")) + return UIElicitationResponse(action, content) def to_dict(self) -> dict: result: dict = {} - result["message"] = from_str(self.message) - if self.ephemeral is not None: - result["ephemeral"] = from_union([from_bool, from_none], self.ephemeral) - if self.level is not None: - result["level"] = from_union([lambda x: to_enum(SessionLogLevel, x), from_none], self.level) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["action"] = to_enum(UIElicitationResponseAction, self.action) + if self.content is not None: + result["content"] = from_union([lambda x: from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], self.content) return result @dataclass -class ShellKillRequest: - process_id: str - """Process identifier returned by shell.exec""" - - signal: ShellKillSignal | None = None - """Signal to send (default: SIGTERM)""" +class UIElicitationSchemaPropertyBoolean: + type: UIElicitationSchemaPropertyBooleanType + default: bool | None = None + description: str | None = None + title: str | None = None @staticmethod - def from_dict(obj: Any) -> 'ShellKillRequest': + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyBoolean': assert isinstance(obj, dict) - process_id = from_str(obj.get("processId")) - signal = from_union([ShellKillSignal, from_none], obj.get("signal")) - return ShellKillRequest(process_id, signal) + type = UIElicitationSchemaPropertyBooleanType(obj.get("type")) + default = from_union([from_bool, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationSchemaPropertyBoolean(type, default, description, title) def to_dict(self) -> dict: result: dict = {} - result["processId"] = from_str(self.process_id) - if self.signal is not None: - result["signal"] = from_union([lambda x: to_enum(ShellKillSignal, x), from_none], self.signal) + result["type"] = to_enum(UIElicitationSchemaPropertyBooleanType, self.type) + if self.default is not None: + result["default"] = from_union([from_bool, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class HistoryCompactResult: - messages_removed: int - """Number of messages removed during compaction""" - - success: bool - """Whether compaction completed successfully""" - - tokens_removed: int - """Number of tokens freed by compaction""" - - context_window: HistoryCompactContextWindow | None = None - """Post-compaction context window usage breakdown""" +class UIElicitationSchemaPropertyNumber: + type: UIElicitationSchemaPropertyNumberType + default: float | None = None + description: str | None = None + maximum: float | None = None + minimum: float | None = None + title: str | None = None @staticmethod - def from_dict(obj: Any) -> 'HistoryCompactResult': + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyNumber': assert isinstance(obj, dict) - messages_removed = from_int(obj.get("messagesRemoved")) - success = from_bool(obj.get("success")) - tokens_removed = from_int(obj.get("tokensRemoved")) - context_window = from_union([HistoryCompactContextWindow.from_dict, from_none], obj.get("contextWindow")) - return HistoryCompactResult(messages_removed, success, tokens_removed, context_window) + type = UIElicitationSchemaPropertyNumberType(obj.get("type")) + default = from_union([from_float, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + maximum = from_union([from_float, from_none], obj.get("maximum")) + minimum = from_union([from_float, from_none], obj.get("minimum")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationSchemaPropertyNumber(type, default, description, maximum, minimum, title) def to_dict(self) -> dict: result: dict = {} - result["messagesRemoved"] = from_int(self.messages_removed) - result["success"] = from_bool(self.success) - result["tokensRemoved"] = from_int(self.tokens_removed) - if self.context_window is not None: - result["contextWindow"] = from_union([lambda x: to_class(HistoryCompactContextWindow, x), from_none], self.context_window) + result["type"] = to_enum(UIElicitationSchemaPropertyNumberType, self.type) + if self.default is not None: + result["default"] = from_union([to_float, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.maximum is not None: + result["maximum"] = from_union([to_float, from_none], self.maximum) + if self.minimum is not None: + result["minimum"] = from_union([to_float, from_none], self.minimum) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result @dataclass @@ -3371,66 +3063,173 @@ def to_dict(self) -> dict: return result @dataclass -class SessionFSReaddirWithTypesEntry: - name: str - """Entry name""" +class Workspace: + id: UUID + branch: str | None = None + chronicle_sync_dismissed: bool | None = None + created_at: datetime | None = None + cwd: str | None = None + git_root: str | None = None + host_type: HostType | None = None + mc_last_event_id: str | None = None + mc_session_id: str | None = None + mc_task_id: str | None = None + name: str | None = None + remote_steerable: bool | None = None + repository: str | None = None + session_sync_level: SessionSyncLevel | None = None + summary: str | None = None + summary_count: int | None = None + updated_at: datetime | None = None - type: SessionFSReaddirWithTypesEntryType - """Entry type""" + @staticmethod + def from_dict(obj: Any) -> 'Workspace': + assert isinstance(obj, dict) + id = UUID(obj.get("id")) + branch = from_union([from_str, from_none], obj.get("branch")) + chronicle_sync_dismissed = from_union([from_bool, from_none], obj.get("chronicle_sync_dismissed")) + created_at = from_union([from_datetime, from_none], obj.get("created_at")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + git_root = from_union([from_str, from_none], obj.get("git_root")) + host_type = from_union([HostType, from_none], obj.get("host_type")) + mc_last_event_id = from_union([from_str, from_none], obj.get("mc_last_event_id")) + mc_session_id = from_union([from_str, from_none], obj.get("mc_session_id")) + mc_task_id = from_union([from_str, from_none], obj.get("mc_task_id")) + name = from_union([from_str, from_none], obj.get("name")) + remote_steerable = from_union([from_bool, from_none], obj.get("remote_steerable")) + repository = from_union([from_str, from_none], obj.get("repository")) + session_sync_level = from_union([SessionSyncLevel, from_none], obj.get("session_sync_level")) + summary = from_union([from_str, from_none], obj.get("summary")) + summary_count = from_union([from_int, from_none], obj.get("summary_count")) + updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) + return Workspace(id, branch, chronicle_sync_dismissed, created_at, cwd, git_root, host_type, mc_last_event_id, mc_session_id, mc_task_id, name, remote_steerable, repository, session_sync_level, summary, summary_count, updated_at) + + def to_dict(self) -> dict: + result: dict = {} + result["id"] = str(self.id) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.chronicle_sync_dismissed is not None: + result["chronicle_sync_dismissed"] = from_union([from_bool, from_none], self.chronicle_sync_dismissed) + if self.created_at is not None: + result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.git_root is not None: + result["git_root"] = from_union([from_str, from_none], self.git_root) + if self.host_type is not None: + result["host_type"] = from_union([lambda x: to_enum(HostType, x), from_none], self.host_type) + if self.mc_last_event_id is not None: + result["mc_last_event_id"] = from_union([from_str, from_none], self.mc_last_event_id) + if self.mc_session_id is not None: + result["mc_session_id"] = from_union([from_str, from_none], self.mc_session_id) + if self.mc_task_id is not None: + result["mc_task_id"] = from_union([from_str, from_none], self.mc_task_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.remote_steerable is not None: + result["remote_steerable"] = from_union([from_bool, from_none], self.remote_steerable) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + if self.session_sync_level is not None: + result["session_sync_level"] = from_union([lambda x: to_enum(SessionSyncLevel, x), from_none], self.session_sync_level) + if self.summary is not None: + result["summary"] = from_union([from_str, from_none], self.summary) + if self.summary_count is not None: + result["summary_count"] = from_union([from_int, from_none], self.summary_count) + if self.updated_at is not None: + result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) + return result + +@dataclass +class MCPDiscoverResult: + servers: list[DiscoveredMCPServer] + """MCP servers discovered from all sources""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesEntry': + def from_dict(obj: Any) -> 'MCPDiscoverResult': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - type = SessionFSReaddirWithTypesEntryType(obj.get("type")) - return SessionFSReaddirWithTypesEntry(name, type) + servers = from_list(DiscoveredMCPServer.from_dict, obj.get("servers")) + return MCPDiscoverResult(servers) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["type"] = to_enum(SessionFSReaddirWithTypesEntryType, self.type) + result["servers"] = from_list(lambda x: to_class(DiscoveredMCPServer, x), self.servers) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MCPConfigList: - servers: dict[str, MCPServerConfigValue] - """All MCP servers from user config, keyed by name""" +class ExtensionList: + extensions: list[Extension] + """Discovered extensions and their current status""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigList': + def from_dict(obj: Any) -> 'ExtensionList': assert isinstance(obj, dict) - servers = from_dict(MCPServerConfigValue.from_dict, obj.get("servers")) - return MCPConfigList(servers) + extensions = from_list(Extension.from_dict, obj.get("extensions")) + return ExtensionList(extensions) + + def to_dict(self) -> dict: + result: dict = {} + result["extensions"] = from_list(lambda x: to_class(Extension, x), self.extensions) + return result + +@dataclass +class InstructionsGetSourcesResult: + sources: list[InstructionsSources] + """Instruction sources for the session""" + + @staticmethod + def from_dict(obj: Any) -> 'InstructionsGetSourcesResult': + assert isinstance(obj, dict) + sources = from_list(InstructionsSources.from_dict, obj.get("sources")) + return InstructionsGetSourcesResult(sources) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_dict(lambda x: to_class(MCPServerConfigValue, x), self.servers) + result["sources"] = from_list(lambda x: to_class(InstructionsSources, x), self.sources) return result @dataclass class MCPConfigAddRequest: - config: MCPConfigAddRequestMCPServerConfig + config: MCPServerConfig """MCP server configuration (local/stdio or remote/http)""" name: str """Unique name for the MCP server""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigAddRequest': + def from_dict(obj: Any) -> 'MCPConfigAddRequest': + assert isinstance(obj, dict) + config = MCPServerConfig.from_dict(obj.get("config")) + name = from_str(obj.get("name")) + return MCPConfigAddRequest(config, name) + + def to_dict(self) -> dict: + result: dict = {} + result["config"] = to_class(MCPServerConfig, self.config) + result["name"] = from_str(self.name) + return result + +@dataclass +class MCPConfigList: + servers: dict[str, MCPServerConfig] + """All MCP servers from user config, keyed by name""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPConfigList': assert isinstance(obj, dict) - config = MCPConfigAddRequestMCPServerConfig.from_dict(obj.get("config")) - name = from_str(obj.get("name")) - return MCPConfigAddRequest(config, name) + servers = from_dict(MCPServerConfig.from_dict, obj.get("servers")) + return MCPConfigList(servers) def to_dict(self) -> dict: result: dict = {} - result["config"] = to_class(MCPConfigAddRequestMCPServerConfig, self.config) - result["name"] = from_str(self.name) + result["servers"] = from_dict(lambda x: to_class(MCPServerConfig, x), self.servers) return result @dataclass class MCPConfigUpdateRequest: - config: MCPConfigUpdateRequestMCPServerConfig + config: MCPServerConfig """MCP server configuration (local/stdio or remote/http)""" name: str @@ -3439,30 +3238,30 @@ class MCPConfigUpdateRequest: @staticmethod def from_dict(obj: Any) -> 'MCPConfigUpdateRequest': assert isinstance(obj, dict) - config = MCPConfigUpdateRequestMCPServerConfig.from_dict(obj.get("config")) + config = MCPServerConfig.from_dict(obj.get("config")) name = from_str(obj.get("name")) return MCPConfigUpdateRequest(config, name) def to_dict(self) -> dict: result: dict = {} - result["config"] = to_class(MCPConfigUpdateRequestMCPServerConfig, self.config) + result["config"] = to_class(MCPServerConfig, self.config) result["name"] = from_str(self.name) return result @dataclass -class MCPDiscoverResult: - servers: list[ServerElement] - """MCP servers discovered from all sources""" +class MCPServerList: + servers: list[MCPServer] + """Configured MCP servers""" @staticmethod - def from_dict(obj: Any) -> 'MCPDiscoverResult': + def from_dict(obj: Any) -> 'MCPServerList': assert isinstance(obj, dict) - servers = from_list(ServerElement.from_dict, obj.get("servers")) - return MCPDiscoverResult(servers) + servers = from_list(MCPServer.from_dict, obj.get("servers")) + return MCPServerList(servers) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_list(lambda x: to_class(ServerElement, x), self.servers) + result["servers"] = from_list(lambda x: to_class(MCPServer, x), self.servers) return result @dataclass @@ -3491,221 +3290,218 @@ def to_dict(self) -> dict: return result @dataclass -class MCPServerList: - servers: list[MCPServer] - """Configured MCP servers""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPServerList': - assert isinstance(obj, dict) - servers = from_list(MCPServer.from_dict, obj.get("servers")) - return MCPServerList(servers) - - def to_dict(self) -> dict: - result: dict = {} - result["servers"] = from_list(lambda x: to_class(MCPServer, x), self.servers) - return result +class PermissionDecisionRequest: + request_id: str + """Request ID of the pending permission request""" -@dataclass -class UIElicitationArrayEnumField: - items: UIElicitationArrayEnumFieldItems - type: UIElicitationArrayEnumFieldType - default: list[str] | None = None - description: str | None = None - max_items: float | None = None - min_items: float | None = None - title: str | None = None + result: PermissionDecision @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayEnumField': + def from_dict(obj: Any) -> 'PermissionDecisionRequest': assert isinstance(obj, dict) - items = UIElicitationArrayEnumFieldItems.from_dict(obj.get("items")) - type = UIElicitationArrayEnumFieldType(obj.get("type")) - default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - max_items = from_union([from_float, from_none], obj.get("maxItems")) - min_items = from_union([from_float, from_none], obj.get("minItems")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationArrayEnumField(items, type, default, description, max_items, min_items, title) + request_id = from_str(obj.get("requestId")) + result = PermissionDecision.from_dict(obj.get("result")) + return PermissionDecisionRequest(request_id, result) def to_dict(self) -> dict: result: dict = {} - result["items"] = to_class(UIElicitationArrayEnumFieldItems, self.items) - result["type"] = to_enum(UIElicitationArrayEnumFieldType, self.type) - if self.default is not None: - result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.max_items is not None: - result["maxItems"] = from_union([to_float, from_none], self.max_items) - if self.min_items is not None: - result["minItems"] = from_union([to_float, from_none], self.min_items) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["requestId"] = from_str(self.request_id) + result["result"] = to_class(PermissionDecision, self.result) return result @dataclass -class UIElicitationArrayAnyOfField: - items: UIElicitationArrayAnyOfFieldItems - type: UIElicitationArrayEnumFieldType - default: list[str] | None = None - description: str | None = None - max_items: float | None = None - min_items: float | None = None - title: str | None = None +class SessionFSReadFileResult: + content: str + """File content as UTF-8 string""" + + error: SessionFSError | None = None + """Describes a filesystem error.""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfField': + def from_dict(obj: Any) -> 'SessionFSReadFileResult': assert isinstance(obj, dict) - items = UIElicitationArrayAnyOfFieldItems.from_dict(obj.get("items")) - type = UIElicitationArrayEnumFieldType(obj.get("type")) - default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - max_items = from_union([from_float, from_none], obj.get("maxItems")) - min_items = from_union([from_float, from_none], obj.get("minItems")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationArrayAnyOfField(items, type, default, description, max_items, min_items, title) + content = from_str(obj.get("content")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSReadFileResult(content, error) def to_dict(self) -> dict: result: dict = {} - result["items"] = to_class(UIElicitationArrayAnyOfFieldItems, self.items) - result["type"] = to_enum(UIElicitationArrayEnumFieldType, self.type) - if self.default is not None: - result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.max_items is not None: - result["maxItems"] = from_union([to_float, from_none], self.max_items) - if self.min_items is not None: - result["minItems"] = from_union([to_float, from_none], self.min_items) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["content"] = from_str(self.content) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) return result @dataclass -class UIHandlePendingElicitationRequest: - request_id: str - """The unique request ID from the elicitation.requested event""" +class SessionFSReaddirResult: + entries: list[str] + """Entry names in the directory""" - result: UIElicitationResponse - """The elicitation response (accept with form values, decline, or cancel)""" + error: SessionFSError | None = None + """Describes a filesystem error.""" @staticmethod - def from_dict(obj: Any) -> 'UIHandlePendingElicitationRequest': + def from_dict(obj: Any) -> 'SessionFSReaddirResult': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - result = UIElicitationResponse.from_dict(obj.get("result")) - return UIHandlePendingElicitationRequest(request_id, result) + entries = from_list(from_str, obj.get("entries")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSReaddirResult(entries, error) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["result"] = to_class(UIElicitationResponse, self.result) + result["entries"] = from_list(from_str, self.entries) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) return result @dataclass -class PermissionDecisionRequest: - request_id: str - """Request ID of the pending permission request""" - - result: PermissionDecision +class SessionFSStatResult: + birthtime: datetime + """ISO 8601 timestamp of creation""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionRequest': - assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - result = PermissionDecision.from_dict(obj.get("result")) - return PermissionDecisionRequest(request_id, result) + is_directory: bool + """Whether the path is a directory""" - def to_dict(self) -> dict: - result: dict = {} - result["requestId"] = from_str(self.request_id) - result["result"] = to_class(PermissionDecision, self.result) - return result + is_file: bool + """Whether the path is a file""" -@dataclass -class ModelCapabilitiesClass: - """Override individual model capabilities resolved by the runtime""" + mtime: datetime + """ISO 8601 timestamp of last modification""" - limits: ModelCapabilitiesLimitsClass | None = None - """Token limits for prompts, outputs, and context window""" + size: int + """File size in bytes""" - supports: ModelCapabilitiesOverrideSupports | None = None - """Feature flags indicating what the model supports""" + error: SessionFSError | None = None + """Describes a filesystem error.""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesClass': + def from_dict(obj: Any) -> 'SessionFSStatResult': assert isinstance(obj, dict) - limits = from_union([ModelCapabilitiesLimitsClass.from_dict, from_none], obj.get("limits")) - supports = from_union([ModelCapabilitiesOverrideSupports.from_dict, from_none], obj.get("supports")) - return ModelCapabilitiesClass(limits, supports) + birthtime = from_datetime(obj.get("birthtime")) + is_directory = from_bool(obj.get("isDirectory")) + is_file = from_bool(obj.get("isFile")) + mtime = from_datetime(obj.get("mtime")) + size = from_int(obj.get("size")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSStatResult(birthtime, is_directory, is_file, mtime, size, error) def to_dict(self) -> dict: result: dict = {} - if self.limits is not None: - result["limits"] = from_union([lambda x: to_class(ModelCapabilitiesLimitsClass, x), from_none], self.limits) - if self.supports is not None: - result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideSupports, x), from_none], self.supports) + result["birthtime"] = self.birthtime.isoformat() + result["isDirectory"] = from_bool(self.is_directory) + result["isFile"] = from_bool(self.is_file) + result["mtime"] = self.mtime.isoformat() + result["size"] = from_int(self.size) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) return result @dataclass -class WorkspacesGetWorkspaceResult: - workspace: Workspace | None = None - """Current workspace metadata, or null if not available""" +class SessionFSReaddirWithTypesResult: + entries: list[SessionFSReaddirWithTypesEntry] + """Directory entries with type information""" + + error: SessionFSError | None = None + """Describes a filesystem error.""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesGetWorkspaceResult': + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesResult': assert isinstance(obj, dict) - workspace = from_union([Workspace.from_dict, from_none], obj.get("workspace")) - return WorkspacesGetWorkspaceResult(workspace) + entries = from_list(SessionFSReaddirWithTypesEntry.from_dict, obj.get("entries")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSReaddirWithTypesResult(entries, error) def to_dict(self) -> dict: result: dict = {} - result["workspace"] = from_union([lambda x: to_class(Workspace, x), from_none], self.workspace) + result["entries"] = from_list(lambda x: to_class(SessionFSReaddirWithTypesEntry, x), self.entries) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) return result @dataclass -class InstructionsGetSourcesResult: - sources: list[InstructionsSources] - """Instruction sources for the session""" +class UIElicitationArrayAnyOfField: + items: UIElicitationArrayAnyOfFieldItems + type: UIElicitationArrayAnyOfFieldType + default: list[str] | None = None + description: str | None = None + max_items: float | None = None + min_items: float | None = None + title: str | None = None @staticmethod - def from_dict(obj: Any) -> 'InstructionsGetSourcesResult': + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfField': assert isinstance(obj, dict) - sources = from_list(InstructionsSources.from_dict, obj.get("sources")) - return InstructionsGetSourcesResult(sources) + items = UIElicitationArrayAnyOfFieldItems.from_dict(obj.get("items")) + type = UIElicitationArrayAnyOfFieldType(obj.get("type")) + default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + max_items = from_union([from_float, from_none], obj.get("maxItems")) + min_items = from_union([from_float, from_none], obj.get("minItems")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationArrayAnyOfField(items, type, default, description, max_items, min_items, title) def to_dict(self) -> dict: result: dict = {} - result["sources"] = from_list(lambda x: to_class(InstructionsSources, x), self.sources) + result["items"] = to_class(UIElicitationArrayAnyOfFieldItems, self.items) + result["type"] = to_enum(UIElicitationArrayAnyOfFieldType, self.type) + if self.default is not None: + result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.max_items is not None: + result["maxItems"] = from_union([to_float, from_none], self.max_items) + if self.min_items is not None: + result["minItems"] = from_union([to_float, from_none], self.min_items) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExtensionList: - extensions: list[Extension] - """Discovered extensions and their current status""" +class UIElicitationArrayEnumField: + items: UIElicitationArrayEnumFieldItems + type: UIElicitationArrayAnyOfFieldType + default: list[str] | None = None + description: str | None = None + max_items: float | None = None + min_items: float | None = None + title: str | None = None @staticmethod - def from_dict(obj: Any) -> 'ExtensionList': + def from_dict(obj: Any) -> 'UIElicitationArrayEnumField': assert isinstance(obj, dict) - extensions = from_list(Extension.from_dict, obj.get("extensions")) - return ExtensionList(extensions) + items = UIElicitationArrayEnumFieldItems.from_dict(obj.get("items")) + type = UIElicitationArrayAnyOfFieldType(obj.get("type")) + default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + max_items = from_union([from_float, from_none], obj.get("maxItems")) + min_items = from_union([from_float, from_none], obj.get("minItems")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationArrayEnumField(items, type, default, description, max_items, min_items, title) def to_dict(self) -> dict: result: dict = {} - result["extensions"] = from_list(lambda x: to_class(Extension, x), self.extensions) + result["items"] = to_class(UIElicitationArrayEnumFieldItems, self.items) + result["type"] = to_enum(UIElicitationArrayAnyOfFieldType, self.type) + if self.default is not None: + result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.max_items is not None: + result["maxItems"] = from_union([to_float, from_none], self.max_items) + if self.min_items is not None: + result["minItems"] = from_union([to_float, from_none], self.min_items) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result @dataclass class UIElicitationSchemaProperty: - type: UIElicitationSchemaPropertyNumberType + type: UIElicitationSchemaPropertyType default: float | bool | list[str] | str | None = None description: str | None = None enum: list[str] | None = None enum_names: list[str] | None = None title: str | None = None - one_of: list[UIElicitationSchemaPropertyOneOf] | None = None + one_of: list[UIElicitationStringOneOfFieldOneOf] | None = None items: UIElicitationArrayFieldItems | None = None max_items: float | None = None min_items: float | None = None @@ -3718,13 +3514,13 @@ class UIElicitationSchemaProperty: @staticmethod def from_dict(obj: Any) -> 'UIElicitationSchemaProperty': assert isinstance(obj, dict) - type = UIElicitationSchemaPropertyNumberType(obj.get("type")) + type = UIElicitationSchemaPropertyType(obj.get("type")) default = from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str, from_none], obj.get("default")) description = from_union([from_str, from_none], obj.get("description")) enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) title = from_union([from_str, from_none], obj.get("title")) - one_of = from_union([lambda x: from_list(UIElicitationSchemaPropertyOneOf.from_dict, x), from_none], obj.get("oneOf")) + one_of = from_union([lambda x: from_list(UIElicitationStringOneOfFieldOneOf.from_dict, x), from_none], obj.get("oneOf")) items = from_union([UIElicitationArrayFieldItems.from_dict, from_none], obj.get("items")) max_items = from_union([from_float, from_none], obj.get("maxItems")) min_items = from_union([from_float, from_none], obj.get("minItems")) @@ -3737,7 +3533,7 @@ def from_dict(obj: Any) -> 'UIElicitationSchemaProperty': def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationSchemaPropertyNumberType, self.type) + result["type"] = to_enum(UIElicitationSchemaPropertyType, self.type) if self.default is not None: result["default"] = from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str, from_none], self.default) if self.description is not None: @@ -3749,7 +3545,7 @@ def to_dict(self) -> dict: if self.title is not None: result["title"] = from_union([from_str, from_none], self.title) if self.one_of is not None: - result["oneOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationSchemaPropertyOneOf, x), x), from_none], self.one_of) + result["oneOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), x), from_none], self.one_of) if self.items is not None: result["items"] = from_union([lambda x: to_class(UIElicitationArrayFieldItems, x), from_none], self.items) if self.max_items is not None: @@ -3768,6 +3564,27 @@ def to_dict(self) -> dict: result["minimum"] = from_union([to_float, from_none], self.minimum) return result +@dataclass +class UIHandlePendingElicitationRequest: + request_id: str + """The unique request ID from the elicitation.requested event""" + + result: UIElicitationResponse + """The elicitation response (accept with form values, decline, or cancel)""" + + @staticmethod + def from_dict(obj: Any) -> 'UIHandlePendingElicitationRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + result = UIElicitationResponse.from_dict(obj.get("result")) + return UIHandlePendingElicitationRequest(request_id, result) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + result["result"] = to_class(UIElicitationResponse, self.result) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UsageGetMetricsResult: @@ -3828,19 +3645,19 @@ def to_dict(self) -> dict: return result @dataclass -class SessionFSReaddirWithTypesResult: - entries: list[SessionFSReaddirWithTypesEntry] - """Directory entries with type information""" +class WorkspacesGetWorkspaceResult: + workspace: Workspace | None = None + """Current workspace metadata, or null if not available""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesResult': + def from_dict(obj: Any) -> 'WorkspacesGetWorkspaceResult': assert isinstance(obj, dict) - entries = from_list(SessionFSReaddirWithTypesEntry.from_dict, obj.get("entries")) - return SessionFSReaddirWithTypesResult(entries) + workspace = from_union([Workspace.from_dict, from_none], obj.get("workspace")) + return WorkspacesGetWorkspaceResult(workspace) def to_dict(self) -> dict: result: dict = {} - result["entries"] = from_list(lambda x: to_class(SessionFSReaddirWithTypesEntry, x), self.entries) + result["workspace"] = from_union([lambda x: to_class(Workspace, x), from_none], self.workspace) return result @dataclass @@ -3850,7 +3667,7 @@ class UIElicitationSchema: properties: dict[str, UIElicitationSchemaProperty] """Form field definitions, keyed by field name""" - type: RequestedSchemaType + type: UIElicitationSchemaType """Schema type indicator (always 'object')""" required: list[str] | None = None @@ -3860,14 +3677,14 @@ class UIElicitationSchema: def from_dict(obj: Any) -> 'UIElicitationSchema': assert isinstance(obj, dict) properties = from_dict(UIElicitationSchemaProperty.from_dict, obj.get("properties")) - type = RequestedSchemaType(obj.get("type")) + type = UIElicitationSchemaType(obj.get("type")) required = from_union([lambda x: from_list(from_str, x), from_none], obj.get("required")) return UIElicitationSchema(properties, type, required) def to_dict(self) -> dict: result: dict = {} result["properties"] = from_dict(lambda x: to_class(UIElicitationSchemaProperty, x), self.properties) - result["type"] = to_enum(RequestedSchemaType, self.type) + result["type"] = to_enum(UIElicitationSchemaType, self.type) if self.required is not None: result["required"] = from_union([lambda x: from_list(from_str, x), from_none], self.required) return result @@ -3918,34 +3735,9 @@ def to_dict(self) -> dict: result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesSupports, x), from_none], self.supports) return result -@dataclass -class CapabilitiesClass: - """Model capabilities and limits""" - - limits: CapabilitiesLimits | None = None - """Token limits for prompts, outputs, and context window""" - - supports: CapabilitiesSupports | None = None - """Feature flags indicating what the model supports""" - - @staticmethod - def from_dict(obj: Any) -> 'CapabilitiesClass': - assert isinstance(obj, dict) - limits = from_union([CapabilitiesLimits.from_dict, from_none], obj.get("limits")) - supports = from_union([CapabilitiesSupports.from_dict, from_none], obj.get("supports")) - return CapabilitiesClass(limits, supports) - - def to_dict(self) -> dict: - result: dict = {} - if self.limits is not None: - result["limits"] = from_union([lambda x: to_class(CapabilitiesLimits, x), from_none], self.limits) - if self.supports is not None: - result["supports"] = from_union([lambda x: to_class(CapabilitiesSupports, x), from_none], self.supports) - return result - @dataclass class Model: - capabilities: CapabilitiesClass + capabilities: ModelCapabilities """Model capabilities and limits""" id: str @@ -3969,7 +3761,7 @@ class Model: @staticmethod def from_dict(obj: Any) -> 'Model': assert isinstance(obj, dict) - capabilities = CapabilitiesClass.from_dict(obj.get("capabilities")) + capabilities = ModelCapabilities.from_dict(obj.get("capabilities")) id = from_str(obj.get("id")) name = from_str(obj.get("name")) billing = from_union([ModelBilling.from_dict, from_none], obj.get("billing")) @@ -3980,7 +3772,7 @@ def from_dict(obj: Any) -> 'Model': def to_dict(self) -> dict: result: dict = {} - result["capabilities"] = to_class(CapabilitiesClass, self.capabilities) + result["capabilities"] = to_class(ModelCapabilities, self.capabilities) result["id"] = from_str(self.id) result["name"] = from_str(self.name) if self.billing is not None: @@ -4014,7 +3806,7 @@ class ModelSwitchToRequest: model_id: str """Model identifier to switch to""" - model_capabilities: ModelCapabilitiesClass | None = None + model_capabilities: ModelCapabilitiesOverride | None = None """Override individual model capabilities resolved by the runtime""" reasoning_effort: str | None = None @@ -4024,7 +3816,7 @@ class ModelSwitchToRequest: def from_dict(obj: Any) -> 'ModelSwitchToRequest': assert isinstance(obj, dict) model_id = from_str(obj.get("modelId")) - model_capabilities = from_union([ModelCapabilitiesClass.from_dict, from_none], obj.get("modelCapabilities")) + model_capabilities = from_union([ModelCapabilitiesOverride.from_dict, from_none], obj.get("modelCapabilities")) reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) return ModelSwitchToRequest(model_id, model_capabilities, reasoning_effort) @@ -4032,634 +3824,514 @@ def to_dict(self) -> dict: result: dict = {} result["modelId"] = from_str(self.model_id) if self.model_capabilities is not None: - result["modelCapabilities"] = from_union([lambda x: to_class(ModelCapabilitiesClass, x), from_none], self.model_capabilities) + result["modelCapabilities"] = from_union([lambda x: to_class(ModelCapabilitiesOverride, x), from_none], self.model_capabilities) if self.reasoning_effort is not None: result["reasoningEffort"] = from_union([from_str, from_none], self.reasoning_effort) return result -def model_capabilities_from_dict(s: Any) -> ModelCapabilities: - return ModelCapabilities.from_dict(s) - -def model_capabilities_to_dict(x: ModelCapabilities) -> Any: - return to_class(ModelCapabilities, x) - -def model_capabilities_limits_vision_from_dict(s: Any) -> ModelCapabilitiesLimitsVision: - return ModelCapabilitiesLimitsVision.from_dict(s) - -def model_capabilities_limits_vision_to_dict(x: ModelCapabilitiesLimitsVision) -> Any: - return to_class(ModelCapabilitiesLimitsVision, x) - -def mcp_server_config_from_dict(s: Any) -> MCPServerConfig: - return MCPServerConfig.from_dict(s) - -def mcp_server_config_to_dict(x: MCPServerConfig) -> Any: - return to_class(MCPServerConfig, x) - -def filter_mapping_from_dict(s: Any) -> dict[str, FilterMappingString] | FilterMappingString: - return from_union([lambda x: from_dict(FilterMappingString, x), FilterMappingString], s) - -def filter_mapping_to_dict(x: dict[str, FilterMappingString] | FilterMappingString) -> Any: - return from_union([lambda x: from_dict(lambda x: to_enum(FilterMappingString, x), x), lambda x: to_enum(FilterMappingString, x)], x) - -def discovered_mcp_server_from_dict(s: Any) -> DiscoveredMCPServer: - return DiscoveredMCPServer.from_dict(s) - -def discovered_mcp_server_to_dict(x: DiscoveredMCPServer) -> Any: - return to_class(DiscoveredMCPServer, x) - -def server_skill_list_from_dict(s: Any) -> ServerSkillList: - return ServerSkillList.from_dict(s) - -def server_skill_list_to_dict(x: ServerSkillList) -> Any: - return to_class(ServerSkillList, x) - -def server_skill_from_dict(s: Any) -> ServerSkill: - return ServerSkill.from_dict(s) - -def server_skill_to_dict(x: ServerSkill) -> Any: - return to_class(ServerSkill, x) - -def current_model_from_dict(s: Any) -> CurrentModel: - return CurrentModel.from_dict(s) - -def current_model_to_dict(x: CurrentModel) -> Any: - return to_class(CurrentModel, x) - -def model_capabilities_override_from_dict(s: Any) -> ModelCapabilitiesOverride: - return ModelCapabilitiesOverride.from_dict(s) - -def model_capabilities_override_to_dict(x: ModelCapabilitiesOverride) -> Any: - return to_class(ModelCapabilitiesOverride, x) - -def session_mode_from_dict(s: Any) -> SessionMode: - return SessionMode(s) - -def session_mode_to_dict(x: SessionMode) -> Any: - return to_enum(SessionMode, x) - -def agent_info_from_dict(s: Any) -> AgentInfo: - return AgentInfo.from_dict(s) - -def agent_info_to_dict(x: AgentInfo) -> Any: - return to_class(AgentInfo, x) - -def mcp_server_list_from_dict(s: Any) -> MCPServerList: - return MCPServerList.from_dict(s) - -def mcp_server_list_to_dict(x: MCPServerList) -> Any: - return to_class(MCPServerList, x) - -def tool_call_result_from_dict(s: Any) -> ToolCallResult: - return ToolCallResult.from_dict(s) - -def tool_call_result_to_dict(x: ToolCallResult) -> Any: - return to_class(ToolCallResult, x) - -def handle_tool_call_result_from_dict(s: Any) -> HandleToolCallResult: - return HandleToolCallResult.from_dict(s) - -def handle_tool_call_result_to_dict(x: HandleToolCallResult) -> Any: - return to_class(HandleToolCallResult, x) - -def ui_elicitation_string_enum_field_from_dict(s: Any) -> UIElicitationStringEnumField: - return UIElicitationStringEnumField.from_dict(s) - -def ui_elicitation_string_enum_field_to_dict(x: UIElicitationStringEnumField) -> Any: - return to_class(UIElicitationStringEnumField, x) - -def ui_elicitation_string_one_of_field_from_dict(s: Any) -> UIElicitationStringOneOfField: - return UIElicitationStringOneOfField.from_dict(s) - -def ui_elicitation_string_one_of_field_to_dict(x: UIElicitationStringOneOfField) -> Any: - return to_class(UIElicitationStringOneOfField, x) - -def ui_elicitation_array_enum_field_from_dict(s: Any) -> UIElicitationArrayEnumField: - return UIElicitationArrayEnumField.from_dict(s) - -def ui_elicitation_array_enum_field_to_dict(x: UIElicitationArrayEnumField) -> Any: - return to_class(UIElicitationArrayEnumField, x) - -def ui_elicitation_array_any_of_field_from_dict(s: Any) -> UIElicitationArrayAnyOfField: - return UIElicitationArrayAnyOfField.from_dict(s) - -def ui_elicitation_array_any_of_field_to_dict(x: UIElicitationArrayAnyOfField) -> Any: - return to_class(UIElicitationArrayAnyOfField, x) - -def ui_elicitation_response_from_dict(s: Any) -> UIElicitationResponse: - return UIElicitationResponse.from_dict(s) - -def ui_elicitation_response_to_dict(x: UIElicitationResponse) -> Any: - return to_class(UIElicitationResponse, x) - -def ui_elicitation_response_action_from_dict(s: Any) -> UIElicitationResponseAction: - return UIElicitationResponseAction(s) - -def ui_elicitation_response_action_to_dict(x: UIElicitationResponseAction) -> Any: - return to_enum(UIElicitationResponseAction, x) - -def ui_elicitation_response_content_from_dict(s: Any) -> dict[str, float | bool | list[str] | str]: - return from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), s) - -def ui_elicitation_response_content_to_dict(x: dict[str, float | bool | list[str] | str]) -> Any: - return from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x) - -def ui_elicitation_field_value_from_dict(s: Any) -> float | bool | list[str] | str: - return from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], s) - -def ui_elicitation_field_value_to_dict(x: float | bool | list[str] | str) -> Any: - return from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x) - -def ui_handle_pending_elicitation_request_from_dict(s: Any) -> UIHandlePendingElicitationRequest: - return UIHandlePendingElicitationRequest.from_dict(s) - -def ui_handle_pending_elicitation_request_to_dict(x: UIHandlePendingElicitationRequest) -> Any: - return to_class(UIHandlePendingElicitationRequest, x) - -def ui_elicitation_result_from_dict(s: Any) -> UIElicitationResult: - return UIElicitationResult.from_dict(s) - -def ui_elicitation_result_to_dict(x: UIElicitationResult) -> Any: - return to_class(UIElicitationResult, x) - -def permission_decision_request_from_dict(s: Any) -> PermissionDecisionRequest: - return PermissionDecisionRequest.from_dict(s) - -def permission_decision_request_to_dict(x: PermissionDecisionRequest) -> Any: - return to_class(PermissionDecisionRequest, x) - -def permission_decision_from_dict(s: Any) -> PermissionDecision: - return PermissionDecision.from_dict(s) - -def permission_decision_to_dict(x: PermissionDecision) -> Any: - return to_class(PermissionDecision, x) - -def permission_request_result_from_dict(s: Any) -> PermissionRequestResult: - return PermissionRequestResult.from_dict(s) - -def permission_request_result_to_dict(x: PermissionRequestResult) -> Any: - return to_class(PermissionRequestResult, x) - -def session_log_level_from_dict(s: Any) -> SessionLogLevel: - return SessionLogLevel(s) - -def session_log_level_to_dict(x: SessionLogLevel) -> Any: - return to_enum(SessionLogLevel, x) - -def ping_result_from_dict(s: Any) -> PingResult: - return PingResult.from_dict(s) - -def ping_result_to_dict(x: PingResult) -> Any: - return to_class(PingResult, x) - -def ping_request_from_dict(s: Any) -> PingRequest: - return PingRequest.from_dict(s) - -def ping_request_to_dict(x: PingRequest) -> Any: - return to_class(PingRequest, x) - -def model_list_from_dict(s: Any) -> ModelList: - return ModelList.from_dict(s) - -def model_list_to_dict(x: ModelList) -> Any: - return to_class(ModelList, x) - -def tool_list_from_dict(s: Any) -> ToolList: - return ToolList.from_dict(s) - -def tool_list_to_dict(x: ToolList) -> Any: - return to_class(ToolList, x) - -def tools_list_request_from_dict(s: Any) -> ToolsListRequest: - return ToolsListRequest.from_dict(s) - -def tools_list_request_to_dict(x: ToolsListRequest) -> Any: - return to_class(ToolsListRequest, x) - -def account_get_quota_result_from_dict(s: Any) -> AccountGetQuotaResult: - return AccountGetQuotaResult.from_dict(s) - -def account_get_quota_result_to_dict(x: AccountGetQuotaResult) -> Any: - return to_class(AccountGetQuotaResult, x) - -def mcp_config_list_from_dict(s: Any) -> MCPConfigList: - return MCPConfigList.from_dict(s) - -def mcp_config_list_to_dict(x: MCPConfigList) -> Any: - return to_class(MCPConfigList, x) - -def mcp_config_add_request_from_dict(s: Any) -> MCPConfigAddRequest: - return MCPConfigAddRequest.from_dict(s) - -def mcp_config_add_request_to_dict(x: MCPConfigAddRequest) -> Any: - return to_class(MCPConfigAddRequest, x) - -def mcp_config_update_request_from_dict(s: Any) -> MCPConfigUpdateRequest: - return MCPConfigUpdateRequest.from_dict(s) - -def mcp_config_update_request_to_dict(x: MCPConfigUpdateRequest) -> Any: - return to_class(MCPConfigUpdateRequest, x) - -def mcp_config_remove_request_from_dict(s: Any) -> MCPConfigRemoveRequest: - return MCPConfigRemoveRequest.from_dict(s) - -def mcp_config_remove_request_to_dict(x: MCPConfigRemoveRequest) -> Any: - return to_class(MCPConfigRemoveRequest, x) - -def mcp_discover_result_from_dict(s: Any) -> MCPDiscoverResult: - return MCPDiscoverResult.from_dict(s) - -def mcp_discover_result_to_dict(x: MCPDiscoverResult) -> Any: - return to_class(MCPDiscoverResult, x) - -def mcp_discover_request_from_dict(s: Any) -> MCPDiscoverRequest: - return MCPDiscoverRequest.from_dict(s) - -def mcp_discover_request_to_dict(x: MCPDiscoverRequest) -> Any: - return to_class(MCPDiscoverRequest, x) - -def skills_config_set_disabled_skills_request_from_dict(s: Any) -> SkillsConfigSetDisabledSkillsRequest: - return SkillsConfigSetDisabledSkillsRequest.from_dict(s) - -def skills_config_set_disabled_skills_request_to_dict(x: SkillsConfigSetDisabledSkillsRequest) -> Any: - return to_class(SkillsConfigSetDisabledSkillsRequest, x) - -def skills_discover_request_from_dict(s: Any) -> SkillsDiscoverRequest: - return SkillsDiscoverRequest.from_dict(s) - -def skills_discover_request_to_dict(x: SkillsDiscoverRequest) -> Any: - return to_class(SkillsDiscoverRequest, x) - -def session_fs_set_provider_result_from_dict(s: Any) -> SessionFSSetProviderResult: - return SessionFSSetProviderResult.from_dict(s) - -def session_fs_set_provider_result_to_dict(x: SessionFSSetProviderResult) -> Any: - return to_class(SessionFSSetProviderResult, x) - -def session_fs_set_provider_request_from_dict(s: Any) -> SessionFSSetProviderRequest: - return SessionFSSetProviderRequest.from_dict(s) - -def session_fs_set_provider_request_to_dict(x: SessionFSSetProviderRequest) -> Any: - return to_class(SessionFSSetProviderRequest, x) - -def sessions_fork_result_from_dict(s: Any) -> SessionsForkResult: - return SessionsForkResult.from_dict(s) - -def sessions_fork_result_to_dict(x: SessionsForkResult) -> Any: - return to_class(SessionsForkResult, x) - -def sessions_fork_request_from_dict(s: Any) -> SessionsForkRequest: - return SessionsForkRequest.from_dict(s) - -def sessions_fork_request_to_dict(x: SessionsForkRequest) -> Any: - return to_class(SessionsForkRequest, x) - -def model_switch_to_result_from_dict(s: Any) -> ModelSwitchToResult: - return ModelSwitchToResult.from_dict(s) - -def model_switch_to_result_to_dict(x: ModelSwitchToResult) -> Any: - return to_class(ModelSwitchToResult, x) - -def model_switch_to_request_from_dict(s: Any) -> ModelSwitchToRequest: - return ModelSwitchToRequest.from_dict(s) - -def model_switch_to_request_to_dict(x: ModelSwitchToRequest) -> Any: - return to_class(ModelSwitchToRequest, x) - -def mode_set_request_from_dict(s: Any) -> ModeSetRequest: - return ModeSetRequest.from_dict(s) - -def mode_set_request_to_dict(x: ModeSetRequest) -> Any: - return to_class(ModeSetRequest, x) - -def name_get_result_from_dict(s: Any) -> NameGetResult: - return NameGetResult.from_dict(s) - -def name_get_result_to_dict(x: NameGetResult) -> Any: - return to_class(NameGetResult, x) - -def name_set_request_from_dict(s: Any) -> NameSetRequest: - return NameSetRequest.from_dict(s) - -def name_set_request_to_dict(x: NameSetRequest) -> Any: - return to_class(NameSetRequest, x) - -def plan_read_result_from_dict(s: Any) -> PlanReadResult: - return PlanReadResult.from_dict(s) - -def plan_read_result_to_dict(x: PlanReadResult) -> Any: - return to_class(PlanReadResult, x) - -def plan_update_request_from_dict(s: Any) -> PlanUpdateRequest: - return PlanUpdateRequest.from_dict(s) - -def plan_update_request_to_dict(x: PlanUpdateRequest) -> Any: - return to_class(PlanUpdateRequest, x) - -def workspaces_get_workspace_result_from_dict(s: Any) -> WorkspacesGetWorkspaceResult: - return WorkspacesGetWorkspaceResult.from_dict(s) - -def workspaces_get_workspace_result_to_dict(x: WorkspacesGetWorkspaceResult) -> Any: - return to_class(WorkspacesGetWorkspaceResult, x) - -def workspaces_list_files_result_from_dict(s: Any) -> WorkspacesListFilesResult: - return WorkspacesListFilesResult.from_dict(s) - -def workspaces_list_files_result_to_dict(x: WorkspacesListFilesResult) -> Any: - return to_class(WorkspacesListFilesResult, x) - -def workspaces_read_file_result_from_dict(s: Any) -> WorkspacesReadFileResult: - return WorkspacesReadFileResult.from_dict(s) - -def workspaces_read_file_result_to_dict(x: WorkspacesReadFileResult) -> Any: - return to_class(WorkspacesReadFileResult, x) - -def workspaces_read_file_request_from_dict(s: Any) -> WorkspacesReadFileRequest: - return WorkspacesReadFileRequest.from_dict(s) - -def workspaces_read_file_request_to_dict(x: WorkspacesReadFileRequest) -> Any: - return to_class(WorkspacesReadFileRequest, x) - -def workspaces_create_file_request_from_dict(s: Any) -> WorkspacesCreateFileRequest: - return WorkspacesCreateFileRequest.from_dict(s) - -def workspaces_create_file_request_to_dict(x: WorkspacesCreateFileRequest) -> Any: - return to_class(WorkspacesCreateFileRequest, x) - -def instructions_get_sources_result_from_dict(s: Any) -> InstructionsGetSourcesResult: - return InstructionsGetSourcesResult.from_dict(s) - -def instructions_get_sources_result_to_dict(x: InstructionsGetSourcesResult) -> Any: - return to_class(InstructionsGetSourcesResult, x) - -def fleet_start_result_from_dict(s: Any) -> FleetStartResult: - return FleetStartResult.from_dict(s) - -def fleet_start_result_to_dict(x: FleetStartResult) -> Any: - return to_class(FleetStartResult, x) - -def fleet_start_request_from_dict(s: Any) -> FleetStartRequest: - return FleetStartRequest.from_dict(s) - -def fleet_start_request_to_dict(x: FleetStartRequest) -> Any: - return to_class(FleetStartRequest, x) - -def agent_list_from_dict(s: Any) -> AgentList: - return AgentList.from_dict(s) - -def agent_list_to_dict(x: AgentList) -> Any: - return to_class(AgentList, x) - -def agent_get_current_result_from_dict(s: Any) -> AgentGetCurrentResult: - return AgentGetCurrentResult.from_dict(s) - -def agent_get_current_result_to_dict(x: AgentGetCurrentResult) -> Any: - return to_class(AgentGetCurrentResult, x) - -def agent_select_result_from_dict(s: Any) -> AgentSelectResult: - return AgentSelectResult.from_dict(s) - -def agent_select_result_to_dict(x: AgentSelectResult) -> Any: - return to_class(AgentSelectResult, x) - -def agent_select_request_from_dict(s: Any) -> AgentSelectRequest: - return AgentSelectRequest.from_dict(s) - -def agent_select_request_to_dict(x: AgentSelectRequest) -> Any: - return to_class(AgentSelectRequest, x) - -def agent_reload_result_from_dict(s: Any) -> AgentReloadResult: - return AgentReloadResult.from_dict(s) - -def agent_reload_result_to_dict(x: AgentReloadResult) -> Any: - return to_class(AgentReloadResult, x) - -def skill_list_from_dict(s: Any) -> SkillList: - return SkillList.from_dict(s) - -def skill_list_to_dict(x: SkillList) -> Any: - return to_class(SkillList, x) - -def skills_enable_request_from_dict(s: Any) -> SkillsEnableRequest: - return SkillsEnableRequest.from_dict(s) - -def skills_enable_request_to_dict(x: SkillsEnableRequest) -> Any: - return to_class(SkillsEnableRequest, x) - -def skills_disable_request_from_dict(s: Any) -> SkillsDisableRequest: - return SkillsDisableRequest.from_dict(s) - -def skills_disable_request_to_dict(x: SkillsDisableRequest) -> Any: - return to_class(SkillsDisableRequest, x) - -def mcp_enable_request_from_dict(s: Any) -> MCPEnableRequest: - return MCPEnableRequest.from_dict(s) - -def mcp_enable_request_to_dict(x: MCPEnableRequest) -> Any: - return to_class(MCPEnableRequest, x) - -def mcp_disable_request_from_dict(s: Any) -> MCPDisableRequest: - return MCPDisableRequest.from_dict(s) - -def mcp_disable_request_to_dict(x: MCPDisableRequest) -> Any: - return to_class(MCPDisableRequest, x) - -def plugin_list_from_dict(s: Any) -> PluginList: - return PluginList.from_dict(s) - -def plugin_list_to_dict(x: PluginList) -> Any: - return to_class(PluginList, x) - -def extension_list_from_dict(s: Any) -> ExtensionList: - return ExtensionList.from_dict(s) - -def extension_list_to_dict(x: ExtensionList) -> Any: - return to_class(ExtensionList, x) - -def extensions_enable_request_from_dict(s: Any) -> ExtensionsEnableRequest: - return ExtensionsEnableRequest.from_dict(s) - -def extensions_enable_request_to_dict(x: ExtensionsEnableRequest) -> Any: - return to_class(ExtensionsEnableRequest, x) - -def extensions_disable_request_from_dict(s: Any) -> ExtensionsDisableRequest: - return ExtensionsDisableRequest.from_dict(s) - -def extensions_disable_request_to_dict(x: ExtensionsDisableRequest) -> Any: - return to_class(ExtensionsDisableRequest, x) - -def tools_handle_pending_tool_call_request_from_dict(s: Any) -> ToolsHandlePendingToolCallRequest: - return ToolsHandlePendingToolCallRequest.from_dict(s) - -def tools_handle_pending_tool_call_request_to_dict(x: ToolsHandlePendingToolCallRequest) -> Any: - return to_class(ToolsHandlePendingToolCallRequest, x) - -def commands_handle_pending_command_result_from_dict(s: Any) -> CommandsHandlePendingCommandResult: - return CommandsHandlePendingCommandResult.from_dict(s) - -def commands_handle_pending_command_result_to_dict(x: CommandsHandlePendingCommandResult) -> Any: - return to_class(CommandsHandlePendingCommandResult, x) - -def commands_handle_pending_command_request_from_dict(s: Any) -> CommandsHandlePendingCommandRequest: - return CommandsHandlePendingCommandRequest.from_dict(s) - -def commands_handle_pending_command_request_to_dict(x: CommandsHandlePendingCommandRequest) -> Any: - return to_class(CommandsHandlePendingCommandRequest, x) - -def ui_elicitation_request_from_dict(s: Any) -> UIElicitationRequest: - return UIElicitationRequest.from_dict(s) - -def ui_elicitation_request_to_dict(x: UIElicitationRequest) -> Any: - return to_class(UIElicitationRequest, x) - -def log_result_from_dict(s: Any) -> LogResult: - return LogResult.from_dict(s) - -def log_result_to_dict(x: LogResult) -> Any: - return to_class(LogResult, x) - -def log_request_from_dict(s: Any) -> LogRequest: - return LogRequest.from_dict(s) - -def log_request_to_dict(x: LogRequest) -> Any: - return to_class(LogRequest, x) - -def shell_exec_result_from_dict(s: Any) -> ShellExecResult: - return ShellExecResult.from_dict(s) - -def shell_exec_result_to_dict(x: ShellExecResult) -> Any: - return to_class(ShellExecResult, x) - -def shell_exec_request_from_dict(s: Any) -> ShellExecRequest: - return ShellExecRequest.from_dict(s) - -def shell_exec_request_to_dict(x: ShellExecRequest) -> Any: - return to_class(ShellExecRequest, x) - -def shell_kill_result_from_dict(s: Any) -> ShellKillResult: - return ShellKillResult.from_dict(s) - -def shell_kill_result_to_dict(x: ShellKillResult) -> Any: - return to_class(ShellKillResult, x) - -def shell_kill_request_from_dict(s: Any) -> ShellKillRequest: - return ShellKillRequest.from_dict(s) - -def shell_kill_request_to_dict(x: ShellKillRequest) -> Any: - return to_class(ShellKillRequest, x) - -def history_compact_result_from_dict(s: Any) -> HistoryCompactResult: - return HistoryCompactResult.from_dict(s) - -def history_compact_result_to_dict(x: HistoryCompactResult) -> Any: - return to_class(HistoryCompactResult, x) - -def history_truncate_result_from_dict(s: Any) -> HistoryTruncateResult: - return HistoryTruncateResult.from_dict(s) - -def history_truncate_result_to_dict(x: HistoryTruncateResult) -> Any: - return to_class(HistoryTruncateResult, x) - -def history_truncate_request_from_dict(s: Any) -> HistoryTruncateRequest: - return HistoryTruncateRequest.from_dict(s) - -def history_truncate_request_to_dict(x: HistoryTruncateRequest) -> Any: - return to_class(HistoryTruncateRequest, x) - -def usage_get_metrics_result_from_dict(s: Any) -> UsageGetMetricsResult: - return UsageGetMetricsResult.from_dict(s) - -def usage_get_metrics_result_to_dict(x: UsageGetMetricsResult) -> Any: - return to_class(UsageGetMetricsResult, x) - -def session_fs_read_file_result_from_dict(s: Any) -> SessionFSReadFileResult: - return SessionFSReadFileResult.from_dict(s) - -def session_fs_read_file_result_to_dict(x: SessionFSReadFileResult) -> Any: - return to_class(SessionFSReadFileResult, x) - -def session_fs_read_file_request_from_dict(s: Any) -> SessionFSReadFileRequest: - return SessionFSReadFileRequest.from_dict(s) - -def session_fs_read_file_request_to_dict(x: SessionFSReadFileRequest) -> Any: - return to_class(SessionFSReadFileRequest, x) - -def session_fs_write_file_request_from_dict(s: Any) -> SessionFSWriteFileRequest: - return SessionFSWriteFileRequest.from_dict(s) - -def session_fs_write_file_request_to_dict(x: SessionFSWriteFileRequest) -> Any: - return to_class(SessionFSWriteFileRequest, x) - -def session_fs_append_file_request_from_dict(s: Any) -> SessionFSAppendFileRequest: - return SessionFSAppendFileRequest.from_dict(s) - -def session_fs_append_file_request_to_dict(x: SessionFSAppendFileRequest) -> Any: - return to_class(SessionFSAppendFileRequest, x) - -def session_fs_exists_result_from_dict(s: Any) -> SessionFSExistsResult: - return SessionFSExistsResult.from_dict(s) - -def session_fs_exists_result_to_dict(x: SessionFSExistsResult) -> Any: - return to_class(SessionFSExistsResult, x) - -def session_fs_exists_request_from_dict(s: Any) -> SessionFSExistsRequest: - return SessionFSExistsRequest.from_dict(s) - -def session_fs_exists_request_to_dict(x: SessionFSExistsRequest) -> Any: - return to_class(SessionFSExistsRequest, x) - -def session_fs_stat_result_from_dict(s: Any) -> SessionFSStatResult: - return SessionFSStatResult.from_dict(s) - -def session_fs_stat_result_to_dict(x: SessionFSStatResult) -> Any: - return to_class(SessionFSStatResult, x) - -def session_fs_stat_request_from_dict(s: Any) -> SessionFSStatRequest: - return SessionFSStatRequest.from_dict(s) - -def session_fs_stat_request_to_dict(x: SessionFSStatRequest) -> Any: - return to_class(SessionFSStatRequest, x) - -def session_fs_mkdir_request_from_dict(s: Any) -> SessionFSMkdirRequest: - return SessionFSMkdirRequest.from_dict(s) - -def session_fs_mkdir_request_to_dict(x: SessionFSMkdirRequest) -> Any: - return to_class(SessionFSMkdirRequest, x) - -def session_fs_readdir_result_from_dict(s: Any) -> SessionFSReaddirResult: - return SessionFSReaddirResult.from_dict(s) - -def session_fs_readdir_result_to_dict(x: SessionFSReaddirResult) -> Any: - return to_class(SessionFSReaddirResult, x) - -def session_fs_readdir_request_from_dict(s: Any) -> SessionFSReaddirRequest: - return SessionFSReaddirRequest.from_dict(s) - -def session_fs_readdir_request_to_dict(x: SessionFSReaddirRequest) -> Any: - return to_class(SessionFSReaddirRequest, x) - -def session_fs_readdir_with_types_result_from_dict(s: Any) -> SessionFSReaddirWithTypesResult: - return SessionFSReaddirWithTypesResult.from_dict(s) - -def session_fs_readdir_with_types_result_to_dict(x: SessionFSReaddirWithTypesResult) -> Any: - return to_class(SessionFSReaddirWithTypesResult, x) - -def session_fs_readdir_with_types_request_from_dict(s: Any) -> SessionFSReaddirWithTypesRequest: - return SessionFSReaddirWithTypesRequest.from_dict(s) - -def session_fs_readdir_with_types_request_to_dict(x: SessionFSReaddirWithTypesRequest) -> Any: - return to_class(SessionFSReaddirWithTypesRequest, x) - -def session_fs_rm_request_from_dict(s: Any) -> SessionFSRmRequest: - return SessionFSRmRequest.from_dict(s) - -def session_fs_rm_request_to_dict(x: SessionFSRmRequest) -> Any: - return to_class(SessionFSRmRequest, x) - -def session_fs_rename_request_from_dict(s: Any) -> SessionFSRenameRequest: - return SessionFSRenameRequest.from_dict(s) - -def session_fs_rename_request_to_dict(x: SessionFSRenameRequest) -> Any: - return to_class(SessionFSRenameRequest, x) +@dataclass +class RPC: + account_get_quota_result: AccountGetQuotaResult + account_quota_snapshot: AccountQuotaSnapshot + agent_get_current_result: AgentGetCurrentResult + agent_info: AgentInfo + agent_list: AgentList + agent_reload_result: AgentReloadResult + agent_select_request: AgentSelectRequest + agent_select_result: AgentSelectResult + commands_handle_pending_command_request: CommandsHandlePendingCommandRequest + commands_handle_pending_command_result: CommandsHandlePendingCommandResult + current_model: CurrentModel + discovered_mcp_server: DiscoveredMCPServer + discovered_mcp_server_source: MCPServerSource + discovered_mcp_server_type: DiscoveredMCPServerType + extension: Extension + extension_list: ExtensionList + extensions_disable_request: ExtensionsDisableRequest + extensions_enable_request: ExtensionsEnableRequest + extension_source: ExtensionSource + extension_status: ExtensionStatus + filter_mapping: dict[str, FilterMappingString] | FilterMappingString + filter_mapping_string: FilterMappingString + filter_mapping_value: FilterMappingString + fleet_start_request: FleetStartRequest + fleet_start_result: FleetStartResult + handle_tool_call_result: HandleToolCallResult + history_compact_context_window: HistoryCompactContextWindow + history_compact_result: HistoryCompactResult + history_truncate_request: HistoryTruncateRequest + history_truncate_result: HistoryTruncateResult + instructions_get_sources_result: InstructionsGetSourcesResult + instructions_sources: InstructionsSources + instructions_sources_location: InstructionsSourcesLocation + instructions_sources_type: InstructionsSourcesType + log_request: LogRequest + log_result: LogResult + mcp_config_add_request: MCPConfigAddRequest + mcp_config_list: MCPConfigList + mcp_config_remove_request: MCPConfigRemoveRequest + mcp_config_update_request: MCPConfigUpdateRequest + mcp_disable_request: MCPDisableRequest + mcp_discover_request: MCPDiscoverRequest + mcp_discover_result: MCPDiscoverResult + mcp_enable_request: MCPEnableRequest + mcp_server: MCPServer + mcp_server_config: MCPServerConfig + mcp_server_config_http: MCPServerConfigHTTP + mcp_server_config_http_type: MCPServerConfigHTTPType + mcp_server_config_local: MCPServerConfigLocal + mcp_server_config_local_type: MCPServerConfigLocalType + mcp_server_list: MCPServerList + mcp_server_source: MCPServerSource + mcp_server_status: MCPServerStatus + model: Model + model_billing: ModelBilling + model_capabilities: ModelCapabilities + model_capabilities_limits: ModelCapabilitiesLimits + model_capabilities_limits_vision: ModelCapabilitiesLimitsVision + model_capabilities_override: ModelCapabilitiesOverride + model_capabilities_override_limits: ModelCapabilitiesOverrideLimits + model_capabilities_override_limits_vision: ModelCapabilitiesOverrideLimitsVision + model_capabilities_override_supports: ModelCapabilitiesOverrideSupports + model_capabilities_supports: ModelCapabilitiesSupports + model_list: ModelList + model_policy: ModelPolicy + model_switch_to_request: ModelSwitchToRequest + model_switch_to_result: ModelSwitchToResult + mode_set_request: ModeSetRequest + name_get_result: NameGetResult + name_set_request: NameSetRequest + permission_decision: PermissionDecision + permission_decision_approved: PermissionDecisionApproved + permission_decision_denied_by_content_exclusion_policy: PermissionDecisionDeniedByContentExclusionPolicy + permission_decision_denied_by_permission_request_hook: PermissionDecisionDeniedByPermissionRequestHook + permission_decision_denied_by_rules: PermissionDecisionDeniedByRules + permission_decision_denied_interactively_by_user: PermissionDecisionDeniedInteractivelyByUser + permission_decision_denied_no_approval_rule_and_could_not_request_from_user: PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser + permission_decision_request: PermissionDecisionRequest + permission_request_result: PermissionRequestResult + ping_request: PingRequest + ping_result: PingResult + plan_read_result: PlanReadResult + plan_update_request: PlanUpdateRequest + plugin: Plugin + plugin_list: PluginList + server_skill: ServerSkill + server_skill_list: ServerSkillList + session_fs_append_file_request: SessionFSAppendFileRequest + session_fs_error: SessionFSError + session_fs_error_code: SessionFSErrorCode + session_fs_exists_request: SessionFSExistsRequest + session_fs_exists_result: SessionFSExistsResult + session_fs_mkdir_request: SessionFSMkdirRequest + session_fs_readdir_request: SessionFSReaddirRequest + session_fs_readdir_result: SessionFSReaddirResult + session_fs_readdir_with_types_entry: SessionFSReaddirWithTypesEntry + session_fs_readdir_with_types_entry_type: SessionFSReaddirWithTypesEntryType + session_fs_readdir_with_types_request: SessionFSReaddirWithTypesRequest + session_fs_readdir_with_types_result: SessionFSReaddirWithTypesResult + session_fs_read_file_request: SessionFSReadFileRequest + session_fs_read_file_result: SessionFSReadFileResult + session_fs_rename_request: SessionFSRenameRequest + session_fs_rm_request: SessionFSRmRequest + session_fs_set_provider_conventions: SessionFSSetProviderConventions + session_fs_set_provider_request: SessionFSSetProviderRequest + session_fs_set_provider_result: SessionFSSetProviderResult + session_fs_stat_request: SessionFSStatRequest + session_fs_stat_result: SessionFSStatResult + session_fs_write_file_request: SessionFSWriteFileRequest + session_log_level: SessionLogLevel + session_mode: SessionMode + sessions_fork_request: SessionsForkRequest + sessions_fork_result: SessionsForkResult + shell_exec_request: ShellExecRequest + shell_exec_result: ShellExecResult + shell_kill_request: ShellKillRequest + shell_kill_result: ShellKillResult + shell_kill_signal: ShellKillSignal + skill: Skill + skill_list: SkillList + skills_config_set_disabled_skills_request: SkillsConfigSetDisabledSkillsRequest + skills_disable_request: SkillsDisableRequest + skills_discover_request: SkillsDiscoverRequest + skills_enable_request: SkillsEnableRequest + tool: Tool + tool_call_result: ToolCallResult + tool_list: ToolList + tools_handle_pending_tool_call: ToolCallResult | str + tools_handle_pending_tool_call_request: ToolsHandlePendingToolCallRequest + tools_list_request: ToolsListRequest + ui_elicitation_array_any_of_field: UIElicitationArrayAnyOfField + ui_elicitation_array_any_of_field_items: UIElicitationArrayAnyOfFieldItems + ui_elicitation_array_any_of_field_items_any_of: UIElicitationArrayAnyOfFieldItemsAnyOf + ui_elicitation_array_enum_field: UIElicitationArrayEnumField + ui_elicitation_array_enum_field_items: UIElicitationArrayEnumFieldItems + ui_elicitation_field_value: float | bool | list[str] | str + ui_elicitation_request: UIElicitationRequest + ui_elicitation_response: UIElicitationResponse + ui_elicitation_response_action: UIElicitationResponseAction + ui_elicitation_response_content: dict[str, float | bool | list[str] | str] + ui_elicitation_result: UIElicitationResult + ui_elicitation_schema: UIElicitationSchema + ui_elicitation_schema_property: UIElicitationSchemaProperty + ui_elicitation_schema_property_boolean: UIElicitationSchemaPropertyBoolean + ui_elicitation_schema_property_number: UIElicitationSchemaPropertyNumber + ui_elicitation_schema_property_number_type: UIElicitationSchemaPropertyNumberType + ui_elicitation_schema_property_string: UIElicitationSchemaPropertyString + ui_elicitation_schema_property_string_format: UIElicitationSchemaPropertyStringFormat + ui_elicitation_string_enum_field: UIElicitationStringEnumField + ui_elicitation_string_one_of_field: UIElicitationStringOneOfField + ui_elicitation_string_one_of_field_one_of: UIElicitationStringOneOfFieldOneOf + ui_handle_pending_elicitation_request: UIHandlePendingElicitationRequest + usage_get_metrics_result: UsageGetMetricsResult + usage_metrics_code_changes: UsageMetricsCodeChanges + usage_metrics_model_metric: UsageMetricsModelMetric + usage_metrics_model_metric_requests: UsageMetricsModelMetricRequests + usage_metrics_model_metric_usage: UsageMetricsModelMetricUsage + workspaces_create_file_request: WorkspacesCreateFileRequest + workspaces_get_workspace_result: WorkspacesGetWorkspaceResult + workspaces_list_files_result: WorkspacesListFilesResult + workspaces_read_file_request: WorkspacesReadFileRequest + workspaces_read_file_result: WorkspacesReadFileResult + + @staticmethod + def from_dict(obj: Any) -> 'RPC': + assert isinstance(obj, dict) + account_get_quota_result = AccountGetQuotaResult.from_dict(obj.get("AccountGetQuotaResult")) + account_quota_snapshot = AccountQuotaSnapshot.from_dict(obj.get("AccountQuotaSnapshot")) + agent_get_current_result = AgentGetCurrentResult.from_dict(obj.get("AgentGetCurrentResult")) + agent_info = AgentInfo.from_dict(obj.get("AgentInfo")) + agent_list = AgentList.from_dict(obj.get("AgentList")) + agent_reload_result = AgentReloadResult.from_dict(obj.get("AgentReloadResult")) + agent_select_request = AgentSelectRequest.from_dict(obj.get("AgentSelectRequest")) + agent_select_result = AgentSelectResult.from_dict(obj.get("AgentSelectResult")) + commands_handle_pending_command_request = CommandsHandlePendingCommandRequest.from_dict(obj.get("CommandsHandlePendingCommandRequest")) + commands_handle_pending_command_result = CommandsHandlePendingCommandResult.from_dict(obj.get("CommandsHandlePendingCommandResult")) + current_model = CurrentModel.from_dict(obj.get("CurrentModel")) + discovered_mcp_server = DiscoveredMCPServer.from_dict(obj.get("DiscoveredMcpServer")) + discovered_mcp_server_source = MCPServerSource(obj.get("DiscoveredMcpServerSource")) + discovered_mcp_server_type = DiscoveredMCPServerType(obj.get("DiscoveredMcpServerType")) + extension = Extension.from_dict(obj.get("Extension")) + extension_list = ExtensionList.from_dict(obj.get("ExtensionList")) + extensions_disable_request = ExtensionsDisableRequest.from_dict(obj.get("ExtensionsDisableRequest")) + extensions_enable_request = ExtensionsEnableRequest.from_dict(obj.get("ExtensionsEnableRequest")) + extension_source = ExtensionSource(obj.get("ExtensionSource")) + extension_status = ExtensionStatus(obj.get("ExtensionStatus")) + filter_mapping = from_union([lambda x: from_dict(FilterMappingString, x), FilterMappingString], obj.get("FilterMapping")) + filter_mapping_string = FilterMappingString(obj.get("FilterMappingString")) + filter_mapping_value = FilterMappingString(obj.get("FilterMappingValue")) + fleet_start_request = FleetStartRequest.from_dict(obj.get("FleetStartRequest")) + fleet_start_result = FleetStartResult.from_dict(obj.get("FleetStartResult")) + handle_tool_call_result = HandleToolCallResult.from_dict(obj.get("HandleToolCallResult")) + history_compact_context_window = HistoryCompactContextWindow.from_dict(obj.get("HistoryCompactContextWindow")) + history_compact_result = HistoryCompactResult.from_dict(obj.get("HistoryCompactResult")) + history_truncate_request = HistoryTruncateRequest.from_dict(obj.get("HistoryTruncateRequest")) + history_truncate_result = HistoryTruncateResult.from_dict(obj.get("HistoryTruncateResult")) + instructions_get_sources_result = InstructionsGetSourcesResult.from_dict(obj.get("InstructionsGetSourcesResult")) + instructions_sources = InstructionsSources.from_dict(obj.get("InstructionsSources")) + instructions_sources_location = InstructionsSourcesLocation(obj.get("InstructionsSourcesLocation")) + instructions_sources_type = InstructionsSourcesType(obj.get("InstructionsSourcesType")) + log_request = LogRequest.from_dict(obj.get("LogRequest")) + log_result = LogResult.from_dict(obj.get("LogResult")) + mcp_config_add_request = MCPConfigAddRequest.from_dict(obj.get("McpConfigAddRequest")) + mcp_config_list = MCPConfigList.from_dict(obj.get("McpConfigList")) + mcp_config_remove_request = MCPConfigRemoveRequest.from_dict(obj.get("McpConfigRemoveRequest")) + mcp_config_update_request = MCPConfigUpdateRequest.from_dict(obj.get("McpConfigUpdateRequest")) + mcp_disable_request = MCPDisableRequest.from_dict(obj.get("McpDisableRequest")) + mcp_discover_request = MCPDiscoverRequest.from_dict(obj.get("McpDiscoverRequest")) + mcp_discover_result = MCPDiscoverResult.from_dict(obj.get("McpDiscoverResult")) + mcp_enable_request = MCPEnableRequest.from_dict(obj.get("McpEnableRequest")) + mcp_server = MCPServer.from_dict(obj.get("McpServer")) + mcp_server_config = MCPServerConfig.from_dict(obj.get("McpServerConfig")) + mcp_server_config_http = MCPServerConfigHTTP.from_dict(obj.get("McpServerConfigHttp")) + mcp_server_config_http_type = MCPServerConfigHTTPType(obj.get("McpServerConfigHttpType")) + mcp_server_config_local = MCPServerConfigLocal.from_dict(obj.get("McpServerConfigLocal")) + mcp_server_config_local_type = MCPServerConfigLocalType(obj.get("McpServerConfigLocalType")) + mcp_server_list = MCPServerList.from_dict(obj.get("McpServerList")) + mcp_server_source = MCPServerSource(obj.get("McpServerSource")) + mcp_server_status = MCPServerStatus(obj.get("McpServerStatus")) + model = Model.from_dict(obj.get("Model")) + model_billing = ModelBilling.from_dict(obj.get("ModelBilling")) + model_capabilities = ModelCapabilities.from_dict(obj.get("ModelCapabilities")) + model_capabilities_limits = ModelCapabilitiesLimits.from_dict(obj.get("ModelCapabilitiesLimits")) + model_capabilities_limits_vision = ModelCapabilitiesLimitsVision.from_dict(obj.get("ModelCapabilitiesLimitsVision")) + model_capabilities_override = ModelCapabilitiesOverride.from_dict(obj.get("ModelCapabilitiesOverride")) + model_capabilities_override_limits = ModelCapabilitiesOverrideLimits.from_dict(obj.get("ModelCapabilitiesOverrideLimits")) + model_capabilities_override_limits_vision = ModelCapabilitiesOverrideLimitsVision.from_dict(obj.get("ModelCapabilitiesOverrideLimitsVision")) + model_capabilities_override_supports = ModelCapabilitiesOverrideSupports.from_dict(obj.get("ModelCapabilitiesOverrideSupports")) + model_capabilities_supports = ModelCapabilitiesSupports.from_dict(obj.get("ModelCapabilitiesSupports")) + model_list = ModelList.from_dict(obj.get("ModelList")) + model_policy = ModelPolicy.from_dict(obj.get("ModelPolicy")) + model_switch_to_request = ModelSwitchToRequest.from_dict(obj.get("ModelSwitchToRequest")) + model_switch_to_result = ModelSwitchToResult.from_dict(obj.get("ModelSwitchToResult")) + mode_set_request = ModeSetRequest.from_dict(obj.get("ModeSetRequest")) + name_get_result = NameGetResult.from_dict(obj.get("NameGetResult")) + name_set_request = NameSetRequest.from_dict(obj.get("NameSetRequest")) + permission_decision = PermissionDecision.from_dict(obj.get("PermissionDecision")) + permission_decision_approved = PermissionDecisionApproved.from_dict(obj.get("PermissionDecisionApproved")) + permission_decision_denied_by_content_exclusion_policy = PermissionDecisionDeniedByContentExclusionPolicy.from_dict(obj.get("PermissionDecisionDeniedByContentExclusionPolicy")) + permission_decision_denied_by_permission_request_hook = PermissionDecisionDeniedByPermissionRequestHook.from_dict(obj.get("PermissionDecisionDeniedByPermissionRequestHook")) + permission_decision_denied_by_rules = PermissionDecisionDeniedByRules.from_dict(obj.get("PermissionDecisionDeniedByRules")) + permission_decision_denied_interactively_by_user = PermissionDecisionDeniedInteractivelyByUser.from_dict(obj.get("PermissionDecisionDeniedInteractivelyByUser")) + permission_decision_denied_no_approval_rule_and_could_not_request_from_user = PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser.from_dict(obj.get("PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser")) + permission_decision_request = PermissionDecisionRequest.from_dict(obj.get("PermissionDecisionRequest")) + permission_request_result = PermissionRequestResult.from_dict(obj.get("PermissionRequestResult")) + ping_request = PingRequest.from_dict(obj.get("PingRequest")) + ping_result = PingResult.from_dict(obj.get("PingResult")) + plan_read_result = PlanReadResult.from_dict(obj.get("PlanReadResult")) + plan_update_request = PlanUpdateRequest.from_dict(obj.get("PlanUpdateRequest")) + plugin = Plugin.from_dict(obj.get("Plugin")) + plugin_list = PluginList.from_dict(obj.get("PluginList")) + server_skill = ServerSkill.from_dict(obj.get("ServerSkill")) + server_skill_list = ServerSkillList.from_dict(obj.get("ServerSkillList")) + session_fs_append_file_request = SessionFSAppendFileRequest.from_dict(obj.get("SessionFsAppendFileRequest")) + session_fs_error = SessionFSError.from_dict(obj.get("SessionFsError")) + session_fs_error_code = SessionFSErrorCode(obj.get("SessionFsErrorCode")) + session_fs_exists_request = SessionFSExistsRequest.from_dict(obj.get("SessionFsExistsRequest")) + session_fs_exists_result = SessionFSExistsResult.from_dict(obj.get("SessionFsExistsResult")) + session_fs_mkdir_request = SessionFSMkdirRequest.from_dict(obj.get("SessionFsMkdirRequest")) + session_fs_readdir_request = SessionFSReaddirRequest.from_dict(obj.get("SessionFsReaddirRequest")) + session_fs_readdir_result = SessionFSReaddirResult.from_dict(obj.get("SessionFsReaddirResult")) + session_fs_readdir_with_types_entry = SessionFSReaddirWithTypesEntry.from_dict(obj.get("SessionFsReaddirWithTypesEntry")) + session_fs_readdir_with_types_entry_type = SessionFSReaddirWithTypesEntryType(obj.get("SessionFsReaddirWithTypesEntryType")) + session_fs_readdir_with_types_request = SessionFSReaddirWithTypesRequest.from_dict(obj.get("SessionFsReaddirWithTypesRequest")) + session_fs_readdir_with_types_result = SessionFSReaddirWithTypesResult.from_dict(obj.get("SessionFsReaddirWithTypesResult")) + session_fs_read_file_request = SessionFSReadFileRequest.from_dict(obj.get("SessionFsReadFileRequest")) + session_fs_read_file_result = SessionFSReadFileResult.from_dict(obj.get("SessionFsReadFileResult")) + session_fs_rename_request = SessionFSRenameRequest.from_dict(obj.get("SessionFsRenameRequest")) + session_fs_rm_request = SessionFSRmRequest.from_dict(obj.get("SessionFsRmRequest")) + session_fs_set_provider_conventions = SessionFSSetProviderConventions(obj.get("SessionFsSetProviderConventions")) + session_fs_set_provider_request = SessionFSSetProviderRequest.from_dict(obj.get("SessionFsSetProviderRequest")) + session_fs_set_provider_result = SessionFSSetProviderResult.from_dict(obj.get("SessionFsSetProviderResult")) + session_fs_stat_request = SessionFSStatRequest.from_dict(obj.get("SessionFsStatRequest")) + session_fs_stat_result = SessionFSStatResult.from_dict(obj.get("SessionFsStatResult")) + session_fs_write_file_request = SessionFSWriteFileRequest.from_dict(obj.get("SessionFsWriteFileRequest")) + session_log_level = SessionLogLevel(obj.get("SessionLogLevel")) + session_mode = SessionMode(obj.get("SessionMode")) + sessions_fork_request = SessionsForkRequest.from_dict(obj.get("SessionsForkRequest")) + sessions_fork_result = SessionsForkResult.from_dict(obj.get("SessionsForkResult")) + shell_exec_request = ShellExecRequest.from_dict(obj.get("ShellExecRequest")) + shell_exec_result = ShellExecResult.from_dict(obj.get("ShellExecResult")) + shell_kill_request = ShellKillRequest.from_dict(obj.get("ShellKillRequest")) + shell_kill_result = ShellKillResult.from_dict(obj.get("ShellKillResult")) + shell_kill_signal = ShellKillSignal(obj.get("ShellKillSignal")) + skill = Skill.from_dict(obj.get("Skill")) + skill_list = SkillList.from_dict(obj.get("SkillList")) + skills_config_set_disabled_skills_request = SkillsConfigSetDisabledSkillsRequest.from_dict(obj.get("SkillsConfigSetDisabledSkillsRequest")) + skills_disable_request = SkillsDisableRequest.from_dict(obj.get("SkillsDisableRequest")) + skills_discover_request = SkillsDiscoverRequest.from_dict(obj.get("SkillsDiscoverRequest")) + skills_enable_request = SkillsEnableRequest.from_dict(obj.get("SkillsEnableRequest")) + tool = Tool.from_dict(obj.get("Tool")) + tool_call_result = ToolCallResult.from_dict(obj.get("ToolCallResult")) + tool_list = ToolList.from_dict(obj.get("ToolList")) + tools_handle_pending_tool_call = from_union([ToolCallResult.from_dict, from_str], obj.get("ToolsHandlePendingToolCall")) + tools_handle_pending_tool_call_request = ToolsHandlePendingToolCallRequest.from_dict(obj.get("ToolsHandlePendingToolCallRequest")) + tools_list_request = ToolsListRequest.from_dict(obj.get("ToolsListRequest")) + ui_elicitation_array_any_of_field = UIElicitationArrayAnyOfField.from_dict(obj.get("UIElicitationArrayAnyOfField")) + ui_elicitation_array_any_of_field_items = UIElicitationArrayAnyOfFieldItems.from_dict(obj.get("UIElicitationArrayAnyOfFieldItems")) + ui_elicitation_array_any_of_field_items_any_of = UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict(obj.get("UIElicitationArrayAnyOfFieldItemsAnyOf")) + ui_elicitation_array_enum_field = UIElicitationArrayEnumField.from_dict(obj.get("UIElicitationArrayEnumField")) + ui_elicitation_array_enum_field_items = UIElicitationArrayEnumFieldItems.from_dict(obj.get("UIElicitationArrayEnumFieldItems")) + ui_elicitation_field_value = from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], obj.get("UIElicitationFieldValue")) + ui_elicitation_request = UIElicitationRequest.from_dict(obj.get("UIElicitationRequest")) + ui_elicitation_response = UIElicitationResponse.from_dict(obj.get("UIElicitationResponse")) + ui_elicitation_response_action = UIElicitationResponseAction(obj.get("UIElicitationResponseAction")) + ui_elicitation_response_content = from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), obj.get("UIElicitationResponseContent")) + ui_elicitation_result = UIElicitationResult.from_dict(obj.get("UIElicitationResult")) + ui_elicitation_schema = UIElicitationSchema.from_dict(obj.get("UIElicitationSchema")) + ui_elicitation_schema_property = UIElicitationSchemaProperty.from_dict(obj.get("UIElicitationSchemaProperty")) + ui_elicitation_schema_property_boolean = UIElicitationSchemaPropertyBoolean.from_dict(obj.get("UIElicitationSchemaPropertyBoolean")) + ui_elicitation_schema_property_number = UIElicitationSchemaPropertyNumber.from_dict(obj.get("UIElicitationSchemaPropertyNumber")) + ui_elicitation_schema_property_number_type = UIElicitationSchemaPropertyNumberType(obj.get("UIElicitationSchemaPropertyNumberType")) + ui_elicitation_schema_property_string = UIElicitationSchemaPropertyString.from_dict(obj.get("UIElicitationSchemaPropertyString")) + ui_elicitation_schema_property_string_format = UIElicitationSchemaPropertyStringFormat(obj.get("UIElicitationSchemaPropertyStringFormat")) + ui_elicitation_string_enum_field = UIElicitationStringEnumField.from_dict(obj.get("UIElicitationStringEnumField")) + ui_elicitation_string_one_of_field = UIElicitationStringOneOfField.from_dict(obj.get("UIElicitationStringOneOfField")) + ui_elicitation_string_one_of_field_one_of = UIElicitationStringOneOfFieldOneOf.from_dict(obj.get("UIElicitationStringOneOfFieldOneOf")) + ui_handle_pending_elicitation_request = UIHandlePendingElicitationRequest.from_dict(obj.get("UIHandlePendingElicitationRequest")) + usage_get_metrics_result = UsageGetMetricsResult.from_dict(obj.get("UsageGetMetricsResult")) + usage_metrics_code_changes = UsageMetricsCodeChanges.from_dict(obj.get("UsageMetricsCodeChanges")) + usage_metrics_model_metric = UsageMetricsModelMetric.from_dict(obj.get("UsageMetricsModelMetric")) + usage_metrics_model_metric_requests = UsageMetricsModelMetricRequests.from_dict(obj.get("UsageMetricsModelMetricRequests")) + usage_metrics_model_metric_usage = UsageMetricsModelMetricUsage.from_dict(obj.get("UsageMetricsModelMetricUsage")) + workspaces_create_file_request = WorkspacesCreateFileRequest.from_dict(obj.get("WorkspacesCreateFileRequest")) + workspaces_get_workspace_result = WorkspacesGetWorkspaceResult.from_dict(obj.get("WorkspacesGetWorkspaceResult")) + workspaces_list_files_result = WorkspacesListFilesResult.from_dict(obj.get("WorkspacesListFilesResult")) + workspaces_read_file_request = WorkspacesReadFileRequest.from_dict(obj.get("WorkspacesReadFileRequest")) + workspaces_read_file_result = WorkspacesReadFileResult.from_dict(obj.get("WorkspacesReadFileResult")) + return RPC(account_get_quota_result, account_quota_snapshot, agent_get_current_result, agent_info, agent_list, agent_reload_result, agent_select_request, agent_select_result, commands_handle_pending_command_request, commands_handle_pending_command_result, current_model, discovered_mcp_server, discovered_mcp_server_source, discovered_mcp_server_type, extension, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, filter_mapping, filter_mapping_string, filter_mapping_value, fleet_start_request, fleet_start_result, handle_tool_call_result, history_compact_context_window, history_compact_result, history_truncate_request, history_truncate_result, instructions_get_sources_result, instructions_sources, instructions_sources_location, instructions_sources_type, log_request, log_result, mcp_config_add_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_server, mcp_server_config, mcp_server_config_http, mcp_server_config_http_type, mcp_server_config_local, mcp_server_config_local_type, mcp_server_list, mcp_server_source, mcp_server_status, model, model_billing, 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_policy, model_switch_to_request, model_switch_to_result, mode_set_request, name_get_result, name_set_request, permission_decision, permission_decision_approved, 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_request, permission_request_result, ping_request, ping_result, plan_read_result, plan_update_request, plugin, plugin_list, server_skill, server_skill_list, 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_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_log_level, session_mode, sessions_fork_request, sessions_fork_result, shell_exec_request, shell_exec_result, shell_kill_request, shell_kill_result, shell_kill_signal, skill, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, tool, tool_call_result, tool_list, tools_handle_pending_tool_call, tools_handle_pending_tool_call_request, tools_list_request, 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_handle_pending_elicitation_request, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_usage, workspaces_create_file_request, workspaces_get_workspace_result, workspaces_list_files_result, workspaces_read_file_request, workspaces_read_file_result) + + def to_dict(self) -> dict: + result: dict = {} + result["AccountGetQuotaResult"] = to_class(AccountGetQuotaResult, self.account_get_quota_result) + result["AccountQuotaSnapshot"] = to_class(AccountQuotaSnapshot, self.account_quota_snapshot) + result["AgentGetCurrentResult"] = to_class(AgentGetCurrentResult, self.agent_get_current_result) + result["AgentInfo"] = to_class(AgentInfo, self.agent_info) + result["AgentList"] = to_class(AgentList, self.agent_list) + result["AgentReloadResult"] = to_class(AgentReloadResult, self.agent_reload_result) + result["AgentSelectRequest"] = to_class(AgentSelectRequest, self.agent_select_request) + result["AgentSelectResult"] = to_class(AgentSelectResult, self.agent_select_result) + result["CommandsHandlePendingCommandRequest"] = to_class(CommandsHandlePendingCommandRequest, self.commands_handle_pending_command_request) + result["CommandsHandlePendingCommandResult"] = to_class(CommandsHandlePendingCommandResult, self.commands_handle_pending_command_result) + result["CurrentModel"] = to_class(CurrentModel, self.current_model) + result["DiscoveredMcpServer"] = to_class(DiscoveredMCPServer, self.discovered_mcp_server) + result["DiscoveredMcpServerSource"] = to_enum(MCPServerSource, self.discovered_mcp_server_source) + result["DiscoveredMcpServerType"] = to_enum(DiscoveredMCPServerType, self.discovered_mcp_server_type) + result["Extension"] = to_class(Extension, self.extension) + result["ExtensionList"] = to_class(ExtensionList, self.extension_list) + result["ExtensionsDisableRequest"] = to_class(ExtensionsDisableRequest, self.extensions_disable_request) + result["ExtensionsEnableRequest"] = to_class(ExtensionsEnableRequest, self.extensions_enable_request) + result["ExtensionSource"] = to_enum(ExtensionSource, self.extension_source) + result["ExtensionStatus"] = to_enum(ExtensionStatus, self.extension_status) + result["FilterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(FilterMappingString, x), x), lambda x: to_enum(FilterMappingString, x)], self.filter_mapping) + result["FilterMappingString"] = to_enum(FilterMappingString, self.filter_mapping_string) + result["FilterMappingValue"] = to_enum(FilterMappingString, self.filter_mapping_value) + result["FleetStartRequest"] = to_class(FleetStartRequest, self.fleet_start_request) + result["FleetStartResult"] = to_class(FleetStartResult, self.fleet_start_result) + result["HandleToolCallResult"] = to_class(HandleToolCallResult, self.handle_tool_call_result) + result["HistoryCompactContextWindow"] = to_class(HistoryCompactContextWindow, self.history_compact_context_window) + result["HistoryCompactResult"] = to_class(HistoryCompactResult, self.history_compact_result) + result["HistoryTruncateRequest"] = to_class(HistoryTruncateRequest, self.history_truncate_request) + result["HistoryTruncateResult"] = to_class(HistoryTruncateResult, self.history_truncate_result) + result["InstructionsGetSourcesResult"] = to_class(InstructionsGetSourcesResult, self.instructions_get_sources_result) + result["InstructionsSources"] = to_class(InstructionsSources, self.instructions_sources) + result["InstructionsSourcesLocation"] = to_enum(InstructionsSourcesLocation, self.instructions_sources_location) + result["InstructionsSourcesType"] = to_enum(InstructionsSourcesType, self.instructions_sources_type) + result["LogRequest"] = to_class(LogRequest, self.log_request) + result["LogResult"] = to_class(LogResult, self.log_result) + result["McpConfigAddRequest"] = to_class(MCPConfigAddRequest, self.mcp_config_add_request) + result["McpConfigList"] = to_class(MCPConfigList, self.mcp_config_list) + result["McpConfigRemoveRequest"] = to_class(MCPConfigRemoveRequest, self.mcp_config_remove_request) + result["McpConfigUpdateRequest"] = to_class(MCPConfigUpdateRequest, self.mcp_config_update_request) + result["McpDisableRequest"] = to_class(MCPDisableRequest, self.mcp_disable_request) + result["McpDiscoverRequest"] = to_class(MCPDiscoverRequest, self.mcp_discover_request) + result["McpDiscoverResult"] = to_class(MCPDiscoverResult, self.mcp_discover_result) + result["McpEnableRequest"] = to_class(MCPEnableRequest, self.mcp_enable_request) + result["McpServer"] = to_class(MCPServer, self.mcp_server) + result["McpServerConfig"] = to_class(MCPServerConfig, self.mcp_server_config) + result["McpServerConfigHttp"] = to_class(MCPServerConfigHTTP, self.mcp_server_config_http) + result["McpServerConfigHttpType"] = to_enum(MCPServerConfigHTTPType, self.mcp_server_config_http_type) + result["McpServerConfigLocal"] = to_class(MCPServerConfigLocal, self.mcp_server_config_local) + result["McpServerConfigLocalType"] = to_enum(MCPServerConfigLocalType, self.mcp_server_config_local_type) + result["McpServerList"] = to_class(MCPServerList, self.mcp_server_list) + result["McpServerSource"] = to_enum(MCPServerSource, self.mcp_server_source) + result["McpServerStatus"] = to_enum(MCPServerStatus, self.mcp_server_status) + result["Model"] = to_class(Model, self.model) + result["ModelBilling"] = to_class(ModelBilling, self.model_billing) + result["ModelCapabilities"] = to_class(ModelCapabilities, self.model_capabilities) + result["ModelCapabilitiesLimits"] = to_class(ModelCapabilitiesLimits, self.model_capabilities_limits) + result["ModelCapabilitiesLimitsVision"] = to_class(ModelCapabilitiesLimitsVision, self.model_capabilities_limits_vision) + result["ModelCapabilitiesOverride"] = to_class(ModelCapabilitiesOverride, self.model_capabilities_override) + result["ModelCapabilitiesOverrideLimits"] = to_class(ModelCapabilitiesOverrideLimits, self.model_capabilities_override_limits) + result["ModelCapabilitiesOverrideLimitsVision"] = to_class(ModelCapabilitiesOverrideLimitsVision, self.model_capabilities_override_limits_vision) + result["ModelCapabilitiesOverrideSupports"] = to_class(ModelCapabilitiesOverrideSupports, self.model_capabilities_override_supports) + result["ModelCapabilitiesSupports"] = to_class(ModelCapabilitiesSupports, self.model_capabilities_supports) + result["ModelList"] = to_class(ModelList, self.model_list) + result["ModelPolicy"] = to_class(ModelPolicy, self.model_policy) + result["ModelSwitchToRequest"] = to_class(ModelSwitchToRequest, self.model_switch_to_request) + result["ModelSwitchToResult"] = to_class(ModelSwitchToResult, self.model_switch_to_result) + result["ModeSetRequest"] = to_class(ModeSetRequest, self.mode_set_request) + result["NameGetResult"] = to_class(NameGetResult, self.name_get_result) + result["NameSetRequest"] = to_class(NameSetRequest, self.name_set_request) + result["PermissionDecision"] = to_class(PermissionDecision, self.permission_decision) + result["PermissionDecisionApproved"] = to_class(PermissionDecisionApproved, self.permission_decision_approved) + result["PermissionDecisionDeniedByContentExclusionPolicy"] = to_class(PermissionDecisionDeniedByContentExclusionPolicy, self.permission_decision_denied_by_content_exclusion_policy) + result["PermissionDecisionDeniedByPermissionRequestHook"] = to_class(PermissionDecisionDeniedByPermissionRequestHook, self.permission_decision_denied_by_permission_request_hook) + result["PermissionDecisionDeniedByRules"] = to_class(PermissionDecisionDeniedByRules, self.permission_decision_denied_by_rules) + result["PermissionDecisionDeniedInteractivelyByUser"] = to_class(PermissionDecisionDeniedInteractivelyByUser, self.permission_decision_denied_interactively_by_user) + result["PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser"] = to_class(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser, self.permission_decision_denied_no_approval_rule_and_could_not_request_from_user) + result["PermissionDecisionRequest"] = to_class(PermissionDecisionRequest, self.permission_decision_request) + result["PermissionRequestResult"] = to_class(PermissionRequestResult, self.permission_request_result) + result["PingRequest"] = to_class(PingRequest, self.ping_request) + result["PingResult"] = to_class(PingResult, self.ping_result) + result["PlanReadResult"] = to_class(PlanReadResult, self.plan_read_result) + result["PlanUpdateRequest"] = to_class(PlanUpdateRequest, self.plan_update_request) + result["Plugin"] = to_class(Plugin, self.plugin) + result["PluginList"] = to_class(PluginList, self.plugin_list) + result["ServerSkill"] = to_class(ServerSkill, self.server_skill) + result["ServerSkillList"] = to_class(ServerSkillList, self.server_skill_list) + result["SessionFsAppendFileRequest"] = to_class(SessionFSAppendFileRequest, self.session_fs_append_file_request) + result["SessionFsError"] = to_class(SessionFSError, self.session_fs_error) + result["SessionFsErrorCode"] = to_enum(SessionFSErrorCode, self.session_fs_error_code) + result["SessionFsExistsRequest"] = to_class(SessionFSExistsRequest, self.session_fs_exists_request) + result["SessionFsExistsResult"] = to_class(SessionFSExistsResult, self.session_fs_exists_result) + result["SessionFsMkdirRequest"] = to_class(SessionFSMkdirRequest, self.session_fs_mkdir_request) + result["SessionFsReaddirRequest"] = to_class(SessionFSReaddirRequest, self.session_fs_readdir_request) + result["SessionFsReaddirResult"] = to_class(SessionFSReaddirResult, self.session_fs_readdir_result) + result["SessionFsReaddirWithTypesEntry"] = to_class(SessionFSReaddirWithTypesEntry, self.session_fs_readdir_with_types_entry) + result["SessionFsReaddirWithTypesEntryType"] = to_enum(SessionFSReaddirWithTypesEntryType, self.session_fs_readdir_with_types_entry_type) + result["SessionFsReaddirWithTypesRequest"] = to_class(SessionFSReaddirWithTypesRequest, self.session_fs_readdir_with_types_request) + result["SessionFsReaddirWithTypesResult"] = to_class(SessionFSReaddirWithTypesResult, self.session_fs_readdir_with_types_result) + result["SessionFsReadFileRequest"] = to_class(SessionFSReadFileRequest, self.session_fs_read_file_request) + result["SessionFsReadFileResult"] = to_class(SessionFSReadFileResult, self.session_fs_read_file_result) + result["SessionFsRenameRequest"] = to_class(SessionFSRenameRequest, self.session_fs_rename_request) + result["SessionFsRmRequest"] = to_class(SessionFSRmRequest, self.session_fs_rm_request) + result["SessionFsSetProviderConventions"] = to_enum(SessionFSSetProviderConventions, self.session_fs_set_provider_conventions) + result["SessionFsSetProviderRequest"] = to_class(SessionFSSetProviderRequest, self.session_fs_set_provider_request) + result["SessionFsSetProviderResult"] = to_class(SessionFSSetProviderResult, self.session_fs_set_provider_result) + result["SessionFsStatRequest"] = to_class(SessionFSStatRequest, self.session_fs_stat_request) + result["SessionFsStatResult"] = to_class(SessionFSStatResult, self.session_fs_stat_result) + result["SessionFsWriteFileRequest"] = to_class(SessionFSWriteFileRequest, self.session_fs_write_file_request) + result["SessionLogLevel"] = to_enum(SessionLogLevel, self.session_log_level) + result["SessionMode"] = to_enum(SessionMode, self.session_mode) + result["SessionsForkRequest"] = to_class(SessionsForkRequest, self.sessions_fork_request) + result["SessionsForkResult"] = to_class(SessionsForkResult, self.sessions_fork_result) + result["ShellExecRequest"] = to_class(ShellExecRequest, self.shell_exec_request) + result["ShellExecResult"] = to_class(ShellExecResult, self.shell_exec_result) + result["ShellKillRequest"] = to_class(ShellKillRequest, self.shell_kill_request) + result["ShellKillResult"] = to_class(ShellKillResult, self.shell_kill_result) + result["ShellKillSignal"] = to_enum(ShellKillSignal, self.shell_kill_signal) + result["Skill"] = to_class(Skill, self.skill) + result["SkillList"] = to_class(SkillList, self.skill_list) + result["SkillsConfigSetDisabledSkillsRequest"] = to_class(SkillsConfigSetDisabledSkillsRequest, self.skills_config_set_disabled_skills_request) + result["SkillsDisableRequest"] = to_class(SkillsDisableRequest, self.skills_disable_request) + result["SkillsDiscoverRequest"] = to_class(SkillsDiscoverRequest, self.skills_discover_request) + result["SkillsEnableRequest"] = to_class(SkillsEnableRequest, self.skills_enable_request) + result["Tool"] = to_class(Tool, self.tool) + result["ToolCallResult"] = to_class(ToolCallResult, self.tool_call_result) + result["ToolList"] = to_class(ToolList, self.tool_list) + result["ToolsHandlePendingToolCall"] = from_union([lambda x: to_class(ToolCallResult, x), from_str], self.tools_handle_pending_tool_call) + result["ToolsHandlePendingToolCallRequest"] = to_class(ToolsHandlePendingToolCallRequest, self.tools_handle_pending_tool_call_request) + result["ToolsListRequest"] = to_class(ToolsListRequest, self.tools_list_request) + result["UIElicitationArrayAnyOfField"] = to_class(UIElicitationArrayAnyOfField, self.ui_elicitation_array_any_of_field) + result["UIElicitationArrayAnyOfFieldItems"] = to_class(UIElicitationArrayAnyOfFieldItems, self.ui_elicitation_array_any_of_field_items) + result["UIElicitationArrayAnyOfFieldItemsAnyOf"] = to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, self.ui_elicitation_array_any_of_field_items_any_of) + result["UIElicitationArrayEnumField"] = to_class(UIElicitationArrayEnumField, self.ui_elicitation_array_enum_field) + result["UIElicitationArrayEnumFieldItems"] = to_class(UIElicitationArrayEnumFieldItems, self.ui_elicitation_array_enum_field_items) + result["UIElicitationFieldValue"] = from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], self.ui_elicitation_field_value) + result["UIElicitationRequest"] = to_class(UIElicitationRequest, self.ui_elicitation_request) + result["UIElicitationResponse"] = to_class(UIElicitationResponse, self.ui_elicitation_response) + result["UIElicitationResponseAction"] = to_enum(UIElicitationResponseAction, self.ui_elicitation_response_action) + result["UIElicitationResponseContent"] = from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), self.ui_elicitation_response_content) + result["UIElicitationResult"] = to_class(UIElicitationResult, self.ui_elicitation_result) + result["UIElicitationSchema"] = to_class(UIElicitationSchema, self.ui_elicitation_schema) + result["UIElicitationSchemaProperty"] = to_class(UIElicitationSchemaProperty, self.ui_elicitation_schema_property) + result["UIElicitationSchemaPropertyBoolean"] = to_class(UIElicitationSchemaPropertyBoolean, self.ui_elicitation_schema_property_boolean) + result["UIElicitationSchemaPropertyNumber"] = to_class(UIElicitationSchemaPropertyNumber, self.ui_elicitation_schema_property_number) + result["UIElicitationSchemaPropertyNumberType"] = to_enum(UIElicitationSchemaPropertyNumberType, self.ui_elicitation_schema_property_number_type) + result["UIElicitationSchemaPropertyString"] = to_class(UIElicitationSchemaPropertyString, self.ui_elicitation_schema_property_string) + result["UIElicitationSchemaPropertyStringFormat"] = to_enum(UIElicitationSchemaPropertyStringFormat, self.ui_elicitation_schema_property_string_format) + result["UIElicitationStringEnumField"] = to_class(UIElicitationStringEnumField, self.ui_elicitation_string_enum_field) + result["UIElicitationStringOneOfField"] = to_class(UIElicitationStringOneOfField, self.ui_elicitation_string_one_of_field) + result["UIElicitationStringOneOfFieldOneOf"] = to_class(UIElicitationStringOneOfFieldOneOf, self.ui_elicitation_string_one_of_field_one_of) + result["UIHandlePendingElicitationRequest"] = to_class(UIHandlePendingElicitationRequest, self.ui_handle_pending_elicitation_request) + result["UsageGetMetricsResult"] = to_class(UsageGetMetricsResult, self.usage_get_metrics_result) + result["UsageMetricsCodeChanges"] = to_class(UsageMetricsCodeChanges, self.usage_metrics_code_changes) + result["UsageMetricsModelMetric"] = to_class(UsageMetricsModelMetric, self.usage_metrics_model_metric) + result["UsageMetricsModelMetricRequests"] = to_class(UsageMetricsModelMetricRequests, self.usage_metrics_model_metric_requests) + result["UsageMetricsModelMetricUsage"] = to_class(UsageMetricsModelMetricUsage, self.usage_metrics_model_metric_usage) + result["WorkspacesCreateFileRequest"] = to_class(WorkspacesCreateFileRequest, self.workspaces_create_file_request) + result["WorkspacesGetWorkspaceResult"] = to_class(WorkspacesGetWorkspaceResult, self.workspaces_get_workspace_result) + result["WorkspacesListFilesResult"] = to_class(WorkspacesListFilesResult, self.workspaces_list_files_result) + result["WorkspacesReadFileRequest"] = to_class(WorkspacesReadFileRequest, self.workspaces_read_file_request) + result["WorkspacesReadFileResult"] = to_class(WorkspacesReadFileResult, self.workspaces_read_file_result) + return result + +def rpc_from_dict(s: Any) -> RPC: + return RPC.from_dict(s) + +def rpc_to_dict(x: RPC) -> Any: + return to_class(RPC, x) def _timeout_kwargs(timeout: float | None) -> dict: @@ -5129,23 +4801,23 @@ async def log(self, params: LogRequest, *, timeout: float | None = None) -> LogR class SessionFsHandler(Protocol): async def read_file(self, params: SessionFSReadFileRequest) -> SessionFSReadFileResult: pass - async def write_file(self, params: SessionFSWriteFileRequest) -> None: + async def write_file(self, params: SessionFSWriteFileRequest) -> SessionFSError | None: pass - async def append_file(self, params: SessionFSAppendFileRequest) -> None: + async def append_file(self, params: SessionFSAppendFileRequest) -> SessionFSError | None: pass async def exists(self, params: SessionFSExistsRequest) -> SessionFSExistsResult: pass async def stat(self, params: SessionFSStatRequest) -> SessionFSStatResult: pass - async def mkdir(self, params: SessionFSMkdirRequest) -> None: + async def mkdir(self, params: SessionFSMkdirRequest) -> SessionFSError | None: pass async def readdir(self, params: SessionFSReaddirRequest) -> SessionFSReaddirResult: pass async def readdir_with_types(self, params: SessionFSReaddirWithTypesRequest) -> SessionFSReaddirWithTypesResult: pass - async def rm(self, params: SessionFSRmRequest) -> None: + async def rm(self, params: SessionFSRmRequest) -> SessionFSError | None: pass - async def rename(self, params: SessionFSRenameRequest) -> None: + async def rename(self, params: SessionFSRenameRequest) -> SessionFSError | None: pass @dataclass @@ -5168,15 +4840,15 @@ async def handle_session_fs_write_file(params: dict) -> dict | None: request = SessionFSWriteFileRequest.from_dict(params) handler = get_handlers(request.session_id).session_fs if handler is None: raise RuntimeError(f"No session_fs handler registered for session: {request.session_id}") - await handler.write_file(request) - return None + result = await handler.write_file(request) + return result.to_dict() if result is not None else None client.set_request_handler("sessionFs.writeFile", handle_session_fs_write_file) async def handle_session_fs_append_file(params: dict) -> dict | None: request = SessionFSAppendFileRequest.from_dict(params) handler = get_handlers(request.session_id).session_fs if handler is None: raise RuntimeError(f"No session_fs handler registered for session: {request.session_id}") - await handler.append_file(request) - return None + result = await handler.append_file(request) + return result.to_dict() if result is not None else None client.set_request_handler("sessionFs.appendFile", handle_session_fs_append_file) async def handle_session_fs_exists(params: dict) -> dict | None: request = SessionFSExistsRequest.from_dict(params) @@ -5196,8 +4868,8 @@ async def handle_session_fs_mkdir(params: dict) -> dict | None: request = SessionFSMkdirRequest.from_dict(params) handler = get_handlers(request.session_id).session_fs if handler is None: raise RuntimeError(f"No session_fs handler registered for session: {request.session_id}") - await handler.mkdir(request) - return None + result = await handler.mkdir(request) + return result.to_dict() if result is not None else None client.set_request_handler("sessionFs.mkdir", handle_session_fs_mkdir) async def handle_session_fs_readdir(params: dict) -> dict | None: request = SessionFSReaddirRequest.from_dict(params) @@ -5217,13 +4889,13 @@ async def handle_session_fs_rm(params: dict) -> dict | None: request = SessionFSRmRequest.from_dict(params) handler = get_handlers(request.session_id).session_fs if handler is None: raise RuntimeError(f"No session_fs handler registered for session: {request.session_id}") - await handler.rm(request) - return None + result = await handler.rm(request) + return result.to_dict() if result is not None else None client.set_request_handler("sessionFs.rm", handle_session_fs_rm) async def handle_session_fs_rename(params: dict) -> dict | None: request = SessionFSRenameRequest.from_dict(params) handler = get_handlers(request.session_id).session_fs if handler is None: raise RuntimeError(f"No session_fs handler registered for session: {request.session_id}") - await handler.rename(request) - return None + result = await handler.rename(request) + return result.to_dict() if result is not None else None client.set_request_handler("sessionFs.rename", handle_session_fs_rename) diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index 7cbff3039..1b3452bd4 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -252,3676 +252,3720 @@ def to_dict(self) -> dict: @dataclass -class WorkingDirectoryContext: - "Working directory and git context at session start" - cwd: str - git_root: str | None = None - repository: str | None = None - host_type: WorkingDirectoryContextHostType | None = None - branch: str | None = None - head_commit: str | None = None - base_commit: str | None = None +class AbortData: + "Turn abort information including the reason for termination" + reason: str @staticmethod - def from_dict(obj: Any) -> "WorkingDirectoryContext": + def from_dict(obj: Any) -> "AbortData": assert isinstance(obj, dict) - cwd = from_str(obj.get("cwd")) - git_root = from_union([from_none, from_str], obj.get("gitRoot")) - repository = from_union([from_none, from_str], obj.get("repository")) - host_type = from_union([from_none, lambda x: parse_enum(WorkingDirectoryContextHostType, x)], obj.get("hostType")) - branch = from_union([from_none, from_str], obj.get("branch")) - head_commit = from_union([from_none, from_str], obj.get("headCommit")) - base_commit = from_union([from_none, from_str], obj.get("baseCommit")) - return WorkingDirectoryContext( - cwd=cwd, - git_root=git_root, - repository=repository, - host_type=host_type, - branch=branch, - head_commit=head_commit, - base_commit=base_commit, + reason = from_str(obj.get("reason")) + return AbortData( + reason=reason, ) def to_dict(self) -> dict: result: dict = {} - result["cwd"] = from_str(self.cwd) - if self.git_root is not None: - result["gitRoot"] = from_union([from_none, from_str], self.git_root) - if self.repository is not None: - result["repository"] = from_union([from_none, from_str], self.repository) - if self.host_type is not None: - result["hostType"] = from_union([from_none, lambda x: to_enum(WorkingDirectoryContextHostType, x)], self.host_type) - if self.branch is not None: - result["branch"] = from_union([from_none, from_str], self.branch) - if self.head_commit is not None: - result["headCommit"] = from_union([from_none, from_str], self.head_commit) - if self.base_commit is not None: - result["baseCommit"] = from_union([from_none, from_str], self.base_commit) + result["reason"] = from_str(self.reason) return result @dataclass -class SessionStartData: - "Session initialization metadata including context and configuration" - session_id: str - version: float - producer: str - copilot_version: str - start_time: datetime - selected_model: str | None = None - reasoning_effort: str | None = None - context: WorkingDirectoryContext | None = None - already_in_use: bool | None = None - remote_steerable: bool | None = None +class AssistantIntentData: + "Agent intent description for current activity or plan" + intent: str @staticmethod - def from_dict(obj: Any) -> "SessionStartData": + def from_dict(obj: Any) -> "AssistantIntentData": assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - version = from_float(obj.get("version")) - producer = from_str(obj.get("producer")) - copilot_version = from_str(obj.get("copilotVersion")) - start_time = from_datetime(obj.get("startTime")) - selected_model = from_union([from_none, from_str], obj.get("selectedModel")) - reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) - context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) - already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) - remote_steerable = from_union([from_none, from_bool], obj.get("remoteSteerable")) - return SessionStartData( - session_id=session_id, - version=version, - producer=producer, - copilot_version=copilot_version, - start_time=start_time, - selected_model=selected_model, - reasoning_effort=reasoning_effort, - context=context, - already_in_use=already_in_use, - remote_steerable=remote_steerable, + intent = from_str(obj.get("intent")) + return AssistantIntentData( + intent=intent, ) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) - result["version"] = to_float(self.version) - result["producer"] = from_str(self.producer) - result["copilotVersion"] = from_str(self.copilot_version) - result["startTime"] = to_datetime(self.start_time) - if self.selected_model is not None: - result["selectedModel"] = from_union([from_none, from_str], self.selected_model) - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) - if self.context is not None: - result["context"] = from_union([from_none, lambda x: to_class(WorkingDirectoryContext, x)], self.context) - if self.already_in_use is not None: - result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) - if self.remote_steerable is not None: - result["remoteSteerable"] = from_union([from_none, from_bool], self.remote_steerable) + result["intent"] = from_str(self.intent) return result @dataclass -class SessionResumeData: - "Session resume metadata including current context and event count" - resume_time: datetime - event_count: float - selected_model: str | None = None - reasoning_effort: str | None = None - context: WorkingDirectoryContext | None = None - already_in_use: bool | None = None - remote_steerable: bool | None = None +class AssistantMessageData: + "Assistant response containing text content, optional tool requests, and interaction metadata" + content: str + message_id: str + encrypted_content: str | None = None + interaction_id: str | None = None + output_tokens: float | None = None + # Deprecated: this field is deprecated. + parent_tool_call_id: str | None = None + phase: str | None = None + reasoning_opaque: str | None = None + reasoning_text: str | None = None + request_id: str | None = None + tool_requests: list[AssistantMessageToolRequest] | None = None @staticmethod - def from_dict(obj: Any) -> "SessionResumeData": + def from_dict(obj: Any) -> "AssistantMessageData": assert isinstance(obj, dict) - resume_time = from_datetime(obj.get("resumeTime")) - event_count = from_float(obj.get("eventCount")) - selected_model = from_union([from_none, from_str], obj.get("selectedModel")) - reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) - context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) - already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) - remote_steerable = from_union([from_none, from_bool], obj.get("remoteSteerable")) - return SessionResumeData( - resume_time=resume_time, - event_count=event_count, - selected_model=selected_model, - reasoning_effort=reasoning_effort, - context=context, - already_in_use=already_in_use, - remote_steerable=remote_steerable, + content = from_str(obj.get("content")) + message_id = from_str(obj.get("messageId")) + encrypted_content = from_union([from_none, from_str], obj.get("encryptedContent")) + interaction_id = from_union([from_none, from_str], obj.get("interactionId")) + output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) + parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) + phase = from_union([from_none, from_str], obj.get("phase")) + reasoning_opaque = from_union([from_none, from_str], obj.get("reasoningOpaque")) + reasoning_text = from_union([from_none, from_str], obj.get("reasoningText")) + request_id = from_union([from_none, from_str], obj.get("requestId")) + tool_requests = from_union([from_none, lambda x: from_list(AssistantMessageToolRequest.from_dict, x)], obj.get("toolRequests")) + return AssistantMessageData( + content=content, + message_id=message_id, + encrypted_content=encrypted_content, + interaction_id=interaction_id, + output_tokens=output_tokens, + parent_tool_call_id=parent_tool_call_id, + phase=phase, + reasoning_opaque=reasoning_opaque, + reasoning_text=reasoning_text, + request_id=request_id, + tool_requests=tool_requests, ) def to_dict(self) -> dict: result: dict = {} - result["resumeTime"] = to_datetime(self.resume_time) - result["eventCount"] = to_float(self.event_count) - if self.selected_model is not None: - result["selectedModel"] = from_union([from_none, from_str], self.selected_model) - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) - if self.context is not None: - result["context"] = from_union([from_none, lambda x: to_class(WorkingDirectoryContext, x)], self.context) - if self.already_in_use is not None: - result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) - if self.remote_steerable is not None: - result["remoteSteerable"] = from_union([from_none, from_bool], self.remote_steerable) + result["content"] = from_str(self.content) + result["messageId"] = from_str(self.message_id) + if self.encrypted_content is not None: + result["encryptedContent"] = from_union([from_none, from_str], self.encrypted_content) + if self.interaction_id is not None: + result["interactionId"] = from_union([from_none, from_str], self.interaction_id) + if self.output_tokens is not None: + result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) + if self.parent_tool_call_id is not None: + result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) + if self.phase is not None: + result["phase"] = from_union([from_none, from_str], self.phase) + if self.reasoning_opaque is not None: + result["reasoningOpaque"] = from_union([from_none, from_str], self.reasoning_opaque) + if self.reasoning_text is not None: + result["reasoningText"] = from_union([from_none, from_str], self.reasoning_text) + if self.request_id is not None: + result["requestId"] = from_union([from_none, from_str], self.request_id) + if self.tool_requests is not None: + result["toolRequests"] = from_union([from_none, lambda x: from_list(lambda x: to_class(AssistantMessageToolRequest, x), x)], self.tool_requests) return result @dataclass -class SessionRemoteSteerableChangedData: - "Notifies Mission Control that the session's remote steering capability has changed" - remote_steerable: bool +class AssistantMessageDeltaData: + "Streaming assistant message delta for incremental response updates" + delta_content: str + message_id: str + # Deprecated: this field is deprecated. + parent_tool_call_id: str | None = None @staticmethod - def from_dict(obj: Any) -> "SessionRemoteSteerableChangedData": + def from_dict(obj: Any) -> "AssistantMessageDeltaData": assert isinstance(obj, dict) - remote_steerable = from_bool(obj.get("remoteSteerable")) - return SessionRemoteSteerableChangedData( - remote_steerable=remote_steerable, + delta_content = from_str(obj.get("deltaContent")) + message_id = from_str(obj.get("messageId")) + parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) + return AssistantMessageDeltaData( + delta_content=delta_content, + message_id=message_id, + parent_tool_call_id=parent_tool_call_id, ) def to_dict(self) -> dict: result: dict = {} - result["remoteSteerable"] = from_bool(self.remote_steerable) + result["deltaContent"] = from_str(self.delta_content) + result["messageId"] = from_str(self.message_id) + if self.parent_tool_call_id is not None: + result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) return result @dataclass -class SessionErrorData: - "Error details for timeline display including message and optional diagnostic information" - error_type: str - message: str - stack: str | None = None - status_code: int | None = None - provider_call_id: str | None = None - url: str | None = None +class AssistantMessageToolRequest: + "A tool invocation request from the assistant" + name: str + tool_call_id: str + arguments: Any = None + intention_summary: str | None = None + mcp_server_name: str | None = None + tool_title: str | None = None + type: AssistantMessageToolRequestType | None = None @staticmethod - def from_dict(obj: Any) -> "SessionErrorData": + def from_dict(obj: Any) -> "AssistantMessageToolRequest": assert isinstance(obj, dict) - error_type = from_str(obj.get("errorType")) - message = from_str(obj.get("message")) - stack = from_union([from_none, from_str], obj.get("stack")) - status_code = from_union([from_none, from_int], obj.get("statusCode")) - provider_call_id = from_union([from_none, from_str], obj.get("providerCallId")) - url = from_union([from_none, from_str], obj.get("url")) - return SessionErrorData( - error_type=error_type, - message=message, - stack=stack, - status_code=status_code, - provider_call_id=provider_call_id, - url=url, + name = from_str(obj.get("name")) + tool_call_id = from_str(obj.get("toolCallId")) + arguments = obj.get("arguments") + intention_summary = from_union([from_none, from_str], obj.get("intentionSummary")) + mcp_server_name = from_union([from_none, from_str], obj.get("mcpServerName")) + tool_title = from_union([from_none, from_str], obj.get("toolTitle")) + type = from_union([from_none, lambda x: parse_enum(AssistantMessageToolRequestType, x)], obj.get("type")) + return AssistantMessageToolRequest( + name=name, + tool_call_id=tool_call_id, + arguments=arguments, + intention_summary=intention_summary, + mcp_server_name=mcp_server_name, + tool_title=tool_title, + type=type, ) def to_dict(self) -> dict: result: dict = {} - result["errorType"] = from_str(self.error_type) - result["message"] = from_str(self.message) - if self.stack is not None: - result["stack"] = from_union([from_none, from_str], self.stack) - if self.status_code is not None: - result["statusCode"] = from_union([from_none, to_int], self.status_code) - if self.provider_call_id is not None: - result["providerCallId"] = from_union([from_none, from_str], self.provider_call_id) - if self.url is not None: - result["url"] = from_union([from_none, from_str], self.url) + result["name"] = from_str(self.name) + result["toolCallId"] = from_str(self.tool_call_id) + if self.arguments is not None: + result["arguments"] = self.arguments + if self.intention_summary is not None: + result["intentionSummary"] = from_union([from_none, from_str], self.intention_summary) + if self.mcp_server_name is not None: + result["mcpServerName"] = from_union([from_none, from_str], self.mcp_server_name) + if self.tool_title is not None: + result["toolTitle"] = from_union([from_none, from_str], self.tool_title) + if self.type is not None: + result["type"] = from_union([from_none, lambda x: to_enum(AssistantMessageToolRequestType, x)], self.type) return result @dataclass -class SessionIdleData: - "Payload indicating the session is idle with no background agents in flight" - aborted: bool | None = None +class AssistantReasoningData: + "Assistant reasoning content for timeline display with complete thinking text" + content: str + reasoning_id: str @staticmethod - def from_dict(obj: Any) -> "SessionIdleData": + def from_dict(obj: Any) -> "AssistantReasoningData": assert isinstance(obj, dict) - aborted = from_union([from_none, from_bool], obj.get("aborted")) - return SessionIdleData( - aborted=aborted, + content = from_str(obj.get("content")) + reasoning_id = from_str(obj.get("reasoningId")) + return AssistantReasoningData( + content=content, + reasoning_id=reasoning_id, ) def to_dict(self) -> dict: result: dict = {} - if self.aborted is not None: - result["aborted"] = from_union([from_none, from_bool], self.aborted) + result["content"] = from_str(self.content) + result["reasoningId"] = from_str(self.reasoning_id) return result @dataclass -class SessionTitleChangedData: - "Session title change payload containing the new display title" - title: str +class AssistantReasoningDeltaData: + "Streaming reasoning delta for incremental extended thinking updates" + delta_content: str + reasoning_id: str @staticmethod - def from_dict(obj: Any) -> "SessionTitleChangedData": + def from_dict(obj: Any) -> "AssistantReasoningDeltaData": assert isinstance(obj, dict) - title = from_str(obj.get("title")) - return SessionTitleChangedData( - title=title, + delta_content = from_str(obj.get("deltaContent")) + reasoning_id = from_str(obj.get("reasoningId")) + return AssistantReasoningDeltaData( + delta_content=delta_content, + reasoning_id=reasoning_id, ) def to_dict(self) -> dict: result: dict = {} - result["title"] = from_str(self.title) + result["deltaContent"] = from_str(self.delta_content) + result["reasoningId"] = from_str(self.reasoning_id) return result @dataclass -class SessionInfoData: - "Informational message for timeline display with categorization" - info_type: str - message: str - url: str | None = None +class AssistantStreamingDeltaData: + "Streaming response progress with cumulative byte count" + total_response_size_bytes: float @staticmethod - def from_dict(obj: Any) -> "SessionInfoData": + def from_dict(obj: Any) -> "AssistantStreamingDeltaData": assert isinstance(obj, dict) - info_type = from_str(obj.get("infoType")) - message = from_str(obj.get("message")) - url = from_union([from_none, from_str], obj.get("url")) - return SessionInfoData( - info_type=info_type, - message=message, - url=url, + total_response_size_bytes = from_float(obj.get("totalResponseSizeBytes")) + return AssistantStreamingDeltaData( + total_response_size_bytes=total_response_size_bytes, ) def to_dict(self) -> dict: result: dict = {} - result["infoType"] = from_str(self.info_type) - result["message"] = from_str(self.message) - if self.url is not None: - result["url"] = from_union([from_none, from_str], self.url) + result["totalResponseSizeBytes"] = to_float(self.total_response_size_bytes) return result @dataclass -class SessionWarningData: - "Warning message for timeline display with categorization" - warning_type: str - message: str - url: str | None = None +class AssistantTurnEndData: + "Turn completion metadata including the turn identifier" + turn_id: str @staticmethod - def from_dict(obj: Any) -> "SessionWarningData": + def from_dict(obj: Any) -> "AssistantTurnEndData": assert isinstance(obj, dict) - warning_type = from_str(obj.get("warningType")) - message = from_str(obj.get("message")) - url = from_union([from_none, from_str], obj.get("url")) - return SessionWarningData( - warning_type=warning_type, - message=message, - url=url, + turn_id = from_str(obj.get("turnId")) + return AssistantTurnEndData( + turn_id=turn_id, ) def to_dict(self) -> dict: result: dict = {} - result["warningType"] = from_str(self.warning_type) - result["message"] = from_str(self.message) - if self.url is not None: - result["url"] = from_union([from_none, from_str], self.url) + result["turnId"] = from_str(self.turn_id) return result @dataclass -class SessionModelChangeData: - "Model change details including previous and new model identifiers" - new_model: str - previous_model: str | None = None - previous_reasoning_effort: str | None = None - reasoning_effort: str | None = None +class AssistantTurnStartData: + "Turn initialization metadata including identifier and interaction tracking" + turn_id: str + interaction_id: str | None = None @staticmethod - def from_dict(obj: Any) -> "SessionModelChangeData": + def from_dict(obj: Any) -> "AssistantTurnStartData": assert isinstance(obj, dict) - new_model = from_str(obj.get("newModel")) - previous_model = from_union([from_none, from_str], obj.get("previousModel")) - previous_reasoning_effort = from_union([from_none, from_str], obj.get("previousReasoningEffort")) - reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) - return SessionModelChangeData( - new_model=new_model, - previous_model=previous_model, - previous_reasoning_effort=previous_reasoning_effort, - reasoning_effort=reasoning_effort, + turn_id = from_str(obj.get("turnId")) + interaction_id = from_union([from_none, from_str], obj.get("interactionId")) + return AssistantTurnStartData( + turn_id=turn_id, + interaction_id=interaction_id, ) def to_dict(self) -> dict: result: dict = {} - result["newModel"] = from_str(self.new_model) - if self.previous_model is not None: - result["previousModel"] = from_union([from_none, from_str], self.previous_model) - if self.previous_reasoning_effort is not None: - result["previousReasoningEffort"] = from_union([from_none, from_str], self.previous_reasoning_effort) - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) + result["turnId"] = from_str(self.turn_id) + if self.interaction_id is not None: + result["interactionId"] = from_union([from_none, from_str], self.interaction_id) return result @dataclass -class SessionModeChangedData: - "Agent mode change details including previous and new modes" - previous_mode: str - new_mode: str +class AssistantUsageCopilotUsage: + "Per-request cost and usage data from the CAPI copilot_usage response field" + token_details: list[AssistantUsageCopilotUsageTokenDetail] + total_nano_aiu: float @staticmethod - def from_dict(obj: Any) -> "SessionModeChangedData": + def from_dict(obj: Any) -> "AssistantUsageCopilotUsage": assert isinstance(obj, dict) - previous_mode = from_str(obj.get("previousMode")) - new_mode = from_str(obj.get("newMode")) - return SessionModeChangedData( - previous_mode=previous_mode, - new_mode=new_mode, + token_details = from_list(AssistantUsageCopilotUsageTokenDetail.from_dict, obj.get("tokenDetails")) + total_nano_aiu = from_float(obj.get("totalNanoAiu")) + return AssistantUsageCopilotUsage( + token_details=token_details, + total_nano_aiu=total_nano_aiu, ) def to_dict(self) -> dict: result: dict = {} - result["previousMode"] = from_str(self.previous_mode) - result["newMode"] = from_str(self.new_mode) + result["tokenDetails"] = from_list(lambda x: to_class(AssistantUsageCopilotUsageTokenDetail, x), self.token_details) + result["totalNanoAiu"] = to_float(self.total_nano_aiu) return result @dataclass -class SessionPlanChangedData: - "Plan file operation details indicating what changed" - operation: SessionPlanChangedDataOperation +class AssistantUsageCopilotUsageTokenDetail: + "Token usage detail for a single billing category" + batch_size: float + cost_per_batch: float + token_count: float + token_type: str @staticmethod - def from_dict(obj: Any) -> "SessionPlanChangedData": + def from_dict(obj: Any) -> "AssistantUsageCopilotUsageTokenDetail": assert isinstance(obj, dict) - operation = parse_enum(SessionPlanChangedDataOperation, obj.get("operation")) - return SessionPlanChangedData( - operation=operation, + batch_size = from_float(obj.get("batchSize")) + cost_per_batch = from_float(obj.get("costPerBatch")) + token_count = from_float(obj.get("tokenCount")) + token_type = from_str(obj.get("tokenType")) + return AssistantUsageCopilotUsageTokenDetail( + batch_size=batch_size, + cost_per_batch=cost_per_batch, + token_count=token_count, + token_type=token_type, ) def to_dict(self) -> dict: result: dict = {} - result["operation"] = to_enum(SessionPlanChangedDataOperation, self.operation) + result["batchSize"] = to_float(self.batch_size) + result["costPerBatch"] = to_float(self.cost_per_batch) + result["tokenCount"] = to_float(self.token_count) + result["tokenType"] = from_str(self.token_type) return result @dataclass -class SessionWorkspaceFileChangedData: - "Workspace file change details including path and operation type" - path: str - operation: SessionWorkspaceFileChangedDataOperation +class AssistantUsageData: + "LLM API call usage metrics including tokens, costs, quotas, and billing information" + model: str + api_call_id: str | None = None + cache_read_tokens: float | None = None + cache_write_tokens: float | None = None + copilot_usage: AssistantUsageCopilotUsage | None = None + cost: float | None = None + duration: float | None = None + initiator: str | None = None + input_tokens: float | None = None + inter_token_latency_ms: float | None = None + output_tokens: float | None = None + # Deprecated: this field is deprecated. + parent_tool_call_id: str | None = None + provider_call_id: str | None = None + quota_snapshots: dict[str, AssistantUsageQuotaSnapshot] | None = None + reasoning_effort: str | None = None + reasoning_tokens: float | None = None + ttft_ms: float | None = None @staticmethod - def from_dict(obj: Any) -> "SessionWorkspaceFileChangedData": + def from_dict(obj: Any) -> "AssistantUsageData": assert isinstance(obj, dict) - path = from_str(obj.get("path")) - operation = parse_enum(SessionWorkspaceFileChangedDataOperation, obj.get("operation")) - return SessionWorkspaceFileChangedData( - path=path, - operation=operation, - ) - - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - result["operation"] = to_enum(SessionWorkspaceFileChangedDataOperation, self.operation) - return result - - -@dataclass -class HandoffRepository: - "Repository context for the handed-off session" - owner: str - name: str - branch: str | None = None - - @staticmethod - def from_dict(obj: Any) -> "HandoffRepository": - assert isinstance(obj, dict) - owner = from_str(obj.get("owner")) - name = from_str(obj.get("name")) - branch = from_union([from_none, from_str], obj.get("branch")) - return HandoffRepository( - owner=owner, - name=name, - branch=branch, + model = from_str(obj.get("model")) + api_call_id = from_union([from_none, from_str], obj.get("apiCallId")) + cache_read_tokens = from_union([from_none, from_float], obj.get("cacheReadTokens")) + cache_write_tokens = from_union([from_none, from_float], obj.get("cacheWriteTokens")) + copilot_usage = from_union([from_none, AssistantUsageCopilotUsage.from_dict], obj.get("copilotUsage")) + cost = from_union([from_none, from_float], obj.get("cost")) + duration = from_union([from_none, from_float], obj.get("duration")) + initiator = from_union([from_none, from_str], obj.get("initiator")) + input_tokens = from_union([from_none, from_float], obj.get("inputTokens")) + inter_token_latency_ms = from_union([from_none, from_float], obj.get("interTokenLatencyMs")) + output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) + parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) + provider_call_id = from_union([from_none, from_str], obj.get("providerCallId")) + quota_snapshots = from_union([from_none, lambda x: from_dict(AssistantUsageQuotaSnapshot.from_dict, x)], obj.get("quotaSnapshots")) + reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) + reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) + ttft_ms = from_union([from_none, from_float], obj.get("ttftMs")) + return AssistantUsageData( + model=model, + api_call_id=api_call_id, + cache_read_tokens=cache_read_tokens, + cache_write_tokens=cache_write_tokens, + copilot_usage=copilot_usage, + cost=cost, + duration=duration, + initiator=initiator, + input_tokens=input_tokens, + inter_token_latency_ms=inter_token_latency_ms, + output_tokens=output_tokens, + parent_tool_call_id=parent_tool_call_id, + provider_call_id=provider_call_id, + quota_snapshots=quota_snapshots, + reasoning_effort=reasoning_effort, + reasoning_tokens=reasoning_tokens, + ttft_ms=ttft_ms, ) def to_dict(self) -> dict: result: dict = {} - result["owner"] = from_str(self.owner) - result["name"] = from_str(self.name) - if self.branch is not None: - result["branch"] = from_union([from_none, from_str], self.branch) + result["model"] = from_str(self.model) + if self.api_call_id is not None: + result["apiCallId"] = from_union([from_none, from_str], self.api_call_id) + if self.cache_read_tokens is not None: + result["cacheReadTokens"] = from_union([from_none, to_float], self.cache_read_tokens) + if self.cache_write_tokens is not None: + result["cacheWriteTokens"] = from_union([from_none, to_float], self.cache_write_tokens) + if self.copilot_usage is not None: + result["copilotUsage"] = from_union([from_none, lambda x: to_class(AssistantUsageCopilotUsage, x)], self.copilot_usage) + if self.cost is not None: + result["cost"] = from_union([from_none, to_float], self.cost) + if self.duration is not None: + result["duration"] = from_union([from_none, to_float], self.duration) + if self.initiator is not None: + result["initiator"] = from_union([from_none, from_str], self.initiator) + if self.input_tokens is not None: + result["inputTokens"] = from_union([from_none, to_float], self.input_tokens) + if self.inter_token_latency_ms is not None: + result["interTokenLatencyMs"] = from_union([from_none, to_float], self.inter_token_latency_ms) + if self.output_tokens is not None: + result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) + if self.parent_tool_call_id is not None: + result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) + if self.provider_call_id is not None: + result["providerCallId"] = from_union([from_none, from_str], self.provider_call_id) + if self.quota_snapshots is not None: + result["quotaSnapshots"] = from_union([from_none, lambda x: from_dict(lambda x: to_class(AssistantUsageQuotaSnapshot, x), x)], self.quota_snapshots) + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) + if self.reasoning_tokens is not None: + result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) + if self.ttft_ms is not None: + result["ttftMs"] = from_union([from_none, to_float], self.ttft_ms) return result @dataclass -class SessionHandoffData: - "Session handoff metadata including source, context, and repository information" - handoff_time: datetime - source_type: HandoffSourceType - repository: HandoffRepository | None = None - context: str | None = None - summary: str | None = None - remote_session_id: str | None = None - host: str | None = None +class AssistantUsageQuotaSnapshot: + entitlement_requests: float + is_unlimited_entitlement: bool + overage: float + overage_allowed_with_exhausted_quota: bool + remaining_percentage: float + usage_allowed_with_exhausted_quota: bool + used_requests: float + reset_date: datetime | None = None @staticmethod - def from_dict(obj: Any) -> "SessionHandoffData": + def from_dict(obj: Any) -> "AssistantUsageQuotaSnapshot": assert isinstance(obj, dict) - handoff_time = from_datetime(obj.get("handoffTime")) - source_type = parse_enum(HandoffSourceType, obj.get("sourceType")) - repository = from_union([from_none, HandoffRepository.from_dict], obj.get("repository")) - context = from_union([from_none, from_str], obj.get("context")) - summary = from_union([from_none, from_str], obj.get("summary")) - remote_session_id = from_union([from_none, from_str], obj.get("remoteSessionId")) - host = from_union([from_none, from_str], obj.get("host")) - return SessionHandoffData( - handoff_time=handoff_time, - source_type=source_type, - repository=repository, - context=context, - summary=summary, - remote_session_id=remote_session_id, - host=host, + entitlement_requests = from_float(obj.get("entitlementRequests")) + is_unlimited_entitlement = from_bool(obj.get("isUnlimitedEntitlement")) + overage = from_float(obj.get("overage")) + overage_allowed_with_exhausted_quota = from_bool(obj.get("overageAllowedWithExhaustedQuota")) + remaining_percentage = from_float(obj.get("remainingPercentage")) + usage_allowed_with_exhausted_quota = from_bool(obj.get("usageAllowedWithExhaustedQuota")) + used_requests = from_float(obj.get("usedRequests")) + reset_date = from_union([from_none, from_datetime], obj.get("resetDate")) + return AssistantUsageQuotaSnapshot( + entitlement_requests=entitlement_requests, + is_unlimited_entitlement=is_unlimited_entitlement, + overage=overage, + overage_allowed_with_exhausted_quota=overage_allowed_with_exhausted_quota, + remaining_percentage=remaining_percentage, + usage_allowed_with_exhausted_quota=usage_allowed_with_exhausted_quota, + used_requests=used_requests, + reset_date=reset_date, ) def to_dict(self) -> dict: result: dict = {} - result["handoffTime"] = to_datetime(self.handoff_time) - result["sourceType"] = to_enum(HandoffSourceType, self.source_type) - if self.repository is not None: - result["repository"] = from_union([from_none, lambda x: to_class(HandoffRepository, x)], self.repository) - if self.context is not None: - result["context"] = from_union([from_none, from_str], self.context) - if self.summary is not None: - result["summary"] = from_union([from_none, from_str], self.summary) - if self.remote_session_id is not None: - result["remoteSessionId"] = from_union([from_none, from_str], self.remote_session_id) - if self.host is not None: - result["host"] = from_union([from_none, from_str], self.host) + result["entitlementRequests"] = to_float(self.entitlement_requests) + result["isUnlimitedEntitlement"] = from_bool(self.is_unlimited_entitlement) + result["overage"] = to_float(self.overage) + result["overageAllowedWithExhaustedQuota"] = from_bool(self.overage_allowed_with_exhausted_quota) + result["remainingPercentage"] = to_float(self.remaining_percentage) + result["usageAllowedWithExhaustedQuota"] = from_bool(self.usage_allowed_with_exhausted_quota) + result["usedRequests"] = to_float(self.used_requests) + if self.reset_date is not None: + result["resetDate"] = from_union([from_none, to_datetime], self.reset_date) return result @dataclass -class SessionTruncationData: - "Conversation truncation statistics including token counts and removed content metrics" - token_limit: float - pre_truncation_tokens_in_messages: float - pre_truncation_messages_length: float - post_truncation_tokens_in_messages: float - post_truncation_messages_length: float - tokens_removed_during_truncation: float - messages_removed_during_truncation: float - performed_by: str +class CapabilitiesChangedData: + "Session capability change notification" + ui: CapabilitiesChangedUI | None = None @staticmethod - def from_dict(obj: Any) -> "SessionTruncationData": + def from_dict(obj: Any) -> "CapabilitiesChangedData": assert isinstance(obj, dict) - token_limit = from_float(obj.get("tokenLimit")) - pre_truncation_tokens_in_messages = from_float(obj.get("preTruncationTokensInMessages")) - pre_truncation_messages_length = from_float(obj.get("preTruncationMessagesLength")) - post_truncation_tokens_in_messages = from_float(obj.get("postTruncationTokensInMessages")) - post_truncation_messages_length = from_float(obj.get("postTruncationMessagesLength")) - tokens_removed_during_truncation = from_float(obj.get("tokensRemovedDuringTruncation")) - messages_removed_during_truncation = from_float(obj.get("messagesRemovedDuringTruncation")) - performed_by = from_str(obj.get("performedBy")) - return SessionTruncationData( - token_limit=token_limit, - pre_truncation_tokens_in_messages=pre_truncation_tokens_in_messages, - pre_truncation_messages_length=pre_truncation_messages_length, - post_truncation_tokens_in_messages=post_truncation_tokens_in_messages, - post_truncation_messages_length=post_truncation_messages_length, - tokens_removed_during_truncation=tokens_removed_during_truncation, - messages_removed_during_truncation=messages_removed_during_truncation, - performed_by=performed_by, + ui = from_union([from_none, CapabilitiesChangedUI.from_dict], obj.get("ui")) + return CapabilitiesChangedData( + ui=ui, ) def to_dict(self) -> dict: result: dict = {} - result["tokenLimit"] = to_float(self.token_limit) - result["preTruncationTokensInMessages"] = to_float(self.pre_truncation_tokens_in_messages) - result["preTruncationMessagesLength"] = to_float(self.pre_truncation_messages_length) - result["postTruncationTokensInMessages"] = to_float(self.post_truncation_tokens_in_messages) - result["postTruncationMessagesLength"] = to_float(self.post_truncation_messages_length) - result["tokensRemovedDuringTruncation"] = to_float(self.tokens_removed_during_truncation) - result["messagesRemovedDuringTruncation"] = to_float(self.messages_removed_during_truncation) - result["performedBy"] = from_str(self.performed_by) + if self.ui is not None: + result["ui"] = from_union([from_none, lambda x: to_class(CapabilitiesChangedUI, x)], self.ui) return result @dataclass -class SessionSnapshotRewindData: - "Session rewind details including target event and count of removed events" - up_to_event_id: str - events_removed: float +class CapabilitiesChangedUI: + "UI capability changes" + elicitation: bool | None = None @staticmethod - def from_dict(obj: Any) -> "SessionSnapshotRewindData": + def from_dict(obj: Any) -> "CapabilitiesChangedUI": assert isinstance(obj, dict) - up_to_event_id = from_str(obj.get("upToEventId")) - events_removed = from_float(obj.get("eventsRemoved")) - return SessionSnapshotRewindData( - up_to_event_id=up_to_event_id, - events_removed=events_removed, + elicitation = from_union([from_none, from_bool], obj.get("elicitation")) + return CapabilitiesChangedUI( + elicitation=elicitation, ) def to_dict(self) -> dict: result: dict = {} - result["upToEventId"] = from_str(self.up_to_event_id) - result["eventsRemoved"] = to_float(self.events_removed) + if self.elicitation is not None: + result["elicitation"] = from_union([from_none, from_bool], self.elicitation) return result @dataclass -class ShutdownCodeChanges: - "Aggregate code change metrics for the session" - lines_added: float - lines_removed: float - files_modified: list[str] +class CommandCompletedData: + "Queued command completion notification signaling UI dismissal" + request_id: str @staticmethod - def from_dict(obj: Any) -> "ShutdownCodeChanges": + def from_dict(obj: Any) -> "CommandCompletedData": assert isinstance(obj, dict) - lines_added = from_float(obj.get("linesAdded")) - lines_removed = from_float(obj.get("linesRemoved")) - files_modified = from_list(from_str, obj.get("filesModified")) - return ShutdownCodeChanges( - lines_added=lines_added, - lines_removed=lines_removed, - files_modified=files_modified, + request_id = from_str(obj.get("requestId")) + return CommandCompletedData( + request_id=request_id, ) def to_dict(self) -> dict: result: dict = {} - result["linesAdded"] = to_float(self.lines_added) - result["linesRemoved"] = to_float(self.lines_removed) - result["filesModified"] = from_list(from_str, self.files_modified) + result["requestId"] = from_str(self.request_id) return result @dataclass -class ShutdownModelMetricRequests: - "Request count and cost metrics" - count: float - cost: float +class CommandExecuteData: + "Registered command dispatch request routed to the owning client" + args: str + command: str + command_name: str + request_id: str @staticmethod - def from_dict(obj: Any) -> "ShutdownModelMetricRequests": + def from_dict(obj: Any) -> "CommandExecuteData": assert isinstance(obj, dict) - count = from_float(obj.get("count")) - cost = from_float(obj.get("cost")) - return ShutdownModelMetricRequests( - count=count, - cost=cost, + args = from_str(obj.get("args")) + command = from_str(obj.get("command")) + command_name = from_str(obj.get("commandName")) + request_id = from_str(obj.get("requestId")) + return CommandExecuteData( + args=args, + command=command, + command_name=command_name, + request_id=request_id, ) def to_dict(self) -> dict: result: dict = {} - result["count"] = to_float(self.count) - result["cost"] = to_float(self.cost) + result["args"] = from_str(self.args) + result["command"] = from_str(self.command) + result["commandName"] = from_str(self.command_name) + result["requestId"] = from_str(self.request_id) return result @dataclass -class ShutdownModelMetricUsage: - "Token usage breakdown" - input_tokens: float - output_tokens: float - cache_read_tokens: float - cache_write_tokens: float - reasoning_tokens: float | None = None +class CommandQueuedData: + "Queued slash command dispatch request for client execution" + command: str + request_id: str @staticmethod - def from_dict(obj: Any) -> "ShutdownModelMetricUsage": + def from_dict(obj: Any) -> "CommandQueuedData": assert isinstance(obj, dict) - input_tokens = from_float(obj.get("inputTokens")) - output_tokens = from_float(obj.get("outputTokens")) - cache_read_tokens = from_float(obj.get("cacheReadTokens")) - cache_write_tokens = from_float(obj.get("cacheWriteTokens")) - reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) - return ShutdownModelMetricUsage( - input_tokens=input_tokens, - output_tokens=output_tokens, - cache_read_tokens=cache_read_tokens, - cache_write_tokens=cache_write_tokens, - reasoning_tokens=reasoning_tokens, + command = from_str(obj.get("command")) + request_id = from_str(obj.get("requestId")) + return CommandQueuedData( + command=command, + request_id=request_id, ) def to_dict(self) -> dict: result: dict = {} - result["inputTokens"] = to_float(self.input_tokens) - result["outputTokens"] = to_float(self.output_tokens) - result["cacheReadTokens"] = to_float(self.cache_read_tokens) - result["cacheWriteTokens"] = to_float(self.cache_write_tokens) - if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) + result["command"] = from_str(self.command) + result["requestId"] = from_str(self.request_id) return result @dataclass -class ShutdownModelMetric: - requests: ShutdownModelMetricRequests - usage: ShutdownModelMetricUsage +class CommandsChangedCommand: + name: str + description: str | None = None @staticmethod - def from_dict(obj: Any) -> "ShutdownModelMetric": + def from_dict(obj: Any) -> "CommandsChangedCommand": assert isinstance(obj, dict) - requests = ShutdownModelMetricRequests.from_dict(obj.get("requests")) - usage = ShutdownModelMetricUsage.from_dict(obj.get("usage")) - return ShutdownModelMetric( - requests=requests, - usage=usage, + name = from_str(obj.get("name")) + description = from_union([from_none, from_str], obj.get("description")) + return CommandsChangedCommand( + name=name, + description=description, ) def to_dict(self) -> dict: result: dict = {} - result["requests"] = to_class(ShutdownModelMetricRequests, self.requests) - result["usage"] = to_class(ShutdownModelMetricUsage, self.usage) + result["name"] = from_str(self.name) + if self.description is not None: + result["description"] = from_union([from_none, from_str], self.description) return result @dataclass -class SessionShutdownData: - "Session termination metrics including usage statistics, code changes, and shutdown reason" - shutdown_type: ShutdownType - total_premium_requests: float - total_api_duration_ms: float - session_start_time: float - code_changes: ShutdownCodeChanges - model_metrics: dict[str, ShutdownModelMetric] - error_reason: str | None = None - current_model: str | None = None - current_tokens: float | None = None - system_tokens: float | None = None - conversation_tokens: float | None = None - tool_definitions_tokens: float | None = None +class CommandsChangedData: + "SDK command registration change notification" + commands: list[CommandsChangedCommand] @staticmethod - def from_dict(obj: Any) -> "SessionShutdownData": + def from_dict(obj: Any) -> "CommandsChangedData": assert isinstance(obj, dict) - shutdown_type = parse_enum(ShutdownType, obj.get("shutdownType")) - total_premium_requests = from_float(obj.get("totalPremiumRequests")) - total_api_duration_ms = from_float(obj.get("totalApiDurationMs")) - session_start_time = from_float(obj.get("sessionStartTime")) - code_changes = ShutdownCodeChanges.from_dict(obj.get("codeChanges")) - model_metrics = from_dict(ShutdownModelMetric.from_dict, obj.get("modelMetrics")) - error_reason = from_union([from_none, from_str], obj.get("errorReason")) - current_model = from_union([from_none, from_str], obj.get("currentModel")) - current_tokens = from_union([from_none, from_float], obj.get("currentTokens")) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) - return SessionShutdownData( - shutdown_type=shutdown_type, - total_premium_requests=total_premium_requests, - total_api_duration_ms=total_api_duration_ms, - session_start_time=session_start_time, - code_changes=code_changes, - model_metrics=model_metrics, - error_reason=error_reason, - current_model=current_model, - current_tokens=current_tokens, - system_tokens=system_tokens, - conversation_tokens=conversation_tokens, - tool_definitions_tokens=tool_definitions_tokens, + commands = from_list(CommandsChangedCommand.from_dict, obj.get("commands")) + return CommandsChangedData( + commands=commands, ) def to_dict(self) -> dict: result: dict = {} - result["shutdownType"] = to_enum(ShutdownType, self.shutdown_type) - result["totalPremiumRequests"] = to_float(self.total_premium_requests) - result["totalApiDurationMs"] = to_float(self.total_api_duration_ms) - result["sessionStartTime"] = to_float(self.session_start_time) - result["codeChanges"] = to_class(ShutdownCodeChanges, self.code_changes) - result["modelMetrics"] = from_dict(lambda x: to_class(ShutdownModelMetric, x), self.model_metrics) - if self.error_reason is not None: - result["errorReason"] = from_union([from_none, from_str], self.error_reason) - if self.current_model is not None: - result["currentModel"] = from_union([from_none, from_str], self.current_model) - if self.current_tokens is not None: - result["currentTokens"] = from_union([from_none, to_float], self.current_tokens) - if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) - if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) - if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + result["commands"] = from_list(lambda x: to_class(CommandsChangedCommand, x), self.commands) return result @dataclass -class SessionContextChangedData: - "Working directory and git context at session start" - cwd: str - git_root: str | None = None - repository: str | None = None - host_type: SessionContextChangedDataHostType | None = None - branch: str | None = None - head_commit: str | None = None - base_commit: str | None = None +class CompactionCompleteCompactionTokensUsed: + "Token usage breakdown for the compaction LLM call" + cached_input: float + input: float + output: float @staticmethod - def from_dict(obj: Any) -> "SessionContextChangedData": + def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": assert isinstance(obj, dict) - cwd = from_str(obj.get("cwd")) - git_root = from_union([from_none, from_str], obj.get("gitRoot")) - repository = from_union([from_none, from_str], obj.get("repository")) - host_type = from_union([from_none, lambda x: parse_enum(SessionContextChangedDataHostType, x)], obj.get("hostType")) - branch = from_union([from_none, from_str], obj.get("branch")) - head_commit = from_union([from_none, from_str], obj.get("headCommit")) - base_commit = from_union([from_none, from_str], obj.get("baseCommit")) - return SessionContextChangedData( - cwd=cwd, - git_root=git_root, - repository=repository, - host_type=host_type, - branch=branch, - head_commit=head_commit, - base_commit=base_commit, + cached_input = from_float(obj.get("cachedInput")) + input = from_float(obj.get("input")) + output = from_float(obj.get("output")) + return CompactionCompleteCompactionTokensUsed( + cached_input=cached_input, + input=input, + output=output, ) def to_dict(self) -> dict: result: dict = {} - result["cwd"] = from_str(self.cwd) - if self.git_root is not None: - result["gitRoot"] = from_union([from_none, from_str], self.git_root) - if self.repository is not None: - result["repository"] = from_union([from_none, from_str], self.repository) - if self.host_type is not None: - result["hostType"] = from_union([from_none, lambda x: to_enum(SessionContextChangedDataHostType, x)], self.host_type) - if self.branch is not None: - result["branch"] = from_union([from_none, from_str], self.branch) - if self.head_commit is not None: - result["headCommit"] = from_union([from_none, from_str], self.head_commit) - if self.base_commit is not None: - result["baseCommit"] = from_union([from_none, from_str], self.base_commit) + result["cachedInput"] = to_float(self.cached_input) + result["input"] = to_float(self.input) + result["output"] = to_float(self.output) return result @dataclass -class SessionUsageInfoData: - "Current context window usage statistics including token and message counts" - token_limit: float - current_tokens: float - messages_length: float - system_tokens: float | None = None - conversation_tokens: float | None = None - tool_definitions_tokens: float | None = None - is_initial: bool | None = None +class CustomAgentsUpdatedAgent: + description: str + display_name: str + id: str + name: str + source: str + tools: list[str] + user_invocable: bool + model: str | None = None @staticmethod - def from_dict(obj: Any) -> "SessionUsageInfoData": + def from_dict(obj: Any) -> "CustomAgentsUpdatedAgent": assert isinstance(obj, dict) - token_limit = from_float(obj.get("tokenLimit")) - current_tokens = from_float(obj.get("currentTokens")) - messages_length = from_float(obj.get("messagesLength")) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) - is_initial = from_union([from_none, from_bool], obj.get("isInitial")) - return SessionUsageInfoData( - token_limit=token_limit, - current_tokens=current_tokens, - messages_length=messages_length, - system_tokens=system_tokens, - conversation_tokens=conversation_tokens, - tool_definitions_tokens=tool_definitions_tokens, - is_initial=is_initial, + description = from_str(obj.get("description")) + display_name = from_str(obj.get("displayName")) + id = from_str(obj.get("id")) + name = from_str(obj.get("name")) + source = from_str(obj.get("source")) + tools = from_list(from_str, obj.get("tools")) + user_invocable = from_bool(obj.get("userInvocable")) + model = from_union([from_none, from_str], obj.get("model")) + return CustomAgentsUpdatedAgent( + description=description, + display_name=display_name, + id=id, + name=name, + source=source, + tools=tools, + user_invocable=user_invocable, + model=model, ) def to_dict(self) -> dict: result: dict = {} - result["tokenLimit"] = to_float(self.token_limit) - result["currentTokens"] = to_float(self.current_tokens) - result["messagesLength"] = to_float(self.messages_length) - if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) - if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) - if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) - if self.is_initial is not None: - result["isInitial"] = from_union([from_none, from_bool], self.is_initial) + result["description"] = from_str(self.description) + result["displayName"] = from_str(self.display_name) + result["id"] = from_str(self.id) + result["name"] = from_str(self.name) + result["source"] = from_str(self.source) + result["tools"] = from_list(from_str, self.tools) + result["userInvocable"] = from_bool(self.user_invocable) + if self.model is not None: + result["model"] = from_union([from_none, from_str], self.model) return result @dataclass -class SessionCompactionStartData: - "Context window breakdown at the start of LLM-powered conversation compaction" - system_tokens: float | None = None - conversation_tokens: float | None = None - tool_definitions_tokens: float | None = None +class ElicitationCompletedData: + "Elicitation request completion with the user's response" + request_id: str + action: ElicitationCompletedAction | None = None + content: dict[str, Any] | None = None @staticmethod - def from_dict(obj: Any) -> "SessionCompactionStartData": + def from_dict(obj: Any) -> "ElicitationCompletedData": assert isinstance(obj, dict) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) - return SessionCompactionStartData( - system_tokens=system_tokens, - conversation_tokens=conversation_tokens, - tool_definitions_tokens=tool_definitions_tokens, + request_id = from_str(obj.get("requestId")) + action = from_union([from_none, lambda x: parse_enum(ElicitationCompletedAction, x)], obj.get("action")) + content = from_union([from_none, lambda x: from_dict(lambda x: x, x)], obj.get("content")) + return ElicitationCompletedData( + request_id=request_id, + action=action, + content=content, ) def to_dict(self) -> dict: result: dict = {} - if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) - if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) - if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + result["requestId"] = from_str(self.request_id) + if self.action is not None: + result["action"] = from_union([from_none, lambda x: to_enum(ElicitationCompletedAction, x)], self.action) + if self.content is not None: + result["content"] = from_union([from_none, lambda x: from_dict(lambda x: x, x)], self.content) return result @dataclass -class CompactionCompleteCompactionTokensUsed: - "Token usage breakdown for the compaction LLM call" - input: float - output: float - cached_input: float +class ElicitationRequestedData: + "Elicitation request; may be form-based (structured input) or URL-based (browser redirect)" + message: str + request_id: str + elicitation_source: str | None = None + mode: ElicitationRequestedMode | None = None + requested_schema: ElicitationRequestedSchema | None = None + tool_call_id: str | None = None + url: str | None = None @staticmethod - def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": + def from_dict(obj: Any) -> "ElicitationRequestedData": assert isinstance(obj, dict) - input = from_float(obj.get("input")) - output = from_float(obj.get("output")) - cached_input = from_float(obj.get("cachedInput")) - return CompactionCompleteCompactionTokensUsed( - input=input, - output=output, - cached_input=cached_input, + message = from_str(obj.get("message")) + request_id = from_str(obj.get("requestId")) + elicitation_source = from_union([from_none, from_str], obj.get("elicitationSource")) + mode = from_union([from_none, lambda x: parse_enum(ElicitationRequestedMode, x)], obj.get("mode")) + requested_schema = from_union([from_none, ElicitationRequestedSchema.from_dict], obj.get("requestedSchema")) + tool_call_id = from_union([from_none, from_str], obj.get("toolCallId")) + url = from_union([from_none, from_str], obj.get("url")) + return ElicitationRequestedData( + message=message, + request_id=request_id, + elicitation_source=elicitation_source, + mode=mode, + requested_schema=requested_schema, + tool_call_id=tool_call_id, + url=url, ) def to_dict(self) -> dict: result: dict = {} - result["input"] = to_float(self.input) - result["output"] = to_float(self.output) - result["cachedInput"] = to_float(self.cached_input) + result["message"] = from_str(self.message) + result["requestId"] = from_str(self.request_id) + if self.elicitation_source is not None: + result["elicitationSource"] = from_union([from_none, from_str], self.elicitation_source) + if self.mode is not None: + result["mode"] = from_union([from_none, lambda x: to_enum(ElicitationRequestedMode, x)], self.mode) + if self.requested_schema is not None: + result["requestedSchema"] = from_union([from_none, lambda x: to_class(ElicitationRequestedSchema, x)], self.requested_schema) + if self.tool_call_id is not None: + result["toolCallId"] = from_union([from_none, from_str], self.tool_call_id) + if self.url is not None: + result["url"] = from_union([from_none, from_str], self.url) return result @dataclass -class SessionCompactionCompleteData: - "Conversation compaction results including success status, metrics, and optional error details" - success: bool - error: str | None = None - pre_compaction_tokens: float | None = None - post_compaction_tokens: float | None = None - pre_compaction_messages_length: float | None = None - messages_removed: float | None = None - tokens_removed: float | None = None - summary_content: str | None = None - checkpoint_number: float | None = None - checkpoint_path: str | None = None - compaction_tokens_used: CompactionCompleteCompactionTokensUsed | None = None - request_id: str | None = None - system_tokens: float | None = None - conversation_tokens: float | None = None - tool_definitions_tokens: float | None = None +class ElicitationRequestedSchema: + "JSON Schema describing the form fields to present to the user (form mode only)" + properties: dict[str, Any] + type: str + required: list[str] | None = None @staticmethod - def from_dict(obj: Any) -> "SessionCompactionCompleteData": + def from_dict(obj: Any) -> "ElicitationRequestedSchema": assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - error = from_union([from_none, from_str], obj.get("error")) - pre_compaction_tokens = from_union([from_none, from_float], obj.get("preCompactionTokens")) - post_compaction_tokens = from_union([from_none, from_float], obj.get("postCompactionTokens")) - pre_compaction_messages_length = from_union([from_none, from_float], obj.get("preCompactionMessagesLength")) - messages_removed = from_union([from_none, from_float], obj.get("messagesRemoved")) - tokens_removed = from_union([from_none, from_float], obj.get("tokensRemoved")) - summary_content = from_union([from_none, from_str], obj.get("summaryContent")) - checkpoint_number = from_union([from_none, from_float], obj.get("checkpointNumber")) - checkpoint_path = from_union([from_none, from_str], obj.get("checkpointPath")) - compaction_tokens_used = from_union([from_none, CompactionCompleteCompactionTokensUsed.from_dict], obj.get("compactionTokensUsed")) - request_id = from_union([from_none, from_str], obj.get("requestId")) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) - return SessionCompactionCompleteData( - success=success, - error=error, - pre_compaction_tokens=pre_compaction_tokens, - post_compaction_tokens=post_compaction_tokens, - pre_compaction_messages_length=pre_compaction_messages_length, - messages_removed=messages_removed, - tokens_removed=tokens_removed, - summary_content=summary_content, - checkpoint_number=checkpoint_number, - checkpoint_path=checkpoint_path, - compaction_tokens_used=compaction_tokens_used, - request_id=request_id, - system_tokens=system_tokens, - conversation_tokens=conversation_tokens, - tool_definitions_tokens=tool_definitions_tokens, + properties = from_dict(lambda x: x, obj.get("properties")) + type = from_str(obj.get("type")) + required = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("required")) + return ElicitationRequestedSchema( + properties=properties, + type=type, + required=required, ) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) - if self.error is not None: - result["error"] = from_union([from_none, from_str], self.error) - if self.pre_compaction_tokens is not None: - result["preCompactionTokens"] = from_union([from_none, to_float], self.pre_compaction_tokens) - if self.post_compaction_tokens is not None: - result["postCompactionTokens"] = from_union([from_none, to_float], self.post_compaction_tokens) - if self.pre_compaction_messages_length is not None: - result["preCompactionMessagesLength"] = from_union([from_none, to_float], self.pre_compaction_messages_length) - if self.messages_removed is not None: - result["messagesRemoved"] = from_union([from_none, to_float], self.messages_removed) - if self.tokens_removed is not None: - result["tokensRemoved"] = from_union([from_none, to_float], self.tokens_removed) - if self.summary_content is not None: - result["summaryContent"] = from_union([from_none, from_str], self.summary_content) - if self.checkpoint_number is not None: - result["checkpointNumber"] = from_union([from_none, to_float], self.checkpoint_number) - if self.checkpoint_path is not None: - result["checkpointPath"] = from_union([from_none, from_str], self.checkpoint_path) - if self.compaction_tokens_used is not None: - result["compactionTokensUsed"] = from_union([from_none, lambda x: to_class(CompactionCompleteCompactionTokensUsed, x)], self.compaction_tokens_used) - if self.request_id is not None: - result["requestId"] = from_union([from_none, from_str], self.request_id) - if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) - if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) - if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + result["properties"] = from_dict(lambda x: x, self.properties) + result["type"] = from_str(self.type) + if self.required is not None: + result["required"] = from_union([from_none, lambda x: from_list(from_str, x)], self.required) return result @dataclass -class SessionTaskCompleteData: - "Task completion notification with summary from the agent" - summary: str | None = None - success: bool | None = None +class ExitPlanModeCompletedData: + "Plan mode exit completion with the user's approval decision and optional feedback" + request_id: str + approved: bool | None = None + auto_approve_edits: bool | None = None + feedback: str | None = None + selected_action: str | None = None @staticmethod - def from_dict(obj: Any) -> "SessionTaskCompleteData": + def from_dict(obj: Any) -> "ExitPlanModeCompletedData": assert isinstance(obj, dict) - summary = from_union([from_none, from_str], obj.get("summary", "")) - success = from_union([from_none, from_bool], obj.get("success")) - return SessionTaskCompleteData( - summary=summary, - success=success, + request_id = from_str(obj.get("requestId")) + approved = from_union([from_none, from_bool], obj.get("approved")) + auto_approve_edits = from_union([from_none, from_bool], obj.get("autoApproveEdits")) + feedback = from_union([from_none, from_str], obj.get("feedback")) + selected_action = from_union([from_none, from_str], obj.get("selectedAction")) + return ExitPlanModeCompletedData( + request_id=request_id, + approved=approved, + auto_approve_edits=auto_approve_edits, + feedback=feedback, + selected_action=selected_action, ) def to_dict(self) -> dict: result: dict = {} - if self.summary is not None: - result["summary"] = from_union([from_none, from_str], self.summary) - if self.success is not None: - result["success"] = from_union([from_none, from_bool], self.success) + result["requestId"] = from_str(self.request_id) + if self.approved is not None: + result["approved"] = from_union([from_none, from_bool], self.approved) + if self.auto_approve_edits is not None: + result["autoApproveEdits"] = from_union([from_none, from_bool], self.auto_approve_edits) + if self.feedback is not None: + result["feedback"] = from_union([from_none, from_str], self.feedback) + if self.selected_action is not None: + result["selectedAction"] = from_union([from_none, from_str], self.selected_action) return result @dataclass -class UserMessageAttachmentFileLineRange: - "Optional line range to scope the attachment to a specific section of the file" - start: float - end: float +class ExitPlanModeRequestedData: + "Plan approval request with plan content and available user actions" + actions: list[str] + plan_content: str + recommended_action: str + request_id: str + summary: str @staticmethod - def from_dict(obj: Any) -> "UserMessageAttachmentFileLineRange": + def from_dict(obj: Any) -> "ExitPlanModeRequestedData": assert isinstance(obj, dict) - start = from_float(obj.get("start")) - end = from_float(obj.get("end")) - return UserMessageAttachmentFileLineRange( - start=start, - end=end, + actions = from_list(from_str, obj.get("actions")) + plan_content = from_str(obj.get("planContent")) + recommended_action = from_str(obj.get("recommendedAction")) + request_id = from_str(obj.get("requestId")) + summary = from_str(obj.get("summary")) + return ExitPlanModeRequestedData( + actions=actions, + plan_content=plan_content, + recommended_action=recommended_action, + request_id=request_id, + summary=summary, ) def to_dict(self) -> dict: result: dict = {} - result["start"] = to_float(self.start) - result["end"] = to_float(self.end) + result["actions"] = from_list(from_str, self.actions) + result["planContent"] = from_str(self.plan_content) + result["recommendedAction"] = from_str(self.recommended_action) + result["requestId"] = from_str(self.request_id) + result["summary"] = from_str(self.summary) return result @dataclass -class UserMessageAttachmentSelectionDetailsStart: - "Start position of the selection" - line: float - character: float +class ExtensionsLoadedExtension: + id: str + name: str + source: ExtensionsLoadedExtensionSource + status: ExtensionsLoadedExtensionStatus @staticmethod - def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsStart": + def from_dict(obj: Any) -> "ExtensionsLoadedExtension": assert isinstance(obj, dict) - line = from_float(obj.get("line")) - character = from_float(obj.get("character")) - return UserMessageAttachmentSelectionDetailsStart( - line=line, - character=character, + id = from_str(obj.get("id")) + name = from_str(obj.get("name")) + source = parse_enum(ExtensionsLoadedExtensionSource, obj.get("source")) + status = parse_enum(ExtensionsLoadedExtensionStatus, obj.get("status")) + return ExtensionsLoadedExtension( + id=id, + name=name, + source=source, + status=status, ) def to_dict(self) -> dict: result: dict = {} - result["line"] = to_float(self.line) - result["character"] = to_float(self.character) + result["id"] = from_str(self.id) + result["name"] = from_str(self.name) + result["source"] = to_enum(ExtensionsLoadedExtensionSource, self.source) + result["status"] = to_enum(ExtensionsLoadedExtensionStatus, self.status) return result @dataclass -class UserMessageAttachmentSelectionDetailsEnd: - "End position of the selection" - line: float - character: float +class ExternalToolCompletedData: + "External tool completion notification signaling UI dismissal" + request_id: str @staticmethod - def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsEnd": + def from_dict(obj: Any) -> "ExternalToolCompletedData": assert isinstance(obj, dict) - line = from_float(obj.get("line")) - character = from_float(obj.get("character")) - return UserMessageAttachmentSelectionDetailsEnd( - line=line, - character=character, + request_id = from_str(obj.get("requestId")) + return ExternalToolCompletedData( + request_id=request_id, ) def to_dict(self) -> dict: result: dict = {} - result["line"] = to_float(self.line) - result["character"] = to_float(self.character) + result["requestId"] = from_str(self.request_id) return result @dataclass -class UserMessageAttachmentSelectionDetails: - "Position range of the selection within the file" - start: UserMessageAttachmentSelectionDetailsStart - end: UserMessageAttachmentSelectionDetailsEnd +class ExternalToolRequestedData: + "External tool invocation request for client-side tool execution" + request_id: str + session_id: str + tool_call_id: str + tool_name: str + arguments: Any = None + traceparent: str | None = None + tracestate: str | None = None @staticmethod - def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetails": + def from_dict(obj: Any) -> "ExternalToolRequestedData": assert isinstance(obj, dict) - start = UserMessageAttachmentSelectionDetailsStart.from_dict(obj.get("start")) - end = UserMessageAttachmentSelectionDetailsEnd.from_dict(obj.get("end")) - return UserMessageAttachmentSelectionDetails( - start=start, - end=end, + request_id = from_str(obj.get("requestId")) + session_id = from_str(obj.get("sessionId")) + tool_call_id = from_str(obj.get("toolCallId")) + tool_name = from_str(obj.get("toolName")) + arguments = obj.get("arguments") + traceparent = from_union([from_none, from_str], obj.get("traceparent")) + tracestate = from_union([from_none, from_str], obj.get("tracestate")) + return ExternalToolRequestedData( + request_id=request_id, + session_id=session_id, + tool_call_id=tool_call_id, + tool_name=tool_name, + arguments=arguments, + traceparent=traceparent, + tracestate=tracestate, ) def to_dict(self) -> dict: result: dict = {} - result["start"] = to_class(UserMessageAttachmentSelectionDetailsStart, self.start) - result["end"] = to_class(UserMessageAttachmentSelectionDetailsEnd, self.end) + result["requestId"] = from_str(self.request_id) + result["sessionId"] = from_str(self.session_id) + result["toolCallId"] = from_str(self.tool_call_id) + result["toolName"] = from_str(self.tool_name) + if self.arguments is not None: + result["arguments"] = self.arguments + if self.traceparent is not None: + result["traceparent"] = from_union([from_none, from_str], self.traceparent) + if self.tracestate is not None: + result["tracestate"] = from_union([from_none, from_str], self.tracestate) return result @dataclass -class UserMessageAttachment: - "A user message attachment — a file, directory, code selection, blob, or GitHub reference" - type: UserMessageAttachmentType - path: str | None = None - display_name: str | None = None - line_range: UserMessageAttachmentFileLineRange | None = None - file_path: str | None = None - text: str | None = None - selection: UserMessageAttachmentSelectionDetails | None = None - number: float | None = None - title: str | None = None - reference_type: UserMessageAttachmentGithubReferenceType | None = None - state: str | None = None - url: str | None = None - data: str | None = None - mime_type: str | None = None +class HandoffRepository: + "Repository context for the handed-off session" + name: str + owner: str + branch: str | None = None @staticmethod - def from_dict(obj: Any) -> "UserMessageAttachment": + def from_dict(obj: Any) -> "HandoffRepository": assert isinstance(obj, dict) - type = parse_enum(UserMessageAttachmentType, obj.get("type")) - path = from_union([from_none, from_str], obj.get("path")) - display_name = from_union([from_none, from_str], obj.get("displayName")) - line_range = from_union([from_none, UserMessageAttachmentFileLineRange.from_dict], obj.get("lineRange")) - file_path = from_union([from_none, from_str], obj.get("filePath")) - text = from_union([from_none, from_str], obj.get("text")) - selection = from_union([from_none, UserMessageAttachmentSelectionDetails.from_dict], obj.get("selection")) - number = from_union([from_none, from_float], obj.get("number")) - title = from_union([from_none, from_str], obj.get("title")) - reference_type = from_union([from_none, lambda x: parse_enum(UserMessageAttachmentGithubReferenceType, x)], obj.get("referenceType")) - state = from_union([from_none, from_str], obj.get("state")) - url = from_union([from_none, from_str], obj.get("url")) - data = from_union([from_none, from_str], obj.get("data")) - mime_type = from_union([from_none, from_str], obj.get("mimeType")) - return UserMessageAttachment( - type=type, - path=path, - display_name=display_name, - line_range=line_range, - file_path=file_path, - text=text, - selection=selection, - number=number, - title=title, - reference_type=reference_type, - state=state, - url=url, - data=data, - mime_type=mime_type, + name = from_str(obj.get("name")) + owner = from_str(obj.get("owner")) + branch = from_union([from_none, from_str], obj.get("branch")) + return HandoffRepository( + name=name, + owner=owner, + branch=branch, ) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UserMessageAttachmentType, self.type) - if self.path is not None: - result["path"] = from_union([from_none, from_str], self.path) - if self.display_name is not None: - result["displayName"] = from_union([from_none, from_str], self.display_name) - if self.line_range is not None: - result["lineRange"] = from_union([from_none, lambda x: to_class(UserMessageAttachmentFileLineRange, x)], self.line_range) - if self.file_path is not None: - result["filePath"] = from_union([from_none, from_str], self.file_path) - if self.text is not None: - result["text"] = from_union([from_none, from_str], self.text) - if self.selection is not None: - result["selection"] = from_union([from_none, lambda x: to_class(UserMessageAttachmentSelectionDetails, x)], self.selection) - if self.number is not None: - result["number"] = from_union([from_none, to_float], self.number) - if self.title is not None: - result["title"] = from_union([from_none, from_str], self.title) - if self.reference_type is not None: - result["referenceType"] = from_union([from_none, lambda x: to_enum(UserMessageAttachmentGithubReferenceType, x)], self.reference_type) - if self.state is not None: - result["state"] = from_union([from_none, from_str], self.state) - if self.url is not None: - result["url"] = from_union([from_none, from_str], self.url) - if self.data is not None: - result["data"] = from_union([from_none, from_str], self.data) - if self.mime_type is not None: - result["mimeType"] = from_union([from_none, from_str], self.mime_type) + result["name"] = from_str(self.name) + result["owner"] = from_str(self.owner) + if self.branch is not None: + result["branch"] = from_union([from_none, from_str], self.branch) return result @dataclass -class UserMessageData: - content: str - transformed_content: str | None = None - attachments: list[UserMessageAttachment] | None = None - supported_native_document_mime_types: list[str] | None = None - native_document_path_fallback_paths: list[str] | None = None - source: str | None = None - agent_mode: UserMessageAgentMode | None = None - interaction_id: str | None = None +class HookEndData: + "Hook invocation completion details including output, success status, and error information" + hook_invocation_id: str + hook_type: str + success: bool + error: HookEndError | None = None + output: Any = None @staticmethod - def from_dict(obj: Any) -> "UserMessageData": + def from_dict(obj: Any) -> "HookEndData": assert isinstance(obj, dict) - content = from_str(obj.get("content")) - transformed_content = from_union([from_none, from_str], obj.get("transformedContent")) - attachments = from_union([from_none, lambda x: from_list(UserMessageAttachment.from_dict, x)], obj.get("attachments")) - supported_native_document_mime_types = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("supportedNativeDocumentMimeTypes")) - native_document_path_fallback_paths = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("nativeDocumentPathFallbackPaths")) - source = from_union([from_none, from_str], obj.get("source")) - agent_mode = from_union([from_none, lambda x: parse_enum(UserMessageAgentMode, x)], obj.get("agentMode")) - interaction_id = from_union([from_none, from_str], obj.get("interactionId")) - return UserMessageData( - content=content, - transformed_content=transformed_content, - attachments=attachments, - supported_native_document_mime_types=supported_native_document_mime_types, - native_document_path_fallback_paths=native_document_path_fallback_paths, - source=source, - agent_mode=agent_mode, - interaction_id=interaction_id, + hook_invocation_id = from_str(obj.get("hookInvocationId")) + hook_type = from_str(obj.get("hookType")) + success = from_bool(obj.get("success")) + error = from_union([from_none, HookEndError.from_dict], obj.get("error")) + output = obj.get("output") + return HookEndData( + hook_invocation_id=hook_invocation_id, + hook_type=hook_type, + success=success, + error=error, + output=output, ) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - if self.transformed_content is not None: - result["transformedContent"] = from_union([from_none, from_str], self.transformed_content) - if self.attachments is not None: - result["attachments"] = from_union([from_none, lambda x: from_list(lambda x: to_class(UserMessageAttachment, x), x)], self.attachments) - if self.supported_native_document_mime_types is not None: - result["supportedNativeDocumentMimeTypes"] = from_union([from_none, lambda x: from_list(from_str, x)], self.supported_native_document_mime_types) - if self.native_document_path_fallback_paths is not None: - result["nativeDocumentPathFallbackPaths"] = from_union([from_none, lambda x: from_list(from_str, x)], self.native_document_path_fallback_paths) - if self.source is not None: - result["source"] = from_union([from_none, from_str], self.source) - if self.agent_mode is not None: - result["agentMode"] = from_union([from_none, lambda x: to_enum(UserMessageAgentMode, x)], self.agent_mode) - if self.interaction_id is not None: - result["interactionId"] = from_union([from_none, from_str], self.interaction_id) + result["hookInvocationId"] = from_str(self.hook_invocation_id) + result["hookType"] = from_str(self.hook_type) + result["success"] = from_bool(self.success) + if self.error is not None: + result["error"] = from_union([from_none, lambda x: to_class(HookEndError, x)], self.error) + if self.output is not None: + result["output"] = self.output return result @dataclass -class PendingMessagesModifiedData: - "Empty payload; the event signals that the pending message queue has changed" - @staticmethod - def from_dict(obj: Any) -> "PendingMessagesModifiedData": - assert isinstance(obj, dict) - return PendingMessagesModifiedData() - - def to_dict(self) -> dict: - return {} - - -@dataclass -class AssistantTurnStartData: - "Turn initialization metadata including identifier and interaction tracking" - turn_id: str - interaction_id: str | None = None +class HookEndError: + "Error details when the hook failed" + message: str + stack: str | None = None @staticmethod - def from_dict(obj: Any) -> "AssistantTurnStartData": + def from_dict(obj: Any) -> "HookEndError": assert isinstance(obj, dict) - turn_id = from_str(obj.get("turnId")) - interaction_id = from_union([from_none, from_str], obj.get("interactionId")) - return AssistantTurnStartData( - turn_id=turn_id, - interaction_id=interaction_id, + message = from_str(obj.get("message")) + stack = from_union([from_none, from_str], obj.get("stack")) + return HookEndError( + message=message, + stack=stack, ) def to_dict(self) -> dict: result: dict = {} - result["turnId"] = from_str(self.turn_id) - if self.interaction_id is not None: - result["interactionId"] = from_union([from_none, from_str], self.interaction_id) + result["message"] = from_str(self.message) + if self.stack is not None: + result["stack"] = from_union([from_none, from_str], self.stack) return result @dataclass -class AssistantIntentData: - "Agent intent description for current activity or plan" - intent: str +class HookStartData: + "Hook invocation start details including type and input data" + hook_invocation_id: str + hook_type: str + input: Any = None @staticmethod - def from_dict(obj: Any) -> "AssistantIntentData": + def from_dict(obj: Any) -> "HookStartData": assert isinstance(obj, dict) - intent = from_str(obj.get("intent")) - return AssistantIntentData( - intent=intent, + hook_invocation_id = from_str(obj.get("hookInvocationId")) + hook_type = from_str(obj.get("hookType")) + input = obj.get("input") + return HookStartData( + hook_invocation_id=hook_invocation_id, + hook_type=hook_type, + input=input, ) def to_dict(self) -> dict: result: dict = {} - result["intent"] = from_str(self.intent) + result["hookInvocationId"] = from_str(self.hook_invocation_id) + result["hookType"] = from_str(self.hook_type) + if self.input is not None: + result["input"] = self.input return result @dataclass -class AssistantReasoningData: - "Assistant reasoning content for timeline display with complete thinking text" - reasoning_id: str - content: str +class McpOauthCompletedData: + "MCP OAuth request completion notification" + request_id: str @staticmethod - def from_dict(obj: Any) -> "AssistantReasoningData": + def from_dict(obj: Any) -> "McpOauthCompletedData": assert isinstance(obj, dict) - reasoning_id = from_str(obj.get("reasoningId")) - content = from_str(obj.get("content")) - return AssistantReasoningData( - reasoning_id=reasoning_id, - content=content, + request_id = from_str(obj.get("requestId")) + return McpOauthCompletedData( + request_id=request_id, ) def to_dict(self) -> dict: result: dict = {} - result["reasoningId"] = from_str(self.reasoning_id) - result["content"] = from_str(self.content) + result["requestId"] = from_str(self.request_id) return result @dataclass -class AssistantReasoningDeltaData: - "Streaming reasoning delta for incremental extended thinking updates" - reasoning_id: str - delta_content: str +class McpOauthRequiredData: + "OAuth authentication request for an MCP server" + request_id: str + server_name: str + server_url: str + static_client_config: McpOauthRequiredStaticClientConfig | None = None @staticmethod - def from_dict(obj: Any) -> "AssistantReasoningDeltaData": + def from_dict(obj: Any) -> "McpOauthRequiredData": assert isinstance(obj, dict) - reasoning_id = from_str(obj.get("reasoningId")) - delta_content = from_str(obj.get("deltaContent")) - return AssistantReasoningDeltaData( - reasoning_id=reasoning_id, - delta_content=delta_content, + request_id = from_str(obj.get("requestId")) + server_name = from_str(obj.get("serverName")) + server_url = from_str(obj.get("serverUrl")) + static_client_config = from_union([from_none, McpOauthRequiredStaticClientConfig.from_dict], obj.get("staticClientConfig")) + return McpOauthRequiredData( + request_id=request_id, + server_name=server_name, + server_url=server_url, + static_client_config=static_client_config, ) def to_dict(self) -> dict: result: dict = {} - result["reasoningId"] = from_str(self.reasoning_id) - result["deltaContent"] = from_str(self.delta_content) + result["requestId"] = from_str(self.request_id) + result["serverName"] = from_str(self.server_name) + result["serverUrl"] = from_str(self.server_url) + if self.static_client_config is not None: + result["staticClientConfig"] = from_union([from_none, lambda x: to_class(McpOauthRequiredStaticClientConfig, x)], self.static_client_config) return result @dataclass -class AssistantStreamingDeltaData: - "Streaming response progress with cumulative byte count" - total_response_size_bytes: float +class McpOauthRequiredStaticClientConfig: + "Static OAuth client configuration, if the server specifies one" + client_id: str + public_client: bool | None = None @staticmethod - def from_dict(obj: Any) -> "AssistantStreamingDeltaData": + def from_dict(obj: Any) -> "McpOauthRequiredStaticClientConfig": assert isinstance(obj, dict) - total_response_size_bytes = from_float(obj.get("totalResponseSizeBytes")) - return AssistantStreamingDeltaData( - total_response_size_bytes=total_response_size_bytes, + client_id = from_str(obj.get("clientId")) + public_client = from_union([from_none, from_bool], obj.get("publicClient")) + return McpOauthRequiredStaticClientConfig( + client_id=client_id, + public_client=public_client, ) def to_dict(self) -> dict: result: dict = {} - result["totalResponseSizeBytes"] = to_float(self.total_response_size_bytes) + result["clientId"] = from_str(self.client_id) + if self.public_client is not None: + result["publicClient"] = from_union([from_none, from_bool], self.public_client) return result @dataclass -class AssistantMessageToolRequest: - "A tool invocation request from the assistant" - tool_call_id: str +class McpServersLoadedServer: name: str - arguments: Any = None - type: AssistantMessageToolRequestType | None = None - tool_title: str | None = None - mcp_server_name: str | None = None - intention_summary: str | None = None + status: McpServersLoadedServerStatus + error: str | None = None + source: str | None = None @staticmethod - def from_dict(obj: Any) -> "AssistantMessageToolRequest": + def from_dict(obj: Any) -> "McpServersLoadedServer": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) name = from_str(obj.get("name")) - arguments = obj.get("arguments") - type = from_union([from_none, lambda x: parse_enum(AssistantMessageToolRequestType, x)], obj.get("type")) - tool_title = from_union([from_none, from_str], obj.get("toolTitle")) - mcp_server_name = from_union([from_none, from_str], obj.get("mcpServerName")) - intention_summary = from_union([from_none, from_str], obj.get("intentionSummary")) - return AssistantMessageToolRequest( - tool_call_id=tool_call_id, + status = parse_enum(McpServersLoadedServerStatus, obj.get("status")) + error = from_union([from_none, from_str], obj.get("error")) + source = from_union([from_none, from_str], obj.get("source")) + return McpServersLoadedServer( name=name, - arguments=arguments, - type=type, - tool_title=tool_title, - mcp_server_name=mcp_server_name, - intention_summary=intention_summary, + status=status, + error=error, + source=source, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) result["name"] = from_str(self.name) - if self.arguments is not None: - result["arguments"] = self.arguments - if self.type is not None: - result["type"] = from_union([from_none, lambda x: to_enum(AssistantMessageToolRequestType, x)], self.type) - if self.tool_title is not None: - result["toolTitle"] = from_union([from_none, from_str], self.tool_title) - if self.mcp_server_name is not None: - result["mcpServerName"] = from_union([from_none, from_str], self.mcp_server_name) - if self.intention_summary is not None: - result["intentionSummary"] = from_union([from_none, from_str], self.intention_summary) + result["status"] = to_enum(McpServersLoadedServerStatus, self.status) + if self.error is not None: + result["error"] = from_union([from_none, from_str], self.error) + if self.source is not None: + result["source"] = from_union([from_none, from_str], self.source) return result @dataclass -class AssistantMessageData: - "Assistant response containing text content, optional tool requests, and interaction metadata" - message_id: str - content: str - tool_requests: list[AssistantMessageToolRequest] | None = None - reasoning_opaque: str | None = None - reasoning_text: str | None = None - encrypted_content: str | None = None - phase: str | None = None - output_tokens: float | None = None - interaction_id: str | None = None - request_id: str | None = None - # Deprecated: this field is deprecated. - parent_tool_call_id: str | None = None +class PendingMessagesModifiedData: + "Empty payload; the event signals that the pending message queue has changed" + @staticmethod + def from_dict(obj: Any) -> "PendingMessagesModifiedData": + assert isinstance(obj, dict) + return PendingMessagesModifiedData() + + def to_dict(self) -> dict: + return {} + + +@dataclass +class PermissionCompletedData: + "Permission request completion notification signaling UI dismissal" + request_id: str + result: PermissionCompletedResult @staticmethod - def from_dict(obj: Any) -> "AssistantMessageData": + def from_dict(obj: Any) -> "PermissionCompletedData": assert isinstance(obj, dict) - message_id = from_str(obj.get("messageId")) - content = from_str(obj.get("content")) - tool_requests = from_union([from_none, lambda x: from_list(AssistantMessageToolRequest.from_dict, x)], obj.get("toolRequests")) - reasoning_opaque = from_union([from_none, from_str], obj.get("reasoningOpaque")) - reasoning_text = from_union([from_none, from_str], obj.get("reasoningText")) - encrypted_content = from_union([from_none, from_str], obj.get("encryptedContent")) - phase = from_union([from_none, from_str], obj.get("phase")) - output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) - interaction_id = from_union([from_none, from_str], obj.get("interactionId")) - request_id = from_union([from_none, from_str], obj.get("requestId")) - parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) - return AssistantMessageData( - message_id=message_id, - content=content, - tool_requests=tool_requests, - reasoning_opaque=reasoning_opaque, - reasoning_text=reasoning_text, - encrypted_content=encrypted_content, - phase=phase, - output_tokens=output_tokens, - interaction_id=interaction_id, + request_id = from_str(obj.get("requestId")) + result = PermissionCompletedResult.from_dict(obj.get("result")) + return PermissionCompletedData( request_id=request_id, - parent_tool_call_id=parent_tool_call_id, + result=result, ) def to_dict(self) -> dict: result: dict = {} - result["messageId"] = from_str(self.message_id) - result["content"] = from_str(self.content) - if self.tool_requests is not None: - result["toolRequests"] = from_union([from_none, lambda x: from_list(lambda x: to_class(AssistantMessageToolRequest, x), x)], self.tool_requests) - if self.reasoning_opaque is not None: - result["reasoningOpaque"] = from_union([from_none, from_str], self.reasoning_opaque) - if self.reasoning_text is not None: - result["reasoningText"] = from_union([from_none, from_str], self.reasoning_text) - if self.encrypted_content is not None: - result["encryptedContent"] = from_union([from_none, from_str], self.encrypted_content) - if self.phase is not None: - result["phase"] = from_union([from_none, from_str], self.phase) - if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) - if self.interaction_id is not None: - result["interactionId"] = from_union([from_none, from_str], self.interaction_id) - if self.request_id is not None: - result["requestId"] = from_union([from_none, from_str], self.request_id) - if self.parent_tool_call_id is not None: - result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) + result["requestId"] = from_str(self.request_id) + result["result"] = to_class(PermissionCompletedResult, self.result) return result @dataclass -class AssistantMessageDeltaData: - "Streaming assistant message delta for incremental response updates" - message_id: str - delta_content: str - # Deprecated: this field is deprecated. - parent_tool_call_id: str | None = None +class PermissionCompletedResult: + "The result of the permission request" + kind: PermissionCompletedKind @staticmethod - def from_dict(obj: Any) -> "AssistantMessageDeltaData": + def from_dict(obj: Any) -> "PermissionCompletedResult": assert isinstance(obj, dict) - message_id = from_str(obj.get("messageId")) - delta_content = from_str(obj.get("deltaContent")) - parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) - return AssistantMessageDeltaData( - message_id=message_id, - delta_content=delta_content, - parent_tool_call_id=parent_tool_call_id, + kind = parse_enum(PermissionCompletedKind, obj.get("kind")) + return PermissionCompletedResult( + kind=kind, ) def to_dict(self) -> dict: result: dict = {} - result["messageId"] = from_str(self.message_id) - result["deltaContent"] = from_str(self.delta_content) - if self.parent_tool_call_id is not None: - result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) + result["kind"] = to_enum(PermissionCompletedKind, self.kind) return result @dataclass -class AssistantTurnEndData: - "Turn completion metadata including the turn identifier" - turn_id: str +class PermissionRequest: + "Details of the permission being requested" + kind: PermissionRequestKind + action: PermissionRequestMemoryAction | None = None + args: Any = None + can_offer_session_approval: bool | None = None + citations: str | None = None + commands: list[PermissionRequestShellCommand] | None = None + diff: str | None = None + direction: PermissionRequestMemoryDirection | None = None + fact: str | None = None + file_name: str | None = None + full_command_text: str | None = None + has_write_file_redirection: bool | None = None + hook_message: str | None = None + intention: str | None = None + new_file_contents: str | None = None + path: str | None = None + possible_paths: list[str] | None = None + possible_urls: list[PermissionRequestShellPossibleUrl] | None = None + read_only: bool | None = None + reason: str | None = None + server_name: str | None = None + subject: str | None = None + tool_args: Any = None + tool_call_id: str | None = None + tool_description: str | None = None + tool_name: str | None = None + tool_title: str | None = None + url: str | None = None + warning: str | None = None @staticmethod - def from_dict(obj: Any) -> "AssistantTurnEndData": + def from_dict(obj: Any) -> "PermissionRequest": assert isinstance(obj, dict) - turn_id = from_str(obj.get("turnId")) - return AssistantTurnEndData( - turn_id=turn_id, + kind = parse_enum(PermissionRequestKind, obj.get("kind")) + action = from_union([from_none, lambda x: parse_enum(PermissionRequestMemoryAction, x)], obj.get("action", "store")) + args = obj.get("args") + can_offer_session_approval = from_union([from_none, from_bool], obj.get("canOfferSessionApproval")) + citations = from_union([from_none, from_str], obj.get("citations")) + commands = from_union([from_none, lambda x: from_list(PermissionRequestShellCommand.from_dict, x)], obj.get("commands")) + diff = from_union([from_none, from_str], obj.get("diff")) + direction = from_union([from_none, lambda x: parse_enum(PermissionRequestMemoryDirection, x)], obj.get("direction")) + fact = from_union([from_none, from_str], obj.get("fact")) + file_name = from_union([from_none, from_str], obj.get("fileName")) + full_command_text = from_union([from_none, from_str], obj.get("fullCommandText")) + has_write_file_redirection = from_union([from_none, from_bool], obj.get("hasWriteFileRedirection")) + hook_message = from_union([from_none, from_str], obj.get("hookMessage")) + intention = from_union([from_none, from_str], obj.get("intention")) + new_file_contents = from_union([from_none, from_str], obj.get("newFileContents")) + path = from_union([from_none, from_str], obj.get("path")) + possible_paths = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("possiblePaths")) + possible_urls = from_union([from_none, lambda x: from_list(PermissionRequestShellPossibleUrl.from_dict, x)], obj.get("possibleUrls")) + read_only = from_union([from_none, from_bool], obj.get("readOnly")) + reason = from_union([from_none, from_str], obj.get("reason")) + server_name = from_union([from_none, from_str], obj.get("serverName")) + subject = from_union([from_none, from_str], obj.get("subject")) + tool_args = obj.get("toolArgs") + tool_call_id = from_union([from_none, from_str], obj.get("toolCallId")) + tool_description = from_union([from_none, from_str], obj.get("toolDescription")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + tool_title = from_union([from_none, from_str], obj.get("toolTitle")) + url = from_union([from_none, from_str], obj.get("url")) + warning = from_union([from_none, from_str], obj.get("warning")) + return PermissionRequest( + kind=kind, + action=action, + args=args, + can_offer_session_approval=can_offer_session_approval, + citations=citations, + commands=commands, + diff=diff, + direction=direction, + fact=fact, + file_name=file_name, + full_command_text=full_command_text, + has_write_file_redirection=has_write_file_redirection, + hook_message=hook_message, + intention=intention, + new_file_contents=new_file_contents, + path=path, + possible_paths=possible_paths, + possible_urls=possible_urls, + read_only=read_only, + reason=reason, + server_name=server_name, + subject=subject, + tool_args=tool_args, + tool_call_id=tool_call_id, + tool_description=tool_description, + tool_name=tool_name, + tool_title=tool_title, + url=url, + warning=warning, ) def to_dict(self) -> dict: result: dict = {} - result["turnId"] = from_str(self.turn_id) + result["kind"] = to_enum(PermissionRequestKind, self.kind) + if self.action is not None: + result["action"] = from_union([from_none, lambda x: to_enum(PermissionRequestMemoryAction, x)], self.action) + if self.args is not None: + result["args"] = self.args + if self.can_offer_session_approval is not None: + result["canOfferSessionApproval"] = from_union([from_none, from_bool], self.can_offer_session_approval) + if self.citations is not None: + result["citations"] = from_union([from_none, from_str], self.citations) + if self.commands is not None: + result["commands"] = from_union([from_none, lambda x: from_list(lambda x: to_class(PermissionRequestShellCommand, x), x)], self.commands) + if self.diff is not None: + result["diff"] = from_union([from_none, from_str], self.diff) + if self.direction is not None: + result["direction"] = from_union([from_none, lambda x: to_enum(PermissionRequestMemoryDirection, x)], self.direction) + if self.fact is not None: + result["fact"] = from_union([from_none, from_str], self.fact) + if self.file_name is not None: + result["fileName"] = from_union([from_none, from_str], self.file_name) + if self.full_command_text is not None: + result["fullCommandText"] = from_union([from_none, from_str], self.full_command_text) + if self.has_write_file_redirection is not None: + result["hasWriteFileRedirection"] = from_union([from_none, from_bool], self.has_write_file_redirection) + if self.hook_message is not None: + result["hookMessage"] = from_union([from_none, from_str], self.hook_message) + if self.intention is not None: + result["intention"] = from_union([from_none, from_str], self.intention) + if self.new_file_contents is not None: + result["newFileContents"] = from_union([from_none, from_str], self.new_file_contents) + if self.path is not None: + result["path"] = from_union([from_none, from_str], self.path) + if self.possible_paths is not None: + result["possiblePaths"] = from_union([from_none, lambda x: from_list(from_str, x)], self.possible_paths) + if self.possible_urls is not None: + result["possibleUrls"] = from_union([from_none, lambda x: from_list(lambda x: to_class(PermissionRequestShellPossibleUrl, x), x)], self.possible_urls) + if self.read_only is not None: + result["readOnly"] = from_union([from_none, from_bool], self.read_only) + if self.reason is not None: + result["reason"] = from_union([from_none, from_str], self.reason) + if self.server_name is not None: + result["serverName"] = from_union([from_none, from_str], self.server_name) + if self.subject is not None: + result["subject"] = from_union([from_none, from_str], self.subject) + if self.tool_args is not None: + result["toolArgs"] = self.tool_args + if self.tool_call_id is not None: + result["toolCallId"] = from_union([from_none, from_str], self.tool_call_id) + if self.tool_description is not None: + result["toolDescription"] = from_union([from_none, from_str], self.tool_description) + if self.tool_name is not None: + result["toolName"] = from_union([from_none, from_str], self.tool_name) + if self.tool_title is not None: + result["toolTitle"] = from_union([from_none, from_str], self.tool_title) + if self.url is not None: + result["url"] = from_union([from_none, from_str], self.url) + if self.warning is not None: + result["warning"] = from_union([from_none, from_str], self.warning) return result @dataclass -class AssistantUsageQuotaSnapshot: - is_unlimited_entitlement: bool - entitlement_requests: float - used_requests: float - usage_allowed_with_exhausted_quota: bool - overage: float - overage_allowed_with_exhausted_quota: bool - remaining_percentage: float - reset_date: datetime | None = None +class PermissionRequestShellCommand: + identifier: str + read_only: bool @staticmethod - def from_dict(obj: Any) -> "AssistantUsageQuotaSnapshot": + def from_dict(obj: Any) -> "PermissionRequestShellCommand": assert isinstance(obj, dict) - is_unlimited_entitlement = from_bool(obj.get("isUnlimitedEntitlement")) - entitlement_requests = from_float(obj.get("entitlementRequests")) - used_requests = from_float(obj.get("usedRequests")) - usage_allowed_with_exhausted_quota = from_bool(obj.get("usageAllowedWithExhaustedQuota")) - overage = from_float(obj.get("overage")) - overage_allowed_with_exhausted_quota = from_bool(obj.get("overageAllowedWithExhaustedQuota")) - remaining_percentage = from_float(obj.get("remainingPercentage")) - reset_date = from_union([from_none, from_datetime], obj.get("resetDate")) - return AssistantUsageQuotaSnapshot( - is_unlimited_entitlement=is_unlimited_entitlement, - entitlement_requests=entitlement_requests, - used_requests=used_requests, - usage_allowed_with_exhausted_quota=usage_allowed_with_exhausted_quota, - overage=overage, - overage_allowed_with_exhausted_quota=overage_allowed_with_exhausted_quota, - remaining_percentage=remaining_percentage, - reset_date=reset_date, + identifier = from_str(obj.get("identifier")) + read_only = from_bool(obj.get("readOnly")) + return PermissionRequestShellCommand( + identifier=identifier, + read_only=read_only, ) def to_dict(self) -> dict: result: dict = {} - result["isUnlimitedEntitlement"] = from_bool(self.is_unlimited_entitlement) - result["entitlementRequests"] = to_float(self.entitlement_requests) - result["usedRequests"] = to_float(self.used_requests) - result["usageAllowedWithExhaustedQuota"] = from_bool(self.usage_allowed_with_exhausted_quota) - result["overage"] = to_float(self.overage) - result["overageAllowedWithExhaustedQuota"] = from_bool(self.overage_allowed_with_exhausted_quota) - result["remainingPercentage"] = to_float(self.remaining_percentage) - if self.reset_date is not None: - result["resetDate"] = from_union([from_none, to_datetime], self.reset_date) + result["identifier"] = from_str(self.identifier) + result["readOnly"] = from_bool(self.read_only) return result @dataclass -class AssistantUsageCopilotUsageTokenDetail: - "Token usage detail for a single billing category" - batch_size: float - cost_per_batch: float - token_count: float - token_type: str +class PermissionRequestShellPossibleUrl: + url: str @staticmethod - def from_dict(obj: Any) -> "AssistantUsageCopilotUsageTokenDetail": + def from_dict(obj: Any) -> "PermissionRequestShellPossibleUrl": assert isinstance(obj, dict) - batch_size = from_float(obj.get("batchSize")) - cost_per_batch = from_float(obj.get("costPerBatch")) - token_count = from_float(obj.get("tokenCount")) - token_type = from_str(obj.get("tokenType")) - return AssistantUsageCopilotUsageTokenDetail( - batch_size=batch_size, - cost_per_batch=cost_per_batch, - token_count=token_count, - token_type=token_type, + url = from_str(obj.get("url")) + return PermissionRequestShellPossibleUrl( + url=url, ) def to_dict(self) -> dict: result: dict = {} - result["batchSize"] = to_float(self.batch_size) - result["costPerBatch"] = to_float(self.cost_per_batch) - result["tokenCount"] = to_float(self.token_count) - result["tokenType"] = from_str(self.token_type) + result["url"] = from_str(self.url) return result @dataclass -class AssistantUsageCopilotUsage: - "Per-request cost and usage data from the CAPI copilot_usage response field" - token_details: list[AssistantUsageCopilotUsageTokenDetail] - total_nano_aiu: float +class PermissionRequestedData: + "Permission request notification requiring client approval with request details" + permission_request: PermissionRequest + request_id: str + resolved_by_hook: bool | None = None @staticmethod - def from_dict(obj: Any) -> "AssistantUsageCopilotUsage": + def from_dict(obj: Any) -> "PermissionRequestedData": assert isinstance(obj, dict) - token_details = from_list(AssistantUsageCopilotUsageTokenDetail.from_dict, obj.get("tokenDetails")) - total_nano_aiu = from_float(obj.get("totalNanoAiu")) - return AssistantUsageCopilotUsage( - token_details=token_details, - total_nano_aiu=total_nano_aiu, + permission_request = PermissionRequest.from_dict(obj.get("permissionRequest")) + request_id = from_str(obj.get("requestId")) + resolved_by_hook = from_union([from_none, from_bool], obj.get("resolvedByHook")) + return PermissionRequestedData( + permission_request=permission_request, + request_id=request_id, + resolved_by_hook=resolved_by_hook, ) def to_dict(self) -> dict: result: dict = {} - result["tokenDetails"] = from_list(lambda x: to_class(AssistantUsageCopilotUsageTokenDetail, x), self.token_details) - result["totalNanoAiu"] = to_float(self.total_nano_aiu) + result["permissionRequest"] = to_class(PermissionRequest, self.permission_request) + result["requestId"] = from_str(self.request_id) + if self.resolved_by_hook is not None: + result["resolvedByHook"] = from_union([from_none, from_bool], self.resolved_by_hook) return result @dataclass -class AssistantUsageData: - "LLM API call usage metrics including tokens, costs, quotas, and billing information" - model: str - input_tokens: float | None = None - output_tokens: float | None = None - cache_read_tokens: float | None = None - cache_write_tokens: float | None = None - reasoning_tokens: float | None = None - cost: float | None = None - duration: float | None = None - ttft_ms: float | None = None - inter_token_latency_ms: float | None = None - initiator: str | None = None - api_call_id: str | None = None - provider_call_id: str | None = None - # Deprecated: this field is deprecated. - parent_tool_call_id: str | None = None - quota_snapshots: dict[str, AssistantUsageQuotaSnapshot] | None = None - copilot_usage: AssistantUsageCopilotUsage | None = None - reasoning_effort: str | None = None +class SamplingCompletedData: + "Sampling request completion notification signaling UI dismissal" + request_id: str @staticmethod - def from_dict(obj: Any) -> "AssistantUsageData": + def from_dict(obj: Any) -> "SamplingCompletedData": assert isinstance(obj, dict) - model = from_str(obj.get("model")) - input_tokens = from_union([from_none, from_float], obj.get("inputTokens")) - output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) - cache_read_tokens = from_union([from_none, from_float], obj.get("cacheReadTokens")) - cache_write_tokens = from_union([from_none, from_float], obj.get("cacheWriteTokens")) - reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) - cost = from_union([from_none, from_float], obj.get("cost")) - duration = from_union([from_none, from_float], obj.get("duration")) - ttft_ms = from_union([from_none, from_float], obj.get("ttftMs")) - inter_token_latency_ms = from_union([from_none, from_float], obj.get("interTokenLatencyMs")) - initiator = from_union([from_none, from_str], obj.get("initiator")) - api_call_id = from_union([from_none, from_str], obj.get("apiCallId")) - provider_call_id = from_union([from_none, from_str], obj.get("providerCallId")) - parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) - quota_snapshots = from_union([from_none, lambda x: from_dict(AssistantUsageQuotaSnapshot.from_dict, x)], obj.get("quotaSnapshots")) - copilot_usage = from_union([from_none, AssistantUsageCopilotUsage.from_dict], obj.get("copilotUsage")) - reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) - return AssistantUsageData( - model=model, - input_tokens=input_tokens, - output_tokens=output_tokens, - cache_read_tokens=cache_read_tokens, - cache_write_tokens=cache_write_tokens, - reasoning_tokens=reasoning_tokens, - cost=cost, - duration=duration, - ttft_ms=ttft_ms, - inter_token_latency_ms=inter_token_latency_ms, - initiator=initiator, - api_call_id=api_call_id, - provider_call_id=provider_call_id, - parent_tool_call_id=parent_tool_call_id, - quota_snapshots=quota_snapshots, - copilot_usage=copilot_usage, - reasoning_effort=reasoning_effort, + request_id = from_str(obj.get("requestId")) + return SamplingCompletedData( + request_id=request_id, ) def to_dict(self) -> dict: result: dict = {} - result["model"] = from_str(self.model) - if self.input_tokens is not None: - result["inputTokens"] = from_union([from_none, to_float], self.input_tokens) - if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) - if self.cache_read_tokens is not None: - result["cacheReadTokens"] = from_union([from_none, to_float], self.cache_read_tokens) - if self.cache_write_tokens is not None: - result["cacheWriteTokens"] = from_union([from_none, to_float], self.cache_write_tokens) - if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) - if self.cost is not None: - result["cost"] = from_union([from_none, to_float], self.cost) - if self.duration is not None: - result["duration"] = from_union([from_none, to_float], self.duration) - if self.ttft_ms is not None: - result["ttftMs"] = from_union([from_none, to_float], self.ttft_ms) - if self.inter_token_latency_ms is not None: - result["interTokenLatencyMs"] = from_union([from_none, to_float], self.inter_token_latency_ms) - if self.initiator is not None: - result["initiator"] = from_union([from_none, from_str], self.initiator) - if self.api_call_id is not None: - result["apiCallId"] = from_union([from_none, from_str], self.api_call_id) - if self.provider_call_id is not None: - result["providerCallId"] = from_union([from_none, from_str], self.provider_call_id) - if self.parent_tool_call_id is not None: - result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) - if self.quota_snapshots is not None: - result["quotaSnapshots"] = from_union([from_none, lambda x: from_dict(lambda x: to_class(AssistantUsageQuotaSnapshot, x), x)], self.quota_snapshots) - if self.copilot_usage is not None: - result["copilotUsage"] = from_union([from_none, lambda x: to_class(AssistantUsageCopilotUsage, x)], self.copilot_usage) - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) + result["requestId"] = from_str(self.request_id) return result @dataclass -class AbortData: - "Turn abort information including the reason for termination" - reason: str +class SamplingRequestedData: + "Sampling request from an MCP server; contains the server name and a requestId for correlation" + mcp_request_id: Any + request_id: str + server_name: str @staticmethod - def from_dict(obj: Any) -> "AbortData": + def from_dict(obj: Any) -> "SamplingRequestedData": assert isinstance(obj, dict) - reason = from_str(obj.get("reason")) - return AbortData( - reason=reason, + mcp_request_id = obj.get("mcpRequestId") + request_id = from_str(obj.get("requestId")) + server_name = from_str(obj.get("serverName")) + return SamplingRequestedData( + mcp_request_id=mcp_request_id, + request_id=request_id, + server_name=server_name, ) def to_dict(self) -> dict: result: dict = {} - result["reason"] = from_str(self.reason) + result["mcpRequestId"] = self.mcp_request_id + result["requestId"] = from_str(self.request_id) + result["serverName"] = from_str(self.server_name) return result @dataclass -class ToolUserRequestedData: - "User-initiated tool invocation request with tool name and arguments" - tool_call_id: str - tool_name: str - arguments: Any = None - +class SessionBackgroundTasksChangedData: @staticmethod - def from_dict(obj: Any) -> "ToolUserRequestedData": + def from_dict(obj: Any) -> "SessionBackgroundTasksChangedData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - tool_name = from_str(obj.get("toolName")) - arguments = obj.get("arguments") - return ToolUserRequestedData( - tool_call_id=tool_call_id, - tool_name=tool_name, - arguments=arguments, - ) + return SessionBackgroundTasksChangedData() def to_dict(self) -> dict: - result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["toolName"] = from_str(self.tool_name) - if self.arguments is not None: - result["arguments"] = self.arguments - return result + return {} @dataclass -class ToolExecutionStartData: - "Tool execution startup details including MCP server information when applicable" - tool_call_id: str - tool_name: str - arguments: Any = None - mcp_server_name: str | None = None - mcp_tool_name: str | None = None - # Deprecated: this field is deprecated. - parent_tool_call_id: str | None = None +class SessionCompactionCompleteData: + "Conversation compaction results including success status, metrics, and optional error details" + success: bool + checkpoint_number: float | None = None + checkpoint_path: str | None = None + compaction_tokens_used: CompactionCompleteCompactionTokensUsed | None = None + conversation_tokens: float | None = None + error: str | None = None + messages_removed: float | None = None + post_compaction_tokens: float | None = None + pre_compaction_messages_length: float | None = None + pre_compaction_tokens: float | None = None + request_id: str | None = None + summary_content: str | None = None + system_tokens: float | None = None + tokens_removed: float | None = None + tool_definitions_tokens: float | None = None @staticmethod - def from_dict(obj: Any) -> "ToolExecutionStartData": + def from_dict(obj: Any) -> "SessionCompactionCompleteData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - tool_name = from_str(obj.get("toolName")) - arguments = obj.get("arguments") - mcp_server_name = from_union([from_none, from_str], obj.get("mcpServerName")) - mcp_tool_name = from_union([from_none, from_str], obj.get("mcpToolName")) - parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) - return ToolExecutionStartData( - tool_call_id=tool_call_id, - tool_name=tool_name, - arguments=arguments, - mcp_server_name=mcp_server_name, - mcp_tool_name=mcp_tool_name, - parent_tool_call_id=parent_tool_call_id, + success = from_bool(obj.get("success")) + checkpoint_number = from_union([from_none, from_float], obj.get("checkpointNumber")) + 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_float], obj.get("conversationTokens")) + error = from_union([from_none, from_str], obj.get("error")) + messages_removed = from_union([from_none, from_float], obj.get("messagesRemoved")) + post_compaction_tokens = from_union([from_none, from_float], obj.get("postCompactionTokens")) + pre_compaction_messages_length = from_union([from_none, from_float], obj.get("preCompactionMessagesLength")) + pre_compaction_tokens = from_union([from_none, from_float], obj.get("preCompactionTokens")) + request_id = from_union([from_none, from_str], obj.get("requestId")) + summary_content = from_union([from_none, from_str], obj.get("summaryContent")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + tokens_removed = from_union([from_none, from_float], obj.get("tokensRemoved")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + return SessionCompactionCompleteData( + success=success, + checkpoint_number=checkpoint_number, + checkpoint_path=checkpoint_path, + compaction_tokens_used=compaction_tokens_used, + conversation_tokens=conversation_tokens, + error=error, + messages_removed=messages_removed, + post_compaction_tokens=post_compaction_tokens, + pre_compaction_messages_length=pre_compaction_messages_length, + pre_compaction_tokens=pre_compaction_tokens, + request_id=request_id, + summary_content=summary_content, + system_tokens=system_tokens, + tokens_removed=tokens_removed, + tool_definitions_tokens=tool_definitions_tokens, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["toolName"] = from_str(self.tool_name) - if self.arguments is not None: - result["arguments"] = self.arguments - if self.mcp_server_name is not None: - result["mcpServerName"] = from_union([from_none, from_str], self.mcp_server_name) - if self.mcp_tool_name is not None: - result["mcpToolName"] = from_union([from_none, from_str], self.mcp_tool_name) - if self.parent_tool_call_id is not None: - result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) + result["success"] = from_bool(self.success) + if self.checkpoint_number is not None: + result["checkpointNumber"] = from_union([from_none, to_float], self.checkpoint_number) + if self.checkpoint_path is not None: + result["checkpointPath"] = from_union([from_none, from_str], self.checkpoint_path) + if self.compaction_tokens_used is not None: + 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_float], self.conversation_tokens) + if self.error is not None: + result["error"] = from_union([from_none, from_str], self.error) + if self.messages_removed is not None: + result["messagesRemoved"] = from_union([from_none, to_float], self.messages_removed) + if self.post_compaction_tokens is not None: + result["postCompactionTokens"] = from_union([from_none, to_float], self.post_compaction_tokens) + if self.pre_compaction_messages_length is not None: + result["preCompactionMessagesLength"] = from_union([from_none, to_float], self.pre_compaction_messages_length) + if self.pre_compaction_tokens is not None: + result["preCompactionTokens"] = from_union([from_none, to_float], self.pre_compaction_tokens) + if self.request_id is not None: + result["requestId"] = from_union([from_none, from_str], self.request_id) + if self.summary_content is not None: + result["summaryContent"] = from_union([from_none, from_str], self.summary_content) + if self.system_tokens is not None: + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + if self.tokens_removed is not None: + result["tokensRemoved"] = from_union([from_none, to_float], self.tokens_removed) + if self.tool_definitions_tokens is not None: + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) return result @dataclass -class ToolExecutionPartialResultData: - "Streaming tool execution output for incremental result display" - tool_call_id: str - partial_output: str +class SessionCompactionStartData: + "Context window breakdown at the start of LLM-powered conversation compaction" + conversation_tokens: float | None = None + system_tokens: float | None = None + tool_definitions_tokens: float | None = None @staticmethod - def from_dict(obj: Any) -> "ToolExecutionPartialResultData": + def from_dict(obj: Any) -> "SessionCompactionStartData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - partial_output = from_str(obj.get("partialOutput")) - return ToolExecutionPartialResultData( - tool_call_id=tool_call_id, - partial_output=partial_output, + conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + return SessionCompactionStartData( + conversation_tokens=conversation_tokens, + system_tokens=system_tokens, + tool_definitions_tokens=tool_definitions_tokens, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["partialOutput"] = from_str(self.partial_output) + if self.conversation_tokens is not None: + result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) + if self.system_tokens is not None: + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + if self.tool_definitions_tokens is not None: + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) return result @dataclass -class ToolExecutionProgressData: - "Tool execution progress notification with status message" - tool_call_id: str - progress_message: str +class SessionContextChangedData: + "Working directory and git context at session start" + cwd: str + base_commit: str | None = None + branch: str | None = None + git_root: str | None = None + head_commit: str | None = None + host_type: WorkingDirectoryContextHostType | None = None + repository: str | None = None + repository_host: str | None = None @staticmethod - def from_dict(obj: Any) -> "ToolExecutionProgressData": + def from_dict(obj: Any) -> "SessionContextChangedData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - progress_message = from_str(obj.get("progressMessage")) - return ToolExecutionProgressData( - tool_call_id=tool_call_id, - progress_message=progress_message, + cwd = from_str(obj.get("cwd")) + base_commit = from_union([from_none, from_str], obj.get("baseCommit")) + branch = from_union([from_none, from_str], obj.get("branch")) + git_root = from_union([from_none, from_str], obj.get("gitRoot")) + head_commit = from_union([from_none, from_str], obj.get("headCommit")) + host_type = from_union([from_none, lambda x: parse_enum(WorkingDirectoryContextHostType, x)], obj.get("hostType")) + repository = from_union([from_none, from_str], obj.get("repository")) + repository_host = from_union([from_none, from_str], obj.get("repositoryHost")) + return SessionContextChangedData( + cwd=cwd, + base_commit=base_commit, + branch=branch, + git_root=git_root, + head_commit=head_commit, + host_type=host_type, + repository=repository, + repository_host=repository_host, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["progressMessage"] = from_str(self.progress_message) + result["cwd"] = from_str(self.cwd) + if self.base_commit is not None: + result["baseCommit"] = from_union([from_none, from_str], self.base_commit) + if self.branch is not None: + result["branch"] = from_union([from_none, from_str], self.branch) + if self.git_root is not None: + result["gitRoot"] = from_union([from_none, from_str], self.git_root) + if self.head_commit is not None: + result["headCommit"] = from_union([from_none, from_str], self.head_commit) + if self.host_type is not None: + result["hostType"] = from_union([from_none, lambda x: to_enum(WorkingDirectoryContextHostType, x)], self.host_type) + if self.repository is not None: + result["repository"] = from_union([from_none, from_str], self.repository) + if self.repository_host is not None: + result["repositoryHost"] = from_union([from_none, from_str], self.repository_host) return result @dataclass -class ToolExecutionCompleteDataResultContentsItemIconsItem: - "Icon image for a resource" - src: str - mime_type: str | None = None - sizes: list[str] | None = None - theme: ToolExecutionCompleteDataResultContentsItemIconsItemTheme | None = None +class SessionCustomAgentsUpdatedData: + agents: list[CustomAgentsUpdatedAgent] + errors: list[str] + warnings: list[str] @staticmethod - def from_dict(obj: Any) -> "ToolExecutionCompleteDataResultContentsItemIconsItem": + def from_dict(obj: Any) -> "SessionCustomAgentsUpdatedData": assert isinstance(obj, dict) - src = from_str(obj.get("src")) - mime_type = from_union([from_none, from_str], obj.get("mimeType")) - sizes = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("sizes")) - theme = from_union([from_none, lambda x: parse_enum(ToolExecutionCompleteDataResultContentsItemIconsItemTheme, x)], obj.get("theme")) - return ToolExecutionCompleteDataResultContentsItemIconsItem( - src=src, - mime_type=mime_type, - sizes=sizes, - theme=theme, + agents = from_list(CustomAgentsUpdatedAgent.from_dict, obj.get("agents")) + errors = from_list(from_str, obj.get("errors")) + warnings = from_list(from_str, obj.get("warnings")) + return SessionCustomAgentsUpdatedData( + agents=agents, + errors=errors, + warnings=warnings, ) def to_dict(self) -> dict: result: dict = {} - result["src"] = from_str(self.src) - if self.mime_type is not None: - result["mimeType"] = from_union([from_none, from_str], self.mime_type) - if self.sizes is not None: - result["sizes"] = from_union([from_none, lambda x: from_list(from_str, x)], self.sizes) - if self.theme is not None: - result["theme"] = from_union([from_none, lambda x: to_enum(ToolExecutionCompleteDataResultContentsItemIconsItemTheme, x)], self.theme) + result["agents"] = from_list(lambda x: to_class(CustomAgentsUpdatedAgent, x), self.agents) + result["errors"] = from_list(from_str, self.errors) + result["warnings"] = from_list(from_str, self.warnings) return result @dataclass -class ToolExecutionCompleteDataResultContentsItem: - "A content block within a tool result, which may be text, terminal output, image, audio, or a resource" - type: ToolExecutionCompleteDataResultContentsItemType - text: str | None = None - exit_code: float | None = None - cwd: str | None = None - data: str | None = None - mime_type: str | None = None - icons: list[ToolExecutionCompleteDataResultContentsItemIconsItem] | None = None - name: str | None = None - title: str | None = None - uri: str | None = None - description: str | None = None - size: float | None = None - resource: Any = None +class SessionErrorData: + "Error details for timeline display including message and optional diagnostic information" + error_type: str + message: str + provider_call_id: str | None = None + stack: str | None = None + status_code: int | None = None + url: str | None = None @staticmethod - def from_dict(obj: Any) -> "ToolExecutionCompleteDataResultContentsItem": + def from_dict(obj: Any) -> "SessionErrorData": assert isinstance(obj, dict) - type = parse_enum(ToolExecutionCompleteDataResultContentsItemType, obj.get("type")) - text = from_union([from_none, from_str], obj.get("text")) - exit_code = from_union([from_none, from_float], obj.get("exitCode")) - cwd = from_union([from_none, from_str], obj.get("cwd")) - data = from_union([from_none, from_str], obj.get("data")) - mime_type = from_union([from_none, from_str], obj.get("mimeType")) - icons = from_union([from_none, lambda x: from_list(ToolExecutionCompleteDataResultContentsItemIconsItem.from_dict, x)], obj.get("icons")) - name = from_union([from_none, from_str], obj.get("name")) - title = from_union([from_none, from_str], obj.get("title")) - uri = from_union([from_none, from_str], obj.get("uri")) - description = from_union([from_none, from_str], obj.get("description")) - size = from_union([from_none, from_float], obj.get("size")) - resource = obj.get("resource") - return ToolExecutionCompleteDataResultContentsItem( - type=type, - text=text, - exit_code=exit_code, - cwd=cwd, - data=data, - mime_type=mime_type, - icons=icons, - name=name, - title=title, - uri=uri, - description=description, - size=size, - resource=resource, + error_type = from_str(obj.get("errorType")) + message = from_str(obj.get("message")) + provider_call_id = from_union([from_none, from_str], obj.get("providerCallId")) + stack = from_union([from_none, from_str], obj.get("stack")) + status_code = from_union([from_none, from_int], obj.get("statusCode")) + url = from_union([from_none, from_str], obj.get("url")) + return SessionErrorData( + error_type=error_type, + message=message, + provider_call_id=provider_call_id, + stack=stack, + status_code=status_code, + url=url, ) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(ToolExecutionCompleteDataResultContentsItemType, self.type) - if self.text is not None: - result["text"] = from_union([from_none, from_str], self.text) - if self.exit_code is not None: - result["exitCode"] = from_union([from_none, to_float], self.exit_code) - if self.cwd is not None: - result["cwd"] = from_union([from_none, from_str], self.cwd) - if self.data is not None: - result["data"] = from_union([from_none, from_str], self.data) - if self.mime_type is not None: - result["mimeType"] = from_union([from_none, from_str], self.mime_type) - if self.icons is not None: - result["icons"] = from_union([from_none, lambda x: from_list(lambda x: to_class(ToolExecutionCompleteDataResultContentsItemIconsItem, x), x)], self.icons) - if self.name is not None: - result["name"] = from_union([from_none, from_str], self.name) - if self.title is not None: - result["title"] = from_union([from_none, from_str], self.title) - if self.uri is not None: - result["uri"] = from_union([from_none, from_str], self.uri) - if self.description is not None: - result["description"] = from_union([from_none, from_str], self.description) - if self.size is not None: - result["size"] = from_union([from_none, to_float], self.size) - if self.resource is not None: - result["resource"] = self.resource + result["errorType"] = from_str(self.error_type) + result["message"] = from_str(self.message) + if self.provider_call_id is not None: + result["providerCallId"] = from_union([from_none, from_str], self.provider_call_id) + if self.stack is not None: + result["stack"] = from_union([from_none, from_str], self.stack) + if self.status_code is not None: + result["statusCode"] = from_union([from_none, to_int], self.status_code) + if self.url is not None: + result["url"] = from_union([from_none, from_str], self.url) return result @dataclass -class ToolExecutionCompleteDataResult: - "Tool execution result on success" - content: str - detailed_content: str | None = None - contents: list[ToolExecutionCompleteDataResultContentsItem] | None = None +class SessionExtensionsLoadedData: + extensions: list[ExtensionsLoadedExtension] @staticmethod - def from_dict(obj: Any) -> "ToolExecutionCompleteDataResult": + def from_dict(obj: Any) -> "SessionExtensionsLoadedData": assert isinstance(obj, dict) - content = from_str(obj.get("content")) - detailed_content = from_union([from_none, from_str], obj.get("detailedContent")) - contents = from_union([from_none, lambda x: from_list(ToolExecutionCompleteDataResultContentsItem.from_dict, x)], obj.get("contents")) - return ToolExecutionCompleteDataResult( - content=content, - detailed_content=detailed_content, - contents=contents, + extensions = from_list(ExtensionsLoadedExtension.from_dict, obj.get("extensions")) + return SessionExtensionsLoadedData( + extensions=extensions, ) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - if self.detailed_content is not None: - result["detailedContent"] = from_union([from_none, from_str], self.detailed_content) - if self.contents is not None: - result["contents"] = from_union([from_none, lambda x: from_list(lambda x: to_class(ToolExecutionCompleteDataResultContentsItem, x), x)], self.contents) + result["extensions"] = from_list(lambda x: to_class(ExtensionsLoadedExtension, x), self.extensions) return result @dataclass -class ToolExecutionCompleteDataError: - "Error details when the tool execution failed" - message: str - code: str | None = None +class SessionHandoffData: + "Session handoff metadata including source, context, and repository information" + handoff_time: datetime + source_type: HandoffSourceType + context: str | None = None + host: str | None = None + remote_session_id: str | None = None + repository: HandoffRepository | None = None + summary: str | None = None @staticmethod - def from_dict(obj: Any) -> "ToolExecutionCompleteDataError": + def from_dict(obj: Any) -> "SessionHandoffData": assert isinstance(obj, dict) - message = from_str(obj.get("message")) - code = from_union([from_none, from_str], obj.get("code")) - return ToolExecutionCompleteDataError( - message=message, - code=code, + handoff_time = from_datetime(obj.get("handoffTime")) + source_type = parse_enum(HandoffSourceType, obj.get("sourceType")) + context = from_union([from_none, from_str], obj.get("context")) + host = from_union([from_none, from_str], obj.get("host")) + remote_session_id = from_union([from_none, from_str], obj.get("remoteSessionId")) + repository = from_union([from_none, HandoffRepository.from_dict], obj.get("repository")) + summary = from_union([from_none, from_str], obj.get("summary")) + return SessionHandoffData( + handoff_time=handoff_time, + source_type=source_type, + context=context, + host=host, + remote_session_id=remote_session_id, + repository=repository, + summary=summary, ) def to_dict(self) -> dict: result: dict = {} - result["message"] = from_str(self.message) - if self.code is not None: - result["code"] = from_union([from_none, from_str], self.code) + result["handoffTime"] = to_datetime(self.handoff_time) + result["sourceType"] = to_enum(HandoffSourceType, self.source_type) + if self.context is not None: + result["context"] = from_union([from_none, from_str], self.context) + if self.host is not None: + result["host"] = from_union([from_none, from_str], self.host) + if self.remote_session_id is not None: + result["remoteSessionId"] = from_union([from_none, from_str], self.remote_session_id) + if self.repository is not None: + result["repository"] = from_union([from_none, lambda x: to_class(HandoffRepository, x)], self.repository) + if self.summary is not None: + result["summary"] = from_union([from_none, from_str], self.summary) return result @dataclass -class ToolExecutionCompleteData: - "Tool execution completion results including success status, detailed output, and error information" - tool_call_id: str - success: bool - model: str | None = None - interaction_id: str | None = None - is_user_requested: bool | None = None - result: ToolExecutionCompleteDataResult | None = None - error: ToolExecutionCompleteDataError | None = None - tool_telemetry: dict[str, Any] | None = None - # Deprecated: this field is deprecated. - parent_tool_call_id: str | None = None +class SessionIdleData: + "Payload indicating the session is idle with no background agents in flight" + aborted: bool | None = None @staticmethod - def from_dict(obj: Any) -> "ToolExecutionCompleteData": + def from_dict(obj: Any) -> "SessionIdleData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - success = from_bool(obj.get("success")) - model = from_union([from_none, from_str], obj.get("model")) - interaction_id = from_union([from_none, from_str], obj.get("interactionId")) - is_user_requested = from_union([from_none, from_bool], obj.get("isUserRequested")) - result = from_union([from_none, ToolExecutionCompleteDataResult.from_dict], obj.get("result")) - error = from_union([from_none, ToolExecutionCompleteDataError.from_dict], obj.get("error")) - tool_telemetry = from_union([from_none, lambda x: from_dict(lambda x: x, x)], obj.get("toolTelemetry")) - parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) - return ToolExecutionCompleteData( - tool_call_id=tool_call_id, - success=success, - model=model, - interaction_id=interaction_id, - is_user_requested=is_user_requested, - result=result, - error=error, - tool_telemetry=tool_telemetry, - parent_tool_call_id=parent_tool_call_id, + aborted = from_union([from_none, from_bool], obj.get("aborted")) + return SessionIdleData( + aborted=aborted, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["success"] = from_bool(self.success) - if self.model is not None: - result["model"] = from_union([from_none, from_str], self.model) - if self.interaction_id is not None: - result["interactionId"] = from_union([from_none, from_str], self.interaction_id) - if self.is_user_requested is not None: - result["isUserRequested"] = from_union([from_none, from_bool], self.is_user_requested) - if self.result is not None: - result["result"] = from_union([from_none, lambda x: to_class(ToolExecutionCompleteDataResult, x)], self.result) - if self.error is not None: - result["error"] = from_union([from_none, lambda x: to_class(ToolExecutionCompleteDataError, x)], self.error) - if self.tool_telemetry is not None: - result["toolTelemetry"] = from_union([from_none, lambda x: from_dict(lambda x: x, x)], self.tool_telemetry) - if self.parent_tool_call_id is not None: - result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) + if self.aborted is not None: + result["aborted"] = from_union([from_none, from_bool], self.aborted) return result @dataclass -class SkillInvokedData: - "Skill invocation details including content, allowed tools, and plugin metadata" - name: str - path: str - content: str - allowed_tools: list[str] | None = None - plugin_name: str | None = None - plugin_version: str | None = None - description: str | None = None +class SessionInfoData: + "Informational message for timeline display with categorization" + info_type: str + message: str + url: str | None = None @staticmethod - def from_dict(obj: Any) -> "SkillInvokedData": + def from_dict(obj: Any) -> "SessionInfoData": assert isinstance(obj, dict) - name = from_str(obj.get("name")) - path = from_str(obj.get("path")) - content = from_str(obj.get("content")) - allowed_tools = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("allowedTools")) - plugin_name = from_union([from_none, from_str], obj.get("pluginName")) - plugin_version = from_union([from_none, from_str], obj.get("pluginVersion")) - description = from_union([from_none, from_str], obj.get("description")) - return SkillInvokedData( - name=name, - path=path, - content=content, - allowed_tools=allowed_tools, - plugin_name=plugin_name, - plugin_version=plugin_version, - description=description, + info_type = from_str(obj.get("infoType")) + message = from_str(obj.get("message")) + url = from_union([from_none, from_str], obj.get("url")) + return SessionInfoData( + info_type=info_type, + message=message, + url=url, ) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["path"] = from_str(self.path) - result["content"] = from_str(self.content) - if self.allowed_tools is not None: - result["allowedTools"] = from_union([from_none, lambda x: from_list(from_str, x)], self.allowed_tools) - if self.plugin_name is not None: - result["pluginName"] = from_union([from_none, from_str], self.plugin_name) - if self.plugin_version is not None: - result["pluginVersion"] = from_union([from_none, from_str], self.plugin_version) - if self.description is not None: - result["description"] = from_union([from_none, from_str], self.description) + result["infoType"] = from_str(self.info_type) + result["message"] = from_str(self.message) + if self.url is not None: + result["url"] = from_union([from_none, from_str], self.url) return result @dataclass -class SubagentStartedData: - "Sub-agent startup details including parent tool call and agent information" - tool_call_id: str - agent_name: str - agent_display_name: str - agent_description: str +class SessionMcpServerStatusChangedData: + server_name: str + status: McpServerStatusChangedStatus @staticmethod - def from_dict(obj: Any) -> "SubagentStartedData": + def from_dict(obj: Any) -> "SessionMcpServerStatusChangedData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - agent_name = from_str(obj.get("agentName")) - agent_display_name = from_str(obj.get("agentDisplayName")) - agent_description = from_str(obj.get("agentDescription")) - return SubagentStartedData( - tool_call_id=tool_call_id, - agent_name=agent_name, - agent_display_name=agent_display_name, - agent_description=agent_description, + server_name = from_str(obj.get("serverName")) + status = parse_enum(McpServerStatusChangedStatus, obj.get("status")) + return SessionMcpServerStatusChangedData( + server_name=server_name, + status=status, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["agentName"] = from_str(self.agent_name) - result["agentDisplayName"] = from_str(self.agent_display_name) - result["agentDescription"] = from_str(self.agent_description) + result["serverName"] = from_str(self.server_name) + result["status"] = to_enum(McpServerStatusChangedStatus, self.status) return result @dataclass -class SubagentCompletedData: - "Sub-agent completion details for successful execution" - tool_call_id: str - agent_name: str - agent_display_name: str - model: str | None = None - total_tool_calls: float | None = None - total_tokens: float | None = None - duration_ms: float | None = None +class SessionMcpServersLoadedData: + servers: list[McpServersLoadedServer] @staticmethod - def from_dict(obj: Any) -> "SubagentCompletedData": + def from_dict(obj: Any) -> "SessionMcpServersLoadedData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - agent_name = from_str(obj.get("agentName")) - agent_display_name = from_str(obj.get("agentDisplayName")) - model = from_union([from_none, from_str], obj.get("model")) - total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) - total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) - duration_ms = from_union([from_none, from_float], obj.get("durationMs")) - return SubagentCompletedData( - tool_call_id=tool_call_id, - agent_name=agent_name, - agent_display_name=agent_display_name, - model=model, - total_tool_calls=total_tool_calls, - total_tokens=total_tokens, - duration_ms=duration_ms, + servers = from_list(McpServersLoadedServer.from_dict, obj.get("servers")) + return SessionMcpServersLoadedData( + servers=servers, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["agentName"] = from_str(self.agent_name) - result["agentDisplayName"] = from_str(self.agent_display_name) - if self.model is not None: - result["model"] = from_union([from_none, from_str], self.model) - if self.total_tool_calls is not None: - result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) - if self.total_tokens is not None: - result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) - if self.duration_ms is not None: - result["durationMs"] = from_union([from_none, to_float], self.duration_ms) + result["servers"] = from_list(lambda x: to_class(McpServersLoadedServer, x), self.servers) return result @dataclass -class SubagentFailedData: - "Sub-agent failure details including error message and agent information" - tool_call_id: str - agent_name: str - agent_display_name: str - error: str - model: str | None = None - total_tool_calls: float | None = None - total_tokens: float | None = None - duration_ms: float | None = None +class SessionModeChangedData: + "Agent mode change details including previous and new modes" + new_mode: str + previous_mode: str @staticmethod - def from_dict(obj: Any) -> "SubagentFailedData": + def from_dict(obj: Any) -> "SessionModeChangedData": assert isinstance(obj, dict) - tool_call_id = from_str(obj.get("toolCallId")) - agent_name = from_str(obj.get("agentName")) - agent_display_name = from_str(obj.get("agentDisplayName")) - error = from_str(obj.get("error")) - model = from_union([from_none, from_str], obj.get("model")) - total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) - total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) - duration_ms = from_union([from_none, from_float], obj.get("durationMs")) - return SubagentFailedData( - tool_call_id=tool_call_id, - agent_name=agent_name, - agent_display_name=agent_display_name, - error=error, - model=model, - total_tool_calls=total_tool_calls, - total_tokens=total_tokens, - duration_ms=duration_ms, + new_mode = from_str(obj.get("newMode")) + previous_mode = from_str(obj.get("previousMode")) + return SessionModeChangedData( + new_mode=new_mode, + previous_mode=previous_mode, ) def to_dict(self) -> dict: result: dict = {} - result["toolCallId"] = from_str(self.tool_call_id) - result["agentName"] = from_str(self.agent_name) - result["agentDisplayName"] = from_str(self.agent_display_name) - result["error"] = from_str(self.error) - if self.model is not None: - result["model"] = from_union([from_none, from_str], self.model) - if self.total_tool_calls is not None: - result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) - if self.total_tokens is not None: - result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) - if self.duration_ms is not None: - result["durationMs"] = from_union([from_none, to_float], self.duration_ms) + result["newMode"] = from_str(self.new_mode) + result["previousMode"] = from_str(self.previous_mode) return result @dataclass -class SubagentSelectedData: - "Custom agent selection details including name and available tools" - agent_name: str - agent_display_name: str - tools: list[str] | None +class SessionModelChangeData: + "Model change details including previous and new model identifiers" + new_model: str + previous_model: str | None = None + previous_reasoning_effort: str | None = None + reasoning_effort: str | None = None @staticmethod - def from_dict(obj: Any) -> "SubagentSelectedData": + def from_dict(obj: Any) -> "SessionModelChangeData": assert isinstance(obj, dict) - agent_name = from_str(obj.get("agentName")) - agent_display_name = from_str(obj.get("agentDisplayName")) - tools = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("tools")) - return SubagentSelectedData( - agent_name=agent_name, - agent_display_name=agent_display_name, - tools=tools, + new_model = from_str(obj.get("newModel")) + previous_model = from_union([from_none, from_str], obj.get("previousModel")) + previous_reasoning_effort = from_union([from_none, from_str], obj.get("previousReasoningEffort")) + reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) + return SessionModelChangeData( + new_model=new_model, + previous_model=previous_model, + previous_reasoning_effort=previous_reasoning_effort, + reasoning_effort=reasoning_effort, ) def to_dict(self) -> dict: result: dict = {} - result["agentName"] = from_str(self.agent_name) - result["agentDisplayName"] = from_str(self.agent_display_name) - result["tools"] = from_union([from_none, lambda x: from_list(from_str, x)], self.tools) + result["newModel"] = from_str(self.new_model) + if self.previous_model is not None: + result["previousModel"] = from_union([from_none, from_str], self.previous_model) + if self.previous_reasoning_effort is not None: + result["previousReasoningEffort"] = from_union([from_none, from_str], self.previous_reasoning_effort) + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) return result @dataclass -class SubagentDeselectedData: - "Empty payload; the event signals that the custom agent was deselected, returning to the default agent" - @staticmethod - def from_dict(obj: Any) -> "SubagentDeselectedData": - assert isinstance(obj, dict) - return SubagentDeselectedData() - - def to_dict(self) -> dict: - return {} - - -@dataclass -class HookStartData: - "Hook invocation start details including type and input data" - hook_invocation_id: str - hook_type: str - input: Any = None +class SessionPlanChangedData: + "Plan file operation details indicating what changed" + operation: PlanChangedOperation @staticmethod - def from_dict(obj: Any) -> "HookStartData": + def from_dict(obj: Any) -> "SessionPlanChangedData": assert isinstance(obj, dict) - hook_invocation_id = from_str(obj.get("hookInvocationId")) - hook_type = from_str(obj.get("hookType")) - input = obj.get("input") - return HookStartData( - hook_invocation_id=hook_invocation_id, - hook_type=hook_type, - input=input, + operation = parse_enum(PlanChangedOperation, obj.get("operation")) + return SessionPlanChangedData( + operation=operation, ) def to_dict(self) -> dict: result: dict = {} - result["hookInvocationId"] = from_str(self.hook_invocation_id) - result["hookType"] = from_str(self.hook_type) - if self.input is not None: - result["input"] = self.input + result["operation"] = to_enum(PlanChangedOperation, self.operation) return result @dataclass -class HookEndDataError: - "Error details when the hook failed" - message: str - stack: str | None = None +class SessionRemoteSteerableChangedData: + "Notifies Mission Control that the session's remote steering capability has changed" + remote_steerable: bool @staticmethod - def from_dict(obj: Any) -> "HookEndDataError": + def from_dict(obj: Any) -> "SessionRemoteSteerableChangedData": assert isinstance(obj, dict) - message = from_str(obj.get("message")) - stack = from_union([from_none, from_str], obj.get("stack")) - return HookEndDataError( - message=message, - stack=stack, + remote_steerable = from_bool(obj.get("remoteSteerable")) + return SessionRemoteSteerableChangedData( + remote_steerable=remote_steerable, ) def to_dict(self) -> dict: result: dict = {} - result["message"] = from_str(self.message) - if self.stack is not None: - result["stack"] = from_union([from_none, from_str], self.stack) + result["remoteSteerable"] = from_bool(self.remote_steerable) return result @dataclass -class HookEndData: - "Hook invocation completion details including output, success status, and error information" - hook_invocation_id: str - hook_type: str - success: bool - output: Any = None - error: HookEndDataError | None = None +class SessionResumeData: + "Session resume metadata including current context and event count" + event_count: float + resume_time: datetime + already_in_use: bool | None = None + context: WorkingDirectoryContext | None = None + reasoning_effort: str | None = None + remote_steerable: bool | None = None + selected_model: str | None = None @staticmethod - def from_dict(obj: Any) -> "HookEndData": + def from_dict(obj: Any) -> "SessionResumeData": assert isinstance(obj, dict) - hook_invocation_id = from_str(obj.get("hookInvocationId")) - hook_type = from_str(obj.get("hookType")) - success = from_bool(obj.get("success")) - output = obj.get("output") - error = from_union([from_none, HookEndDataError.from_dict], obj.get("error")) - return HookEndData( - hook_invocation_id=hook_invocation_id, - hook_type=hook_type, - success=success, - output=output, - error=error, + event_count = from_float(obj.get("eventCount")) + resume_time = from_datetime(obj.get("resumeTime")) + already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) + context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) + reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) + remote_steerable = from_union([from_none, from_bool], obj.get("remoteSteerable")) + selected_model = from_union([from_none, from_str], obj.get("selectedModel")) + return SessionResumeData( + event_count=event_count, + resume_time=resume_time, + already_in_use=already_in_use, + context=context, + reasoning_effort=reasoning_effort, + remote_steerable=remote_steerable, + selected_model=selected_model, ) def to_dict(self) -> dict: result: dict = {} - result["hookInvocationId"] = from_str(self.hook_invocation_id) - result["hookType"] = from_str(self.hook_type) - result["success"] = from_bool(self.success) - if self.output is not None: - result["output"] = self.output - if self.error is not None: - result["error"] = from_union([from_none, lambda x: to_class(HookEndDataError, x)], self.error) + result["eventCount"] = to_float(self.event_count) + result["resumeTime"] = to_datetime(self.resume_time) + if self.already_in_use is not None: + result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) + if self.context is not None: + result["context"] = from_union([from_none, lambda x: to_class(WorkingDirectoryContext, x)], self.context) + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) + if self.remote_steerable is not None: + result["remoteSteerable"] = from_union([from_none, from_bool], self.remote_steerable) + if self.selected_model is not None: + result["selectedModel"] = from_union([from_none, from_str], self.selected_model) return result @dataclass -class SystemMessageDataMetadata: - "Metadata about the prompt template and its construction" - prompt_version: str | None = None - variables: dict[str, Any] | None = None +class SessionShutdownData: + "Session termination metrics including usage statistics, code changes, and shutdown reason" + code_changes: ShutdownCodeChanges + model_metrics: dict[str, ShutdownModelMetric] + session_start_time: float + shutdown_type: ShutdownType + total_api_duration_ms: float + total_premium_requests: float + conversation_tokens: float | None = None + current_model: str | None = None + current_tokens: float | None = None + error_reason: str | None = None + system_tokens: float | None = None + tool_definitions_tokens: float | None = None @staticmethod - def from_dict(obj: Any) -> "SystemMessageDataMetadata": + def from_dict(obj: Any) -> "SessionShutdownData": assert isinstance(obj, dict) - prompt_version = from_union([from_none, from_str], obj.get("promptVersion")) - variables = from_union([from_none, lambda x: from_dict(lambda x: x, x)], obj.get("variables")) - return SystemMessageDataMetadata( - prompt_version=prompt_version, - variables=variables, + code_changes = ShutdownCodeChanges.from_dict(obj.get("codeChanges")) + model_metrics = from_dict(ShutdownModelMetric.from_dict, obj.get("modelMetrics")) + session_start_time = from_float(obj.get("sessionStartTime")) + shutdown_type = parse_enum(ShutdownType, obj.get("shutdownType")) + total_api_duration_ms = from_float(obj.get("totalApiDurationMs")) + total_premium_requests = from_float(obj.get("totalPremiumRequests")) + conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) + current_model = from_union([from_none, from_str], obj.get("currentModel")) + current_tokens = from_union([from_none, from_float], obj.get("currentTokens")) + error_reason = from_union([from_none, from_str], obj.get("errorReason")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + return SessionShutdownData( + code_changes=code_changes, + model_metrics=model_metrics, + session_start_time=session_start_time, + shutdown_type=shutdown_type, + total_api_duration_ms=total_api_duration_ms, + total_premium_requests=total_premium_requests, + conversation_tokens=conversation_tokens, + current_model=current_model, + current_tokens=current_tokens, + error_reason=error_reason, + system_tokens=system_tokens, + tool_definitions_tokens=tool_definitions_tokens, ) def to_dict(self) -> dict: result: dict = {} - if self.prompt_version is not None: - result["promptVersion"] = from_union([from_none, from_str], self.prompt_version) - if self.variables is not None: - result["variables"] = from_union([from_none, lambda x: from_dict(lambda x: x, x)], self.variables) + result["codeChanges"] = to_class(ShutdownCodeChanges, self.code_changes) + result["modelMetrics"] = from_dict(lambda x: to_class(ShutdownModelMetric, x), self.model_metrics) + result["sessionStartTime"] = to_float(self.session_start_time) + result["shutdownType"] = to_enum(ShutdownType, self.shutdown_type) + result["totalApiDurationMs"] = to_float(self.total_api_duration_ms) + result["totalPremiumRequests"] = to_float(self.total_premium_requests) + if self.conversation_tokens is not None: + result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) + if self.current_model is not None: + result["currentModel"] = from_union([from_none, from_str], self.current_model) + if self.current_tokens is not None: + result["currentTokens"] = from_union([from_none, to_float], self.current_tokens) + if self.error_reason is not None: + result["errorReason"] = from_union([from_none, from_str], self.error_reason) + if self.system_tokens is not None: + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + if self.tool_definitions_tokens is not None: + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) return result @dataclass -class SystemMessageData: - "System/developer instruction content with role and optional template metadata" - content: str - role: SystemMessageDataRole - name: str | None = None - metadata: SystemMessageDataMetadata | None = None +class SessionSkillsLoadedData: + skills: list[SkillsLoadedSkill] @staticmethod - def from_dict(obj: Any) -> "SystemMessageData": + def from_dict(obj: Any) -> "SessionSkillsLoadedData": assert isinstance(obj, dict) - content = from_str(obj.get("content")) - role = parse_enum(SystemMessageDataRole, obj.get("role")) - name = from_union([from_none, from_str], obj.get("name")) - metadata = from_union([from_none, SystemMessageDataMetadata.from_dict], obj.get("metadata")) - return SystemMessageData( - content=content, - role=role, - name=name, - metadata=metadata, + skills = from_list(SkillsLoadedSkill.from_dict, obj.get("skills")) + return SessionSkillsLoadedData( + skills=skills, ) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["role"] = to_enum(SystemMessageDataRole, self.role) - if self.name is not None: - result["name"] = from_union([from_none, from_str], self.name) - if self.metadata is not None: - result["metadata"] = from_union([from_none, lambda x: to_class(SystemMessageDataMetadata, x)], self.metadata) + result["skills"] = from_list(lambda x: to_class(SkillsLoadedSkill, x), self.skills) return result @dataclass -class SystemNotificationDataKind: - "Structured metadata identifying what triggered this notification" - type: SystemNotificationDataKindType - agent_id: str | None = None - agent_type: str | None = None - status: SystemNotificationDataKindStatus | None = None - description: str | None = None - prompt: str | None = None - shell_id: str | None = None - exit_code: float | None = None +class SessionSnapshotRewindData: + "Session rewind details including target event and count of removed events" + events_removed: float + up_to_event_id: str @staticmethod - def from_dict(obj: Any) -> "SystemNotificationDataKind": + def from_dict(obj: Any) -> "SessionSnapshotRewindData": assert isinstance(obj, dict) - type = parse_enum(SystemNotificationDataKindType, obj.get("type")) - agent_id = from_union([from_none, from_str], obj.get("agentId")) - agent_type = from_union([from_none, from_str], obj.get("agentType")) - status = from_union([from_none, lambda x: parse_enum(SystemNotificationDataKindStatus, x)], obj.get("status")) - description = from_union([from_none, from_str], obj.get("description")) - prompt = from_union([from_none, from_str], obj.get("prompt")) - shell_id = from_union([from_none, from_str], obj.get("shellId")) - exit_code = from_union([from_none, from_float], obj.get("exitCode")) - return SystemNotificationDataKind( - type=type, - agent_id=agent_id, - agent_type=agent_type, - status=status, - description=description, - prompt=prompt, - shell_id=shell_id, - exit_code=exit_code, + events_removed = from_float(obj.get("eventsRemoved")) + up_to_event_id = from_str(obj.get("upToEventId")) + return SessionSnapshotRewindData( + events_removed=events_removed, + up_to_event_id=up_to_event_id, ) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(SystemNotificationDataKindType, self.type) - if self.agent_id is not None: - result["agentId"] = from_union([from_none, from_str], self.agent_id) - if self.agent_type is not None: - result["agentType"] = from_union([from_none, from_str], self.agent_type) - if self.status is not None: - result["status"] = from_union([from_none, lambda x: to_enum(SystemNotificationDataKindStatus, x)], self.status) - if self.description is not None: - result["description"] = from_union([from_none, from_str], self.description) - if self.prompt is not None: - result["prompt"] = from_union([from_none, from_str], self.prompt) - if self.shell_id is not None: - result["shellId"] = from_union([from_none, from_str], self.shell_id) - if self.exit_code is not None: - result["exitCode"] = from_union([from_none, to_float], self.exit_code) + result["eventsRemoved"] = to_float(self.events_removed) + result["upToEventId"] = from_str(self.up_to_event_id) return result @dataclass -class SystemNotificationData: - "System-generated notification for runtime events like background task completion" - content: str - kind: SystemNotificationDataKind +class SessionStartData: + "Session initialization metadata including context and configuration" + copilot_version: str + producer: str + session_id: str + start_time: datetime + version: float + already_in_use: bool | None = None + context: WorkingDirectoryContext | None = None + reasoning_effort: str | None = None + remote_steerable: bool | None = None + selected_model: str | None = None @staticmethod - def from_dict(obj: Any) -> "SystemNotificationData": + def from_dict(obj: Any) -> "SessionStartData": assert isinstance(obj, dict) - content = from_str(obj.get("content")) - kind = SystemNotificationDataKind.from_dict(obj.get("kind")) - return SystemNotificationData( - content=content, - kind=kind, + copilot_version = from_str(obj.get("copilotVersion")) + producer = from_str(obj.get("producer")) + session_id = from_str(obj.get("sessionId")) + start_time = from_datetime(obj.get("startTime")) + version = from_float(obj.get("version")) + already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) + context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) + reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) + remote_steerable = from_union([from_none, from_bool], obj.get("remoteSteerable")) + selected_model = from_union([from_none, from_str], obj.get("selectedModel")) + return SessionStartData( + copilot_version=copilot_version, + producer=producer, + session_id=session_id, + start_time=start_time, + version=version, + already_in_use=already_in_use, + context=context, + reasoning_effort=reasoning_effort, + remote_steerable=remote_steerable, + selected_model=selected_model, ) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["kind"] = to_class(SystemNotificationDataKind, self.kind) + result["copilotVersion"] = from_str(self.copilot_version) + result["producer"] = from_str(self.producer) + result["sessionId"] = from_str(self.session_id) + result["startTime"] = to_datetime(self.start_time) + result["version"] = to_float(self.version) + if self.already_in_use is not None: + result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) + if self.context is not None: + result["context"] = from_union([from_none, lambda x: to_class(WorkingDirectoryContext, x)], self.context) + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) + if self.remote_steerable is not None: + result["remoteSteerable"] = from_union([from_none, from_bool], self.remote_steerable) + if self.selected_model is not None: + result["selectedModel"] = from_union([from_none, from_str], self.selected_model) return result @dataclass -class PermissionRequestShellCommand: - identifier: str - read_only: bool +class SessionTaskCompleteData: + "Task completion notification with summary from the agent" + success: bool | None = None + summary: str | None = None @staticmethod - def from_dict(obj: Any) -> "PermissionRequestShellCommand": + def from_dict(obj: Any) -> "SessionTaskCompleteData": assert isinstance(obj, dict) - identifier = from_str(obj.get("identifier")) - read_only = from_bool(obj.get("readOnly")) - return PermissionRequestShellCommand( - identifier=identifier, - read_only=read_only, + success = from_union([from_none, from_bool], obj.get("success")) + summary = from_union([from_none, from_str], obj.get("summary", "")) + return SessionTaskCompleteData( + success=success, + summary=summary, ) def to_dict(self) -> dict: result: dict = {} - result["identifier"] = from_str(self.identifier) - result["readOnly"] = from_bool(self.read_only) + if self.success is not None: + result["success"] = from_union([from_none, from_bool], self.success) + if self.summary is not None: + result["summary"] = from_union([from_none, from_str], self.summary) return result @dataclass -class PermissionRequestShellPossibleURL: - url: str +class SessionTitleChangedData: + "Session title change payload containing the new display title" + title: str @staticmethod - def from_dict(obj: Any) -> "PermissionRequestShellPossibleURL": + def from_dict(obj: Any) -> "SessionTitleChangedData": assert isinstance(obj, dict) - url = from_str(obj.get("url")) - return PermissionRequestShellPossibleURL( - url=url, + title = from_str(obj.get("title")) + return SessionTitleChangedData( + title=title, ) def to_dict(self) -> dict: result: dict = {} - result["url"] = from_str(self.url) + result["title"] = from_str(self.title) return result @dataclass -class PermissionRequest: - "Details of the permission being requested" - kind: PermissionRequestedDataPermissionRequestKind - tool_call_id: str | None = None - full_command_text: str | None = None - intention: str | None = None - commands: list[PermissionRequestShellCommand] | None = None - possible_paths: list[str] | None = None - possible_urls: list[PermissionRequestShellPossibleURL] | None = None - has_write_file_redirection: bool | None = None - can_offer_session_approval: bool | None = None - warning: str | None = None - file_name: str | None = None - diff: str | None = None - new_file_contents: str | None = None - path: str | None = None - server_name: str | None = None - tool_name: str | None = None - tool_title: str | None = None - args: Any = None - read_only: bool | None = None +class SessionToolsUpdatedData: + model: str + + @staticmethod + def from_dict(obj: Any) -> "SessionToolsUpdatedData": + assert isinstance(obj, dict) + model = from_str(obj.get("model")) + return SessionToolsUpdatedData( + model=model, + ) + + def to_dict(self) -> dict: + result: dict = {} + result["model"] = from_str(self.model) + return result + + +@dataclass +class SessionTruncationData: + "Conversation truncation statistics including token counts and removed content metrics" + messages_removed_during_truncation: float + performed_by: str + post_truncation_messages_length: float + post_truncation_tokens_in_messages: float + pre_truncation_messages_length: float + pre_truncation_tokens_in_messages: float + token_limit: float + tokens_removed_during_truncation: float + + @staticmethod + def from_dict(obj: Any) -> "SessionTruncationData": + assert isinstance(obj, dict) + messages_removed_during_truncation = from_float(obj.get("messagesRemovedDuringTruncation")) + performed_by = from_str(obj.get("performedBy")) + post_truncation_messages_length = from_float(obj.get("postTruncationMessagesLength")) + post_truncation_tokens_in_messages = from_float(obj.get("postTruncationTokensInMessages")) + pre_truncation_messages_length = from_float(obj.get("preTruncationMessagesLength")) + pre_truncation_tokens_in_messages = from_float(obj.get("preTruncationTokensInMessages")) + token_limit = from_float(obj.get("tokenLimit")) + tokens_removed_during_truncation = from_float(obj.get("tokensRemovedDuringTruncation")) + return SessionTruncationData( + messages_removed_during_truncation=messages_removed_during_truncation, + performed_by=performed_by, + post_truncation_messages_length=post_truncation_messages_length, + post_truncation_tokens_in_messages=post_truncation_tokens_in_messages, + pre_truncation_messages_length=pre_truncation_messages_length, + pre_truncation_tokens_in_messages=pre_truncation_tokens_in_messages, + token_limit=token_limit, + tokens_removed_during_truncation=tokens_removed_during_truncation, + ) + + def to_dict(self) -> dict: + result: dict = {} + result["messagesRemovedDuringTruncation"] = to_float(self.messages_removed_during_truncation) + result["performedBy"] = from_str(self.performed_by) + result["postTruncationMessagesLength"] = to_float(self.post_truncation_messages_length) + result["postTruncationTokensInMessages"] = to_float(self.post_truncation_tokens_in_messages) + result["preTruncationMessagesLength"] = to_float(self.pre_truncation_messages_length) + result["preTruncationTokensInMessages"] = to_float(self.pre_truncation_tokens_in_messages) + result["tokenLimit"] = to_float(self.token_limit) + result["tokensRemovedDuringTruncation"] = to_float(self.tokens_removed_during_truncation) + return result + + +@dataclass +class SessionUsageInfoData: + "Current context window usage statistics including token and message counts" + current_tokens: float + messages_length: float + token_limit: float + conversation_tokens: float | None = None + is_initial: bool | None = None + system_tokens: float | None = None + tool_definitions_tokens: float | None = None + + @staticmethod + def from_dict(obj: Any) -> "SessionUsageInfoData": + assert isinstance(obj, dict) + current_tokens = from_float(obj.get("currentTokens")) + messages_length = from_float(obj.get("messagesLength")) + token_limit = from_float(obj.get("tokenLimit")) + conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) + is_initial = from_union([from_none, from_bool], obj.get("isInitial")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + return SessionUsageInfoData( + current_tokens=current_tokens, + messages_length=messages_length, + token_limit=token_limit, + conversation_tokens=conversation_tokens, + is_initial=is_initial, + system_tokens=system_tokens, + tool_definitions_tokens=tool_definitions_tokens, + ) + + def to_dict(self) -> dict: + result: dict = {} + result["currentTokens"] = to_float(self.current_tokens) + result["messagesLength"] = to_float(self.messages_length) + result["tokenLimit"] = to_float(self.token_limit) + if self.conversation_tokens is not None: + result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) + if self.is_initial is not None: + result["isInitial"] = from_union([from_none, from_bool], self.is_initial) + if self.system_tokens is not None: + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + if self.tool_definitions_tokens is not None: + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + return result + + +@dataclass +class SessionWarningData: + "Warning message for timeline display with categorization" + message: str + warning_type: str url: str | None = None - action: PermissionRequestMemoryAction | None = None - subject: str | None = None - fact: str | None = None - citations: str | None = None - direction: PermissionRequestMemoryDirection | None = None - reason: str | None = None - tool_description: str | None = None - tool_args: Any = None - hook_message: str | None = None @staticmethod - def from_dict(obj: Any) -> "PermissionRequest": + def from_dict(obj: Any) -> "SessionWarningData": assert isinstance(obj, dict) - kind = parse_enum(PermissionRequestedDataPermissionRequestKind, obj.get("kind")) - tool_call_id = from_union([from_none, from_str], obj.get("toolCallId")) - full_command_text = from_union([from_none, from_str], obj.get("fullCommandText")) - intention = from_union([from_none, from_str], obj.get("intention")) - commands = from_union([from_none, lambda x: from_list(PermissionRequestShellCommand.from_dict, x)], obj.get("commands")) - possible_paths = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("possiblePaths")) - possible_urls = from_union([from_none, lambda x: from_list(PermissionRequestShellPossibleURL.from_dict, x)], obj.get("possibleUrls")) - has_write_file_redirection = from_union([from_none, from_bool], obj.get("hasWriteFileRedirection")) - can_offer_session_approval = from_union([from_none, from_bool], obj.get("canOfferSessionApproval")) - warning = from_union([from_none, from_str], obj.get("warning")) - file_name = from_union([from_none, from_str], obj.get("fileName")) - diff = from_union([from_none, from_str], obj.get("diff")) - new_file_contents = from_union([from_none, from_str], obj.get("newFileContents")) - path = from_union([from_none, from_str], obj.get("path")) - server_name = from_union([from_none, from_str], obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - tool_title = from_union([from_none, from_str], obj.get("toolTitle")) - args = obj.get("args") - read_only = from_union([from_none, from_bool], obj.get("readOnly")) + message = from_str(obj.get("message")) + warning_type = from_str(obj.get("warningType")) url = from_union([from_none, from_str], obj.get("url")) - action = from_union([from_none, lambda x: parse_enum(PermissionRequestMemoryAction, x)], obj.get("action", "store")) - subject = from_union([from_none, from_str], obj.get("subject")) - fact = from_union([from_none, from_str], obj.get("fact")) - citations = from_union([from_none, from_str], obj.get("citations")) - direction = from_union([from_none, lambda x: parse_enum(PermissionRequestMemoryDirection, x)], obj.get("direction")) - reason = from_union([from_none, from_str], obj.get("reason")) - tool_description = from_union([from_none, from_str], obj.get("toolDescription")) - tool_args = obj.get("toolArgs") - hook_message = from_union([from_none, from_str], obj.get("hookMessage")) - return PermissionRequest( - kind=kind, - tool_call_id=tool_call_id, - full_command_text=full_command_text, - intention=intention, - commands=commands, - possible_paths=possible_paths, - possible_urls=possible_urls, - has_write_file_redirection=has_write_file_redirection, - can_offer_session_approval=can_offer_session_approval, - warning=warning, - file_name=file_name, - diff=diff, - new_file_contents=new_file_contents, - path=path, - server_name=server_name, - tool_name=tool_name, - tool_title=tool_title, - args=args, - read_only=read_only, + return SessionWarningData( + message=message, + warning_type=warning_type, url=url, - action=action, - subject=subject, - fact=fact, - citations=citations, - direction=direction, - reason=reason, - tool_description=tool_description, - tool_args=tool_args, - hook_message=hook_message, ) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionRequestedDataPermissionRequestKind, self.kind) - if self.tool_call_id is not None: - result["toolCallId"] = from_union([from_none, from_str], self.tool_call_id) - if self.full_command_text is not None: - result["fullCommandText"] = from_union([from_none, from_str], self.full_command_text) - if self.intention is not None: - result["intention"] = from_union([from_none, from_str], self.intention) - if self.commands is not None: - result["commands"] = from_union([from_none, lambda x: from_list(lambda x: to_class(PermissionRequestShellCommand, x), x)], self.commands) - if self.possible_paths is not None: - result["possiblePaths"] = from_union([from_none, lambda x: from_list(from_str, x)], self.possible_paths) - if self.possible_urls is not None: - result["possibleUrls"] = from_union([from_none, lambda x: from_list(lambda x: to_class(PermissionRequestShellPossibleURL, x), x)], self.possible_urls) - if self.has_write_file_redirection is not None: - result["hasWriteFileRedirection"] = from_union([from_none, from_bool], self.has_write_file_redirection) - if self.can_offer_session_approval is not None: - result["canOfferSessionApproval"] = from_union([from_none, from_bool], self.can_offer_session_approval) - if self.warning is not None: - result["warning"] = from_union([from_none, from_str], self.warning) - if self.file_name is not None: - result["fileName"] = from_union([from_none, from_str], self.file_name) - if self.diff is not None: - result["diff"] = from_union([from_none, from_str], self.diff) - if self.new_file_contents is not None: - result["newFileContents"] = from_union([from_none, from_str], self.new_file_contents) - if self.path is not None: - result["path"] = from_union([from_none, from_str], self.path) - if self.server_name is not None: - result["serverName"] = from_union([from_none, from_str], self.server_name) - if self.tool_name is not None: - result["toolName"] = from_union([from_none, from_str], self.tool_name) - if self.tool_title is not None: - result["toolTitle"] = from_union([from_none, from_str], self.tool_title) - if self.args is not None: - result["args"] = self.args - if self.read_only is not None: - result["readOnly"] = from_union([from_none, from_bool], self.read_only) + result["message"] = from_str(self.message) + result["warningType"] = from_str(self.warning_type) if self.url is not None: result["url"] = from_union([from_none, from_str], self.url) - if self.action is not None: - result["action"] = from_union([from_none, lambda x: to_enum(PermissionRequestMemoryAction, x)], self.action) - if self.subject is not None: - result["subject"] = from_union([from_none, from_str], self.subject) - if self.fact is not None: - result["fact"] = from_union([from_none, from_str], self.fact) - if self.citations is not None: - result["citations"] = from_union([from_none, from_str], self.citations) - if self.direction is not None: - result["direction"] = from_union([from_none, lambda x: to_enum(PermissionRequestMemoryDirection, x)], self.direction) - if self.reason is not None: - result["reason"] = from_union([from_none, from_str], self.reason) - if self.tool_description is not None: - result["toolDescription"] = from_union([from_none, from_str], self.tool_description) - if self.tool_args is not None: - result["toolArgs"] = self.tool_args - if self.hook_message is not None: - result["hookMessage"] = from_union([from_none, from_str], self.hook_message) return result @dataclass -class PermissionRequestedData: - "Permission request notification requiring client approval with request details" - request_id: str - permission_request: PermissionRequest - resolved_by_hook: bool | None = None +class SessionWorkspaceFileChangedData: + "Workspace file change details including path and operation type" + operation: WorkspaceFileChangedOperation + path: str @staticmethod - def from_dict(obj: Any) -> "PermissionRequestedData": + def from_dict(obj: Any) -> "SessionWorkspaceFileChangedData": + assert isinstance(obj, dict) + operation = parse_enum(WorkspaceFileChangedOperation, obj.get("operation")) + path = from_str(obj.get("path")) + return SessionWorkspaceFileChangedData( + operation=operation, + path=path, + ) + + def to_dict(self) -> dict: + result: dict = {} + result["operation"] = to_enum(WorkspaceFileChangedOperation, self.operation) + result["path"] = from_str(self.path) + return result + + +@dataclass +class ShutdownCodeChanges: + "Aggregate code change metrics for the session" + files_modified: list[str] + lines_added: float + lines_removed: float + + @staticmethod + def from_dict(obj: Any) -> "ShutdownCodeChanges": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - permission_request = PermissionRequest.from_dict(obj.get("permissionRequest")) - resolved_by_hook = from_union([from_none, from_bool], obj.get("resolvedByHook")) - return PermissionRequestedData( - request_id=request_id, - permission_request=permission_request, - resolved_by_hook=resolved_by_hook, + files_modified = from_list(from_str, obj.get("filesModified")) + lines_added = from_float(obj.get("linesAdded")) + lines_removed = from_float(obj.get("linesRemoved")) + return ShutdownCodeChanges( + files_modified=files_modified, + lines_added=lines_added, + lines_removed=lines_removed, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["permissionRequest"] = to_class(PermissionRequest, self.permission_request) - if self.resolved_by_hook is not None: - result["resolvedByHook"] = from_union([from_none, from_bool], self.resolved_by_hook) + result["filesModified"] = from_list(from_str, self.files_modified) + result["linesAdded"] = to_float(self.lines_added) + result["linesRemoved"] = to_float(self.lines_removed) return result @dataclass -class PermissionCompletedDataResult: - "The result of the permission request" - kind: PermissionCompletedKind +class ShutdownModelMetric: + requests: ShutdownModelMetricRequests + usage: ShutdownModelMetricUsage @staticmethod - def from_dict(obj: Any) -> "PermissionCompletedDataResult": + def from_dict(obj: Any) -> "ShutdownModelMetric": assert isinstance(obj, dict) - kind = parse_enum(PermissionCompletedKind, obj.get("kind")) - return PermissionCompletedDataResult( - kind=kind, + requests = ShutdownModelMetricRequests.from_dict(obj.get("requests")) + usage = ShutdownModelMetricUsage.from_dict(obj.get("usage")) + return ShutdownModelMetric( + requests=requests, + usage=usage, ) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionCompletedKind, self.kind) + result["requests"] = to_class(ShutdownModelMetricRequests, self.requests) + result["usage"] = to_class(ShutdownModelMetricUsage, self.usage) return result @dataclass -class PermissionCompletedData: - "Permission request completion notification signaling UI dismissal" - request_id: str - result: PermissionCompletedDataResult +class ShutdownModelMetricRequests: + "Request count and cost metrics" + cost: float + count: float @staticmethod - def from_dict(obj: Any) -> "PermissionCompletedData": + def from_dict(obj: Any) -> "ShutdownModelMetricRequests": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - result = PermissionCompletedDataResult.from_dict(obj.get("result")) - return PermissionCompletedData( - request_id=request_id, - result=result, + cost = from_float(obj.get("cost")) + count = from_float(obj.get("count")) + return ShutdownModelMetricRequests( + cost=cost, + count=count, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["result"] = to_class(PermissionCompletedDataResult, self.result) + result["cost"] = to_float(self.cost) + result["count"] = to_float(self.count) return result @dataclass -class UserInputRequestedData: - "User input request notification with question and optional predefined choices" - request_id: str - question: str - choices: list[str] | None = None - allow_freeform: bool | None = None - tool_call_id: str | None = None +class ShutdownModelMetricUsage: + "Token usage breakdown" + cache_read_tokens: float + cache_write_tokens: float + input_tokens: float + output_tokens: float + reasoning_tokens: float | None = None @staticmethod - def from_dict(obj: Any) -> "UserInputRequestedData": + def from_dict(obj: Any) -> "ShutdownModelMetricUsage": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - question = from_str(obj.get("question")) - choices = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("choices")) - allow_freeform = from_union([from_none, from_bool], obj.get("allowFreeform")) - tool_call_id = from_union([from_none, from_str], obj.get("toolCallId")) - return UserInputRequestedData( - request_id=request_id, - question=question, - choices=choices, - allow_freeform=allow_freeform, - tool_call_id=tool_call_id, + cache_read_tokens = from_float(obj.get("cacheReadTokens")) + cache_write_tokens = from_float(obj.get("cacheWriteTokens")) + input_tokens = from_float(obj.get("inputTokens")) + output_tokens = from_float(obj.get("outputTokens")) + reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) + return ShutdownModelMetricUsage( + cache_read_tokens=cache_read_tokens, + cache_write_tokens=cache_write_tokens, + input_tokens=input_tokens, + output_tokens=output_tokens, + reasoning_tokens=reasoning_tokens, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["question"] = from_str(self.question) - if self.choices is not None: - result["choices"] = from_union([from_none, lambda x: from_list(from_str, x)], self.choices) - if self.allow_freeform is not None: - result["allowFreeform"] = from_union([from_none, from_bool], self.allow_freeform) - if self.tool_call_id is not None: - result["toolCallId"] = from_union([from_none, from_str], self.tool_call_id) + result["cacheReadTokens"] = to_float(self.cache_read_tokens) + result["cacheWriteTokens"] = to_float(self.cache_write_tokens) + result["inputTokens"] = to_float(self.input_tokens) + result["outputTokens"] = to_float(self.output_tokens) + if self.reasoning_tokens is not None: + result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) return result @dataclass -class UserInputCompletedData: - "User input request completion with the user's response" - request_id: str - answer: str | None = None - was_freeform: bool | None = None +class SkillInvokedData: + "Skill invocation details including content, allowed tools, and plugin metadata" + content: str + name: str + path: str + allowed_tools: list[str] | None = None + description: str | None = None + plugin_name: str | None = None + plugin_version: str | None = None @staticmethod - def from_dict(obj: Any) -> "UserInputCompletedData": + def from_dict(obj: Any) -> "SkillInvokedData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - answer = from_union([from_none, from_str], obj.get("answer")) - was_freeform = from_union([from_none, from_bool], obj.get("wasFreeform")) - return UserInputCompletedData( - request_id=request_id, - answer=answer, - was_freeform=was_freeform, + content = from_str(obj.get("content")) + name = from_str(obj.get("name")) + path = from_str(obj.get("path")) + allowed_tools = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("allowedTools")) + description = from_union([from_none, from_str], obj.get("description")) + plugin_name = from_union([from_none, from_str], obj.get("pluginName")) + plugin_version = from_union([from_none, from_str], obj.get("pluginVersion")) + return SkillInvokedData( + content=content, + name=name, + path=path, + allowed_tools=allowed_tools, + description=description, + plugin_name=plugin_name, + plugin_version=plugin_version, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.answer is not None: - result["answer"] = from_union([from_none, from_str], self.answer) - if self.was_freeform is not None: - result["wasFreeform"] = from_union([from_none, from_bool], self.was_freeform) + result["content"] = from_str(self.content) + result["name"] = from_str(self.name) + result["path"] = from_str(self.path) + if self.allowed_tools is not None: + result["allowedTools"] = from_union([from_none, lambda x: from_list(from_str, x)], self.allowed_tools) + if self.description is not None: + result["description"] = from_union([from_none, from_str], self.description) + if self.plugin_name is not None: + result["pluginName"] = from_union([from_none, from_str], self.plugin_name) + if self.plugin_version is not None: + result["pluginVersion"] = from_union([from_none, from_str], self.plugin_version) return result @dataclass -class ElicitationRequestedSchema: - "JSON Schema describing the form fields to present to the user (form mode only)" - type: str - properties: dict[str, Any] - required: list[str] | None = None +class SkillsLoadedSkill: + description: str + enabled: bool + name: str + source: str + user_invocable: bool + path: str | None = None @staticmethod - def from_dict(obj: Any) -> "ElicitationRequestedSchema": + def from_dict(obj: Any) -> "SkillsLoadedSkill": assert isinstance(obj, dict) - type = from_str(obj.get("type")) - properties = from_dict(lambda x: x, obj.get("properties")) - required = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("required")) - return ElicitationRequestedSchema( - type=type, - properties=properties, - required=required, + description = from_str(obj.get("description")) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = from_str(obj.get("source")) + user_invocable = from_bool(obj.get("userInvocable")) + path = from_union([from_none, from_str], obj.get("path")) + return SkillsLoadedSkill( + description=description, + enabled=enabled, + name=name, + source=source, + user_invocable=user_invocable, + path=path, ) def to_dict(self) -> dict: result: dict = {} - result["type"] = from_str(self.type) - result["properties"] = from_dict(lambda x: x, self.properties) - if self.required is not None: - result["required"] = from_union([from_none, lambda x: from_list(from_str, x)], self.required) + result["description"] = from_str(self.description) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = from_str(self.source) + result["userInvocable"] = from_bool(self.user_invocable) + if self.path is not None: + result["path"] = from_union([from_none, from_str], self.path) return result @dataclass -class ElicitationRequestedData: - "Elicitation request; may be form-based (structured input) or URL-based (browser redirect)" - request_id: str - message: str - tool_call_id: str | None = None - elicitation_source: str | None = None - mode: ElicitationRequestedMode | None = None - requested_schema: ElicitationRequestedSchema | None = None - url: str | None = None +class SubagentCompletedData: + "Sub-agent completion details for successful execution" + agent_display_name: str + agent_name: str + tool_call_id: str + duration_ms: float | None = None + model: str | None = None + total_tokens: float | None = None + total_tool_calls: float | None = None @staticmethod - def from_dict(obj: Any) -> "ElicitationRequestedData": + def from_dict(obj: Any) -> "SubagentCompletedData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - message = from_str(obj.get("message")) - tool_call_id = from_union([from_none, from_str], obj.get("toolCallId")) - elicitation_source = from_union([from_none, from_str], obj.get("elicitationSource")) - mode = from_union([from_none, lambda x: parse_enum(ElicitationRequestedMode, x)], obj.get("mode")) - requested_schema = from_union([from_none, ElicitationRequestedSchema.from_dict], obj.get("requestedSchema")) - url = from_union([from_none, from_str], obj.get("url")) - return ElicitationRequestedData( - request_id=request_id, - message=message, + agent_display_name = from_str(obj.get("agentDisplayName")) + agent_name = from_str(obj.get("agentName")) + tool_call_id = from_str(obj.get("toolCallId")) + duration_ms = from_union([from_none, from_float], obj.get("durationMs")) + model = from_union([from_none, from_str], obj.get("model")) + total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) + total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) + return SubagentCompletedData( + agent_display_name=agent_display_name, + agent_name=agent_name, tool_call_id=tool_call_id, - elicitation_source=elicitation_source, - mode=mode, - requested_schema=requested_schema, - url=url, + duration_ms=duration_ms, + model=model, + total_tokens=total_tokens, + total_tool_calls=total_tool_calls, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["message"] = from_str(self.message) - if self.tool_call_id is not None: - result["toolCallId"] = from_union([from_none, from_str], self.tool_call_id) - if self.elicitation_source is not None: - result["elicitationSource"] = from_union([from_none, from_str], self.elicitation_source) - if self.mode is not None: - result["mode"] = from_union([from_none, lambda x: to_enum(ElicitationRequestedMode, x)], self.mode) - if self.requested_schema is not None: - result["requestedSchema"] = from_union([from_none, lambda x: to_class(ElicitationRequestedSchema, x)], self.requested_schema) - if self.url is not None: - result["url"] = from_union([from_none, from_str], self.url) + result["agentDisplayName"] = from_str(self.agent_display_name) + result["agentName"] = from_str(self.agent_name) + result["toolCallId"] = from_str(self.tool_call_id) + if self.duration_ms is not None: + result["durationMs"] = from_union([from_none, to_float], self.duration_ms) + if self.model is not None: + result["model"] = from_union([from_none, from_str], self.model) + if self.total_tokens is not None: + result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) + if self.total_tool_calls is not None: + result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) return result @dataclass -class ElicitationCompletedData: - "Elicitation request completion with the user's response" - request_id: str - action: ElicitationCompletedAction | None = None - content: dict[str, Any] | None = None +class SubagentDeselectedData: + "Empty payload; the event signals that the custom agent was deselected, returning to the default agent" + @staticmethod + def from_dict(obj: Any) -> "SubagentDeselectedData": + assert isinstance(obj, dict) + return SubagentDeselectedData() + + def to_dict(self) -> dict: + return {} + + +@dataclass +class SubagentFailedData: + "Sub-agent failure details including error message and agent information" + agent_display_name: str + agent_name: str + error: str + tool_call_id: str + duration_ms: float | None = None + model: str | None = None + total_tokens: float | None = None + total_tool_calls: float | None = None @staticmethod - def from_dict(obj: Any) -> "ElicitationCompletedData": + def from_dict(obj: Any) -> "SubagentFailedData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - action = from_union([from_none, lambda x: parse_enum(ElicitationCompletedAction, x)], obj.get("action")) - content = from_union([from_none, lambda x: from_dict(lambda x: x, x)], obj.get("content")) - return ElicitationCompletedData( - request_id=request_id, - action=action, - content=content, + agent_display_name = from_str(obj.get("agentDisplayName")) + agent_name = from_str(obj.get("agentName")) + error = from_str(obj.get("error")) + tool_call_id = from_str(obj.get("toolCallId")) + duration_ms = from_union([from_none, from_float], obj.get("durationMs")) + model = from_union([from_none, from_str], obj.get("model")) + total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) + total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) + return SubagentFailedData( + agent_display_name=agent_display_name, + agent_name=agent_name, + error=error, + tool_call_id=tool_call_id, + duration_ms=duration_ms, + model=model, + total_tokens=total_tokens, + total_tool_calls=total_tool_calls, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.action is not None: - result["action"] = from_union([from_none, lambda x: to_enum(ElicitationCompletedAction, x)], self.action) - if self.content is not None: - result["content"] = from_union([from_none, lambda x: from_dict(lambda x: x, x)], self.content) + result["agentDisplayName"] = from_str(self.agent_display_name) + result["agentName"] = from_str(self.agent_name) + result["error"] = from_str(self.error) + result["toolCallId"] = from_str(self.tool_call_id) + if self.duration_ms is not None: + result["durationMs"] = from_union([from_none, to_float], self.duration_ms) + if self.model is not None: + result["model"] = from_union([from_none, from_str], self.model) + if self.total_tokens is not None: + result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) + if self.total_tool_calls is not None: + result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) return result @dataclass -class SamplingRequestedData: - "Sampling request from an MCP server; contains the server name and a requestId for correlation" - request_id: str - server_name: str - mcp_request_id: Any +class SubagentSelectedData: + "Custom agent selection details including name and available tools" + agent_display_name: str + agent_name: str + tools: list[str] | None @staticmethod - def from_dict(obj: Any) -> "SamplingRequestedData": + def from_dict(obj: Any) -> "SubagentSelectedData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - server_name = from_str(obj.get("serverName")) - mcp_request_id = obj.get("mcpRequestId") - return SamplingRequestedData( - request_id=request_id, - server_name=server_name, - mcp_request_id=mcp_request_id, + agent_display_name = from_str(obj.get("agentDisplayName")) + agent_name = from_str(obj.get("agentName")) + tools = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("tools")) + return SubagentSelectedData( + agent_display_name=agent_display_name, + agent_name=agent_name, + tools=tools, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["serverName"] = from_str(self.server_name) - result["mcpRequestId"] = self.mcp_request_id + result["agentDisplayName"] = from_str(self.agent_display_name) + result["agentName"] = from_str(self.agent_name) + result["tools"] = from_union([from_none, lambda x: from_list(from_str, x)], self.tools) return result @dataclass -class SamplingCompletedData: - "Sampling request completion notification signaling UI dismissal" - request_id: str +class SubagentStartedData: + "Sub-agent startup details including parent tool call and agent information" + agent_description: str + agent_display_name: str + agent_name: str + tool_call_id: str @staticmethod - def from_dict(obj: Any) -> "SamplingCompletedData": + def from_dict(obj: Any) -> "SubagentStartedData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - return SamplingCompletedData( - request_id=request_id, + agent_description = from_str(obj.get("agentDescription")) + agent_display_name = from_str(obj.get("agentDisplayName")) + agent_name = from_str(obj.get("agentName")) + tool_call_id = from_str(obj.get("toolCallId")) + return SubagentStartedData( + agent_description=agent_description, + agent_display_name=agent_display_name, + agent_name=agent_name, + tool_call_id=tool_call_id, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) + result["agentDescription"] = from_str(self.agent_description) + result["agentDisplayName"] = from_str(self.agent_display_name) + result["agentName"] = from_str(self.agent_name) + result["toolCallId"] = from_str(self.tool_call_id) return result @dataclass -class MCPOauthRequiredStaticClientConfig: - "Static OAuth client configuration, if the server specifies one" - client_id: str - public_client: bool | None = None +class SystemMessageData: + "System/developer instruction content with role and optional template metadata" + content: str + role: SystemMessageRole + metadata: SystemMessageMetadata | None = None + name: str | None = None @staticmethod - def from_dict(obj: Any) -> "MCPOauthRequiredStaticClientConfig": + def from_dict(obj: Any) -> "SystemMessageData": assert isinstance(obj, dict) - client_id = from_str(obj.get("clientId")) - public_client = from_union([from_none, from_bool], obj.get("publicClient")) - return MCPOauthRequiredStaticClientConfig( - client_id=client_id, - public_client=public_client, + content = from_str(obj.get("content")) + role = parse_enum(SystemMessageRole, obj.get("role")) + metadata = from_union([from_none, SystemMessageMetadata.from_dict], obj.get("metadata")) + name = from_union([from_none, from_str], obj.get("name")) + return SystemMessageData( + content=content, + role=role, + metadata=metadata, + name=name, ) def to_dict(self) -> dict: result: dict = {} - result["clientId"] = from_str(self.client_id) - if self.public_client is not None: - result["publicClient"] = from_union([from_none, from_bool], self.public_client) + result["content"] = from_str(self.content) + result["role"] = to_enum(SystemMessageRole, self.role) + if self.metadata is not None: + result["metadata"] = from_union([from_none, lambda x: to_class(SystemMessageMetadata, x)], self.metadata) + if self.name is not None: + result["name"] = from_union([from_none, from_str], self.name) return result @dataclass -class McpOauthRequiredData: - "OAuth authentication request for an MCP server" - request_id: str - server_name: str - server_url: str - static_client_config: MCPOauthRequiredStaticClientConfig | None = None +class SystemMessageMetadata: + "Metadata about the prompt template and its construction" + prompt_version: str | None = None + variables: dict[str, Any] | None = None @staticmethod - def from_dict(obj: Any) -> "McpOauthRequiredData": + def from_dict(obj: Any) -> "SystemMessageMetadata": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - server_name = from_str(obj.get("serverName")) - server_url = from_str(obj.get("serverUrl")) - static_client_config = from_union([from_none, MCPOauthRequiredStaticClientConfig.from_dict], obj.get("staticClientConfig")) - return McpOauthRequiredData( - request_id=request_id, - server_name=server_name, - server_url=server_url, - static_client_config=static_client_config, + prompt_version = from_union([from_none, from_str], obj.get("promptVersion")) + variables = from_union([from_none, lambda x: from_dict(lambda x: x, x)], obj.get("variables")) + return SystemMessageMetadata( + prompt_version=prompt_version, + variables=variables, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["serverName"] = from_str(self.server_name) - result["serverUrl"] = from_str(self.server_url) - if self.static_client_config is not None: - result["staticClientConfig"] = from_union([from_none, lambda x: to_class(MCPOauthRequiredStaticClientConfig, x)], self.static_client_config) + if self.prompt_version is not None: + result["promptVersion"] = from_union([from_none, from_str], self.prompt_version) + if self.variables is not None: + result["variables"] = from_union([from_none, lambda x: from_dict(lambda x: x, x)], self.variables) return result @dataclass -class McpOauthCompletedData: - "MCP OAuth request completion notification" - request_id: str +class SystemNotification: + "Structured metadata identifying what triggered this notification" + type: SystemNotificationType + agent_id: str | None = None + agent_type: str | None = None + description: str | None = None + entry_id: str | None = None + exit_code: float | None = None + prompt: str | None = None + sender_name: str | None = None + sender_type: str | None = None + shell_id: str | None = None + status: SystemNotificationAgentCompletedStatus | None = None + summary: str | None = None @staticmethod - def from_dict(obj: Any) -> "McpOauthCompletedData": + def from_dict(obj: Any) -> "SystemNotification": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - return McpOauthCompletedData( - request_id=request_id, + type = parse_enum(SystemNotificationType, obj.get("type")) + agent_id = from_union([from_none, from_str], obj.get("agentId")) + agent_type = from_union([from_none, from_str], obj.get("agentType")) + description = from_union([from_none, from_str], obj.get("description")) + entry_id = from_union([from_none, from_str], obj.get("entryId")) + exit_code = from_union([from_none, from_float], obj.get("exitCode")) + prompt = from_union([from_none, from_str], obj.get("prompt")) + sender_name = from_union([from_none, from_str], obj.get("senderName")) + sender_type = from_union([from_none, from_str], obj.get("senderType")) + shell_id = from_union([from_none, from_str], obj.get("shellId")) + status = from_union([from_none, lambda x: parse_enum(SystemNotificationAgentCompletedStatus, x)], obj.get("status")) + summary = from_union([from_none, from_str], obj.get("summary")) + return SystemNotification( + type=type, + agent_id=agent_id, + agent_type=agent_type, + description=description, + entry_id=entry_id, + exit_code=exit_code, + prompt=prompt, + sender_name=sender_name, + sender_type=sender_type, + shell_id=shell_id, + status=status, + summary=summary, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) + result["type"] = to_enum(SystemNotificationType, self.type) + if self.agent_id is not None: + result["agentId"] = from_union([from_none, from_str], self.agent_id) + if self.agent_type is not None: + result["agentType"] = from_union([from_none, from_str], self.agent_type) + if self.description is not None: + result["description"] = from_union([from_none, from_str], self.description) + if self.entry_id is not None: + result["entryId"] = from_union([from_none, from_str], self.entry_id) + if self.exit_code is not None: + result["exitCode"] = from_union([from_none, to_float], self.exit_code) + if self.prompt is not None: + result["prompt"] = from_union([from_none, from_str], self.prompt) + if self.sender_name is not None: + result["senderName"] = from_union([from_none, from_str], self.sender_name) + if self.sender_type is not None: + result["senderType"] = from_union([from_none, from_str], self.sender_type) + if self.shell_id is not None: + result["shellId"] = from_union([from_none, from_str], self.shell_id) + if self.status is not None: + result["status"] = from_union([from_none, lambda x: to_enum(SystemNotificationAgentCompletedStatus, x)], self.status) + if self.summary is not None: + result["summary"] = from_union([from_none, from_str], self.summary) return result @dataclass -class ExternalToolRequestedData: - "External tool invocation request for client-side tool execution" - request_id: str - session_id: str - tool_call_id: str - tool_name: str - arguments: Any = None - traceparent: str | None = None - tracestate: str | None = None +class SystemNotificationData: + "System-generated notification for runtime events like background task completion" + content: str + kind: SystemNotification @staticmethod - def from_dict(obj: Any) -> "ExternalToolRequestedData": + def from_dict(obj: Any) -> "SystemNotificationData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - session_id = from_str(obj.get("sessionId")) - tool_call_id = from_str(obj.get("toolCallId")) - tool_name = from_str(obj.get("toolName")) - arguments = obj.get("arguments") - traceparent = from_union([from_none, from_str], obj.get("traceparent")) - tracestate = from_union([from_none, from_str], obj.get("tracestate")) - return ExternalToolRequestedData( - request_id=request_id, - session_id=session_id, - tool_call_id=tool_call_id, - tool_name=tool_name, - arguments=arguments, - traceparent=traceparent, - tracestate=tracestate, + content = from_str(obj.get("content")) + kind = SystemNotification.from_dict(obj.get("kind")) + return SystemNotificationData( + content=content, + kind=kind, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["sessionId"] = from_str(self.session_id) - result["toolCallId"] = from_str(self.tool_call_id) - result["toolName"] = from_str(self.tool_name) - if self.arguments is not None: - result["arguments"] = self.arguments - if self.traceparent is not None: - result["traceparent"] = from_union([from_none, from_str], self.traceparent) - if self.tracestate is not None: - result["tracestate"] = from_union([from_none, from_str], self.tracestate) + result["content"] = from_str(self.content) + result["kind"] = to_class(SystemNotification, self.kind) return result @dataclass -class ExternalToolCompletedData: - "External tool completion notification signaling UI dismissal" - request_id: str +class ToolExecutionCompleteContent: + "A content block within a tool result, which may be text, terminal output, image, audio, or a resource" + type: ToolExecutionCompleteContentType + cwd: str | None = None + data: str | None = None + description: str | None = None + exit_code: float | None = None + icons: list[ToolExecutionCompleteContentResourceLinkIcon] | None = None + mime_type: str | None = None + name: str | None = None + resource: Any = None + size: float | None = None + text: str | None = None + title: str | None = None + uri: str | None = None @staticmethod - def from_dict(obj: Any) -> "ExternalToolCompletedData": + def from_dict(obj: Any) -> "ToolExecutionCompleteContent": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - return ExternalToolCompletedData( - request_id=request_id, + type = parse_enum(ToolExecutionCompleteContentType, obj.get("type")) + cwd = from_union([from_none, from_str], obj.get("cwd")) + data = from_union([from_none, from_str], obj.get("data")) + description = from_union([from_none, from_str], obj.get("description")) + exit_code = from_union([from_none, from_float], obj.get("exitCode")) + icons = from_union([from_none, lambda x: from_list(ToolExecutionCompleteContentResourceLinkIcon.from_dict, x)], obj.get("icons")) + mime_type = from_union([from_none, from_str], obj.get("mimeType")) + name = from_union([from_none, from_str], obj.get("name")) + resource = obj.get("resource") + size = from_union([from_none, from_float], obj.get("size")) + text = from_union([from_none, from_str], obj.get("text")) + title = from_union([from_none, from_str], obj.get("title")) + uri = from_union([from_none, from_str], obj.get("uri")) + return ToolExecutionCompleteContent( + type=type, + cwd=cwd, + data=data, + description=description, + exit_code=exit_code, + icons=icons, + mime_type=mime_type, + name=name, + resource=resource, + size=size, + text=text, + title=title, + uri=uri, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) + result["type"] = to_enum(ToolExecutionCompleteContentType, self.type) + if self.cwd is not None: + result["cwd"] = from_union([from_none, from_str], self.cwd) + if self.data is not None: + result["data"] = from_union([from_none, from_str], self.data) + if self.description is not None: + result["description"] = from_union([from_none, from_str], self.description) + if self.exit_code is not None: + result["exitCode"] = from_union([from_none, to_float], self.exit_code) + if self.icons is not None: + result["icons"] = from_union([from_none, lambda x: from_list(lambda x: to_class(ToolExecutionCompleteContentResourceLinkIcon, x), x)], self.icons) + if self.mime_type is not None: + result["mimeType"] = from_union([from_none, from_str], self.mime_type) + if self.name is not None: + result["name"] = from_union([from_none, from_str], self.name) + if self.resource is not None: + result["resource"] = self.resource + if self.size is not None: + result["size"] = from_union([from_none, to_float], self.size) + if self.text is not None: + result["text"] = from_union([from_none, from_str], self.text) + if self.title is not None: + result["title"] = from_union([from_none, from_str], self.title) + if self.uri is not None: + result["uri"] = from_union([from_none, from_str], self.uri) return result @dataclass -class CommandQueuedData: - "Queued slash command dispatch request for client execution" - request_id: str - command: str +class ToolExecutionCompleteContentResourceLinkIcon: + "Icon image for a resource" + src: str + mime_type: str | None = None + sizes: list[str] | None = None + theme: ToolExecutionCompleteContentResourceLinkIconTheme | None = None @staticmethod - def from_dict(obj: Any) -> "CommandQueuedData": + def from_dict(obj: Any) -> "ToolExecutionCompleteContentResourceLinkIcon": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - command = from_str(obj.get("command")) - return CommandQueuedData( - request_id=request_id, - command=command, + src = from_str(obj.get("src")) + mime_type = from_union([from_none, from_str], obj.get("mimeType")) + sizes = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("sizes")) + theme = from_union([from_none, lambda x: parse_enum(ToolExecutionCompleteContentResourceLinkIconTheme, x)], obj.get("theme")) + return ToolExecutionCompleteContentResourceLinkIcon( + src=src, + mime_type=mime_type, + sizes=sizes, + theme=theme, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["command"] = from_str(self.command) + result["src"] = from_str(self.src) + if self.mime_type is not None: + result["mimeType"] = from_union([from_none, from_str], self.mime_type) + if self.sizes is not None: + result["sizes"] = from_union([from_none, lambda x: from_list(from_str, x)], self.sizes) + if self.theme is not None: + result["theme"] = from_union([from_none, lambda x: to_enum(ToolExecutionCompleteContentResourceLinkIconTheme, x)], self.theme) return result @dataclass -class CommandExecuteData: - "Registered command dispatch request routed to the owning client" - request_id: str - command: str - command_name: str - args: str +class ToolExecutionCompleteData: + "Tool execution completion results including success status, detailed output, and error information" + success: bool + tool_call_id: str + error: ToolExecutionCompleteError | None = None + interaction_id: str | None = None + is_user_requested: bool | None = None + model: str | None = None + # Deprecated: this field is deprecated. + parent_tool_call_id: str | None = None + result: ToolExecutionCompleteResult | None = None + tool_telemetry: dict[str, Any] | None = None @staticmethod - def from_dict(obj: Any) -> "CommandExecuteData": + def from_dict(obj: Any) -> "ToolExecutionCompleteData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - command = from_str(obj.get("command")) - command_name = from_str(obj.get("commandName")) - args = from_str(obj.get("args")) - return CommandExecuteData( - request_id=request_id, - command=command, - command_name=command_name, - args=args, + success = from_bool(obj.get("success")) + tool_call_id = from_str(obj.get("toolCallId")) + error = from_union([from_none, ToolExecutionCompleteError.from_dict], obj.get("error")) + interaction_id = from_union([from_none, from_str], obj.get("interactionId")) + is_user_requested = from_union([from_none, from_bool], obj.get("isUserRequested")) + model = from_union([from_none, from_str], obj.get("model")) + parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) + result = from_union([from_none, ToolExecutionCompleteResult.from_dict], obj.get("result")) + tool_telemetry = from_union([from_none, lambda x: from_dict(lambda x: x, x)], obj.get("toolTelemetry")) + return ToolExecutionCompleteData( + success=success, + tool_call_id=tool_call_id, + error=error, + interaction_id=interaction_id, + is_user_requested=is_user_requested, + model=model, + parent_tool_call_id=parent_tool_call_id, + result=result, + tool_telemetry=tool_telemetry, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["command"] = from_str(self.command) - result["commandName"] = from_str(self.command_name) - result["args"] = from_str(self.args) + result["success"] = from_bool(self.success) + result["toolCallId"] = from_str(self.tool_call_id) + if self.error is not None: + result["error"] = from_union([from_none, lambda x: to_class(ToolExecutionCompleteError, x)], self.error) + if self.interaction_id is not None: + result["interactionId"] = from_union([from_none, from_str], self.interaction_id) + if self.is_user_requested is not None: + result["isUserRequested"] = from_union([from_none, from_bool], self.is_user_requested) + if self.model is not None: + result["model"] = from_union([from_none, from_str], self.model) + if self.parent_tool_call_id is not None: + result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) + if self.result is not None: + result["result"] = from_union([from_none, lambda x: to_class(ToolExecutionCompleteResult, x)], self.result) + if self.tool_telemetry is not None: + result["toolTelemetry"] = from_union([from_none, lambda x: from_dict(lambda x: x, x)], self.tool_telemetry) return result @dataclass -class CommandCompletedData: - "Queued command completion notification signaling UI dismissal" - request_id: str +class ToolExecutionCompleteError: + "Error details when the tool execution failed" + message: str + code: str | None = None @staticmethod - def from_dict(obj: Any) -> "CommandCompletedData": + def from_dict(obj: Any) -> "ToolExecutionCompleteError": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - return CommandCompletedData( - request_id=request_id, + message = from_str(obj.get("message")) + code = from_union([from_none, from_str], obj.get("code")) + return ToolExecutionCompleteError( + message=message, + code=code, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) + result["message"] = from_str(self.message) + if self.code is not None: + result["code"] = from_union([from_none, from_str], self.code) return result @dataclass -class CommandsChangedCommand: - name: str - description: str | None = None +class ToolExecutionCompleteResult: + "Tool execution result on success" + content: str + contents: list[ToolExecutionCompleteContent] | None = None + detailed_content: str | None = None @staticmethod - def from_dict(obj: Any) -> "CommandsChangedCommand": + def from_dict(obj: Any) -> "ToolExecutionCompleteResult": assert isinstance(obj, dict) - name = from_str(obj.get("name")) - description = from_union([from_none, from_str], obj.get("description")) - return CommandsChangedCommand( - name=name, - description=description, + content = from_str(obj.get("content")) + contents = from_union([from_none, lambda x: from_list(ToolExecutionCompleteContent.from_dict, x)], obj.get("contents")) + detailed_content = from_union([from_none, from_str], obj.get("detailedContent")) + return ToolExecutionCompleteResult( + content=content, + contents=contents, + detailed_content=detailed_content, ) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - if self.description is not None: - result["description"] = from_union([from_none, from_str], self.description) + result["content"] = from_str(self.content) + if self.contents is not None: + result["contents"] = from_union([from_none, lambda x: from_list(lambda x: to_class(ToolExecutionCompleteContent, x), x)], self.contents) + if self.detailed_content is not None: + result["detailedContent"] = from_union([from_none, from_str], self.detailed_content) return result @dataclass -class CommandsChangedData: - "SDK command registration change notification" - commands: list[CommandsChangedCommand] +class ToolExecutionPartialResultData: + "Streaming tool execution output for incremental result display" + partial_output: str + tool_call_id: str @staticmethod - def from_dict(obj: Any) -> "CommandsChangedData": + def from_dict(obj: Any) -> "ToolExecutionPartialResultData": assert isinstance(obj, dict) - commands = from_list(CommandsChangedCommand.from_dict, obj.get("commands")) - return CommandsChangedData( - commands=commands, + partial_output = from_str(obj.get("partialOutput")) + tool_call_id = from_str(obj.get("toolCallId")) + return ToolExecutionPartialResultData( + partial_output=partial_output, + tool_call_id=tool_call_id, ) def to_dict(self) -> dict: result: dict = {} - result["commands"] = from_list(lambda x: to_class(CommandsChangedCommand, x), self.commands) + result["partialOutput"] = from_str(self.partial_output) + result["toolCallId"] = from_str(self.tool_call_id) return result @dataclass -class CapabilitiesChangedUI: - "UI capability changes" - elicitation: bool | None = None +class ToolExecutionProgressData: + "Tool execution progress notification with status message" + progress_message: str + tool_call_id: str @staticmethod - def from_dict(obj: Any) -> "CapabilitiesChangedUI": + def from_dict(obj: Any) -> "ToolExecutionProgressData": assert isinstance(obj, dict) - elicitation = from_union([from_none, from_bool], obj.get("elicitation")) - return CapabilitiesChangedUI( - elicitation=elicitation, + progress_message = from_str(obj.get("progressMessage")) + tool_call_id = from_str(obj.get("toolCallId")) + return ToolExecutionProgressData( + progress_message=progress_message, + tool_call_id=tool_call_id, ) def to_dict(self) -> dict: result: dict = {} - if self.elicitation is not None: - result["elicitation"] = from_union([from_none, from_bool], self.elicitation) + result["progressMessage"] = from_str(self.progress_message) + result["toolCallId"] = from_str(self.tool_call_id) return result @dataclass -class CapabilitiesChangedData: - "Session capability change notification" - ui: CapabilitiesChangedUI | None = None +class ToolExecutionStartData: + "Tool execution startup details including MCP server information when applicable" + tool_call_id: str + tool_name: str + arguments: Any = None + mcp_server_name: str | None = None + mcp_tool_name: str | None = None + # Deprecated: this field is deprecated. + parent_tool_call_id: str | None = None @staticmethod - def from_dict(obj: Any) -> "CapabilitiesChangedData": + def from_dict(obj: Any) -> "ToolExecutionStartData": assert isinstance(obj, dict) - ui = from_union([from_none, CapabilitiesChangedUI.from_dict], obj.get("ui")) - return CapabilitiesChangedData( - ui=ui, + tool_call_id = from_str(obj.get("toolCallId")) + tool_name = from_str(obj.get("toolName")) + arguments = obj.get("arguments") + mcp_server_name = from_union([from_none, from_str], obj.get("mcpServerName")) + mcp_tool_name = from_union([from_none, from_str], obj.get("mcpToolName")) + parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) + return ToolExecutionStartData( + tool_call_id=tool_call_id, + tool_name=tool_name, + arguments=arguments, + mcp_server_name=mcp_server_name, + mcp_tool_name=mcp_tool_name, + parent_tool_call_id=parent_tool_call_id, ) def to_dict(self) -> dict: result: dict = {} - if self.ui is not None: - result["ui"] = from_union([from_none, lambda x: to_class(CapabilitiesChangedUI, x)], self.ui) + result["toolCallId"] = from_str(self.tool_call_id) + result["toolName"] = from_str(self.tool_name) + if self.arguments is not None: + result["arguments"] = self.arguments + if self.mcp_server_name is not None: + result["mcpServerName"] = from_union([from_none, from_str], self.mcp_server_name) + if self.mcp_tool_name is not None: + result["mcpToolName"] = from_union([from_none, from_str], self.mcp_tool_name) + if self.parent_tool_call_id is not None: + result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) return result @dataclass -class ExitPlanModeRequestedData: - "Plan approval request with plan content and available user actions" - request_id: str - summary: str - plan_content: str - actions: list[str] - recommended_action: str +class ToolUserRequestedData: + "User-initiated tool invocation request with tool name and arguments" + tool_call_id: str + tool_name: str + arguments: Any = None @staticmethod - def from_dict(obj: Any) -> "ExitPlanModeRequestedData": + def from_dict(obj: Any) -> "ToolUserRequestedData": assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - summary = from_str(obj.get("summary")) - plan_content = from_str(obj.get("planContent")) - actions = from_list(from_str, obj.get("actions")) - recommended_action = from_str(obj.get("recommendedAction")) - return ExitPlanModeRequestedData( - request_id=request_id, - summary=summary, - plan_content=plan_content, - actions=actions, - recommended_action=recommended_action, + tool_call_id = from_str(obj.get("toolCallId")) + tool_name = from_str(obj.get("toolName")) + arguments = obj.get("arguments") + return ToolUserRequestedData( + tool_call_id=tool_call_id, + tool_name=tool_name, + arguments=arguments, ) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["summary"] = from_str(self.summary) - result["planContent"] = from_str(self.plan_content) - result["actions"] = from_list(from_str, self.actions) - result["recommendedAction"] = from_str(self.recommended_action) + result["toolCallId"] = from_str(self.tool_call_id) + result["toolName"] = from_str(self.tool_name) + if self.arguments is not None: + result["arguments"] = self.arguments return result @dataclass -class ExitPlanModeCompletedData: - "Plan mode exit completion with the user's approval decision and optional feedback" +class UserInputCompletedData: + "User input request completion with the user's response" request_id: str - approved: bool | None = None - selected_action: str | None = None - auto_approve_edits: bool | None = None - feedback: str | None = None + answer: str | None = None + was_freeform: bool | None = None @staticmethod - def from_dict(obj: Any) -> "ExitPlanModeCompletedData": + def from_dict(obj: Any) -> "UserInputCompletedData": assert isinstance(obj, dict) request_id = from_str(obj.get("requestId")) - approved = from_union([from_none, from_bool], obj.get("approved")) - selected_action = from_union([from_none, from_str], obj.get("selectedAction")) - auto_approve_edits = from_union([from_none, from_bool], obj.get("autoApproveEdits")) - feedback = from_union([from_none, from_str], obj.get("feedback")) - return ExitPlanModeCompletedData( + answer = from_union([from_none, from_str], obj.get("answer")) + was_freeform = from_union([from_none, from_bool], obj.get("wasFreeform")) + return UserInputCompletedData( request_id=request_id, - approved=approved, - selected_action=selected_action, - auto_approve_edits=auto_approve_edits, - feedback=feedback, + answer=answer, + was_freeform=was_freeform, ) def to_dict(self) -> dict: result: dict = {} result["requestId"] = from_str(self.request_id) - if self.approved is not None: - result["approved"] = from_union([from_none, from_bool], self.approved) - if self.selected_action is not None: - result["selectedAction"] = from_union([from_none, from_str], self.selected_action) - if self.auto_approve_edits is not None: - result["autoApproveEdits"] = from_union([from_none, from_bool], self.auto_approve_edits) - if self.feedback is not None: - result["feedback"] = from_union([from_none, from_str], self.feedback) + if self.answer is not None: + result["answer"] = from_union([from_none, from_str], self.answer) + if self.was_freeform is not None: + result["wasFreeform"] = from_union([from_none, from_bool], self.was_freeform) return result @dataclass -class SessionToolsUpdatedData: - model: str +class UserInputRequestedData: + "User input request notification with question and optional predefined choices" + question: str + request_id: str + allow_freeform: bool | None = None + choices: list[str] | None = None + tool_call_id: str | None = None @staticmethod - def from_dict(obj: Any) -> "SessionToolsUpdatedData": + def from_dict(obj: Any) -> "UserInputRequestedData": assert isinstance(obj, dict) - model = from_str(obj.get("model")) - return SessionToolsUpdatedData( - model=model, + question = from_str(obj.get("question")) + request_id = from_str(obj.get("requestId")) + allow_freeform = from_union([from_none, from_bool], obj.get("allowFreeform")) + choices = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("choices")) + tool_call_id = from_union([from_none, from_str], obj.get("toolCallId")) + return UserInputRequestedData( + question=question, + request_id=request_id, + allow_freeform=allow_freeform, + choices=choices, + tool_call_id=tool_call_id, ) def to_dict(self) -> dict: result: dict = {} - result["model"] = from_str(self.model) + result["question"] = from_str(self.question) + result["requestId"] = from_str(self.request_id) + if self.allow_freeform is not None: + result["allowFreeform"] = from_union([from_none, from_bool], self.allow_freeform) + if self.choices is not None: + result["choices"] = from_union([from_none, lambda x: from_list(from_str, x)], self.choices) + if self.tool_call_id is not None: + result["toolCallId"] = from_union([from_none, from_str], self.tool_call_id) return result @dataclass -class SessionBackgroundTasksChangedData: - @staticmethod - def from_dict(obj: Any) -> "SessionBackgroundTasksChangedData": - assert isinstance(obj, dict) - return SessionBackgroundTasksChangedData() - - def to_dict(self) -> dict: - return {} - - -@dataclass -class SkillsLoadedSkill: - name: str - description: str - source: str - user_invocable: bool - enabled: bool +class UserMessageAttachment: + "A user message attachment — a file, directory, code selection, blob, or GitHub reference" + type: UserMessageAttachmentType + data: str | None = None + display_name: str | None = None + file_path: str | None = None + line_range: UserMessageAttachmentFileLineRange | None = None + mime_type: str | None = None + number: float | None = None path: str | None = None + reference_type: UserMessageAttachmentGithubReferenceType | None = None + selection: UserMessageAttachmentSelectionDetails | None = None + state: str | None = None + text: str | None = None + title: str | None = None + url: str | None = None @staticmethod - def from_dict(obj: Any) -> "SkillsLoadedSkill": + def from_dict(obj: Any) -> "UserMessageAttachment": assert isinstance(obj, dict) - name = from_str(obj.get("name")) - description = from_str(obj.get("description")) - source = from_str(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - enabled = from_bool(obj.get("enabled")) + type = parse_enum(UserMessageAttachmentType, obj.get("type")) + data = from_union([from_none, from_str], obj.get("data")) + display_name = from_union([from_none, from_str], obj.get("displayName")) + file_path = from_union([from_none, from_str], obj.get("filePath")) + line_range = from_union([from_none, UserMessageAttachmentFileLineRange.from_dict], obj.get("lineRange")) + mime_type = from_union([from_none, from_str], obj.get("mimeType")) + number = from_union([from_none, from_float], obj.get("number")) path = from_union([from_none, from_str], obj.get("path")) - return SkillsLoadedSkill( - name=name, - description=description, - source=source, - user_invocable=user_invocable, - enabled=enabled, + reference_type = from_union([from_none, lambda x: parse_enum(UserMessageAttachmentGithubReferenceType, x)], obj.get("referenceType")) + selection = from_union([from_none, UserMessageAttachmentSelectionDetails.from_dict], obj.get("selection")) + state = from_union([from_none, from_str], obj.get("state")) + text = from_union([from_none, from_str], obj.get("text")) + title = from_union([from_none, from_str], obj.get("title")) + url = from_union([from_none, from_str], obj.get("url")) + return UserMessageAttachment( + type=type, + data=data, + display_name=display_name, + file_path=file_path, + line_range=line_range, + mime_type=mime_type, + number=number, path=path, + reference_type=reference_type, + selection=selection, + state=state, + text=text, + title=title, + url=url, ) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["description"] = from_str(self.description) - result["source"] = from_str(self.source) - result["userInvocable"] = from_bool(self.user_invocable) - result["enabled"] = from_bool(self.enabled) + result["type"] = to_enum(UserMessageAttachmentType, self.type) + if self.data is not None: + result["data"] = from_union([from_none, from_str], self.data) + if self.display_name is not None: + result["displayName"] = from_union([from_none, from_str], self.display_name) + if self.file_path is not None: + result["filePath"] = from_union([from_none, from_str], self.file_path) + if self.line_range is not None: + result["lineRange"] = from_union([from_none, lambda x: to_class(UserMessageAttachmentFileLineRange, x)], self.line_range) + if self.mime_type is not None: + result["mimeType"] = from_union([from_none, from_str], self.mime_type) + if self.number is not None: + result["number"] = from_union([from_none, to_float], self.number) if self.path is not None: result["path"] = from_union([from_none, from_str], self.path) + if self.reference_type is not None: + result["referenceType"] = from_union([from_none, lambda x: to_enum(UserMessageAttachmentGithubReferenceType, x)], self.reference_type) + if self.selection is not None: + result["selection"] = from_union([from_none, lambda x: to_class(UserMessageAttachmentSelectionDetails, x)], self.selection) + if self.state is not None: + result["state"] = from_union([from_none, from_str], self.state) + if self.text is not None: + result["text"] = from_union([from_none, from_str], self.text) + if self.title is not None: + result["title"] = from_union([from_none, from_str], self.title) + if self.url is not None: + result["url"] = from_union([from_none, from_str], self.url) return result @dataclass -class SessionSkillsLoadedData: - skills: list[SkillsLoadedSkill] - - @staticmethod - def from_dict(obj: Any) -> "SessionSkillsLoadedData": - assert isinstance(obj, dict) - skills = from_list(SkillsLoadedSkill.from_dict, obj.get("skills")) - return SessionSkillsLoadedData( - skills=skills, - ) - - def to_dict(self) -> dict: - result: dict = {} - result["skills"] = from_list(lambda x: to_class(SkillsLoadedSkill, x), self.skills) - return result - - -@dataclass -class CustomAgentsUpdatedAgent: - id: str - name: str - display_name: str - description: str - source: str - tools: list[str] - user_invocable: bool - model: str | None = None +class UserMessageAttachmentFileLineRange: + "Optional line range to scope the attachment to a specific section of the file" + end: float + start: float @staticmethod - def from_dict(obj: Any) -> "CustomAgentsUpdatedAgent": + def from_dict(obj: Any) -> "UserMessageAttachmentFileLineRange": assert isinstance(obj, dict) - id = from_str(obj.get("id")) - name = from_str(obj.get("name")) - display_name = from_str(obj.get("displayName")) - description = from_str(obj.get("description")) - source = from_str(obj.get("source")) - tools = from_list(from_str, obj.get("tools")) - user_invocable = from_bool(obj.get("userInvocable")) - model = from_union([from_none, from_str], obj.get("model")) - return CustomAgentsUpdatedAgent( - id=id, - name=name, - display_name=display_name, - description=description, - source=source, - tools=tools, - user_invocable=user_invocable, - model=model, + end = from_float(obj.get("end")) + start = from_float(obj.get("start")) + return UserMessageAttachmentFileLineRange( + end=end, + start=start, ) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) - result["name"] = from_str(self.name) - result["displayName"] = from_str(self.display_name) - result["description"] = from_str(self.description) - result["source"] = from_str(self.source) - result["tools"] = from_list(from_str, self.tools) - result["userInvocable"] = from_bool(self.user_invocable) - if self.model is not None: - result["model"] = from_union([from_none, from_str], self.model) + result["end"] = to_float(self.end) + result["start"] = to_float(self.start) return result @dataclass -class SessionCustomAgentsUpdatedData: - agents: list[CustomAgentsUpdatedAgent] - warnings: list[str] - errors: list[str] +class UserMessageAttachmentSelectionDetails: + "Position range of the selection within the file" + end: UserMessageAttachmentSelectionDetailsEnd + start: UserMessageAttachmentSelectionDetailsStart @staticmethod - def from_dict(obj: Any) -> "SessionCustomAgentsUpdatedData": + def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetails": assert isinstance(obj, dict) - agents = from_list(CustomAgentsUpdatedAgent.from_dict, obj.get("agents")) - warnings = from_list(from_str, obj.get("warnings")) - errors = from_list(from_str, obj.get("errors")) - return SessionCustomAgentsUpdatedData( - agents=agents, - warnings=warnings, - errors=errors, + end = UserMessageAttachmentSelectionDetailsEnd.from_dict(obj.get("end")) + start = UserMessageAttachmentSelectionDetailsStart.from_dict(obj.get("start")) + return UserMessageAttachmentSelectionDetails( + end=end, + start=start, ) def to_dict(self) -> dict: result: dict = {} - result["agents"] = from_list(lambda x: to_class(CustomAgentsUpdatedAgent, x), self.agents) - result["warnings"] = from_list(from_str, self.warnings) - result["errors"] = from_list(from_str, self.errors) + result["end"] = to_class(UserMessageAttachmentSelectionDetailsEnd, self.end) + result["start"] = to_class(UserMessageAttachmentSelectionDetailsStart, self.start) return result @dataclass -class MCPServersLoadedServer: - name: str - status: MCPServerStatus - source: str | None = None - error: str | None = None +class UserMessageAttachmentSelectionDetailsEnd: + "End position of the selection" + character: float + line: float @staticmethod - def from_dict(obj: Any) -> "MCPServersLoadedServer": + def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsEnd": assert isinstance(obj, dict) - name = from_str(obj.get("name")) - status = parse_enum(MCPServerStatus, obj.get("status")) - source = from_union([from_none, from_str], obj.get("source")) - error = from_union([from_none, from_str], obj.get("error")) - return MCPServersLoadedServer( - name=name, - status=status, - source=source, - error=error, + character = from_float(obj.get("character")) + line = from_float(obj.get("line")) + return UserMessageAttachmentSelectionDetailsEnd( + character=character, + line=line, ) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["status"] = to_enum(MCPServerStatus, self.status) - if self.source is not None: - result["source"] = from_union([from_none, from_str], self.source) - if self.error is not None: - result["error"] = from_union([from_none, from_str], self.error) + result["character"] = to_float(self.character) + result["line"] = to_float(self.line) return result @dataclass -class SessionMcpServersLoadedData: - servers: list[MCPServersLoadedServer] +class UserMessageAttachmentSelectionDetailsStart: + "Start position of the selection" + character: float + line: float @staticmethod - def from_dict(obj: Any) -> "SessionMcpServersLoadedData": + def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsStart": assert isinstance(obj, dict) - servers = from_list(MCPServersLoadedServer.from_dict, obj.get("servers")) - return SessionMcpServersLoadedData( - servers=servers, + character = from_float(obj.get("character")) + line = from_float(obj.get("line")) + return UserMessageAttachmentSelectionDetailsStart( + character=character, + line=line, ) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_list(lambda x: to_class(MCPServersLoadedServer, x), self.servers) + result["character"] = to_float(self.character) + result["line"] = to_float(self.line) return result @dataclass -class SessionMcpServerStatusChangedData: - server_name: str - status: SessionMcpServerStatusChangedDataStatus +class UserMessageData: + content: str + agent_mode: UserMessageAgentMode | None = None + attachments: list[UserMessageAttachment] | None = None + interaction_id: str | None = None + native_document_path_fallback_paths: list[str] | None = None + source: str | None = None + supported_native_document_mime_types: list[str] | None = None + transformed_content: str | None = None @staticmethod - def from_dict(obj: Any) -> "SessionMcpServerStatusChangedData": + def from_dict(obj: Any) -> "UserMessageData": assert isinstance(obj, dict) - server_name = from_str(obj.get("serverName")) - status = parse_enum(SessionMcpServerStatusChangedDataStatus, obj.get("status")) - return SessionMcpServerStatusChangedData( - server_name=server_name, - status=status, + content = from_str(obj.get("content")) + agent_mode = from_union([from_none, lambda x: parse_enum(UserMessageAgentMode, x)], obj.get("agentMode")) + attachments = from_union([from_none, lambda x: from_list(UserMessageAttachment.from_dict, x)], obj.get("attachments")) + interaction_id = from_union([from_none, from_str], obj.get("interactionId")) + native_document_path_fallback_paths = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("nativeDocumentPathFallbackPaths")) + source = from_union([from_none, from_str], obj.get("source")) + supported_native_document_mime_types = from_union([from_none, lambda x: from_list(from_str, x)], obj.get("supportedNativeDocumentMimeTypes")) + transformed_content = from_union([from_none, from_str], obj.get("transformedContent")) + return UserMessageData( + content=content, + agent_mode=agent_mode, + attachments=attachments, + interaction_id=interaction_id, + native_document_path_fallback_paths=native_document_path_fallback_paths, + source=source, + supported_native_document_mime_types=supported_native_document_mime_types, + transformed_content=transformed_content, ) def to_dict(self) -> dict: result: dict = {} - result["serverName"] = from_str(self.server_name) - result["status"] = to_enum(SessionMcpServerStatusChangedDataStatus, self.status) + result["content"] = from_str(self.content) + if self.agent_mode is not None: + result["agentMode"] = from_union([from_none, lambda x: to_enum(UserMessageAgentMode, x)], self.agent_mode) + if self.attachments is not None: + result["attachments"] = from_union([from_none, lambda x: from_list(lambda x: to_class(UserMessageAttachment, x), x)], self.attachments) + if self.interaction_id is not None: + result["interactionId"] = from_union([from_none, from_str], self.interaction_id) + if self.native_document_path_fallback_paths is not None: + result["nativeDocumentPathFallbackPaths"] = from_union([from_none, lambda x: from_list(from_str, x)], self.native_document_path_fallback_paths) + if self.source is not None: + result["source"] = from_union([from_none, from_str], self.source) + if self.supported_native_document_mime_types is not None: + result["supportedNativeDocumentMimeTypes"] = from_union([from_none, lambda x: from_list(from_str, x)], self.supported_native_document_mime_types) + if self.transformed_content is not None: + result["transformedContent"] = from_union([from_none, from_str], self.transformed_content) return result @dataclass -class ExtensionsLoadedExtension: - id: str - name: str - source: ExtensionsLoadedExtensionSource - status: ExtensionsLoadedExtensionStatus +class WorkingDirectoryContext: + "Working directory and git context at session start" + cwd: str + base_commit: str | None = None + branch: str | None = None + git_root: str | None = None + head_commit: str | None = None + host_type: WorkingDirectoryContextHostType | None = None + repository: str | None = None + repository_host: str | None = None @staticmethod - def from_dict(obj: Any) -> "ExtensionsLoadedExtension": + def from_dict(obj: Any) -> "WorkingDirectoryContext": assert isinstance(obj, dict) - id = from_str(obj.get("id")) - name = from_str(obj.get("name")) - source = parse_enum(ExtensionsLoadedExtensionSource, obj.get("source")) - status = parse_enum(ExtensionsLoadedExtensionStatus, obj.get("status")) - return ExtensionsLoadedExtension( - id=id, - name=name, - source=source, - status=status, + cwd = from_str(obj.get("cwd")) + base_commit = from_union([from_none, from_str], obj.get("baseCommit")) + branch = from_union([from_none, from_str], obj.get("branch")) + git_root = from_union([from_none, from_str], obj.get("gitRoot")) + head_commit = from_union([from_none, from_str], obj.get("headCommit")) + host_type = from_union([from_none, lambda x: parse_enum(WorkingDirectoryContextHostType, x)], obj.get("hostType")) + repository = from_union([from_none, from_str], obj.get("repository")) + repository_host = from_union([from_none, from_str], obj.get("repositoryHost")) + return WorkingDirectoryContext( + cwd=cwd, + base_commit=base_commit, + branch=branch, + git_root=git_root, + head_commit=head_commit, + host_type=host_type, + repository=repository, + repository_host=repository_host, ) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) - result["name"] = from_str(self.name) - result["source"] = to_enum(ExtensionsLoadedExtensionSource, self.source) - result["status"] = to_enum(ExtensionsLoadedExtensionStatus, self.status) + result["cwd"] = from_str(self.cwd) + if self.base_commit is not None: + result["baseCommit"] = from_union([from_none, from_str], self.base_commit) + if self.branch is not None: + result["branch"] = from_union([from_none, from_str], self.branch) + if self.git_root is not None: + result["gitRoot"] = from_union([from_none, from_str], self.git_root) + if self.head_commit is not None: + result["headCommit"] = from_union([from_none, from_str], self.head_commit) + if self.host_type is not None: + result["hostType"] = from_union([from_none, lambda x: to_enum(WorkingDirectoryContextHostType, x)], self.host_type) + if self.repository is not None: + result["repository"] = from_union([from_none, from_str], self.repository) + if self.repository_host is not None: + result["repositoryHost"] = from_union([from_none, from_str], self.repository_host) return result -@dataclass -class SessionExtensionsLoadedData: - extensions: list[ExtensionsLoadedExtension] +class AssistantMessageToolRequestType(Enum): + "Tool call type: \"function\" for standard tool calls, \"custom\" for grammar-based tool calls. Defaults to \"function\" when absent." + FUNCTION = "function" + CUSTOM = "custom" - @staticmethod - def from_dict(obj: Any) -> "SessionExtensionsLoadedData": - assert isinstance(obj, dict) - extensions = from_list(ExtensionsLoadedExtension.from_dict, obj.get("extensions")) - return SessionExtensionsLoadedData( - extensions=extensions, - ) - def to_dict(self) -> dict: - result: dict = {} - result["extensions"] = from_list(lambda x: to_class(ExtensionsLoadedExtension, x), self.extensions) - return result +class ElicitationCompletedAction(Enum): + "The user action: \"accept\" (submitted form), \"decline\" (explicitly refused), or \"cancel\" (dismissed)" + ACCEPT = "accept" + DECLINE = "decline" + CANCEL = "cancel" -class WorkingDirectoryContextHostType(Enum): - "Hosting platform type of the repository (github or ado)" - GITHUB = "github" - ADO = "ado" +class ElicitationRequestedMode(Enum): + "Elicitation mode; \"form\" for structured input, \"url\" for browser-based. Defaults to \"form\" when absent." + FORM = "form" + URL = "url" -class SessionPlanChangedDataOperation(Enum): - "The type of operation performed on the plan file" - CREATE = "create" - UPDATE = "update" - DELETE = "delete" +class ExtensionsLoadedExtensionSource(Enum): + "Discovery source" + PROJECT = "project" + USER = "user" -class SessionWorkspaceFileChangedDataOperation(Enum): - "Whether the file was newly created or updated" - CREATE = "create" - UPDATE = "update" +class ExtensionsLoadedExtensionStatus(Enum): + "Current status: running, disabled, failed, or starting" + RUNNING = "running" + DISABLED = "disabled" + FAILED = "failed" + STARTING = "starting" class HandoffSourceType(Enum): @@ -3930,85 +3974,37 @@ class HandoffSourceType(Enum): LOCAL = "local" -class ShutdownType(Enum): - "Whether the session ended normally (\"routine\") or due to a crash/fatal error (\"error\")" - ROUTINE = "routine" - ERROR = "error" - - -class SessionContextChangedDataHostType(Enum): - "Hosting platform type of the repository (github or ado)" - GITHUB = "github" - ADO = "ado" - - -class UserMessageAttachmentType(Enum): - "A user message attachment — a file, directory, code selection, blob, or GitHub reference discriminator" - FILE = "file" - DIRECTORY = "directory" - SELECTION = "selection" - GITHUB_REFERENCE = "github_reference" - BLOB = "blob" - - -class UserMessageAttachmentGithubReferenceType(Enum): - "Type of GitHub reference" - ISSUE = "issue" - PR = "pr" - DISCUSSION = "discussion" - - -class UserMessageAgentMode(Enum): - "The agent mode that was active when this message was sent" - INTERACTIVE = "interactive" - PLAN = "plan" - AUTOPILOT = "autopilot" - SHELL = "shell" - - -class AssistantMessageToolRequestType(Enum): - "Tool call type: \"function\" for standard tool calls, \"custom\" for grammar-based tool calls. Defaults to \"function\" when absent." - FUNCTION = "function" - CUSTOM = "custom" - - -class ToolExecutionCompleteDataResultContentsItemType(Enum): - "A content block within a tool result, which may be text, terminal output, image, audio, or a resource discriminator" - TEXT = "text" - TERMINAL = "terminal" - IMAGE = "image" - AUDIO = "audio" - RESOURCE_LINK = "resource_link" - RESOURCE = "resource" - - -class ToolExecutionCompleteDataResultContentsItemIconsItemTheme(Enum): - "Theme variant this icon is intended for" - LIGHT = "light" - DARK = "dark" - - -class SystemMessageDataRole(Enum): - "Message role: \"system\" for system prompts, \"developer\" for developer-injected instructions" - SYSTEM = "system" - DEVELOPER = "developer" +class McpServerStatusChangedStatus(Enum): + "New connection status: connected, failed, needs-auth, pending, disabled, or not_configured" + CONNECTED = "connected" + FAILED = "failed" + NEEDS_AUTH = "needs-auth" + PENDING = "pending" + DISABLED = "disabled" + NOT_CONFIGURED = "not_configured" -class SystemNotificationDataKindType(Enum): - "Structured metadata identifying what triggered this notification discriminator" - AGENT_COMPLETED = "agent_completed" - AGENT_IDLE = "agent_idle" - SHELL_COMPLETED = "shell_completed" - SHELL_DETACHED_COMPLETED = "shell_detached_completed" +class McpServersLoadedServerStatus(Enum): + "Connection status: connected, failed, needs-auth, pending, disabled, or not_configured" + CONNECTED = "connected" + FAILED = "failed" + NEEDS_AUTH = "needs-auth" + PENDING = "pending" + DISABLED = "disabled" + NOT_CONFIGURED = "not_configured" -class SystemNotificationDataKindStatus(Enum): - "Whether the agent completed successfully or failed" - COMPLETED = "completed" - FAILED = "failed" +class PermissionCompletedKind(Enum): + "The outcome of the permission request" + APPROVED = "approved" + DENIED_BY_RULES = "denied-by-rules" + DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" + DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" + DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" + DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" -class PermissionRequestedDataPermissionRequestKind(Enum): +class PermissionRequestKind(Enum): "Details of the permission being requested discriminator" SHELL = "shell" WRITE = "write" @@ -4032,61 +4028,90 @@ class PermissionRequestMemoryDirection(Enum): DOWNVOTE = "downvote" -class PermissionCompletedKind(Enum): - "The outcome of the permission request" - APPROVED = "approved" - DENIED_BY_RULES = "denied-by-rules" - DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" - DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" - DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" - DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" +class PlanChangedOperation(Enum): + "The type of operation performed on the plan file" + CREATE = "create" + UPDATE = "update" + DELETE = "delete" -class ElicitationRequestedMode(Enum): - "Elicitation mode; \"form\" for structured input, \"url\" for browser-based. Defaults to \"form\" when absent." - FORM = "form" - URL = "url" +class ShutdownType(Enum): + "Whether the session ended normally (\"routine\") or due to a crash/fatal error (\"error\")" + ROUTINE = "routine" + ERROR = "error" -class ElicitationCompletedAction(Enum): - "The user action: \"accept\" (submitted form), \"decline\" (explicitly refused), or \"cancel\" (dismissed)" - ACCEPT = "accept" - DECLINE = "decline" - CANCEL = "cancel" +class SystemMessageRole(Enum): + "Message role: \"system\" for system prompts, \"developer\" for developer-injected instructions" + SYSTEM = "system" + DEVELOPER = "developer" -class MCPServerStatus(Enum): - "Connection status: connected, failed, needs-auth, pending, disabled, or not_configured" - CONNECTED = "connected" +class SystemNotificationAgentCompletedStatus(Enum): + "Whether the agent completed successfully or failed" + COMPLETED = "completed" FAILED = "failed" - NEEDS_AUTH = "needs-auth" - PENDING = "pending" - DISABLED = "disabled" - NOT_CONFIGURED = "not_configured" -class SessionMcpServerStatusChangedDataStatus(Enum): - "New connection status: connected, failed, needs-auth, pending, disabled, or not_configured" - CONNECTED = "connected" - FAILED = "failed" - NEEDS_AUTH = "needs-auth" - PENDING = "pending" - DISABLED = "disabled" - NOT_CONFIGURED = "not_configured" +class SystemNotificationType(Enum): + "Structured metadata identifying what triggered this notification discriminator" + AGENT_COMPLETED = "agent_completed" + AGENT_IDLE = "agent_idle" + NEW_INBOX_MESSAGE = "new_inbox_message" + SHELL_COMPLETED = "shell_completed" + SHELL_DETACHED_COMPLETED = "shell_detached_completed" -class ExtensionsLoadedExtensionSource(Enum): - "Discovery source" - PROJECT = "project" - USER = "user" +class ToolExecutionCompleteContentResourceLinkIconTheme(Enum): + "Theme variant this icon is intended for" + LIGHT = "light" + DARK = "dark" -class ExtensionsLoadedExtensionStatus(Enum): - "Current status: running, disabled, failed, or starting" - RUNNING = "running" - DISABLED = "disabled" - FAILED = "failed" - STARTING = "starting" +class ToolExecutionCompleteContentType(Enum): + "A content block within a tool result, which may be text, terminal output, image, audio, or a resource discriminator" + TEXT = "text" + TERMINAL = "terminal" + IMAGE = "image" + AUDIO = "audio" + RESOURCE_LINK = "resource_link" + RESOURCE = "resource" + + +class UserMessageAgentMode(Enum): + "The agent mode that was active when this message was sent" + INTERACTIVE = "interactive" + PLAN = "plan" + AUTOPILOT = "autopilot" + SHELL = "shell" + + +class UserMessageAttachmentGithubReferenceType(Enum): + "Type of GitHub reference" + ISSUE = "issue" + PR = "pr" + DISCUSSION = "discussion" + + +class UserMessageAttachmentType(Enum): + "A user message attachment — a file, directory, code selection, blob, or GitHub reference discriminator" + FILE = "file" + DIRECTORY = "directory" + SELECTION = "selection" + GITHUB_REFERENCE = "github_reference" + BLOB = "blob" + + +class WorkingDirectoryContextHostType(Enum): + "Hosting platform type of the repository (github or ado)" + GITHUB = "github" + ADO = "ado" + + +class WorkspaceFileChangedOperation(Enum): + "Whether the file was newly created or updated" + CREATE = "create" + UPDATE = "update" SessionEventData = SessionStartData | SessionResumeData | SessionRemoteSteerableChangedData | SessionErrorData | SessionIdleData | SessionTitleChangedData | SessionInfoData | SessionWarningData | SessionModelChangeData | SessionModeChangedData | SessionPlanChangedData | SessionWorkspaceFileChangedData | SessionHandoffData | SessionTruncationData | SessionSnapshotRewindData | SessionShutdownData | SessionContextChangedData | SessionUsageInfoData | SessionCompactionStartData | SessionCompactionCompleteData | SessionTaskCompleteData | UserMessageData | PendingMessagesModifiedData | AssistantTurnStartData | AssistantIntentData | AssistantReasoningData | AssistantReasoningDeltaData | AssistantStreamingDeltaData | AssistantMessageData | AssistantMessageDeltaData | AssistantTurnEndData | AssistantUsageData | AbortData | ToolUserRequestedData | ToolExecutionStartData | ToolExecutionPartialResultData | ToolExecutionProgressData | ToolExecutionCompleteData | SkillInvokedData | SubagentStartedData | SubagentCompletedData | SubagentFailedData | SubagentSelectedData | SubagentDeselectedData | HookStartData | HookEndData | SystemMessageData | SystemNotificationData | PermissionRequestedData | PermissionCompletedData | UserInputRequestedData | UserInputCompletedData | ElicitationRequestedData | ElicitationCompletedData | SamplingRequestedData | SamplingCompletedData | McpOauthRequiredData | McpOauthCompletedData | ExternalToolRequestedData | ExternalToolCompletedData | CommandQueuedData | CommandExecuteData | CommandCompletedData | CommandsChangedData | CapabilitiesChangedData | ExitPlanModeRequestedData | ExitPlanModeCompletedData | SessionToolsUpdatedData | SessionBackgroundTasksChangedData | SessionSkillsLoadedData | SessionCustomAgentsUpdatedData | SessionMcpServersLoadedData | SessionMcpServerStatusChangedData | SessionExtensionsLoadedData | RawSessionEventData | Data diff --git a/python/copilot/session.py b/python/copilot/session.py index ac771923a..3398196f4 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -24,13 +24,11 @@ from .generated.rpc import ( ClientSessionApiHandlers, CommandsHandlePendingCommandRequest, - Kind, LogRequest, ModelSwitchToRequest, PermissionDecision, + PermissionDecisionKind, PermissionDecisionRequest, - RequestedSchemaType, - SessionFsHandler, SessionLogLevel, SessionRpc, ToolCallResult, @@ -40,10 +38,11 @@ UIElicitationResponseAction, UIElicitationSchema, UIElicitationSchemaProperty, - UIElicitationSchemaPropertyNumberType, + UIElicitationSchemaPropertyType, + UIElicitationSchemaType, UIHandlePendingElicitationRequest, ) -from .generated.rpc import ModelCapabilitiesClass as _RpcModelCapabilitiesOverride +from .generated.rpc import ModelCapabilitiesOverride as _RpcModelCapabilitiesOverride from .generated.session_events import ( AssistantMessageData, CapabilitiesChangedData, @@ -61,6 +60,7 @@ if TYPE_CHECKING: from .client import ModelCapabilitiesOverride + from .session_fs_provider import SessionFsProvider # Re-export SessionEvent under an alias used internally SessionEventTypeAlias = SessionEvent @@ -410,7 +410,7 @@ class ElicitationContext(TypedDict, total=False): ] """Handler invoked when the server dispatches an elicitation request to this client.""" -CreateSessionFsHandler = Callable[["CopilotSession"], SessionFsHandler] +CreateSessionFsHandler = Callable[["CopilotSession"], "SessionFsProvider"] # ============================================================================ @@ -471,10 +471,10 @@ async def confirm(self, message: str) -> bool: UIElicitationRequest( message=message, requested_schema=UIElicitationSchema( - type=RequestedSchemaType.OBJECT, + type=UIElicitationSchemaType.OBJECT, properties={ "confirmed": UIElicitationSchemaProperty( - type=UIElicitationSchemaPropertyNumberType.BOOLEAN, + type=UIElicitationSchemaPropertyType.BOOLEAN, default=True, ), }, @@ -506,10 +506,10 @@ async def select(self, message: str, options: list[str]) -> str | None: UIElicitationRequest( message=message, requested_schema=UIElicitationSchema( - type=RequestedSchemaType.OBJECT, + type=UIElicitationSchemaType.OBJECT, properties={ "selection": UIElicitationSchemaProperty( - type=UIElicitationSchemaPropertyNumberType.STRING, + type=UIElicitationSchemaPropertyType.STRING, enum=options, ), }, @@ -1436,7 +1436,7 @@ async def _execute_permission_and_respond( return perm_result = PermissionDecision( - kind=Kind(result.kind), + kind=PermissionDecisionKind(result.kind), rules=result.rules, feedback=result.feedback, message=result.message, @@ -1455,7 +1455,7 @@ async def _execute_permission_and_respond( PermissionDecisionRequest( request_id=request_id, result=PermissionDecision( - kind=Kind.DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER, + kind=PermissionDecisionKind.DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER, ), ) ) diff --git a/python/copilot/session_fs_provider.py b/python/copilot/session_fs_provider.py new file mode 100644 index 000000000..ccef43d02 --- /dev/null +++ b/python/copilot/session_fs_provider.py @@ -0,0 +1,223 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# -------------------------------------------------------------------------------------------- + +"""Idiomatic base class for session filesystem providers. + +Subclasses override the abstract methods using standard Python patterns: +raise on error, return values directly. The :func:`create_session_fs_adapter` +function wraps a provider into the generated :class:`SessionFsHandler` +protocol expected by the SDK, converting exceptions into +:class:`SessionFSError` results. + +Errors whose ``errno`` matches :data:`errno.ENOENT` are mapped to the +``ENOENT`` error code; all others map to ``UNKNOWN``. +""" + +from __future__ import annotations + +import abc +import errno +from collections.abc import Sequence +from dataclasses import dataclass +from datetime import datetime + +from .generated.rpc import ( + SessionFSError, + SessionFSErrorCode, + SessionFSExistsResult, + SessionFsHandler, + SessionFSReaddirResult, + SessionFSReaddirWithTypesEntry, + SessionFSReaddirWithTypesResult, + SessionFSReadFileResult, + SessionFSStatResult, +) + + +@dataclass +class SessionFsFileInfo: + """File metadata returned by :meth:`SessionFsProvider.stat`.""" + + is_file: bool + is_directory: bool + size: int + mtime: datetime + birthtime: datetime + + +class SessionFsProvider(abc.ABC): + """Abstract base class for session filesystem providers. + + Subclasses implement the abstract methods below using idiomatic Python: + raise exceptions on errors and return values directly. Use + :func:`create_session_fs_adapter` to wrap a provider into the RPC + handler protocol. + """ + + @abc.abstractmethod + async def read_file(self, path: str) -> str: + """Read the full content of a file. Raise if the file does not exist.""" + + @abc.abstractmethod + async def write_file(self, path: str, content: str, mode: int | None = None) -> None: + """Write *content* to a file, creating parent directories if needed.""" + + @abc.abstractmethod + async def append_file(self, path: str, content: str, mode: int | None = None) -> None: + """Append *content* to a file, creating parent directories if needed.""" + + @abc.abstractmethod + async def exists(self, path: str) -> bool: + """Return whether *path* exists.""" + + @abc.abstractmethod + async def stat(self, path: str) -> SessionFsFileInfo: + """Return metadata for *path*. Raise if it does not exist.""" + + @abc.abstractmethod + async def mkdir(self, path: str, recursive: bool, mode: int | None = None) -> None: + """Create a directory. If *recursive* is ``True``, create parents.""" + + @abc.abstractmethod + async def readdir(self, path: str) -> list[str]: + """List entry names in a directory. Raise if it does not exist.""" + + @abc.abstractmethod + async def readdir_with_types(self, path: str) -> Sequence[SessionFSReaddirWithTypesEntry]: + """List entries with type info. Raise if the directory does not exist.""" + + @abc.abstractmethod + async def rm(self, path: str, recursive: bool, force: bool) -> None: + """Remove a file or directory.""" + + @abc.abstractmethod + async def rename(self, src: str, dest: str) -> None: + """Rename / move a file or directory.""" + + +def create_session_fs_adapter(provider: SessionFsProvider) -> SessionFsHandler: + """Wrap a :class:`SessionFsProvider` into a :class:`SessionFsHandler`. + + The adapter catches exceptions thrown by the provider and converts them + into :class:`SessionFSError` results expected by the runtime. + """ + return _SessionFsAdapter(provider) + + +class _SessionFsAdapter: + """Internal adapter that bridges SessionFsProvider → SessionFsHandler.""" + + def __init__(self, provider: SessionFsProvider) -> None: + self._p = provider + + async def read_file(self, params: object) -> SessionFSReadFileResult: + try: + content = await self._p.read_file(params.path) # type: ignore[attr-defined] + return SessionFSReadFileResult.from_dict({"content": content}) + except Exception as exc: + err = _to_session_fs_error(exc) + return SessionFSReadFileResult.from_dict({"content": "", "error": err.to_dict()}) + + async def write_file(self, params: object) -> SessionFSError | None: + try: + await self._p.write_file(params.path, params.content, getattr(params, "mode", None)) # type: ignore[attr-defined] + return None + except Exception as exc: + return _to_session_fs_error(exc) + + async def append_file(self, params: object) -> SessionFSError | None: + try: + await self._p.append_file(params.path, params.content, getattr(params, "mode", None)) # type: ignore[attr-defined] + return None + except Exception as exc: + return _to_session_fs_error(exc) + + async def exists(self, params: object) -> SessionFSExistsResult: + try: + result = await self._p.exists(params.path) # type: ignore[attr-defined] + return SessionFSExistsResult.from_dict({"exists": result}) + except Exception: + return SessionFSExistsResult.from_dict({"exists": False}) + + async def stat(self, params: object) -> SessionFSStatResult: + try: + info = await self._p.stat(params.path) # type: ignore[attr-defined] + return SessionFSStatResult( + is_file=info.is_file, + is_directory=info.is_directory, + size=info.size, + mtime=info.mtime, + birthtime=info.birthtime, + ) + except Exception as exc: + now = datetime.now(datetime.UTC) # type: ignore[attr-defined] # ty doesn't resolve datetime.UTC (added in 3.11) + err = _to_session_fs_error(exc) + return SessionFSStatResult( + is_file=False, + is_directory=False, + size=0, + mtime=now, + birthtime=now, + error=err, + ) + + async def mkdir(self, params: object) -> SessionFSError | None: + try: + await self._p.mkdir( + params.path, # type: ignore[attr-defined] + getattr(params, "recursive", False), + getattr(params, "mode", None), + ) + return None + except Exception as exc: + return _to_session_fs_error(exc) + + async def readdir(self, params: object) -> SessionFSReaddirResult: + try: + entries = await self._p.readdir(params.path) # type: ignore[attr-defined] + return SessionFSReaddirResult.from_dict({"entries": entries}) + except Exception as exc: + err = _to_session_fs_error(exc) + return SessionFSReaddirResult.from_dict({"entries": [], "error": err.to_dict()}) + + async def readdir_with_types(self, params: object) -> SessionFSReaddirWithTypesResult: + try: + entries = await self._p.readdir_with_types(params.path) # type: ignore[attr-defined] + return SessionFSReaddirWithTypesResult(entries=list(entries)) + except Exception as exc: + err = _to_session_fs_error(exc) + return SessionFSReaddirWithTypesResult.from_dict( + {"entries": [], "error": err.to_dict()} + ) + + async def rm(self, params: object) -> SessionFSError | None: + try: + await self._p.rm( + params.path, # type: ignore[attr-defined] + getattr(params, "recursive", False), + getattr(params, "force", False), + ) + return None + except Exception as exc: + return _to_session_fs_error(exc) + + async def rename(self, params: object) -> SessionFSError | None: + try: + await self._p.rename(params.src, params.dest) # type: ignore[attr-defined] + return None + except Exception as exc: + return _to_session_fs_error(exc) + + +def _to_session_fs_error(exc: Exception) -> SessionFSError: + code = SessionFSErrorCode.ENOENT if _is_enoent(exc) else SessionFSErrorCode.UNKNOWN + return SessionFSError(code=code, message=str(exc)) + + +def _is_enoent(exc: Exception) -> bool: + if isinstance(exc, FileNotFoundError): + return True + if isinstance(exc, OSError) and exc.errno == errno.ENOENT: + return True + return False diff --git a/python/e2e/test_compaction.py b/python/e2e/test_compaction.py index c6df2bffa..b06a0312f 100644 --- a/python/e2e/test_compaction.py +++ b/python/e2e/test_compaction.py @@ -7,7 +7,12 @@ from .testharness import E2ETestContext -pytestmark = pytest.mark.asyncio(loop_scope="module") +pytestmark = [ + pytest.mark.asyncio(loop_scope="module"), + pytest.mark.skip( + reason="Compaction tests are skipped due to flakiness — re-enable once stabilized" + ), +] class TestCompaction: diff --git a/python/e2e/test_session_fs.py b/python/e2e/test_session_fs.py index bc228707b..18c266c64 100644 --- a/python/e2e/test_session_fs.py +++ b/python/e2e/test_session_fs.py @@ -14,14 +14,12 @@ from copilot import CopilotClient, SessionFsConfig, define_tool from copilot.client import ExternalServerConfig, SubprocessConfig from copilot.generated.rpc import ( - SessionFSExistsResult, - SessionFSReaddirResult, - SessionFSReaddirWithTypesResult, - SessionFSReadFileResult, - SessionFSStatResult, + SessionFSReaddirWithTypesEntry, + SessionFSReaddirWithTypesEntryType, ) from copilot.generated.session_events import SessionCompactionCompleteData, SessionEvent from copilot.session import PermissionHandler +from copilot.session_fs_provider import SessionFsFileInfo, SessionFsProvider from .testharness import E2ETestContext @@ -214,90 +212,131 @@ def on_event(event: SessionEvent): await wait_for_content(events_path, "checkpointNumber") + async def test_should_write_workspace_metadata_via_sessionfs( + self, ctx: E2ETestContext, session_fs_client: CopilotClient + ): + provider_root = Path(ctx.work_dir) / "provider" + session = await session_fs_client.create_session( + on_permission_request=PermissionHandler.approve_all, + create_session_fs_handler=create_test_session_fs_handler(provider_root), + ) + + msg = await session.send_and_wait("What is 7 * 8?") + assert msg is not None + assert msg.data.content is not None + assert "56" in msg.data.content + + # WorkspaceManager should have created workspace.yaml via sessionFs + workspace_yaml_path = provider_path( + provider_root, session.session_id, "/session-state/workspace.yaml" + ) + await wait_for_path(workspace_yaml_path) + yaml_content = workspace_yaml_path.read_text(encoding="utf-8") + assert "id:" in yaml_content + + # Checkpoint index should also exist + index_path = provider_path( + provider_root, session.session_id, "/session-state/checkpoints/index.md" + ) + await wait_for_path(index_path) + + await session.disconnect() + + async def test_should_persist_plan_md_via_sessionfs( + self, ctx: E2ETestContext, session_fs_client: CopilotClient + ): + from copilot.generated.rpc import PlanUpdateRequest + + provider_root = Path(ctx.work_dir) / "provider" + session = await session_fs_client.create_session( + on_permission_request=PermissionHandler.approve_all, + create_session_fs_handler=create_test_session_fs_handler(provider_root), + ) + + # Write a plan via the session RPC + await session.send_and_wait("What is 2 + 3?") + await session.rpc.plan.update(PlanUpdateRequest(content="# Test Plan\n\nThis is a test.")) -class _SessionFsHandler: + plan_path = provider_path(provider_root, session.session_id, "/session-state/plan.md") + await wait_for_path(plan_path) + content = plan_path.read_text(encoding="utf-8") + assert "# Test Plan" in content + + await session.disconnect() + + +class _TestSessionFsProvider(SessionFsProvider): def __init__(self, provider_root: Path, session_id: str): self._provider_root = provider_root self._session_id = session_id - async def read_file(self, params) -> SessionFSReadFileResult: - content = provider_path(self._provider_root, self._session_id, params.path).read_text( - encoding="utf-8" - ) - return SessionFSReadFileResult.from_dict({"content": content}) - - async def write_file(self, params) -> None: - path = provider_path(self._provider_root, self._session_id, params.path) - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(params.content, encoding="utf-8") - - async def append_file(self, params) -> None: - path = provider_path(self._provider_root, self._session_id, params.path) - path.parent.mkdir(parents=True, exist_ok=True) - with path.open("a", encoding="utf-8") as handle: - handle.write(params.content) - - async def exists(self, params) -> SessionFSExistsResult: - path = provider_path(self._provider_root, self._session_id, params.path) - return SessionFSExistsResult.from_dict({"exists": path.exists()}) - - async def stat(self, params) -> SessionFSStatResult: - path = provider_path(self._provider_root, self._session_id, params.path) - info = path.stat() - timestamp = dt.datetime.fromtimestamp(info.st_mtime, tz=dt.UTC).isoformat() - if timestamp.endswith("+00:00"): - timestamp = f"{timestamp[:-6]}Z" - return SessionFSStatResult.from_dict( - { - "isFile": not path.is_dir(), - "isDirectory": path.is_dir(), - "size": info.st_size, - "mtime": timestamp, - "birthtime": timestamp, - } + def _path(self, path: str) -> Path: + return provider_path(self._provider_root, self._session_id, path) + + async def read_file(self, path: str) -> str: + return self._path(path).read_text(encoding="utf-8") + + async def write_file(self, path: str, content: str, mode: int | None = None) -> None: + p = self._path(path) + p.parent.mkdir(parents=True, exist_ok=True) + p.write_text(content, encoding="utf-8") + + async def append_file(self, path: str, content: str, mode: int | None = None) -> None: + p = self._path(path) + p.parent.mkdir(parents=True, exist_ok=True) + with p.open("a", encoding="utf-8") as handle: + handle.write(content) + + async def exists(self, path: str) -> bool: + return self._path(path).exists() + + async def stat(self, path: str) -> SessionFsFileInfo: + p = self._path(path) + info = p.stat() + timestamp = dt.datetime.fromtimestamp(info.st_mtime, tz=dt.UTC) + return SessionFsFileInfo( + is_file=not p.is_dir(), + is_directory=p.is_dir(), + size=info.st_size, + mtime=timestamp, + birthtime=timestamp, ) - async def mkdir(self, params) -> None: - path = provider_path(self._provider_root, self._session_id, params.path) - if params.recursive: - path.mkdir(parents=True, exist_ok=True) + async def mkdir(self, path: str, recursive: bool, mode: int | None = None) -> None: + p = self._path(path) + if recursive: + p.mkdir(parents=True, exist_ok=True) else: - path.mkdir() + p.mkdir() - async def readdir(self, params) -> SessionFSReaddirResult: - entries = sorted( - entry.name - for entry in provider_path(self._provider_root, self._session_id, params.path).iterdir() - ) - return SessionFSReaddirResult.from_dict({"entries": entries}) + async def readdir(self, path: str) -> list[str]: + return sorted(entry.name for entry in self._path(path).iterdir()) - async def readdir_with_types(self, params) -> SessionFSReaddirWithTypesResult: + async def readdir_with_types(self, path: str) -> list[SessionFSReaddirWithTypesEntry]: entries = [] - for entry in sorted( - provider_path(self._provider_root, self._session_id, params.path).iterdir(), - key=lambda item: item.name, - ): + for entry in sorted(self._path(path).iterdir(), key=lambda item: item.name): entries.append( - { - "name": entry.name, - "type": "directory" if entry.is_dir() else "file", - } + SessionFSReaddirWithTypesEntry( + name=entry.name, + type=SessionFSReaddirWithTypesEntryType.DIRECTORY + if entry.is_dir() + else SessionFSReaddirWithTypesEntryType.FILE, + ) ) - return SessionFSReaddirWithTypesResult.from_dict({"entries": entries}) + return entries - async def rm(self, params) -> None: - provider_path(self._provider_root, self._session_id, params.path).unlink() + async def rm(self, path: str, recursive: bool, force: bool) -> None: + self._path(path).unlink() - async def rename(self, params) -> None: - src = provider_path(self._provider_root, self._session_id, params.src) - dest = provider_path(self._provider_root, self._session_id, params.dest) - dest.parent.mkdir(parents=True, exist_ok=True) - src.rename(dest) + async def rename(self, src: str, dest: str) -> None: + d = self._path(dest) + d.parent.mkdir(parents=True, exist_ok=True) + self._path(src).rename(d) def create_test_session_fs_handler(provider_root: Path): def create_handler(session): - return _SessionFsHandler(provider_root, session.session_id) + return _TestSessionFsProvider(provider_root, session.session_id) return create_handler diff --git a/scripts/codegen/csharp.ts b/scripts/codegen/csharp.ts index d9a4b0f96..8416d4e40 100644 --- a/scripts/codegen/csharp.ts +++ b/scripts/codegen/csharp.ts @@ -30,6 +30,7 @@ import { isSchemaDeprecated, isObjectSchema, isVoidSchema, + getNullableInner, REPO_ROOT, type ApiSchema, type DefinitionCollections, @@ -150,17 +151,19 @@ function collectRpcMethods(node: Record): RpcMethod[] { } function schemaTypeToCSharp(schema: JSONSchema7, required: boolean, knownTypes: Map): string { - if (schema.anyOf) { - const nonNull = schema.anyOf.filter((s) => typeof s === "object" && s.type !== "null"); - if (nonNull.length === 1 && typeof nonNull[0] === "object") { - // Pass required=true to get the base type, then add "?" for nullable - return schemaTypeToCSharp(nonNull[0] as JSONSchema7, true, knownTypes) + "?"; - } + const nullableInner = getNullableInner(schema); + if (nullableInner) { + // Pass required=true to get the base type, then add "?" for nullable + return schemaTypeToCSharp(nullableInner, true, knownTypes) + "?"; } if (schema.$ref) { const refName = schema.$ref.split("/").pop()!; return knownTypes.get(refName) || refName; } + // Titled union schemas (anyOf with a title) — use the title if it's a known generated type + if (schema.title && schema.anyOf && knownTypes.has(schema.title)) { + return required ? schema.title : `${schema.title}?`; + } const type = schema.type; const format = schema.format; // Handle type: ["string", "null"] patterns (nullable string) @@ -378,7 +381,7 @@ function findDiscriminator(variants: JSONSchema7[]): { property: string; mapping const firstVariant = variants[0]; if (!firstVariant.properties) return null; - for (const [propName, propSchema] of Object.entries(firstVariant.properties)) { + for (const [propName, propSchema] of Object.entries(firstVariant.properties).sort(([a], [b]) => a.localeCompare(b))) { if (typeof propSchema !== "object") continue; const schema = propSchema as JSONSchema7; if (schema.const === undefined) continue; @@ -471,7 +474,7 @@ function generateDerivedClass( lines.push(""); if (schema.properties) { - for (const [propName, propSchema] of Object.entries(schema.properties)) { + for (const [propName, propSchema] of Object.entries(schema.properties).sort(([a], [b]) => a.localeCompare(b))) { if (typeof propSchema !== "object") continue; if (propName === discriminatorProperty) continue; @@ -508,7 +511,7 @@ function generateNestedClass( if (isSchemaDeprecated(schema)) lines.push(`[Obsolete("This member is deprecated and will be removed in a future version.")]`); lines.push(`public partial class ${className}`, `{`); - for (const [propName, propSchema] of Object.entries(schema.properties || {})) { + for (const [propName, propSchema] of Object.entries(schema.properties || {}).sort(([a], [b]) => a.localeCompare(b))) { if (typeof propSchema !== "object") continue; const prop = propSchema as JSONSchema7; const isReq = required.has(propName); @@ -561,16 +564,24 @@ function resolveSessionPropertyType( return resolveSessionPropertyType(refSchema, parentClassName, propName, isRequired, knownTypes, nestedClasses, enumOutput); } if (propSchema.anyOf) { - const hasNull = propSchema.anyOf.some((s) => typeof s === "object" && (s as JSONSchema7).type === "null"); - const nonNull = propSchema.anyOf.filter((s) => typeof s === "object" && (s as JSONSchema7).type !== "null"); - if (nonNull.length === 1) { - return resolveSessionPropertyType(nonNull[0] as JSONSchema7, parentClassName, propName, isRequired && !hasNull, knownTypes, nestedClasses, enumOutput); + const simpleNullable = getNullableInner(propSchema); + if (simpleNullable) { + return resolveSessionPropertyType(simpleNullable, parentClassName, propName, false, knownTypes, nestedClasses, enumOutput); } // Discriminated union: anyOf with multiple object variants sharing a const discriminator + const nonNull = propSchema.anyOf.filter((s) => typeof s === "object" && s !== null && (s as JSONSchema7).type !== "null"); if (nonNull.length > 1) { - const variants = nonNull as JSONSchema7[]; + // Resolve $ref variants to their actual schemas + const variants = (nonNull as JSONSchema7[]).map((v) => { + if (v.$ref) { + const resolved = resolveRef(v.$ref, sessionDefinitions); + return resolved ?? v; + } + return v; + }); const discriminatorInfo = findDiscriminator(variants); if (discriminatorInfo) { + const hasNull = propSchema.anyOf.length > nonNull.length; const baseClassName = (propSchema.title as string) ?? `${parentClassName}${propName}`; const renamedBase = applyTypeRename(baseClassName); const polymorphicCode = generatePolymorphicClasses(baseClassName, discriminatorInfo.property, variants, knownTypes, nestedClasses, enumOutput, propSchema.description); @@ -578,7 +589,7 @@ function resolveSessionPropertyType( return isRequired && !hasNull ? renamedBase : `${renamedBase}?`; } } - return hasNull || !isRequired ? "object?" : "object"; + return !isRequired ? "object?" : "object"; } if (propSchema.enum && Array.isArray(propSchema.enum)) { const enumName = getOrCreateEnum(parentClassName, propName, propSchema.enum as string[], enumOutput, propSchema.description, propSchema.title as string | undefined, isSchemaDeprecated(propSchema)); @@ -602,6 +613,19 @@ function resolveSessionPropertyType( ); return isRequired ? `${itemType}[]` : `${itemType}[]?`; } + if (propSchema.type === "object" && propSchema.additionalProperties && typeof propSchema.additionalProperties === "object") { + const valueSchema = propSchema.additionalProperties as JSONSchema7; + const valueType = resolveSessionPropertyType( + valueSchema, + parentClassName, + `${propName}Value`, + true, + knownTypes, + nestedClasses, + enumOutput + ); + return isRequired ? `IDictionary` : `IDictionary?`; + } return schemaTypeToCSharp(propSchema, isRequired, knownTypes); } @@ -620,7 +644,7 @@ function generateDataClass(variant: EventVariant, knownTypes: Map a.localeCompare(b))) { if (typeof propSchema !== "object") continue; const isReq = required.has(propName); const csharpName = toPascalCase(propName); @@ -787,6 +811,27 @@ function resultTypeName(method: RpcMethod): string { return getRpcSchemaTypeName(getMethodResultSchema(method), `${typeToClassName(method.rpcMethod)}Result`); } +/** Returns the C# type for a method's result, accounting for nullable anyOf wrappers. */ +function resolvedResultTypeName(method: RpcMethod): string { + const schema = getMethodResultSchema(method); + if (!schema) return resultTypeName(method); + const inner = getNullableInner(schema); + if (inner) { + // Nullable wrapper: resolve the inner $ref type name with "?" suffix + const innerName = inner.$ref + ? typeToClassName(refTypeName(inner.$ref, rpcDefinitions)) + : getRpcSchemaTypeName(inner, resultTypeName(method)); + return `${innerName}?`; + } + return resultTypeName(method); +} + +/** Returns the Task or Task string for a method's result type. */ +function resultTaskType(method: RpcMethod): string { + const schema = getMethodResultSchema(method); + return !isVoidSchema(schema) ? `Task<${resolvedResultTypeName(method)}>` : "Task"; +} + function paramsTypeName(method: RpcMethod): string { return getRpcSchemaTypeName(resolveMethodParamsSchema(method), `${typeToClassName(method.rpcMethod)}Request`); } @@ -833,12 +878,35 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam return resolveRpcType(refSchema, isRequired, parentClassName, propName, classes); } - // Handle anyOf: [T, null] → T? (nullable typed property) - if (schema.anyOf) { - const hasNull = schema.anyOf.some((s) => typeof s === "object" && (s as JSONSchema7).type === "null"); - const nonNull = schema.anyOf.filter((s) => typeof s === "object" && (s as JSONSchema7).type !== "null"); - if (nonNull.length === 1) { - return resolveRpcType(nonNull[0] as JSONSchema7, isRequired && !hasNull, parentClassName, propName, classes); + // Handle anyOf: [T, null/{not:{}}] → T? (nullable typed property) + const nullableInner = getNullableInner(schema); + if (nullableInner) { + return resolveRpcType(nullableInner, false, parentClassName, propName, classes); + } + // Discriminated union: anyOf with multiple variants sharing a const discriminator + if (schema.anyOf && Array.isArray(schema.anyOf)) { + const nonNull = schema.anyOf.filter((s) => typeof s === "object" && s !== null && (s as JSONSchema7).type !== "null"); + if (nonNull.length > 1) { + const variants = (nonNull as JSONSchema7[]).map((v) => { + if (v.$ref) { + const resolved = resolveRef(v.$ref, rpcDefinitions); + return resolved ?? v; + } + return v; + }); + const discriminatorInfo = findDiscriminator(variants); + if (discriminatorInfo) { + const hasNull = schema.anyOf.length > nonNull.length; + const baseClassName = (schema.title as string) ?? `${parentClassName}${propName}`; + if (!emittedRpcClassSchemas.has(baseClassName)) { + emittedRpcClassSchemas.set(baseClassName, "polymorphic"); + const nestedMap = new Map(); + const polymorphicCode = generatePolymorphicClasses(baseClassName, discriminatorInfo.property, variants, rpcKnownTypes, nestedMap, rpcEnumOutput, schema.description); + classes.push(polymorphicCode); + for (const nested of nestedMap.values()) classes.push(nested); + } + return isRequired && !hasNull ? baseClassName : `${baseClassName}?`; + } } } // Handle enums (string unions like "interactive" | "plan" | "autopilot") @@ -911,7 +979,7 @@ function emitRpcClass( } lines.push(`${visibility} sealed class ${className}`, `{`); - const props = Object.entries(effectiveSchema.properties || {}); + const props = Object.entries(effectiveSchema.properties || {}).sort(([a], [b]) => a.localeCompare(b)); for (let i = 0; i < props.length; i++) { const [propName, propSchema] = props[i]; if (typeof propSchema !== "object") continue; @@ -1089,6 +1157,13 @@ function emitServerInstanceMethod( const paramEntries = effectiveParams?.properties ? Object.entries(effectiveParams.properties) : []; const requiredSet = new Set(effectiveParams?.required || []); + // Sort so required params come before optional (C# requires defaults at end) + paramEntries.sort((a, b) => { + const aReq = requiredSet.has(a[0]) ? 0 : 1; + const bReq = requiredSet.has(b[0]) ? 0 : 1; + return aReq - bReq; + }); + let requestClassName: string | null = null; if (paramEntries.length > 0) { requestClassName = paramsTypeName(method); @@ -1337,7 +1412,7 @@ function emitClientSessionApiRegistration(clientSchema: Record, const effectiveParams = resolveMethodParamsSchema(method); const hasParams = !!effectiveParams?.properties && Object.keys(effectiveParams.properties).length > 0; const resultSchema = getMethodResultSchema(method); - const taskType = !isVoidSchema(resultSchema) ? `Task<${resultTypeName(method)}>` : "Task"; + const taskType = resultTaskType(method); lines.push(` /// Handles "${method.rpcMethod}".`); if (method.stability === "experimental" && !groupExperimental) { lines.push(` [Experimental(Diagnostics.Experimental)]`); @@ -1385,7 +1460,7 @@ function emitClientSessionApiRegistration(clientSchema: Record, const hasParams = !!effectiveParams?.properties && Object.keys(effectiveParams.properties).length > 0; const resultSchema = getMethodResultSchema(method); const paramsClass = paramsTypeName(method); - const taskType = !isVoidSchema(resultSchema) ? `Task<${resultTypeName(method)}>` : "Task"; + const taskType = resultTaskType(method); const registrationVar = `register${typeToClassName(method.rpcMethod)}Method`; if (hasParams) { diff --git a/scripts/codegen/go.ts b/scripts/codegen/go.ts index 8f9d40321..bb7d85319 100644 --- a/scripts/codegen/go.ts +++ b/scripts/codegen/go.ts @@ -17,12 +17,12 @@ import { getApiSchemaPath, getRpcSchemaTypeName, getSessionEventsSchemaPath, - hoistTitledSchemas, hasSchemaPayload, isNodeFullyExperimental, isNodeFullyDeprecated, isSchemaDeprecated, isVoidSchema, + getNullableInner, isRpcMethod, postProcessSchema, writeGeneratedFile, @@ -110,7 +110,7 @@ function postProcessEnumConstants(code: string): string { return code; } -function collapsePlaceholderGoStructs(code: string): string { +function collapsePlaceholderGoStructs(code: string, knownDefinitionNames?: Set): string { const structBlockRe = /((?:\/\/.*\r?\n)*)type\s+(\w+)\s+struct\s*\{[\s\S]*?^\}/gm; const matches = [...code.matchAll(structBlockRe)].map((match) => ({ fullBlock: match[0], @@ -128,12 +128,14 @@ function collapsePlaceholderGoStructs(code: string): string { for (const group of groups.values()) { if (group.length < 2) continue; - const canonical = chooseCanonicalPlaceholderDuplicate(group.map(({ name }) => name)); + const canonical = chooseCanonicalPlaceholderDuplicate(group.map(({ name }) => name), knownDefinitionNames); if (!canonical) continue; for (const duplicate of group) { if (duplicate.name === canonical) continue; - if (!isPlaceholderTypeName(duplicate.name)) continue; + // Only collapse types that quicktype invented (Class suffix or not + // in the schema's named definitions). Preserve intentionally-named types. + if (!isPlaceholderTypeName(duplicate.name) && knownDefinitionNames?.has(duplicate.name.toLowerCase())) continue; code = code.replace(duplicate.fullBlock, ""); code = code.replace(new RegExp(`\\b${duplicate.name}\\b`, "g"), canonical); @@ -145,7 +147,7 @@ function collapsePlaceholderGoStructs(code: string): string { function normalizeGoStructBlock(block: string, name: string): string { return block - .replace(/^\/\/.*\r?\n/gm, "") + .replace(/^\s*\/\/.*\r?\n/gm, "") .replace(new RegExp(`^type\\s+${name}\\s+struct\\s*\\{`, "m"), "type struct {") .split(/\r?\n/) .map((line) => line.trim()) @@ -153,10 +155,16 @@ function normalizeGoStructBlock(block: string, name: string): string { .join("\n"); } -function chooseCanonicalPlaceholderDuplicate(names: string[]): string | undefined { +function chooseCanonicalPlaceholderDuplicate(names: string[], knownDefinitionNames?: Set): string | undefined { + // Prefer the name that matches a schema definition — it's intentionally named. + if (knownDefinitionNames) { + const definedName = names.find((name) => knownDefinitionNames.has(name.toLowerCase())); + if (definedName) return definedName; + } + // Fallback for Class-suffix placeholders: pick the non-placeholder name. const specificNames = names.filter((name) => !isPlaceholderTypeName(name)); if (specificNames.length === 0) return undefined; - return specificNames.sort((left, right) => right.length - left.length || left.localeCompare(right))[0]; + return specificNames[0]; } function isPlaceholderTypeName(name: string): boolean { @@ -266,6 +274,14 @@ function goResultTypeName(method: RpcMethod): string { return getRpcSchemaTypeName(getMethodResultSchema(method), toPascalCase(method.rpcMethod) + "Result"); } +function goNullableResultTypeName(method: RpcMethod, innerSchema: JSONSchema7): string { + if (innerSchema.$ref) { + const refName = innerSchema.$ref.split("/").pop(); + if (refName) return toPascalCase(refName); + } + return getRpcSchemaTypeName(innerSchema, toPascalCase(method.rpcMethod) + "Result"); +} + function goParamsTypeName(method: RpcMethod): string { const fallback = goRequestFallbackName(method); if (method.rpcMethod.startsWith("session.") && method.params?.$ref) { @@ -428,6 +444,17 @@ function resolveGoPropertyType( // Handle anyOf if (propSchema.anyOf) { + const nullableInnerSchema = getNullableInner(propSchema); + if (nullableInnerSchema) { + // anyOf [T, null/{not:{}}] → nullable T + const innerType = resolveGoPropertyType(nullableInnerSchema, parentTypeName, jsonPropName, true, ctx); + if (isRequired) return innerType; + // Pointer-wrap if not already a pointer, slice, or map + if (innerType.startsWith("*") || innerType.startsWith("[]") || innerType.startsWith("map[")) { + return innerType; + } + return `*${innerType}`; + } const nonNull = (propSchema.anyOf as JSONSchema7[]).filter((s) => s.type !== "null"); const hasNull = (propSchema.anyOf as JSONSchema7[]).some((s) => s.type === "null"); @@ -435,7 +462,6 @@ function resolveGoPropertyType( // anyOf [T, null] → nullable T const innerType = resolveGoPropertyType(nonNull[0], parentTypeName, jsonPropName, true, ctx); if (isRequired && !hasNull) return innerType; - // Pointer-wrap if not already a pointer, slice, or map if (innerType.startsWith("*") || innerType.startsWith("[]") || innerType.startsWith("map[")) { return innerType; } @@ -443,8 +469,15 @@ function resolveGoPropertyType( } if (nonNull.length > 1) { + // Resolve $refs in variants before discriminator analysis + const resolvedVariants = nonNull.map((v) => { + if (v.$ref && typeof v.$ref === "string") { + return resolveRef(v.$ref, ctx.definitions) ?? v; + } + return v; + }); // Check for discriminated union - const disc = findGoDiscriminator(nonNull); + const disc = findGoDiscriminator(resolvedVariants); if (disc) { const unionName = (propSchema.title as string) || nestedName; emitGoFlatDiscriminatedUnion(unionName, disc.property, disc.mapping, ctx, propSchema.description); @@ -571,7 +604,7 @@ function emitGoStruct( } lines.push(`type ${typeName} struct {`); - for (const [propName, propSchema] of Object.entries(schema.properties || {})) { + for (const [propName, propSchema] of Object.entries(schema.properties || {}).sort(([a], [b]) => a.localeCompare(b))) { if (typeof propSchema !== "object") continue; const prop = propSchema as JSONSchema7; const isReq = required.has(propName); @@ -667,7 +700,7 @@ function emitGoFlatDiscriminatedUnion( lines.push(`\t${discGoName} ${discEnumName} \`json:"${discriminatorProp}"\``); // Emit remaining fields - for (const [propName, info] of allProps) { + for (const [propName, info] of [...allProps.entries()].sort(([a], [b]) => a.localeCompare(b))) { if (propName === discriminatorProp) continue; const goName = toGoFieldName(propName); const goType = resolveGoPropertyType(info.schema, typeName, propName, info.requiredInAll, ctx); @@ -713,7 +746,7 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { } lines.push(`type ${variant.dataClassName} struct {`); - for (const [propName, propSchema] of Object.entries(variant.dataSchema.properties || {})) { + for (const [propName, propSchema] of Object.entries(variant.dataSchema.properties || {}).sort(([a], [b]) => a.localeCompare(b))) { if (typeof propSchema !== "object") continue; const prop = propSchema as JSONSchema7; const isReq = required.has(propName); @@ -899,19 +932,19 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { out.push(``); // Per-event data structs - for (const ds of dataStructs) { + for (const ds of dataStructs.sort()) { out.push(ds); out.push(``); } // Nested structs - for (const s of ctx.structs) { + for (const s of ctx.structs.sort()) { out.push(s); out.push(``); } // Enums - for (const e of ctx.enums) { + for (const e of ctx.enums.sort()) { out.push(e); out.push(``); } @@ -919,7 +952,7 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { // Type aliases for types referenced by non-generated SDK code under their short names. const TYPE_ALIASES: Record = { PermissionRequestCommand: "PermissionRequestShellCommand", - PossibleURL: "PermissionRequestShellPossibleUrl", + PossibleURL: "PermissionRequestShellPossibleURL", Attachment: "UserMessageAttachment", AttachmentType: "UserMessageAttachmentType", }; @@ -989,7 +1022,11 @@ async function generateRpc(schemaPath?: string): Promise { for (const method of allMethods) { const resultSchema = getMethodResultSchema(method); - if (isVoidSchema(resultSchema)) { + const nullableInner = resultSchema ? getNullableInner(resultSchema) : undefined; + if (nullableInner) { + // Nullable results (e.g., *SessionFSError) don't need a wrapper type; + // the inner type is already in definitions via shared hoisting. + } else if (isVoidSchema(resultSchema)) { // Emit an empty struct for void results (forward-compatible with adding fields later) combinedSchema.definitions![goResultTypeName(method)] = { title: goResultTypeName(method), @@ -1029,22 +1066,25 @@ async function generateRpc(schemaPath?: string): Promise { } } - const { rootDefinitions, sharedDefinitions } = hoistTitledSchemas(combinedSchema.definitions! as Record); - const allDefinitions = { ...rootDefinitions, ...sharedDefinitions }; + const allDefinitions = combinedSchema.definitions! as Record; const allDefinitionCollections: DefinitionCollections = { definitions: { ...(combinedSchema.$defs ?? {}), ...allDefinitions }, $defs: { ...allDefinitions, ...(combinedSchema.$defs ?? {}) }, }; - // Generate types via quicktype + // Generate types via quicktype — use a single combined schema source so quicktype + // sees each definition exactly once, preventing whimsical prefix disambiguation. const schemaInput = new JSONSchemaInput(new FetchingJSONSchemaStore()); - for (const [name, def] of Object.entries(rootDefinitions)) { - const schemaWithDefs = withSharedDefinitions( - typeof def === "object" ? (def as JSONSchema7) : {}, - allDefinitionCollections - ); - await schemaInput.addSource({ name, schema: JSON.stringify(schemaWithDefs) }); - } + const singleSchema: JSONSchema7 = { + $schema: "http://json-schema.org/draft-07/schema#", + type: "object", + definitions: allDefinitions as Record, + properties: Object.fromEntries( + Object.keys(allDefinitions).map((name) => [name, { $ref: `#/definitions/${name}` }]) + ), + required: Object.keys(allDefinitions), + }; + await schemaInput.addSource({ name: "RpcTypes", schema: JSON.stringify(singleSchema) }); const inputData = new InputData(); inputData.addInput(schemaInput); @@ -1060,7 +1100,8 @@ async function generateRpc(schemaPath?: string): Promise { const quicktypeImports = extractQuicktypeImports(qtCode); qtCode = quicktypeImports.code; qtCode = postProcessEnumConstants(qtCode); - qtCode = collapsePlaceholderGoStructs(qtCode); + const knownDefNames = new Set(Object.keys(allDefinitions).map((n) => n.toLowerCase())); + qtCode = collapsePlaceholderGoStructs(qtCode, knownDefNames); // Strip trailing whitespace from quicktype output (gofmt requirement) qtCode = qtCode.replace(/[ \t]+$/gm, ""); @@ -1082,7 +1123,7 @@ async function generateRpc(schemaPath?: string): Promise { if (method.stability !== "experimental") continue; experimentalTypeNames.add(goResultTypeName(method)); const paramsTypeName = goParamsTypeName(method); - if (rootDefinitions[paramsTypeName]) { + if (allDefinitions[paramsTypeName]) { experimentalTypeNames.add(paramsTypeName); } } @@ -1102,7 +1143,7 @@ async function generateRpc(schemaPath?: string): Promise { } if (!method.params?.$ref) { const paramsTypeName = goParamsTypeName(method); - if (rootDefinitions[paramsTypeName]) { + if (allDefinitions[paramsTypeName]) { deprecatedTypeNames.add(paramsTypeName); } } @@ -1277,7 +1318,11 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio function emitMethod(lines: string[], receiver: string, name: string, method: RpcMethod, isSession: boolean, resolveType: (name: string) => string, fieldNames: Map>, groupExperimental = false, isWrapper = false, groupDeprecated = false): void { const methodName = toPascalCase(name); - const resultType = resolveType(goResultTypeName(method)); + const resultSchema = getMethodResultSchema(method); + const nullableInner = resultSchema ? getNullableInner(resultSchema) : undefined; + const resultType = nullableInner + ? resolveType(goNullableResultTypeName(method, nullableInner)) + : resolveType(goResultTypeName(method)); const effectiveParams = getMethodParamsSchema(method); const paramProps = effectiveParams?.properties || {}; @@ -1388,7 +1433,11 @@ function emitClientSessionApiRegistration(lines: string[], clientSchema: Record< lines.push(`\t// Experimental: ${clientHandlerMethodName(method.rpcMethod)} is an experimental API and may change or be removed in future versions.`); } const paramsType = resolveType(goParamsTypeName(method)); - const resultType = resolveType(goResultTypeName(method)); + const resultSchema = getMethodResultSchema(method); + const nullableInner = resultSchema ? getNullableInner(resultSchema) : undefined; + const resultType = nullableInner + ? resolveType(goNullableResultTypeName(method, nullableInner)) + : resolveType(goResultTypeName(method)); lines.push(`\t${clientHandlerMethodName(method.rpcMethod)}(request *${paramsType}) (*${resultType}, error)`); } lines.push(`}`); diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts index 175c5175b..6fe931994 100644 --- a/scripts/codegen/python.ts +++ b/scripts/codegen/python.ts @@ -16,9 +16,9 @@ import { getApiSchemaPath, getRpcSchemaTypeName, getSessionEventsSchemaPath, - hoistTitledSchemas, isObjectSchema, isVoidSchema, + getNullableInner, isRpcMethod, isNodeFullyExperimental, isNodeFullyDeprecated, @@ -152,7 +152,7 @@ function unwrapRedundantPythonLambdas(code: string): string { ); } -function collapsePlaceholderPythonDataclasses(code: string): string { +function collapsePlaceholderPythonDataclasses(code: string, knownDefinitionNames?: Set): string { const classBlockRe = /(@dataclass\r?\nclass\s+(\w+):[\s\S]*?)(?=^@dataclass|^class\s+\w+|^def\s+\w+|\Z)/gm; const matches = [...code.matchAll(classBlockRe)].map((match) => ({ fullBlock: match[1], @@ -170,12 +170,14 @@ function collapsePlaceholderPythonDataclasses(code: string): string { for (const group of groups.values()) { if (group.length < 2) continue; - const canonical = chooseCanonicalPlaceholderDuplicate(group.map(({ name }) => name)); + const canonical = chooseCanonicalPlaceholderDuplicate(group.map(({ name }) => name), knownDefinitionNames); if (!canonical) continue; for (const duplicate of group) { if (duplicate.name === canonical) continue; - if (!isPlaceholderTypeName(duplicate.name)) continue; + // Only collapse types that quicktype invented (Class suffix or not + // in the schema's named definitions). Preserve intentionally-named types. + if (!isPlaceholderTypeName(duplicate.name) && knownDefinitionNames?.has(duplicate.name.toLowerCase())) continue; code = code.replace(duplicate.fullBlock, ""); code = code.replace(new RegExp(`\\b${duplicate.name}\\b`, "g"), canonical); @@ -346,16 +348,23 @@ function normalizePythonDataclassBlock(block: string, name: string): string { .join("\n"); } -function chooseCanonicalPlaceholderDuplicate(names: string[]): string | undefined { +function chooseCanonicalPlaceholderDuplicate(names: string[], knownDefinitionNames?: Set): string | undefined { + // Prefer the name that matches a schema definition — it's intentionally named. + if (knownDefinitionNames) { + const definedName = names.find((name) => knownDefinitionNames.has(name.toLowerCase())); + if (definedName) return definedName; + } + // Fallback for Class-suffix placeholders: pick the non-placeholder name. const specificNames = names.filter((name) => !isPlaceholderTypeName(name)); if (specificNames.length === 0) return undefined; - return specificNames.sort((left, right) => right.length - left.length || left.localeCompare(right))[0]; + return specificNames[0]; } function isPlaceholderTypeName(name: string): boolean { - return name.endsWith("Class"); + return name.endsWith("Class") || name.endsWith("Enum"); } + function toSnakeCase(s: string): string { return s .replace(/([a-z])([A-Z])/g, "$1_$2") @@ -419,8 +428,14 @@ function getMethodParamsSchema(method: RpcMethod): JSONSchema7 | undefined { ); } -function pythonResultTypeName(method: RpcMethod): string { - return getRpcSchemaTypeName(getMethodResultSchema(method), toPascalCase(method.rpcMethod) + "Result"); +function pythonResultTypeName(method: RpcMethod, schemaOverride?: JSONSchema7): string { + const schema = schemaOverride ?? getMethodResultSchema(method); + // If schema is a $ref, derive the type name from the ref path + if (schema?.$ref) { + const refName = schema.$ref.split("/").pop(); + if (refName) return toPascalCase(refName); + } + return getRpcSchemaTypeName(schema, toPascalCase(method.rpcMethod) + "Result"); } function pythonParamsTypeName(method: RpcMethod): string { @@ -705,7 +720,8 @@ function resolvePyPropertyType( isRequired: boolean, ctx: PyCodegenCtx ): PyResolvedType { - const nestedName = parentTypeName + toPascalCase(jsonPropName); + const fallbackName = parentTypeName + toPascalCase(jsonPropName); + const nestedName = typeof propSchema.title === "string" ? propSchema.title : fallbackName; if (propSchema.$ref && typeof propSchema.$ref === "string") { const typeName = toPascalCase(refTypeName(propSchema.$ref, ctx.definitions)); @@ -995,8 +1011,8 @@ function emitPyClass( ([, value]) => typeof value === "object" ) as Array<[string, JSONSchema7]>; const orderedFieldEntries = [ - ...fieldEntries.filter(([name]) => required.has(name)), - ...fieldEntries.filter(([name]) => !required.has(name)), + ...fieldEntries.filter(([name]) => required.has(name)).sort(([a], [b]) => a.localeCompare(b)), + ...fieldEntries.filter(([name]) => !required.has(name)).sort(([a], [b]) => a.localeCompare(b)), ]; const fieldInfos = orderedFieldEntries.map(([propName, propSchema]) => { @@ -1007,7 +1023,9 @@ function emitPyClass( fieldName: toSnakeCase(propName), isRequired, resolved, - defaultLiteral: isRequired ? undefined : toPythonLiteral(propSchema.default), + defaultLiteral: isRequired ? undefined : toPythonLiteral( + propSchema.default ?? resolveSchema(propSchema, ctx.definitions)?.default + ), }; }); @@ -1140,8 +1158,8 @@ function emitPyFlatDiscriminatedUnion( ]; const orderedFieldEntries = [ - ...fieldEntries.filter(([, , requiredInAll]) => requiredInAll), - ...fieldEntries.filter(([, , requiredInAll]) => !requiredInAll), + ...fieldEntries.filter(([, , requiredInAll]) => requiredInAll).sort(([a], [b]) => a.localeCompare(b)), + ...fieldEntries.filter(([, , requiredInAll]) => !requiredInAll).sort(([a], [b]) => a.localeCompare(b)), ]; const fieldInfos = orderedFieldEntries.map(([propName, propSchema, requiredInAll]) => { @@ -1161,7 +1179,9 @@ function emitPyFlatDiscriminatedUnion( fieldName: toSnakeCase(propName), isRequired: requiredInAll, resolved, - defaultLiteral: requiredInAll ? undefined : toPythonLiteral(propSchema.default), + defaultLiteral: requiredInAll ? undefined : toPythonLiteral( + propSchema.default ?? resolveSchema(propSchema, ctx.definitions)?.default + ), }; }); @@ -1446,12 +1466,12 @@ export function generatePythonSessionEventsCode(schema: JSONSchema7): string { ); out.push(``); out.push(``); - for (const classDef of ctx.classes) { + for (const classDef of ctx.classes.sort()) { out.push(classDef); out.push(``); out.push(``); } - for (const enumDef of ctx.enums) { + for (const enumDef of ctx.enums.sort()) { out.push(enumDef); out.push(``); out.push(``); @@ -1567,10 +1587,14 @@ async function generateRpc(schemaPath?: string): Promise { for (const method of allMethods) { const resultSchema = getMethodResultSchema(method); if (!isVoidSchema(resultSchema)) { - combinedSchema.definitions![pythonResultTypeName(method)] = withRootTitle( - schemaSourceForNamedDefinition(method.result, resultSchema), - pythonResultTypeName(method) - ); + const nullableInner = resultSchema ? getNullableInner(resultSchema) : undefined; + if (!nullableInner) { + combinedSchema.definitions![pythonResultTypeName(method)] = withRootTitle( + schemaSourceForNamedDefinition(method.result, resultSchema), + pythonResultTypeName(method) + ); + } + // For nullable results, the inner type (e.g., SessionFsError) is already in definitions } const resolvedParams = getMethodParamsSchema(method); if (method.params && hasSchemaPayload(resolvedParams)) { @@ -1597,22 +1621,25 @@ async function generateRpc(schemaPath?: string): Promise { } } - const { rootDefinitions, sharedDefinitions } = hoistTitledSchemas(combinedSchema.definitions! as Record); - const allDefinitions = { ...rootDefinitions, ...sharedDefinitions }; + const allDefinitions = combinedSchema.definitions! as Record; const allDefinitionCollections: DefinitionCollections = { definitions: { ...(combinedSchema.$defs ?? {}), ...allDefinitions }, $defs: { ...allDefinitions, ...(combinedSchema.$defs ?? {}) }, }; - // Generate types via quicktype + // Generate types via quicktype — use a single combined schema source to avoid + // quicktype inventing Purple/Fluffy disambiguation prefixes for shared types const schemaInput = new JSONSchemaInput(new FetchingJSONSchemaStore()); - for (const [name, def] of Object.entries(rootDefinitions)) { - const schemaWithDefs = withSharedDefinitions( - typeof def === "object" ? (def as JSONSchema7) : {}, - allDefinitionCollections - ); - await schemaInput.addSource({ name, schema: JSON.stringify(schemaWithDefs) }); - } + const singleSchema: Record = { + $schema: "http://json-schema.org/draft-07/schema#", + type: "object", + definitions: allDefinitions, + properties: Object.fromEntries( + Object.keys(allDefinitions).map((name) => [name, { $ref: `#/definitions/${name}` }]) + ), + required: Object.keys(allDefinitions), + }; + await schemaInput.addSource({ name: "RPC", schema: JSON.stringify(singleSchema) }); const inputData = new InputData(); inputData.addInput(schemaInput); @@ -1632,7 +1659,26 @@ async function generateRpc(schemaPath?: string): Promise { typesCode = typesCode.replace(/^(\s*)pass\n\n(\s*@staticmethod)/gm, "$2"); // Modernize to Python 3.11+ syntax typesCode = modernizePython(typesCode); - typesCode = collapsePlaceholderPythonDataclasses(typesCode); + const knownDefNames = new Set(Object.keys(allDefinitions).map((n) => n.toLowerCase())); + typesCode = collapsePlaceholderPythonDataclasses(typesCode, knownDefNames); + + // Fix quicktype's Enum-suffix renaming: quicktype sometimes renames "Xyz" to + // "XyzEnum" to avoid internal collisions. Strip the suffix to match our schema + // definition names, but fail the build if that introduces a duplicate definition. + for (const defName of Object.keys(allDefinitions)) { + const enumSuffixed = defName + "Enum"; + if (!new RegExp(`\\bclass ${enumSuffixed}\\b`).test(typesCode)) continue; + const renamed = typesCode.replace(new RegExp(`\\b${enumSuffixed}\\b`, "g"), defName); + const classCount = (renamed.match(new RegExp(`^class ${defName}\\b`, "gm")) ?? []).length; + if (classCount > 1) { + throw new Error( + `Python codegen: stripping quicktype's "Enum" suffix from "${enumSuffixed}" ` + + `would produce a duplicate definition for "${defName}". ` + + `Fix the schema definition name or add .withTypeName() to disambiguate.` + ); + } + typesCode = renamed; + } // Reorder class/enum definitions to resolve forward references. // Quicktype may emit classes before their dependencies are defined. @@ -1652,7 +1698,7 @@ async function generateRpc(schemaPath?: string): Promise { if (method.stability !== "experimental") continue; experimentalTypeNames.add(pythonResultTypeName(method)); const paramsTypeName = pythonParamsTypeName(method); - if (rootDefinitions[paramsTypeName]) { + if (allDefinitions[paramsTypeName]) { experimentalTypeNames.add(paramsTypeName); } } @@ -1672,7 +1718,7 @@ async function generateRpc(schemaPath?: string): Promise { } if (!method.params?.$ref) { const paramsTypeName = pythonParamsTypeName(method); - if (rootDefinitions[paramsTypeName]) { + if (allDefinitions[paramsTypeName]) { deprecatedTypeNames.add(paramsTypeName); } } @@ -1876,9 +1922,21 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio function emitMethod(lines: string[], name: string, method: RpcMethod, isSession: boolean, resolveType: (name: string) => string, groupExperimental = false, groupDeprecated = false): void { const methodName = toSnakeCase(name); const resultSchema = getMethodResultSchema(method); - const hasResult = !isVoidSchema(resultSchema); - const resultType = hasResult ? resolveType(pythonResultTypeName(method)) : "None"; - const resultIsObject = isObjectSchema(resultSchema); + const nullableInner = resultSchema ? getNullableInner(resultSchema) : undefined; + const effectiveResultSchema = nullableInner ?? resultSchema; + const hasResult = !isVoidSchema(resultSchema) && !nullableInner; + const hasNullableResult = !!nullableInner; + const resultIsObject = isObjectSchema(effectiveResultSchema); + + let resultType: string; + if (hasNullableResult) { + const innerTypeName = resolveType(pythonResultTypeName(method, nullableInner)); + resultType = `${innerTypeName} | None`; + } else if (hasResult) { + resultType = resolveType(pythonResultTypeName(method)); + } else { + resultType = "None"; + } const effectiveParams = getMethodParamsSchema(method); const paramProps = effectiveParams?.properties || {}; @@ -1900,40 +1958,46 @@ function emitMethod(lines: string[], name: string, method: RpcMethod, isSession: lines.push(` """.. warning:: This API is experimental and may change or be removed in future versions."""`); } - // For object results use .from_dict(); for enums/primitives use direct construction - const deserialize = (expr: string) => resultIsObject ? `${resultType}.from_dict(${expr})` : `${resultType}(${expr})`; + // Deserialize helper + const innerTypeName = hasNullableResult ? resolveType(pythonResultTypeName(method, nullableInner)) : resultType; + const deserialize = (expr: string) => { + if (hasNullableResult) { + return resultIsObject + ? `${innerTypeName}.from_dict(${expr}) if ${expr} is not None else None` + : `${innerTypeName}(${expr}) if ${expr} is not None else None`; + } + return resultIsObject ? `${innerTypeName}.from_dict(${expr})` : `${innerTypeName}(${expr})`; + }; // Build request body with proper serialization/deserialization + const emitRequestCall = (paramsExpr: string) => { + const callExpr = `await self._client.request("${method.rpcMethod}", ${paramsExpr}, **_timeout_kwargs(timeout))`; + if (hasResult || hasNullableResult) { + if (hasNullableResult) { + lines.push(` _result = ${callExpr}`); + lines.push(` return ${deserialize("_result")}`); + } else { + lines.push(` return ${deserialize(callExpr)}`); + } + } else { + lines.push(` ${callExpr}`); + } + }; + if (isSession) { if (hasParams) { lines.push(` params_dict = {k: v for k, v in params.to_dict().items() if v is not None}`); lines.push(` params_dict["sessionId"] = self._session_id`); - if (hasResult) { - lines.push(` return ${deserialize(`await self._client.request("${method.rpcMethod}", params_dict, **_timeout_kwargs(timeout))`)}`); - } else { - lines.push(` await self._client.request("${method.rpcMethod}", params_dict, **_timeout_kwargs(timeout))`); - } + emitRequestCall("params_dict"); } else { - if (hasResult) { - lines.push(` return ${deserialize(`await self._client.request("${method.rpcMethod}", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))`)}`); - } else { - lines.push(` await self._client.request("${method.rpcMethod}", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))`); - } + emitRequestCall(`{"sessionId": self._session_id}`); } } else { if (hasParams) { lines.push(` params_dict = {k: v for k, v in params.to_dict().items() if v is not None}`); - if (hasResult) { - lines.push(` return ${deserialize(`await self._client.request("${method.rpcMethod}", params_dict, **_timeout_kwargs(timeout))`)}`); - } else { - lines.push(` await self._client.request("${method.rpcMethod}", params_dict, **_timeout_kwargs(timeout))`); - } + emitRequestCall("params_dict"); } else { - if (hasResult) { - lines.push(` return ${deserialize(`await self._client.request("${method.rpcMethod}", {}, **_timeout_kwargs(timeout))`)}`); - } else { - lines.push(` await self._client.request("${method.rpcMethod}", {}, **_timeout_kwargs(timeout))`); - } + emitRequestCall("{}"); } } lines.push(``); @@ -2009,7 +2073,15 @@ function emitClientSessionHandlerMethod( ): void { const paramsType = resolveType(pythonParamsTypeName(method)); const resultSchema = getMethodResultSchema(method); - const resultType = !isVoidSchema(resultSchema) ? resolveType(pythonResultTypeName(method)) : "None"; + const nullableInner = resultSchema ? getNullableInner(resultSchema) : undefined; + let resultType: string; + if (nullableInner) { + resultType = `${resolveType(pythonResultTypeName(method, nullableInner))} | None`; + } else if (!isVoidSchema(resultSchema)) { + resultType = resolveType(pythonResultTypeName(method)); + } else { + resultType = "None"; + } lines.push(` async def ${toSnakeCase(name)}(self, params: ${paramsType}) -> ${resultType}:`); if (method.deprecated && !groupDeprecated) { lines.push(` """.. deprecated:: This API is deprecated and will be removed in a future version."""`); @@ -2030,7 +2102,8 @@ function emitClientSessionRegistrationMethod( const handlerVariableName = `handle_${toSnakeCase(groupName)}_${toSnakeCase(methodName)}`; const paramsType = resolveType(pythonParamsTypeName(method)); const resultSchema = getMethodResultSchema(method); - const resultType = !isVoidSchema(resultSchema) ? resolveType(pythonResultTypeName(method)) : null; + const nullableInner = resultSchema ? getNullableInner(resultSchema) : undefined; + const hasResult = !isVoidSchema(resultSchema) && !nullableInner; const handlerField = toSnakeCase(groupName); const handlerMethod = toSnakeCase(methodName); @@ -2040,13 +2113,21 @@ function emitClientSessionRegistrationMethod( lines.push( ` if handler is None: raise RuntimeError(f"No ${handlerField} handler registered for session: {request.session_id}")` ); - if (resultType) { + if (hasResult) { lines.push(` result = await handler.${handlerMethod}(request)`); if (isObjectSchema(resultSchema)) { lines.push(` return result.to_dict()`); } else { lines.push(` return result.value if hasattr(result, 'value') else result`); } + } else if (nullableInner) { + lines.push(` result = await handler.${handlerMethod}(request)`); + const resolvedInner = resolveSchema(nullableInner, rpcDefinitions) ?? nullableInner; + if (isObjectSchema(resolvedInner) || nullableInner.$ref) { + lines.push(` return result.to_dict() if result is not None else None`); + } else { + lines.push(` return result`); + } } else { lines.push(` await handler.${handlerMethod}(request)`); lines.push(` return None`); diff --git a/scripts/codegen/typescript.ts b/scripts/codegen/typescript.ts index 1aba7384c..208e05941 100644 --- a/scripts/codegen/typescript.ts +++ b/scripts/codegen/typescript.ts @@ -12,9 +12,9 @@ import { compile } from "json-schema-to-typescript"; import { getApiSchemaPath, fixNullableRequiredRefsInApiSchema, + getNullableInner, getRpcSchemaTypeName, getSessionEventsSchemaPath, - normalizeSchemaTitles, postProcessSchema, writeGeneratedFile, collectDefinitionCollections, @@ -26,7 +26,6 @@ import { isNodeFullyExperimental, isNodeFullyDeprecated, isVoidSchema, - stripNonAnnotationTitles, type ApiSchema, type DefinitionCollections, type RpcMethod, @@ -143,15 +142,14 @@ function normalizeSchemaForTypeScript(schema: JSONSchema7): JSONSchema7 { const draftDefinitionAliases = new Map(); for (const [key, value] of Object.entries(root.$defs ?? {})) { - let alias = key; - if (alias in definitions) { - alias = `$defs_${key}`; - while (alias in definitions) { - alias = `$defs_${alias}`; - } + if (key in definitions) { + // The definitions entry is authoritative (it went through the full pipeline). + // Drop the $defs duplicate and rewrite any $ref pointing at it to use definitions. + draftDefinitionAliases.set(key, key); + } else { + draftDefinitionAliases.set(key, key); + definitions[key] = value; } - draftDefinitionAliases.set(key, alias); - definitions[alias] = value; } root.definitions = definitions; @@ -169,9 +167,19 @@ function normalizeSchemaForTypeScript(schema: JSONSchema7): JSONSchema7 { Object.entries(value as Record).map(([key, child]) => [key, rewrite(child)]) ) as Record; - if (typeof rewritten.$ref === "string" && rewritten.$ref.startsWith("#/$defs/")) { - const definitionName = rewritten.$ref.slice("#/$defs/".length); - rewritten.$ref = `#/definitions/${draftDefinitionAliases.get(definitionName) ?? definitionName}`; + if (typeof rewritten.$ref === "string") { + if (rewritten.$ref.startsWith("#/$defs/")) { + const definitionName = rewritten.$ref.slice("#/$defs/".length); + rewritten.$ref = `#/definitions/${draftDefinitionAliases.get(definitionName) ?? definitionName}`; + } + // json-schema-to-typescript treats sibling keywords alongside $ref as a + // new inline type instead of reusing the referenced definition. Strip + // siblings so that $ref-only objects compile to a single shared type. + for (const key of Object.keys(rewritten)) { + if (key !== "$ref") { + delete rewritten[key]; + } + } } return rewritten; @@ -180,65 +188,6 @@ function normalizeSchemaForTypeScript(schema: JSONSchema7): JSONSchema7 { return rewrite(root) as JSONSchema7; } -function stableStringify(value: unknown): string { - if (Array.isArray(value)) { - return `[${value.map((item) => stableStringify(item)).join(",")}]`; - } - if (value && typeof value === "object") { - const entries = Object.entries(value as Record).sort(([a], [b]) => a.localeCompare(b)); - return `{${entries.map(([key, child]) => `${JSON.stringify(key)}:${stableStringify(child)}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function replaceDuplicateTitledSchemasWithRefs( - value: unknown, - definitions: Record, - isRoot = false -): unknown { - if (Array.isArray(value)) { - return value.map((item) => replaceDuplicateTitledSchemasWithRefs(item, definitions)); - } - if (!value || typeof value !== "object") { - return value; - } - - const rewritten = Object.fromEntries( - Object.entries(value as Record).map(([key, child]) => [ - key, - replaceDuplicateTitledSchemasWithRefs(child, definitions), - ]) - ) as Record; - - if (!isRoot && typeof rewritten.title === "string") { - const sharedSchema = definitions[rewritten.title]; - if ( - sharedSchema && - typeof sharedSchema === "object" && - stableStringify(normalizeSchemaTitles(rewritten as JSONSchema7)) === - stableStringify(normalizeSchemaTitles(sharedSchema as JSONSchema7)) - ) { - return { $ref: `#/definitions/${rewritten.title}` }; - } - } - - return rewritten; -} - -function reuseSharedTitledSchemas(schema: JSONSchema7): JSONSchema7 { - const definitions = { ...((schema.definitions ?? {}) as Record) }; - - return { - ...schema, - definitions: Object.fromEntries( - Object.entries(definitions).map(([name, definition]) => [ - name, - replaceDuplicateTitledSchemasWithRefs(definition, definitions, true), - ]) - ), - }; -} - // ── Session Events ────────────────────────────────────────────────────────── async function generateSessionEvents(schemaPath?: string): Promise { @@ -246,7 +195,7 @@ async function generateSessionEvents(schemaPath?: string): Promise { const resolvedPath = schemaPath ?? (await getSessionEventsSchemaPath()); const schema = JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as JSONSchema7; - const processed = postProcessSchema(stripNonAnnotationTitles(schema)); + const processed = postProcessSchema(schema); const definitionCollections = collectDefinitionCollections(processed as Record); const sessionEvent = resolveSchema({ $ref: "#/definitions/SessionEvent" }, definitionCollections) ?? @@ -309,6 +258,25 @@ function resultTypeName(method: RpcMethod): string { ); } +function tsNullableResultTypeName(method: RpcMethod): string | undefined { + const resultSchema = getMethodResultSchema(method); + if (!resultSchema) return undefined; + const inner = getNullableInner(resultSchema); + if (!inner) return undefined; + // Resolve $ref to a type name + if (inner.$ref) { + const refName = inner.$ref.split("/").pop(); + if (refName) return `${toPascalCase(refName)} | undefined`; + } + const innerName = getRpcSchemaTypeName(inner, method.rpcMethod.split(".").map(toPascalCase).join("") + "Result"); + return `${innerName} | undefined`; +} + +function tsResultType(method: RpcMethod): string { + if (isVoidSchema(getMethodResultSchema(method))) return "void"; + return tsNullableResultTypeName(method) ?? resultTypeName(method); +} + function paramsTypeName(method: RpcMethod): string { const fallback = rpcRequestFallbackName(method); if (method.rpcMethod.startsWith("session.") && method.params?.$ref) { @@ -354,7 +322,7 @@ import type { MessageConnection } from "vscode-jsonrpc/node.js"; for (const method of [...allMethods, ...clientSessionMethods]) { const resultSchema = getMethodResultSchema(method); - if (!isVoidSchema(resultSchema)) { + if (!isVoidSchema(resultSchema) && !getNullableInner(resultSchema)) { combinedSchema.definitions![resultTypeName(method)] = withRootTitle( schemaSourceForNamedDefinition(method.result, resultSchema), resultTypeName(method) @@ -404,7 +372,7 @@ import type { MessageConnection } from "vscode-jsonrpc/node.js"; } } - const schemaForCompile = reuseSharedTitledSchemas(stripNonAnnotationTitles(combinedSchema)); + const schemaForCompile = combinedSchema; const compiled = await compile(normalizeSchemaForTypeScript(schemaForCompile), "_RpcSchemaRoot", { bannerComment: "", @@ -477,7 +445,7 @@ function emitGroup(node: Record, indent: string, isSession: boo for (const [key, value] of Object.entries(node)) { if (isRpcMethod(value)) { const { rpcMethod, params } = value; - const resultType = !isVoidSchema(getMethodResultSchema(value)) ? resultTypeName(value) : "void"; + const resultType = tsResultType(value); const paramsType = paramsTypeName(value); const effectiveParams = getMethodParamsSchema(value); @@ -582,7 +550,7 @@ function emitClientSessionApiRegistration(clientSchema: Record) const name = handlerMethodName(method.rpcMethod); const hasParams = hasSchemaPayload(getMethodParamsSchema(method)); const pType = hasParams ? paramsTypeName(method) : ""; - const rType = !isVoidSchema(getMethodResultSchema(method)) ? resultTypeName(method) : "void"; + const rType = tsResultType(method); if (method.deprecated && !groupDeprecated) { lines.push(` /** @deprecated */`); diff --git a/scripts/codegen/utils.ts b/scripts/codegen/utils.ts index bc144bf75..9abc9c8fb 100644 --- a/scripts/codegen/utils.ts +++ b/scripts/codegen/utils.ts @@ -74,7 +74,7 @@ export function postProcessSchema(schema: JSONSchema7): JSONSchema7 { if (processed.properties) { const newProps: Record = {}; - for (const [key, value] of Object.entries(processed.properties)) { + for (const [key, value] of Object.entries(processed.properties).sort(([a], [b]) => a.localeCompare(b))) { newProps[key] = typeof value === "object" ? postProcessSchema(value as JSONSchema7) : value; } processed.properties = newProps; @@ -245,43 +245,39 @@ export function isVoidSchema(schema: JSONSchema7 | null | undefined): boolean { return schema.type === "null"; } +/** + * If the schema is a nullable anyOf (anyOf: [nullLike, T] or [T, nullLike]), + * returns the non-null inner schema. Recognizes both `{ type: "null" }` and + * `{ not: {} }` (zod-to-json-schema 2019-09 format for undefined). + * Returns undefined if the schema is not a nullable wrapper. + */ +export function getNullableInner(schema: JSONSchema7): JSONSchema7 | undefined { + if (!schema.anyOf || !Array.isArray(schema.anyOf) || schema.anyOf.length !== 2) return undefined; + const [a, b] = schema.anyOf; + if (isNullLike(a) && !isNullLike(b)) return b as JSONSchema7; + if (isNullLike(b) && !isNullLike(a)) return a as JSONSchema7; + return undefined; +} + +function isNullLike(s: unknown): boolean { + if (!s || typeof s !== "object") return false; + const obj = s as Record; + if (obj.type === "null") return true; + if ("not" in obj && typeof obj.not === "object" && obj.not !== null && Object.keys(obj.not).length === 0) return true; + return false; +} + export function cloneSchemaForCodegen(value: T): T { if (Array.isArray(value)) { return value.map((item) => cloneSchemaForCodegen(item)) as T; } if (value && typeof value === "object") { + const source = value as Record; const result: Record = {}; - for (const [key, child] of Object.entries(value as Record)) { - if (key === "titleSource") { - continue; - } - result[key] = cloneSchemaForCodegen(child); - } - - return result as T; - } - return value; -} - -export function stripNonAnnotationTitles(value: T): T { - if (Array.isArray(value)) { - return value.map((item) => stripNonAnnotationTitles(item)) as T; - } - - if (value && typeof value === "object") { - const result: Record = {}; - const source = value as Record; - const keepTitle = typeof source.title === "string" && source.titleSource === "annotation"; for (const [key, child] of Object.entries(source)) { - if (key === "titleSource") { - continue; - } - if (key === "title" && !keepTitle) { - continue; - } - result[key] = stripNonAnnotationTitles(child); + result[key] = cloneSchemaForCodegen(child); } return result as T; @@ -290,99 +286,6 @@ export function stripNonAnnotationTitles(value: T): T { return value; } -export function hoistTitledSchemas( - rootDefinitions: Record -): { rootDefinitions: Record; sharedDefinitions: Record } { - const sharedDefinitions: Record = {}; - const processedRoots: Record = {}; - - for (const [rootName, definition] of Object.entries(rootDefinitions)) { - processedRoots[rootName] = visitSchema(definition, rootName, sharedDefinitions); - } - - return { rootDefinitions: processedRoots, sharedDefinitions }; -} - -function visitSchema( - schema: JSONSchema7, - rootName: string, - sharedDefinitions: Record -): JSONSchema7 { - const result: JSONSchema7 = { ...schema }; - - if (result.properties) { - result.properties = Object.fromEntries( - Object.entries(result.properties).map(([key, value]) => [ - key, - typeof value === "object" && value !== null && !Array.isArray(value) - ? visitSchema(value as JSONSchema7, rootName, sharedDefinitions) - : value, - ]) - ); - } - - if (result.items) { - if (Array.isArray(result.items)) { - result.items = result.items.map((item) => - typeof item === "object" && item !== null && !Array.isArray(item) - ? visitSchema(item as JSONSchema7, rootName, sharedDefinitions) - : item - ) as JSONSchema7Definition[]; - } else if (typeof result.items === "object" && result.items !== null) { - result.items = visitSchema(result.items as JSONSchema7, rootName, sharedDefinitions); - } - } - - if (typeof result.additionalProperties === "object" && result.additionalProperties !== null) { - result.additionalProperties = visitSchema(result.additionalProperties as JSONSchema7, rootName, sharedDefinitions); - } - - for (const combiner of ["anyOf", "allOf", "oneOf"] as const) { - if (result[combiner]) { - result[combiner] = result[combiner]!.map((item) => - typeof item === "object" && item !== null && !Array.isArray(item) - ? visitSchema(item as JSONSchema7, rootName, sharedDefinitions) - : item - ) as JSONSchema7Definition[]; - } - } - - if (typeof result.title === "string" && result.title !== rootName) { - const existing = sharedDefinitions[result.title]; - if (existing) { - if (stableStringify(existing) !== stableStringify(result)) { - throw new Error(`Conflicting titled schemas for "${result.title}" while preparing quicktype inputs.`); - } - } else { - sharedDefinitions[result.title] = result; - } - return { $ref: `#/definitions/${result.title}`, description: result.description } as JSONSchema7; - } - - return result; -} - -function stableStringify(value: unknown): string { - return JSON.stringify(sortJsonValue(value)); -} - -function sortJsonValue(value: unknown): unknown { - if (Array.isArray(value)) { - return value.map(sortJsonValue); - } - - if (value && typeof value === "object") { - return Object.fromEntries( - Object.entries(value as Record) - .filter(([key]) => key !== "description" && key !== "titleSource") - .sort(([left], [right]) => left.localeCompare(right)) - .map(([key, child]) => [key, sortJsonValue(child)]) - ); - } - - return value; -} - export interface ApiSchema { definitions?: Record; $defs?: Record; @@ -395,135 +298,6 @@ export function isRpcMethod(node: unknown): node is RpcMethod { return typeof node === "object" && node !== null && "rpcMethod" in node; } -function normalizeSchemaDefinitionTitles(definition: JSONSchema7Definition): JSONSchema7Definition { - return typeof definition === "object" && definition !== null - ? normalizeSchemaTitles(definition as JSONSchema7) - : definition; -} - -export function normalizeSchemaTitles(schema: JSONSchema7): JSONSchema7 { - if (typeof schema !== "object" || schema === null) return schema; - - const normalized = { ...schema } as JSONSchema7WithDefs & Record; - delete normalized.title; - delete normalized.titleSource; - - if (normalized.properties) { - const newProps: Record = {}; - for (const [key, value] of Object.entries(normalized.properties)) { - newProps[key] = normalizeSchemaDefinitionTitles(value); - } - normalized.properties = newProps; - } - - if (normalized.items) { - if (typeof normalized.items === "object" && !Array.isArray(normalized.items)) { - normalized.items = normalizeSchemaTitles(normalized.items as JSONSchema7); - } else if (Array.isArray(normalized.items)) { - normalized.items = normalized.items.map((item) => normalizeSchemaDefinitionTitles(item)) as JSONSchema7Definition[]; - } - } - - for (const combiner of ["anyOf", "allOf", "oneOf"] as const) { - if (normalized[combiner]) { - normalized[combiner] = normalized[combiner]!.map((item) => normalizeSchemaDefinitionTitles(item)) as JSONSchema7Definition[]; - } - } - - if (normalized.additionalProperties && typeof normalized.additionalProperties === "object") { - normalized.additionalProperties = normalizeSchemaTitles(normalized.additionalProperties as JSONSchema7); - } - - if (normalized.propertyNames && typeof normalized.propertyNames === "object" && !Array.isArray(normalized.propertyNames)) { - normalized.propertyNames = normalizeSchemaTitles(normalized.propertyNames as JSONSchema7); - } - - if (normalized.contains && typeof normalized.contains === "object" && !Array.isArray(normalized.contains)) { - normalized.contains = normalizeSchemaTitles(normalized.contains as JSONSchema7); - } - - if (normalized.not && typeof normalized.not === "object" && !Array.isArray(normalized.not)) { - normalized.not = normalizeSchemaTitles(normalized.not as JSONSchema7); - } - - if (normalized.if && typeof normalized.if === "object" && !Array.isArray(normalized.if)) { - normalized.if = normalizeSchemaTitles(normalized.if as JSONSchema7); - } - if (normalized.then && typeof normalized.then === "object" && !Array.isArray(normalized.then)) { - normalized.then = normalizeSchemaTitles(normalized.then as JSONSchema7); - } - if (normalized.else && typeof normalized.else === "object" && !Array.isArray(normalized.else)) { - normalized.else = normalizeSchemaTitles(normalized.else as JSONSchema7); - } - - if (normalized.patternProperties) { - const newPatternProps: Record = {}; - for (const [key, value] of Object.entries(normalized.patternProperties)) { - newPatternProps[key] = normalizeSchemaDefinitionTitles(value); - } - normalized.patternProperties = newPatternProps; - } - - const { definitions, $defs } = collectDefinitionCollections(normalized as Record); - if (Object.keys(definitions).length > 0) { - const newDefs: Record = {}; - for (const [key, value] of Object.entries(definitions)) { - newDefs[key] = normalizeSchemaDefinitionTitles(value); - } - normalized.definitions = newDefs; - } - if (Object.keys($defs).length > 0) { - const newDraftDefs: Record = {}; - for (const [key, value] of Object.entries($defs)) { - newDraftDefs[key] = normalizeSchemaDefinitionTitles(value); - } - normalized.$defs = newDraftDefs; - } - - return normalized; -} - -function normalizeApiNode(node: Record | undefined): Record | undefined { - if (!node) return undefined; - - const normalizedNode: Record = {}; - for (const [key, value] of Object.entries(node)) { - if (isRpcMethod(value)) { - const method = value as RpcMethod; - normalizedNode[key] = { - ...method, - params: method.params ? normalizeSchemaTitles(method.params) : method.params, - result: method.result ? normalizeSchemaTitles(method.result) : method.result, - }; - } else if (typeof value === "object" && value !== null) { - normalizedNode[key] = normalizeApiNode(value as Record); - } else { - normalizedNode[key] = value; - } - } - - return normalizedNode; -} - -export function normalizeApiSchema(schema: ApiSchema): ApiSchema { - return { - ...schema, - definitions: schema.definitions - ? Object.fromEntries( - Object.entries(schema.definitions).map(([key, value]) => [key, normalizeSchemaDefinitionTitles(value)]) - ) - : schema.definitions, - $defs: schema.$defs - ? Object.fromEntries( - Object.entries(schema.$defs).map(([key, value]) => [key, normalizeSchemaDefinitionTitles(value)]) - ) - : schema.$defs, - server: normalizeApiNode(schema.server), - session: normalizeApiNode(schema.session), - clientSession: normalizeApiNode(schema.clientSession), - }; -} - /** * Apply `normalizeNullableRequiredRefs` to every JSON Schema reachable from the API schema * (method params, results, and shared definitions). Call after `cloneSchemaForCodegen` to diff --git a/test/snapshots/builtin_tools/should_search_for_patterns_in_files.yaml b/test/snapshots/builtin_tools/should_search_for_patterns_in_files.yaml index 89af253b5..f4e32f773 100644 --- a/test/snapshots/builtin_tools/should_search_for_patterns_in_files.yaml +++ b/test/snapshots/builtin_tools/should_search_for_patterns_in_files.yaml @@ -43,10 +43,10 @@ conversations: - role: tool tool_call_id: toolcall_1 content: |- - ${workdir}/data.txt:1:apple - ${workdir}/data.txt:3:apricot + ./data.txt:1:apple + ./data.txt:3:apricot - role: assistant content: |- - Two lines matched: + The search found **2 lines** starting with 'ap': - Line 1: `apple` - Line 3: `apricot` diff --git a/test/snapshots/session_fs/should_persist_plan_md_via_sessionfs.yaml b/test/snapshots/session_fs/should_persist_plan_md_via_sessionfs.yaml new file mode 100644 index 000000000..5b0e81b22 --- /dev/null +++ b/test/snapshots/session_fs/should_persist_plan_md_via_sessionfs.yaml @@ -0,0 +1,10 @@ +models: + - claude-sonnet-4.5 +conversations: + - messages: + - role: system + content: ${system} + - role: user + content: What is 2 + 3? + - role: assistant + content: 2 + 3 = 5 diff --git a/test/snapshots/session_fs/should_write_workspace_metadata_via_sessionfs.yaml b/test/snapshots/session_fs/should_write_workspace_metadata_via_sessionfs.yaml new file mode 100644 index 000000000..0a0325417 --- /dev/null +++ b/test/snapshots/session_fs/should_write_workspace_metadata_via_sessionfs.yaml @@ -0,0 +1,10 @@ +models: + - claude-sonnet-4.5 +conversations: + - messages: + - role: system + content: ${system} + - role: user + content: What is 7 * 8? + - role: assistant + content: 7 * 8 = 56