diff --git a/docs/features/image-input.md b/docs/features/image-input.md
index acec80d4a..8295b83d7 100644
--- a/docs/features/image-input.md
+++ b/docs/features/image-input.md
@@ -121,7 +121,7 @@ func main() {
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
{
- Type: copilot.File,
+ Type: copilot.AttachmentTypeFile,
Path: &path,
},
},
@@ -147,7 +147,7 @@ session.Send(ctx, copilot.MessageOptions{
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
{
- Type: copilot.File,
+ Type: copilot.AttachmentTypeFile,
Path: &path,
},
},
@@ -315,7 +315,7 @@ func main() {
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
{
- Type: copilot.Blob,
+ Type: copilot.AttachmentTypeBlob,
Data: &base64ImageData,
MIMEType: &mimeType,
DisplayName: &displayName,
@@ -333,7 +333,7 @@ session.Send(ctx, copilot.MessageOptions{
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
{
- Type: copilot.Blob,
+ Type: copilot.AttachmentTypeBlob,
Data: &base64ImageData, // base64-encoded string
MIMEType: &mimeType,
DisplayName: &displayName,
diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs
index 6fc593c12..fabe4817e 100644
--- a/dotnet/src/Generated/Rpc.cs
+++ b/dotnet/src/Generated/Rpc.cs
@@ -245,6 +245,10 @@ internal class SessionLogRequest
/// When true, the message is transient and not persisted to the session event log on disk.
[JsonPropertyName("ephemeral")]
public bool? Ephemeral { get; set; }
+
+ /// Optional URL the user can open in their browser for more details.
+ [JsonPropertyName("url")]
+ public string? Url { get; set; }
}
/// RPC data type for SessionModelGetCurrent operations.
@@ -577,6 +581,347 @@ internal class SessionAgentDeselectRequest
public string SessionId { get; set; } = string.Empty;
}
+/// RPC data type for SessionAgentReload operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionAgentReloadResult
+{
+ /// Reloaded custom agents.
+ [JsonPropertyName("agents")]
+ public List Agents { get => field ??= []; set; }
+}
+
+/// RPC data type for SessionAgentReload operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionAgentReloadRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// RPC data type for Skill operations.
+public class Skill
+{
+ /// 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, plugin).
+ [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.
+ [JsonPropertyName("enabled")]
+ public bool Enabled { get; set; }
+
+ /// Absolute path to the skill file.
+ [JsonPropertyName("path")]
+ public string? Path { get; set; }
+}
+
+/// RPC data type for SessionSkillsList operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionSkillsListResult
+{
+ /// Available skills.
+ [JsonPropertyName("skills")]
+ public List Skills { get => field ??= []; set; }
+}
+
+/// RPC data type for SessionSkillsList operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionSkillsListRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// RPC data type for SessionSkillsEnable operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionSkillsEnableResult
+{
+}
+
+/// RPC data type for SessionSkillsEnable operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionSkillsEnableRequest
+{
+ /// 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;
+}
+
+/// RPC data type for SessionSkillsDisable operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionSkillsDisableResult
+{
+}
+
+/// RPC data type for SessionSkillsDisable operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionSkillsDisableRequest
+{
+ /// 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;
+}
+
+/// RPC data type for SessionSkillsReload operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionSkillsReloadResult
+{
+}
+
+/// RPC data type for SessionSkillsReload operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionSkillsReloadRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// RPC data type for Server operations.
+public class Server
+{
+ /// Server name (config key).
+ [JsonPropertyName("name")]
+ public string Name { get; set; } = string.Empty;
+
+ /// Connection status: connected, failed, pending, disabled, or not_configured.
+ [JsonPropertyName("status")]
+ public ServerStatus Status { get; set; }
+
+ /// Configuration source: user, workspace, plugin, or builtin.
+ [JsonPropertyName("source")]
+ public string? Source { get; set; }
+
+ /// Error message if the server failed to connect.
+ [JsonPropertyName("error")]
+ public string? Error { get; set; }
+}
+
+/// RPC data type for SessionMcpList operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionMcpListResult
+{
+ /// Configured MCP servers.
+ [JsonPropertyName("servers")]
+ public List Servers { get => field ??= []; set; }
+}
+
+/// RPC data type for SessionMcpList operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionMcpListRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// RPC data type for SessionMcpEnable operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionMcpEnableResult
+{
+}
+
+/// RPC data type for SessionMcpEnable operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionMcpEnableRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+
+ /// Name of the MCP server to enable.
+ [JsonPropertyName("serverName")]
+ public string ServerName { get; set; } = string.Empty;
+}
+
+/// RPC data type for SessionMcpDisable operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionMcpDisableResult
+{
+}
+
+/// RPC data type for SessionMcpDisable operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionMcpDisableRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+
+ /// Name of the MCP server to disable.
+ [JsonPropertyName("serverName")]
+ public string ServerName { get; set; } = string.Empty;
+}
+
+/// RPC data type for SessionMcpReload operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionMcpReloadResult
+{
+}
+
+/// RPC data type for SessionMcpReload operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionMcpReloadRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// RPC data type for Plugin operations.
+public class Plugin
+{
+ /// Plugin name.
+ [JsonPropertyName("name")]
+ public string Name { get; set; } = string.Empty;
+
+ /// Marketplace the plugin came from.
+ [JsonPropertyName("marketplace")]
+ public string Marketplace { 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 SessionPluginsList operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionPluginsListResult
+{
+ /// Installed plugins.
+ [JsonPropertyName("plugins")]
+ public List Plugins { get => field ??= []; set; }
+}
+
+/// RPC data type for SessionPluginsList operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionPluginsListRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// RPC data type for Extension operations.
+public class Extension
+{
+ /// Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper').
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ /// Extension name (directory name).
+ [JsonPropertyName("name")]
+ public string Name { get; set; } = string.Empty;
+
+ /// Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/).
+ [JsonPropertyName("source")]
+ public ExtensionSource Source { get; set; }
+
+ /// Current status: running, disabled, failed, or starting.
+ [JsonPropertyName("status")]
+ public ExtensionStatus Status { get; set; }
+
+ /// Process ID if the extension is running.
+ [JsonPropertyName("pid")]
+ public double? Pid { get; set; }
+}
+
+/// RPC data type for SessionExtensionsList operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionExtensionsListResult
+{
+ /// Discovered extensions and their current status.
+ [JsonPropertyName("extensions")]
+ public List Extensions { get => field ??= []; set; }
+}
+
+/// RPC data type for SessionExtensionsList operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionExtensionsListRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// RPC data type for SessionExtensionsEnable operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionExtensionsEnableResult
+{
+}
+
+/// RPC data type for SessionExtensionsEnable operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionExtensionsEnableRequest
+{
+ /// 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;
+}
+
+/// RPC data type for SessionExtensionsDisable operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionExtensionsDisableResult
+{
+}
+
+/// RPC data type for SessionExtensionsDisable operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionExtensionsDisableRequest
+{
+ /// 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;
+}
+
+/// RPC data type for SessionExtensionsReload operations.
+[Experimental(Diagnostics.Experimental)]
+public class SessionExtensionsReloadResult
+{
+}
+
+/// RPC data type for SessionExtensionsReload operations.
+[Experimental(Diagnostics.Experimental)]
+internal class SessionExtensionsReloadRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
/// RPC data type for SessionCompactionCompact operations.
[Experimental(Diagnostics.Experimental)]
public class SessionCompactionCompactResult
@@ -631,6 +976,74 @@ internal class SessionToolsHandlePendingToolCallRequest
public string? Error { get; set; }
}
+/// RPC data type for SessionCommandsHandlePendingCommand operations.
+public class SessionCommandsHandlePendingCommandResult
+{
+ /// Gets or sets the success value.
+ [JsonPropertyName("success")]
+ public bool Success { get; set; }
+}
+
+/// RPC data type for SessionCommandsHandlePendingCommand operations.
+internal class SessionCommandsHandlePendingCommandRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+
+ /// 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; }
+}
+
+/// RPC data type for SessionUiElicitation operations.
+public class SessionUiElicitationResult
+{
+ /// The user's response: accept (submitted), decline (rejected), or cancel (dismissed).
+ [JsonPropertyName("action")]
+ public SessionUiElicitationResultAction Action { get; set; }
+
+ /// The form values submitted by the user (present when action is 'accept').
+ [JsonPropertyName("content")]
+ public Dictionary? Content { get; set; }
+}
+
+/// JSON Schema describing the form fields to present to the user.
+public class SessionUiElicitationRequestRequestedSchema
+{
+ /// Schema type indicator (always 'object').
+ [JsonPropertyName("type")]
+ public string Type { get; set; } = string.Empty;
+
+ /// Form field definitions, keyed by field name.
+ [JsonPropertyName("properties")]
+ public Dictionary Properties { get => field ??= []; set; }
+
+ /// List of required field names.
+ [JsonPropertyName("required")]
+ public List? Required { get; set; }
+}
+
+/// RPC data type for SessionUiElicitation operations.
+internal class SessionUiElicitationRequest
+{
+ /// 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;
+
+ /// JSON Schema describing the form fields to present to the user.
+ [JsonPropertyName("requestedSchema")]
+ public SessionUiElicitationRequestRequestedSchema RequestedSchema { get => field ??= new(); set; }
+}
+
/// RPC data type for SessionPermissionsHandlePendingPermissionRequest operations.
public class SessionPermissionsHandlePendingPermissionRequestResult
{
@@ -739,6 +1152,76 @@ public enum SessionModeGetResultMode
}
+/// Connection status: connected, failed, pending, disabled, or not_configured.
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum ServerStatus
+{
+ /// The connected variant.
+ [JsonStringEnumMemberName("connected")]
+ Connected,
+ /// The failed variant.
+ [JsonStringEnumMemberName("failed")]
+ Failed,
+ /// The pending variant.
+ [JsonStringEnumMemberName("pending")]
+ Pending,
+ /// The disabled variant.
+ [JsonStringEnumMemberName("disabled")]
+ Disabled,
+ /// The not_configured variant.
+ [JsonStringEnumMemberName("not_configured")]
+ NotConfigured,
+}
+
+
+/// Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/).
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum ExtensionSource
+{
+ /// The project variant.
+ [JsonStringEnumMemberName("project")]
+ Project,
+ /// The user variant.
+ [JsonStringEnumMemberName("user")]
+ User,
+}
+
+
+/// Current status: running, disabled, failed, or starting.
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum ExtensionStatus
+{
+ /// The running variant.
+ [JsonStringEnumMemberName("running")]
+ Running,
+ /// The disabled variant.
+ [JsonStringEnumMemberName("disabled")]
+ Disabled,
+ /// The failed variant.
+ [JsonStringEnumMemberName("failed")]
+ Failed,
+ /// The starting variant.
+ [JsonStringEnumMemberName("starting")]
+ Starting,
+}
+
+
+/// The user's response: accept (submitted), decline (rejected), or cancel (dismissed).
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum SessionUiElicitationResultAction
+{
+ /// The accept variant.
+ [JsonStringEnumMemberName("accept")]
+ Accept,
+ /// The decline variant.
+ [JsonStringEnumMemberName("decline")]
+ Decline,
+ /// The cancel variant.
+ [JsonStringEnumMemberName("cancel")]
+ Cancel,
+}
+
+
/// Signal to send (default: SIGTERM).
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum SessionShellKillRequestSignal
@@ -853,8 +1336,14 @@ internal SessionRpc(JsonRpc rpc, string sessionId)
Workspace = new WorkspaceApi(rpc, sessionId);
Fleet = new FleetApi(rpc, sessionId);
Agent = new AgentApi(rpc, sessionId);
+ Skills = new SkillsApi(rpc, sessionId);
+ Mcp = new McpApi(rpc, sessionId);
+ Plugins = new PluginsApi(rpc, sessionId);
+ Extensions = new ExtensionsApi(rpc, sessionId);
Compaction = new CompactionApi(rpc, sessionId);
Tools = new ToolsApi(rpc, sessionId);
+ Commands = new CommandsApi(rpc, sessionId);
+ Ui = new UiApi(rpc, sessionId);
Permissions = new PermissionsApi(rpc, sessionId);
Shell = new ShellApi(rpc, sessionId);
}
@@ -877,12 +1366,30 @@ internal SessionRpc(JsonRpc rpc, string sessionId)
/// Agent APIs.
public AgentApi Agent { get; }
+ /// Skills APIs.
+ public SkillsApi Skills { get; }
+
+ /// Mcp APIs.
+ public McpApi Mcp { get; }
+
+ /// Plugins APIs.
+ public PluginsApi Plugins { get; }
+
+ /// Extensions APIs.
+ public ExtensionsApi Extensions { get; }
+
/// Compaction APIs.
public CompactionApi Compaction { get; }
/// Tools APIs.
public ToolsApi Tools { get; }
+ /// Commands APIs.
+ public CommandsApi Commands { get; }
+
+ /// Ui APIs.
+ public UiApi Ui { get; }
+
/// Permissions APIs.
public PermissionsApi Permissions { get; }
@@ -890,9 +1397,9 @@ internal SessionRpc(JsonRpc rpc, string sessionId)
public ShellApi Shell { get; }
/// Calls "session.log".
- public async Task LogAsync(string message, SessionLogRequestLevel? level = null, bool? ephemeral = null, CancellationToken cancellationToken = default)
+ public async Task LogAsync(string message, SessionLogRequestLevel? level = null, bool? ephemeral = null, string? url = null, CancellationToken cancellationToken = default)
{
- var request = new SessionLogRequest { SessionId = _sessionId, Message = message, Level = level, Ephemeral = ephemeral };
+ var request = new SessionLogRequest { SessionId = _sessionId, Message = message, Level = level, Ephemeral = ephemeral, Url = url };
return await CopilotClient.InvokeRpcAsync(_rpc, "session.log", [request], cancellationToken);
}
}
@@ -1080,6 +1587,160 @@ public async Task DeselectAsync(CancellationToken ca
var request = new SessionAgentDeselectRequest { SessionId = _sessionId };
return await CopilotClient.InvokeRpcAsync(_rpc, "session.agent.deselect", [request], cancellationToken);
}
+
+ /// Calls "session.agent.reload".
+ public async Task ReloadAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionAgentReloadRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.agent.reload", [request], cancellationToken);
+ }
+}
+
+/// Provides session-scoped Skills APIs.
+[Experimental(Diagnostics.Experimental)]
+public class SkillsApi
+{
+ private readonly JsonRpc _rpc;
+ private readonly string _sessionId;
+
+ internal SkillsApi(JsonRpc rpc, string sessionId)
+ {
+ _rpc = rpc;
+ _sessionId = sessionId;
+ }
+
+ /// Calls "session.skills.list".
+ public async Task ListAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionSkillsListRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.skills.list", [request], cancellationToken);
+ }
+
+ /// Calls "session.skills.enable".
+ public async Task EnableAsync(string name, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionSkillsEnableRequest { SessionId = _sessionId, Name = name };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.skills.enable", [request], cancellationToken);
+ }
+
+ /// Calls "session.skills.disable".
+ public async Task DisableAsync(string name, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionSkillsDisableRequest { SessionId = _sessionId, Name = name };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.skills.disable", [request], cancellationToken);
+ }
+
+ /// Calls "session.skills.reload".
+ public async Task ReloadAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionSkillsReloadRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.skills.reload", [request], cancellationToken);
+ }
+}
+
+/// Provides session-scoped Mcp APIs.
+[Experimental(Diagnostics.Experimental)]
+public class McpApi
+{
+ private readonly JsonRpc _rpc;
+ private readonly string _sessionId;
+
+ internal McpApi(JsonRpc rpc, string sessionId)
+ {
+ _rpc = rpc;
+ _sessionId = sessionId;
+ }
+
+ /// Calls "session.mcp.list".
+ public async Task ListAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionMcpListRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.mcp.list", [request], cancellationToken);
+ }
+
+ /// Calls "session.mcp.enable".
+ public async Task EnableAsync(string serverName, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionMcpEnableRequest { SessionId = _sessionId, ServerName = serverName };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.mcp.enable", [request], cancellationToken);
+ }
+
+ /// Calls "session.mcp.disable".
+ public async Task DisableAsync(string serverName, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionMcpDisableRequest { SessionId = _sessionId, ServerName = serverName };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.mcp.disable", [request], cancellationToken);
+ }
+
+ /// Calls "session.mcp.reload".
+ public async Task ReloadAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionMcpReloadRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.mcp.reload", [request], cancellationToken);
+ }
+}
+
+/// Provides session-scoped Plugins APIs.
+[Experimental(Diagnostics.Experimental)]
+public class PluginsApi
+{
+ private readonly JsonRpc _rpc;
+ private readonly string _sessionId;
+
+ internal PluginsApi(JsonRpc rpc, string sessionId)
+ {
+ _rpc = rpc;
+ _sessionId = sessionId;
+ }
+
+ /// Calls "session.plugins.list".
+ public async Task ListAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionPluginsListRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.plugins.list", [request], cancellationToken);
+ }
+}
+
+/// Provides session-scoped Extensions APIs.
+[Experimental(Diagnostics.Experimental)]
+public class ExtensionsApi
+{
+ private readonly JsonRpc _rpc;
+ private readonly string _sessionId;
+
+ internal ExtensionsApi(JsonRpc rpc, string sessionId)
+ {
+ _rpc = rpc;
+ _sessionId = sessionId;
+ }
+
+ /// Calls "session.extensions.list".
+ public async Task ListAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionExtensionsListRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.extensions.list", [request], cancellationToken);
+ }
+
+ /// Calls "session.extensions.enable".
+ public async Task EnableAsync(string id, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionExtensionsEnableRequest { SessionId = _sessionId, Id = id };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.extensions.enable", [request], cancellationToken);
+ }
+
+ /// Calls "session.extensions.disable".
+ public async Task DisableAsync(string id, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionExtensionsDisableRequest { SessionId = _sessionId, Id = id };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.extensions.disable", [request], cancellationToken);
+ }
+
+ /// Calls "session.extensions.reload".
+ public async Task ReloadAsync(CancellationToken cancellationToken = default)
+ {
+ var request = new SessionExtensionsReloadRequest { SessionId = _sessionId };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.extensions.reload", [request], cancellationToken);
+ }
}
/// Provides session-scoped Compaction APIs.
@@ -1123,6 +1784,46 @@ public async Task HandlePendingToolCall
}
}
+/// Provides session-scoped Commands APIs.
+public class CommandsApi
+{
+ private readonly JsonRpc _rpc;
+ private readonly string _sessionId;
+
+ internal CommandsApi(JsonRpc rpc, string sessionId)
+ {
+ _rpc = rpc;
+ _sessionId = sessionId;
+ }
+
+ /// Calls "session.commands.handlePendingCommand".
+ public async Task HandlePendingCommandAsync(string requestId, string? error = null, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionCommandsHandlePendingCommandRequest { SessionId = _sessionId, RequestId = requestId, Error = error };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.commands.handlePendingCommand", [request], cancellationToken);
+ }
+}
+
+/// Provides session-scoped Ui APIs.
+public class UiApi
+{
+ private readonly JsonRpc _rpc;
+ private readonly string _sessionId;
+
+ internal UiApi(JsonRpc rpc, string sessionId)
+ {
+ _rpc = rpc;
+ _sessionId = sessionId;
+ }
+
+ /// Calls "session.ui.elicitation".
+ public async Task ElicitationAsync(string message, SessionUiElicitationRequestRequestedSchema requestedSchema, CancellationToken cancellationToken = default)
+ {
+ var request = new SessionUiElicitationRequest { SessionId = _sessionId, Message = message, RequestedSchema = requestedSchema };
+ return await CopilotClient.InvokeRpcAsync(_rpc, "session.ui.elicitation", [request], cancellationToken);
+ }
+}
+
/// Provides session-scoped Permissions APIs.
public class PermissionsApi
{
@@ -1177,6 +1878,7 @@ public async Task KillAsync(string processId, SessionShe
[JsonSerializable(typeof(AccountGetQuotaResult))]
[JsonSerializable(typeof(AccountGetQuotaResultQuotaSnapshotsValue))]
[JsonSerializable(typeof(Agent))]
+[JsonSerializable(typeof(Extension))]
[JsonSerializable(typeof(Model))]
[JsonSerializable(typeof(ModelBilling))]
[JsonSerializable(typeof(ModelCapabilities))]
@@ -1186,6 +1888,8 @@ public async Task KillAsync(string processId, SessionShe
[JsonSerializable(typeof(ModelsListResult))]
[JsonSerializable(typeof(PingRequest))]
[JsonSerializable(typeof(PingResult))]
+[JsonSerializable(typeof(Plugin))]
+[JsonSerializable(typeof(Server))]
[JsonSerializable(typeof(SessionAgentDeselectRequest))]
[JsonSerializable(typeof(SessionAgentDeselectResult))]
[JsonSerializable(typeof(SessionAgentGetCurrentRequest))]
@@ -1193,15 +1897,35 @@ public async Task KillAsync(string processId, SessionShe
[JsonSerializable(typeof(SessionAgentGetCurrentResultAgent))]
[JsonSerializable(typeof(SessionAgentListRequest))]
[JsonSerializable(typeof(SessionAgentListResult))]
+[JsonSerializable(typeof(SessionAgentReloadRequest))]
+[JsonSerializable(typeof(SessionAgentReloadResult))]
[JsonSerializable(typeof(SessionAgentSelectRequest))]
[JsonSerializable(typeof(SessionAgentSelectResult))]
[JsonSerializable(typeof(SessionAgentSelectResultAgent))]
+[JsonSerializable(typeof(SessionCommandsHandlePendingCommandRequest))]
+[JsonSerializable(typeof(SessionCommandsHandlePendingCommandResult))]
[JsonSerializable(typeof(SessionCompactionCompactRequest))]
[JsonSerializable(typeof(SessionCompactionCompactResult))]
+[JsonSerializable(typeof(SessionExtensionsDisableRequest))]
+[JsonSerializable(typeof(SessionExtensionsDisableResult))]
+[JsonSerializable(typeof(SessionExtensionsEnableRequest))]
+[JsonSerializable(typeof(SessionExtensionsEnableResult))]
+[JsonSerializable(typeof(SessionExtensionsListRequest))]
+[JsonSerializable(typeof(SessionExtensionsListResult))]
+[JsonSerializable(typeof(SessionExtensionsReloadRequest))]
+[JsonSerializable(typeof(SessionExtensionsReloadResult))]
[JsonSerializable(typeof(SessionFleetStartRequest))]
[JsonSerializable(typeof(SessionFleetStartResult))]
[JsonSerializable(typeof(SessionLogRequest))]
[JsonSerializable(typeof(SessionLogResult))]
+[JsonSerializable(typeof(SessionMcpDisableRequest))]
+[JsonSerializable(typeof(SessionMcpDisableResult))]
+[JsonSerializable(typeof(SessionMcpEnableRequest))]
+[JsonSerializable(typeof(SessionMcpEnableResult))]
+[JsonSerializable(typeof(SessionMcpListRequest))]
+[JsonSerializable(typeof(SessionMcpListResult))]
+[JsonSerializable(typeof(SessionMcpReloadRequest))]
+[JsonSerializable(typeof(SessionMcpReloadResult))]
[JsonSerializable(typeof(SessionModeGetRequest))]
[JsonSerializable(typeof(SessionModeGetResult))]
[JsonSerializable(typeof(SessionModeSetRequest))]
@@ -1218,18 +1942,32 @@ public async Task KillAsync(string processId, SessionShe
[JsonSerializable(typeof(SessionPlanReadResult))]
[JsonSerializable(typeof(SessionPlanUpdateRequest))]
[JsonSerializable(typeof(SessionPlanUpdateResult))]
+[JsonSerializable(typeof(SessionPluginsListRequest))]
+[JsonSerializable(typeof(SessionPluginsListResult))]
[JsonSerializable(typeof(SessionShellExecRequest))]
[JsonSerializable(typeof(SessionShellExecResult))]
[JsonSerializable(typeof(SessionShellKillRequest))]
[JsonSerializable(typeof(SessionShellKillResult))]
+[JsonSerializable(typeof(SessionSkillsDisableRequest))]
+[JsonSerializable(typeof(SessionSkillsDisableResult))]
+[JsonSerializable(typeof(SessionSkillsEnableRequest))]
+[JsonSerializable(typeof(SessionSkillsEnableResult))]
+[JsonSerializable(typeof(SessionSkillsListRequest))]
+[JsonSerializable(typeof(SessionSkillsListResult))]
+[JsonSerializable(typeof(SessionSkillsReloadRequest))]
+[JsonSerializable(typeof(SessionSkillsReloadResult))]
[JsonSerializable(typeof(SessionToolsHandlePendingToolCallRequest))]
[JsonSerializable(typeof(SessionToolsHandlePendingToolCallResult))]
+[JsonSerializable(typeof(SessionUiElicitationRequest))]
+[JsonSerializable(typeof(SessionUiElicitationRequestRequestedSchema))]
+[JsonSerializable(typeof(SessionUiElicitationResult))]
[JsonSerializable(typeof(SessionWorkspaceCreateFileRequest))]
[JsonSerializable(typeof(SessionWorkspaceCreateFileResult))]
[JsonSerializable(typeof(SessionWorkspaceListFilesRequest))]
[JsonSerializable(typeof(SessionWorkspaceListFilesResult))]
[JsonSerializable(typeof(SessionWorkspaceReadFileRequest))]
[JsonSerializable(typeof(SessionWorkspaceReadFileResult))]
+[JsonSerializable(typeof(Skill))]
[JsonSerializable(typeof(Tool))]
[JsonSerializable(typeof(ToolsListRequest))]
[JsonSerializable(typeof(ToolsListResult))]
diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs
index 40d2daf22..2821052d0 100644
--- a/dotnet/src/Generated/SessionEvents.cs
+++ b/dotnet/src/Generated/SessionEvents.cs
@@ -29,7 +29,9 @@ namespace GitHub.Copilot.SDK;
[JsonDerivedType(typeof(AssistantTurnStartEvent), "assistant.turn_start")]
[JsonDerivedType(typeof(AssistantUsageEvent), "assistant.usage")]
[JsonDerivedType(typeof(CommandCompletedEvent), "command.completed")]
+[JsonDerivedType(typeof(CommandExecuteEvent), "command.execute")]
[JsonDerivedType(typeof(CommandQueuedEvent), "command.queued")]
+[JsonDerivedType(typeof(CommandsChangedEvent), "commands.changed")]
[JsonDerivedType(typeof(ElicitationCompletedEvent), "elicitation.completed")]
[JsonDerivedType(typeof(ElicitationRequestedEvent), "elicitation.requested")]
[JsonDerivedType(typeof(ExitPlanModeCompletedEvent), "exit_plan_mode.completed")]
@@ -38,6 +40,8 @@ namespace GitHub.Copilot.SDK;
[JsonDerivedType(typeof(ExternalToolRequestedEvent), "external_tool.requested")]
[JsonDerivedType(typeof(HookEndEvent), "hook.end")]
[JsonDerivedType(typeof(HookStartEvent), "hook.start")]
+[JsonDerivedType(typeof(McpOauthCompletedEvent), "mcp.oauth_completed")]
+[JsonDerivedType(typeof(McpOauthRequiredEvent), "mcp.oauth_required")]
[JsonDerivedType(typeof(PendingMessagesModifiedEvent), "pending_messages.modified")]
[JsonDerivedType(typeof(PermissionCompletedEvent), "permission.completed")]
[JsonDerivedType(typeof(PermissionRequestedEvent), "permission.requested")]
@@ -46,14 +50,18 @@ namespace GitHub.Copilot.SDK;
[JsonDerivedType(typeof(SessionCompactionStartEvent), "session.compaction_start")]
[JsonDerivedType(typeof(SessionContextChangedEvent), "session.context_changed")]
[JsonDerivedType(typeof(SessionErrorEvent), "session.error")]
+[JsonDerivedType(typeof(SessionExtensionsLoadedEvent), "session.extensions_loaded")]
[JsonDerivedType(typeof(SessionHandoffEvent), "session.handoff")]
[JsonDerivedType(typeof(SessionIdleEvent), "session.idle")]
[JsonDerivedType(typeof(SessionInfoEvent), "session.info")]
+[JsonDerivedType(typeof(SessionMcpServerStatusChangedEvent), "session.mcp_server_status_changed")]
+[JsonDerivedType(typeof(SessionMcpServersLoadedEvent), "session.mcp_servers_loaded")]
[JsonDerivedType(typeof(SessionModeChangedEvent), "session.mode_changed")]
[JsonDerivedType(typeof(SessionModelChangeEvent), "session.model_change")]
[JsonDerivedType(typeof(SessionPlanChangedEvent), "session.plan_changed")]
[JsonDerivedType(typeof(SessionResumeEvent), "session.resume")]
[JsonDerivedType(typeof(SessionShutdownEvent), "session.shutdown")]
+[JsonDerivedType(typeof(SessionSkillsLoadedEvent), "session.skills_loaded")]
[JsonDerivedType(typeof(SessionSnapshotRewindEvent), "session.snapshot_rewind")]
[JsonDerivedType(typeof(SessionStartEvent), "session.start")]
[JsonDerivedType(typeof(SessionTaskCompleteEvent), "session.task_complete")]
@@ -337,7 +345,7 @@ public partial class SessionUsageInfoEvent : SessionEvent
public required SessionUsageInfoData Data { get; set; }
}
-/// Empty payload; the event signals that LLM-powered conversation compaction has begun.
+/// Context window breakdown at the start of LLM-powered conversation compaction.
/// Represents the session.compaction_start event.
public partial class SessionCompactionStartEvent : SessionEvent
{
@@ -363,7 +371,7 @@ public partial class SessionCompactionCompleteEvent : SessionEvent
public required SessionCompactionCompleteData Data { get; set; }
}
-/// Task completion notification with optional summary from the agent.
+/// Task completion notification with summary from the agent.
/// Represents the session.task_complete event.
public partial class SessionTaskCompleteEvent : SessionEvent
{
@@ -376,8 +384,7 @@ public partial class SessionTaskCompleteEvent : SessionEvent
public required SessionTaskCompleteData Data { get; set; }
}
-/// User message content with optional attachments, source information, and interaction metadata.
-/// Represents the user.message event.
+/// Represents the user.message event.
public partial class UserMessageEvent : SessionEvent
{
///
@@ -779,7 +786,7 @@ public partial class UserInputCompletedEvent : SessionEvent
public required UserInputCompletedData Data { get; set; }
}
-/// Structured form elicitation request with JSON schema definition for form fields.
+/// Elicitation request; may be form-based (structured input) or URL-based (browser redirect).
/// Represents the elicitation.requested event.
public partial class ElicitationRequestedEvent : SessionEvent
{
@@ -805,6 +812,32 @@ public partial class ElicitationCompletedEvent : SessionEvent
public required ElicitationCompletedData Data { get; set; }
}
+/// OAuth authentication request for an MCP server.
+/// Represents the mcp.oauth_required event.
+public partial class McpOauthRequiredEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "mcp.oauth_required";
+
+ /// The mcp.oauth_required event payload.
+ [JsonPropertyName("data")]
+ public required McpOauthRequiredData Data { get; set; }
+}
+
+/// MCP OAuth request completion notification.
+/// Represents the mcp.oauth_completed event.
+public partial class McpOauthCompletedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "mcp.oauth_completed";
+
+ /// The mcp.oauth_completed event payload.
+ [JsonPropertyName("data")]
+ public required McpOauthCompletedData Data { get; set; }
+}
+
/// External tool invocation request for client-side tool execution.
/// Represents the external_tool.requested event.
public partial class ExternalToolRequestedEvent : SessionEvent
@@ -844,6 +877,19 @@ public partial class CommandQueuedEvent : SessionEvent
public required CommandQueuedData Data { get; set; }
}
+/// Registered command dispatch request routed to the owning client.
+/// Represents the command.execute event.
+public partial class CommandExecuteEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "command.execute";
+
+ /// The command.execute event payload.
+ [JsonPropertyName("data")]
+ public required CommandExecuteData Data { get; set; }
+}
+
/// Queued command completion notification signaling UI dismissal.
/// Represents the command.completed event.
public partial class CommandCompletedEvent : SessionEvent
@@ -857,6 +903,19 @@ public partial class CommandCompletedEvent : SessionEvent
public required CommandCompletedData Data { get; set; }
}
+/// SDK command registration change notification.
+/// Represents the commands.changed event.
+public partial class CommandsChangedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "commands.changed";
+
+ /// The commands.changed event payload.
+ [JsonPropertyName("data")]
+ public required CommandsChangedData Data { get; set; }
+}
+
/// Plan approval request with plan content and available user actions.
/// Represents the exit_plan_mode.requested event.
public partial class ExitPlanModeRequestedEvent : SessionEvent
@@ -907,6 +966,54 @@ public partial class SessionBackgroundTasksChangedEvent : SessionEvent
public required SessionBackgroundTasksChangedData Data { get; set; }
}
+/// Represents the session.skills_loaded event.
+public partial class SessionSkillsLoadedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "session.skills_loaded";
+
+ /// The session.skills_loaded event payload.
+ [JsonPropertyName("data")]
+ public required SessionSkillsLoadedData Data { get; set; }
+}
+
+/// Represents the session.mcp_servers_loaded event.
+public partial class SessionMcpServersLoadedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "session.mcp_servers_loaded";
+
+ /// The session.mcp_servers_loaded event payload.
+ [JsonPropertyName("data")]
+ public required SessionMcpServersLoadedData Data { get; set; }
+}
+
+/// Represents the session.mcp_server_status_changed event.
+public partial class SessionMcpServerStatusChangedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "session.mcp_server_status_changed";
+
+ /// The session.mcp_server_status_changed event payload.
+ [JsonPropertyName("data")]
+ public required SessionMcpServerStatusChangedData Data { get; set; }
+}
+
+/// Represents the session.extensions_loaded event.
+public partial class SessionExtensionsLoadedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "session.extensions_loaded";
+
+ /// The session.extensions_loaded event payload.
+ [JsonPropertyName("data")]
+ public required SessionExtensionsLoadedData Data { get; set; }
+}
+
/// Session initialization metadata including context and configuration.
public partial class SessionStartData
{
@@ -1008,6 +1115,11 @@ public partial class SessionErrorData
[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.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("url")]
+ public string? Url { get; set; }
}
/// Payload indicating the agent is idle; includes any background tasks still in flight.
@@ -1037,6 +1149,11 @@ public partial class SessionInfoData
/// Human-readable informational message for display in the timeline.
[JsonPropertyName("message")]
public required string Message { get; set; }
+
+ /// Optional URL associated with this message that the user can open in a browser.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("url")]
+ public string? Url { get; set; }
}
/// Warning message for timeline display with categorization.
@@ -1049,6 +1166,11 @@ public partial class SessionWarningData
/// Human-readable warning message for display in the timeline.
[JsonPropertyName("message")]
public required string Message { get; set; }
+
+ /// Optional URL associated with this warning that the user can open in a browser.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("url")]
+ public string? Url { get; set; }
}
/// Model change details including previous and new model identifiers.
@@ -1222,6 +1344,26 @@ public partial class SessionShutdownData
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("currentModel")]
public string? CurrentModel { get; set; }
+
+ /// Total tokens in context window at shutdown.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("currentTokens")]
+ public double? CurrentTokens { 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; }
}
/// Updated working directory and git context after the change.
@@ -1276,11 +1418,45 @@ public partial class SessionUsageInfoData
/// Current number of messages in the conversation.
[JsonPropertyName("messagesLength")]
public required double MessagesLength { get; set; }
+
+ /// Token count from system message(s).
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [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; }
+
+ /// 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; }
}
-/// Empty payload; the event signals that LLM-powered conversation compaction has begun.
+/// 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 tool definitions at compaction start.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("toolDefinitionsTokens")]
+ public double? ToolDefinitionsTokens { get; set; }
}
/// Conversation compaction results including success status, metrics, and optional error details.
@@ -1344,18 +1520,38 @@ public partial class SessionCompactionCompleteData
[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.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("conversationTokens")]
+ public double? ConversationTokens { get; set; }
+
+ /// Token count from tool definitions after compaction.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("toolDefinitionsTokens")]
+ public double? ToolDefinitionsTokens { get; set; }
}
-/// Task completion notification with optional summary from the agent.
+/// Task completion notification with summary from the agent.
public partial class SessionTaskCompleteData
{
- /// Optional summary of the completed task, provided by the agent.
+ /// 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; }
}
-/// User message content with optional attachments, source information, and interaction metadata.
+/// Event payload for .
public partial class UserMessageData
{
/// The user's message text as displayed in the timeline.
@@ -1372,10 +1568,10 @@ public partial class UserMessageData
[JsonPropertyName("attachments")]
public UserMessageDataAttachmentsItem[]? Attachments { get; set; }
- /// Origin of this message, used for timeline filtering and telemetry (e.g., "user", "autopilot", "skill", or "command").
+ /// Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user).
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("source")]
- public UserMessageDataSource? Source { get; set; }
+ public string? Source { get; set; }
/// The agent mode that was active when this message was sent.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
@@ -1953,6 +2149,11 @@ public partial class UserInputRequestedData
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("allowFreeform")]
public bool? AllowFreeform { get; set; }
+
+ /// The LLM-assigned tool call ID that triggered this request; used by remote UIs to correlate responses.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("toolCallId")]
+ public string? ToolCallId { get; set; }
}
/// User input request completion notification signaling UI dismissal.
@@ -1963,25 +2164,41 @@ public partial class UserInputCompletedData
public required string RequestId { get; set; }
}
-/// Structured form elicitation request with JSON schema definition for form fields.
+/// 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")]
+ public string? ElicitationSource { get; set; }
+
/// Message describing what information is needed from the user.
[JsonPropertyName("message")]
public required string Message { get; set; }
- /// Elicitation mode; currently only "form" is supported. Defaults to "form" when absent.
+ /// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("mode")]
- public string? Mode { get; set; }
+ public ElicitationRequestedDataMode? Mode { get; set; }
- /// JSON Schema describing the form fields to present to the user.
+ /// JSON Schema describing the form fields to present to the user (form mode only).
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("requestedSchema")]
- public required ElicitationRequestedDataRequestedSchema RequestedSchema { get; set; }
+ public ElicitationRequestedDataRequestedSchema? RequestedSchema { get; set; }
+
+ /// URL to open in the user's browser (url mode only).
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("url")]
+ public string? Url { get; set; }
}
/// Elicitation request completion notification signaling UI dismissal.
@@ -1992,6 +2209,35 @@ public partial class ElicitationCompletedData
public required string RequestId { get; set; }
}
+/// OAuth authentication request for an MCP server.
+public partial class McpOauthRequiredData
+{
+ /// Unique identifier for this OAuth request; used to respond via session.respondToMcpOAuth().
+ [JsonPropertyName("requestId")]
+ public required string RequestId { get; set; }
+
+ /// Display name of the MCP server that requires OAuth.
+ [JsonPropertyName("serverName")]
+ public required string ServerName { get; set; }
+
+ /// URL of the MCP server that requires OAuth.
+ [JsonPropertyName("serverUrl")]
+ public required string ServerUrl { get; set; }
+
+ /// Static OAuth client configuration, if the server specifies one.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("staticClientConfig")]
+ public McpOauthRequiredDataStaticClientConfig? StaticClientConfig { get; set; }
+}
+
+/// MCP OAuth request completion notification.
+public partial class McpOauthCompletedData
+{
+ /// Request ID of the resolved OAuth request.
+ [JsonPropertyName("requestId")]
+ public required string RequestId { get; set; }
+}
+
/// External tool invocation request for client-side tool execution.
public partial class ExternalToolRequestedData
{
@@ -2047,6 +2293,26 @@ public partial class CommandQueuedData
public required string Command { 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; }
+
+ /// The full command text (e.g., /deploy production).
+ [JsonPropertyName("command")]
+ public required string Command { get; set; }
+
+ /// Command name without leading /.
+ [JsonPropertyName("commandName")]
+ public required string CommandName { get; set; }
+
+ /// Raw argument string after the command name.
+ [JsonPropertyName("args")]
+ public required string Args { get; set; }
+}
+
/// Queued command completion notification signaling UI dismissal.
public partial class CommandCompletedData
{
@@ -2055,6 +2321,14 @@ public partial class CommandCompletedData
public required string RequestId { get; set; }
}
+/// SDK command registration change notification.
+public partial class CommandsChangedData
+{
+ /// Current list of registered SDK commands.
+ [JsonPropertyName("commands")]
+ public required CommandsChangedDataCommandsItem[] Commands { get; set; }
+}
+
/// Plan approval request with plan content and available user actions.
public partial class ExitPlanModeRequestedData
{
@@ -2100,6 +2374,42 @@ public partial class SessionBackgroundTasksChangedData
{
}
+/// Event payload for .
+public partial class SessionSkillsLoadedData
+{
+ /// Array of resolved skill metadata.
+ [JsonPropertyName("skills")]
+ public required SessionSkillsLoadedDataSkillsItem[] Skills { get; set; }
+}
+
+/// Event payload for .
+public partial class SessionMcpServersLoadedData
+{
+ /// Array of MCP server status summaries.
+ [JsonPropertyName("servers")]
+ public required SessionMcpServersLoadedDataServersItem[] Servers { get; set; }
+}
+
+/// Event payload for .
+public partial class SessionMcpServerStatusChangedData
+{
+ /// Name of the MCP server whose status changed.
+ [JsonPropertyName("serverName")]
+ public required string ServerName { get; set; }
+
+ /// New connection status: connected, failed, pending, disabled, or not_configured.
+ [JsonPropertyName("status")]
+ public required SessionMcpServersLoadedDataServersItemStatus Status { get; set; }
+}
+
+/// Event payload for .
+public partial class SessionExtensionsLoadedData
+{
+ /// Array of discovered extensions and their status.
+ [JsonPropertyName("extensions")]
+ public required SessionExtensionsLoadedDataExtensionsItem[] Extensions { get; set; }
+}
+
/// Working directory and git context at session start.
/// Nested data type for SessionStartDataContext.
public partial class SessionStartDataContext
@@ -2787,6 +3097,27 @@ public partial class SystemNotificationDataKindAgentCompleted : SystemNotificati
public string? Prompt { get; set; }
}
+/// The agent_idle variant of .
+public partial class SystemNotificationDataKindAgentIdle : SystemNotificationDataKind
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "agent_idle";
+
+ /// Unique identifier of the background agent.
+ [JsonPropertyName("agentId")]
+ public required string AgentId { get; set; }
+
+ /// Type of the agent (e.g., explore, task, general-purpose).
+ [JsonPropertyName("agentType")]
+ public required string AgentType { get; set; }
+
+ /// Human-readable description of the agent task.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("description")]
+ public string? Description { get; set; }
+}
+
/// The shell_completed variant of .
public partial class SystemNotificationDataKindShellCompleted : SystemNotificationDataKind
{
@@ -2832,6 +3163,7 @@ public partial class SystemNotificationDataKindShellDetachedCompleted : SystemNo
TypeDiscriminatorPropertyName = "type",
UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)]
[JsonDerivedType(typeof(SystemNotificationDataKindAgentCompleted), "agent_completed")]
+[JsonDerivedType(typeof(SystemNotificationDataKindAgentIdle), "agent_idle")]
[JsonDerivedType(typeof(SystemNotificationDataKindShellCompleted), "shell_completed")]
[JsonDerivedType(typeof(SystemNotificationDataKindShellDetachedCompleted), "shell_detached_completed")]
public partial class SystemNotificationDataKind
@@ -3130,7 +3462,7 @@ public partial class PermissionCompletedDataResult
public required PermissionCompletedDataResultKind Kind { get; set; }
}
-/// JSON Schema describing the form fields to present to the user.
+/// JSON Schema describing the form fields to present to the user (form mode only).
/// Nested data type for ElicitationRequestedDataRequestedSchema.
public partial class ElicitationRequestedDataRequestedSchema
{
@@ -3148,6 +3480,104 @@ public partial class ElicitationRequestedDataRequestedSchema
public string[]? Required { get; set; }
}
+/// Static OAuth client configuration, if the server specifies one.
+/// Nested data type for McpOauthRequiredDataStaticClientConfig.
+public partial class McpOauthRequiredDataStaticClientConfig
+{
+ /// OAuth client ID for the server.
+ [JsonPropertyName("clientId")]
+ public required string ClientId { get; set; }
+
+ /// Whether this is a public OAuth client.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("publicClient")]
+ public bool? PublicClient { get; set; }
+}
+
+/// Nested data type for CommandsChangedDataCommandsItem.
+public partial class CommandsChangedDataCommandsItem
+{
+ /// 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; }
+}
+
+/// Nested data type for SessionSkillsLoadedDataSkillsItem.
+public partial class SessionSkillsLoadedDataSkillsItem
+{
+ /// 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; }
+
+ /// Absolute path to the skill file, if available.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("path")]
+ public string? Path { get; set; }
+}
+
+/// Nested data type for SessionMcpServersLoadedDataServersItem.
+public partial class SessionMcpServersLoadedDataServersItem
+{
+ /// Server name (config key).
+ [JsonPropertyName("name")]
+ public required string Name { get; set; }
+
+ /// Connection status: connected, failed, pending, disabled, or not_configured.
+ [JsonPropertyName("status")]
+ public required SessionMcpServersLoadedDataServersItemStatus 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; }
+}
+
+/// Nested data type for SessionExtensionsLoadedDataExtensionsItem.
+public partial class SessionExtensionsLoadedDataExtensionsItem
+{
+ /// Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper').
+ [JsonPropertyName("id")]
+ public required string Id { get; set; }
+
+ /// Extension name (directory name).
+ [JsonPropertyName("name")]
+ public required string Name { get; set; }
+
+ /// Discovery source.
+ [JsonPropertyName("source")]
+ public required SessionExtensionsLoadedDataExtensionsItemSource Source { get; set; }
+
+ /// Current status: running, disabled, failed, or starting.
+ [JsonPropertyName("status")]
+ public required SessionExtensionsLoadedDataExtensionsItemStatus Status { get; set; }
+}
+
/// Hosting platform type of the repository (github or ado).
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum SessionStartDataContextHostType
@@ -3226,42 +3656,6 @@ public enum UserMessageDataAttachmentsItemGithubReferenceReferenceType
Discussion,
}
-/// Origin of this message, used for timeline filtering and telemetry (e.g., "user", "autopilot", "skill", or "command").
-[JsonConverter(typeof(JsonStringEnumConverter))]
-public enum UserMessageDataSource
-{
- /// The user variant.
- [JsonStringEnumMemberName("user")]
- User,
- /// The autopilot variant.
- [JsonStringEnumMemberName("autopilot")]
- Autopilot,
- /// The skill variant.
- [JsonStringEnumMemberName("skill")]
- Skill,
- /// The system variant.
- [JsonStringEnumMemberName("system")]
- System,
- /// The command variant.
- [JsonStringEnumMemberName("command")]
- Command,
- /// The immediate-prompt variant.
- [JsonStringEnumMemberName("immediate-prompt")]
- ImmediatePrompt,
- /// The jit-instruction variant.
- [JsonStringEnumMemberName("jit-instruction")]
- JitInstruction,
- /// The snippy-blocking variant.
- [JsonStringEnumMemberName("snippy-blocking")]
- SnippyBlocking,
- /// The thinking-exhausted-continuation variant.
- [JsonStringEnumMemberName("thinking-exhausted-continuation")]
- ThinkingExhaustedContinuation,
- /// The other variant.
- [JsonStringEnumMemberName("other")]
- Other,
-}
-
/// The agent mode that was active when this message was sent.
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum UserMessageDataAgentMode
@@ -3349,6 +3743,69 @@ public enum PermissionCompletedDataResultKind
DeniedByContentExclusionPolicy,
}
+/// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent.
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum ElicitationRequestedDataMode
+{
+ /// The form variant.
+ [JsonStringEnumMemberName("form")]
+ Form,
+ /// The url variant.
+ [JsonStringEnumMemberName("url")]
+ Url,
+}
+
+/// Connection status: connected, failed, pending, disabled, or not_configured.
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum SessionMcpServersLoadedDataServersItemStatus
+{
+ /// The connected variant.
+ [JsonStringEnumMemberName("connected")]
+ Connected,
+ /// The failed variant.
+ [JsonStringEnumMemberName("failed")]
+ Failed,
+ /// The pending variant.
+ [JsonStringEnumMemberName("pending")]
+ Pending,
+ /// The disabled variant.
+ [JsonStringEnumMemberName("disabled")]
+ Disabled,
+ /// The not_configured variant.
+ [JsonStringEnumMemberName("not_configured")]
+ NotConfigured,
+}
+
+/// Discovery source.
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum SessionExtensionsLoadedDataExtensionsItemSource
+{
+ /// The project variant.
+ [JsonStringEnumMemberName("project")]
+ Project,
+ /// The user variant.
+ [JsonStringEnumMemberName("user")]
+ User,
+}
+
+/// Current status: running, disabled, failed, or starting.
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum SessionExtensionsLoadedDataExtensionsItemStatus
+{
+ /// The running variant.
+ [JsonStringEnumMemberName("running")]
+ Running,
+ /// The disabled variant.
+ [JsonStringEnumMemberName("disabled")]
+ Disabled,
+ /// The failed variant.
+ [JsonStringEnumMemberName("failed")]
+ Failed,
+ /// The starting variant.
+ [JsonStringEnumMemberName("starting")]
+ Starting,
+}
+
[JsonSourceGenerationOptions(
JsonSerializerDefaults.Web,
AllowOutOfOrderMetadataProperties = true,
@@ -3379,8 +3836,13 @@ public enum PermissionCompletedDataResultKind
[JsonSerializable(typeof(AssistantUsageEvent))]
[JsonSerializable(typeof(CommandCompletedData))]
[JsonSerializable(typeof(CommandCompletedEvent))]
+[JsonSerializable(typeof(CommandExecuteData))]
+[JsonSerializable(typeof(CommandExecuteEvent))]
[JsonSerializable(typeof(CommandQueuedData))]
[JsonSerializable(typeof(CommandQueuedEvent))]
+[JsonSerializable(typeof(CommandsChangedData))]
+[JsonSerializable(typeof(CommandsChangedDataCommandsItem))]
+[JsonSerializable(typeof(CommandsChangedEvent))]
[JsonSerializable(typeof(ElicitationCompletedData))]
[JsonSerializable(typeof(ElicitationCompletedEvent))]
[JsonSerializable(typeof(ElicitationRequestedData))]
@@ -3399,6 +3861,11 @@ public enum PermissionCompletedDataResultKind
[JsonSerializable(typeof(HookEndEvent))]
[JsonSerializable(typeof(HookStartData))]
[JsonSerializable(typeof(HookStartEvent))]
+[JsonSerializable(typeof(McpOauthCompletedData))]
+[JsonSerializable(typeof(McpOauthCompletedEvent))]
+[JsonSerializable(typeof(McpOauthRequiredData))]
+[JsonSerializable(typeof(McpOauthRequiredDataStaticClientConfig))]
+[JsonSerializable(typeof(McpOauthRequiredEvent))]
[JsonSerializable(typeof(PendingMessagesModifiedData))]
[JsonSerializable(typeof(PendingMessagesModifiedEvent))]
[JsonSerializable(typeof(PermissionCompletedData))]
@@ -3429,6 +3896,9 @@ public enum PermissionCompletedDataResultKind
[JsonSerializable(typeof(SessionErrorData))]
[JsonSerializable(typeof(SessionErrorEvent))]
[JsonSerializable(typeof(SessionEvent))]
+[JsonSerializable(typeof(SessionExtensionsLoadedData))]
+[JsonSerializable(typeof(SessionExtensionsLoadedDataExtensionsItem))]
+[JsonSerializable(typeof(SessionExtensionsLoadedEvent))]
[JsonSerializable(typeof(SessionHandoffData))]
[JsonSerializable(typeof(SessionHandoffDataRepository))]
[JsonSerializable(typeof(SessionHandoffEvent))]
@@ -3439,6 +3909,11 @@ public enum PermissionCompletedDataResultKind
[JsonSerializable(typeof(SessionIdleEvent))]
[JsonSerializable(typeof(SessionInfoData))]
[JsonSerializable(typeof(SessionInfoEvent))]
+[JsonSerializable(typeof(SessionMcpServerStatusChangedData))]
+[JsonSerializable(typeof(SessionMcpServerStatusChangedEvent))]
+[JsonSerializable(typeof(SessionMcpServersLoadedData))]
+[JsonSerializable(typeof(SessionMcpServersLoadedDataServersItem))]
+[JsonSerializable(typeof(SessionMcpServersLoadedEvent))]
[JsonSerializable(typeof(SessionModeChangedData))]
[JsonSerializable(typeof(SessionModeChangedEvent))]
[JsonSerializable(typeof(SessionModelChangeData))]
@@ -3451,6 +3926,9 @@ public enum PermissionCompletedDataResultKind
[JsonSerializable(typeof(SessionShutdownData))]
[JsonSerializable(typeof(SessionShutdownDataCodeChanges))]
[JsonSerializable(typeof(SessionShutdownEvent))]
+[JsonSerializable(typeof(SessionSkillsLoadedData))]
+[JsonSerializable(typeof(SessionSkillsLoadedDataSkillsItem))]
+[JsonSerializable(typeof(SessionSkillsLoadedEvent))]
[JsonSerializable(typeof(SessionSnapshotRewindData))]
[JsonSerializable(typeof(SessionSnapshotRewindEvent))]
[JsonSerializable(typeof(SessionStartData))]
@@ -3488,6 +3966,7 @@ public enum PermissionCompletedDataResultKind
[JsonSerializable(typeof(SystemNotificationData))]
[JsonSerializable(typeof(SystemNotificationDataKind))]
[JsonSerializable(typeof(SystemNotificationDataKindAgentCompleted))]
+[JsonSerializable(typeof(SystemNotificationDataKindAgentIdle))]
[JsonSerializable(typeof(SystemNotificationDataKindShellCompleted))]
[JsonSerializable(typeof(SystemNotificationDataKindShellDetachedCompleted))]
[JsonSerializable(typeof(SystemNotificationEvent))]
diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs
index 606c0b052..0014ec7f0 100644
--- a/dotnet/src/Session.cs
+++ b/dotnet/src/Session.cs
@@ -749,6 +749,7 @@ public Task SetModelAsync(string model, CancellationToken cancellationToken = de
/// The message to log.
/// Log level (default: info).
/// When true, the message is not persisted to disk.
+ /// Optional URL to associate with the log entry.
/// Optional cancellation token.
///
///
@@ -758,9 +759,9 @@ public Task SetModelAsync(string model, CancellationToken cancellationToken = de
/// await session.LogAsync("Temporary status", ephemeral: true);
///
///
- public async Task LogAsync(string message, SessionLogRequestLevel? level = null, bool? ephemeral = null, CancellationToken cancellationToken = default)
+ public async Task LogAsync(string message, SessionLogRequestLevel? level = null, bool? ephemeral = null, string? url = null, CancellationToken cancellationToken = default)
{
- await Rpc.LogAsync(message, level, ephemeral, cancellationToken);
+ await Rpc.LogAsync(message, level, ephemeral, url, cancellationToken);
}
///
diff --git a/go/README.md b/go/README.md
index 1d0665130..8cbb382c3 100644
--- a/go/README.md
+++ b/go/README.md
@@ -201,7 +201,7 @@ _, err = session.Send(context.Background(), copilot.MessageOptions{
Prompt: "What's in this image?",
Attachments: []copilot.Attachment{
{
- Type: copilot.Blob,
+ Type: copilot.AttachmentTypeBlob,
Data: &base64ImageData,
MIMEType: &mimeType,
},
diff --git a/go/generated_session_events.go b/go/generated_session_events.go
index 55eea011e..fbdb1597f 100644
--- a/go/generated_session_events.go
+++ b/go/generated_session_events.go
@@ -61,15 +61,12 @@ type SessionEvent struct {
//
// Current context window usage statistics including token and message counts
//
- // Empty payload; the event signals that LLM-powered conversation compaction has begun
+ // Context window breakdown at the start of LLM-powered conversation compaction
//
// Conversation compaction results including success status, metrics, and optional error
// details
//
- // Task completion notification with optional summary from the agent
- //
- // User message content with optional attachments, source information, and interaction
- // metadata
+ // Task completion notification with summary from the agent
//
// Empty payload; the event signals that the pending message queue has changed
//
@@ -135,18 +132,27 @@ type SessionEvent struct {
//
// User input request completion notification signaling UI dismissal
//
- // Structured form elicitation request with JSON schema definition for form fields
+ // Elicitation request; may be form-based (structured input) or URL-based (browser
+ // redirect)
//
// Elicitation request completion notification signaling UI dismissal
//
+ // OAuth authentication request for an MCP server
+ //
+ // MCP OAuth request completion notification
+ //
// External tool invocation request for client-side tool execution
//
// External tool completion notification signaling UI dismissal
//
// Queued slash command dispatch request for client execution
//
+ // Registered command dispatch request routed to the owning client
+ //
// Queued command completion notification signaling UI dismissal
//
+ // SDK command registration change notification
+ //
// Plan approval request with plan content and available user actions
//
// Plan mode exit completion notification signaling UI dismissal
@@ -198,15 +204,12 @@ type SessionEvent struct {
//
// # Current context window usage statistics including token and message counts
//
-// Empty payload; the event signals that LLM-powered conversation compaction has begun
+// # Context window breakdown at the start of LLM-powered conversation compaction
//
// Conversation compaction results including success status, metrics, and optional error
// details
//
-// # Task completion notification with optional summary from the agent
-//
-// User message content with optional attachments, source information, and interaction
-// metadata
+// # Task completion notification with summary from the agent
//
// Empty payload; the event signals that the pending message queue has changed
//
@@ -272,18 +275,27 @@ type SessionEvent struct {
//
// # User input request completion notification signaling UI dismissal
//
-// # Structured form elicitation request with JSON schema definition for form fields
+// Elicitation request; may be form-based (structured input) or URL-based (browser
+// redirect)
//
// # Elicitation request completion notification signaling UI dismissal
//
+// # OAuth authentication request for an MCP server
+//
+// # MCP OAuth request completion notification
+//
// # External tool invocation request for client-side tool execution
//
// # External tool completion notification signaling UI dismissal
//
// # Queued slash command dispatch request for client execution
//
+// # Registered command dispatch request routed to the owning client
+//
// # Queued command completion notification signaling UI dismissal
//
+// # SDK command registration change notification
+//
// # Plan approval request with plan content and available user actions
//
// Plan mode exit completion notification signaling UI dismissal
@@ -343,6 +355,14 @@ type Data struct {
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
+ //
+ // Optional URL associated with this message that the user can open in a browser
+ //
+ // Optional URL associated with this warning that the user can open in a browser
+ //
+ // URL to open in the user's browser (url mode only)
+ URL *string `json:"url,omitempty"`
// Background tasks still running when the agent became idle
BackgroundTasks *BackgroundTasks `json:"backgroundTasks,omitempty"`
// The new display title for the session
@@ -383,7 +403,7 @@ type Data struct {
SourceType *SourceType `json:"sourceType,omitempty"`
// Summary of the work done in the source session
//
- // Optional summary of the completed task, provided by the agent
+ // Summary of the completed task, provided by the agent
//
// Summary of the plan that was created
Summary *string `json:"summary,omitempty"`
@@ -409,8 +429,20 @@ type Data struct {
UpToEventID *string `json:"upToEventId,omitempty"`
// Aggregate code change metrics for the session
CodeChanges *CodeChanges `json:"codeChanges,omitempty"`
+ // Non-system message token count at shutdown
+ //
+ // Token count from non-system messages (user, assistant, tool)
+ //
+ // Token count from non-system messages (user, assistant, tool) at compaction start
+ //
+ // Token count from non-system messages (user, assistant, tool) after compaction
+ 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
+ //
+ // Current number of tokens in the context window
+ CurrentTokens *float64 `json:"currentTokens,omitempty"`
// Error description when shutdownType is "error"
ErrorReason *string `json:"errorReason,omitempty"`
// Per-model usage breakdown, keyed by model identifier
@@ -419,6 +451,22 @@ type Data struct {
SessionStartTime *float64 `json:"sessionStartTime,omitempty"`
// Whether the session ended normally ("routine") or due to a crash/fatal error ("error")
ShutdownType *ShutdownType `json:"shutdownType,omitempty"`
+ // System message token count at shutdown
+ //
+ // Token count from system message(s)
+ //
+ // Token count from system message(s) at compaction start
+ //
+ // Token count from system message(s) after compaction
+ SystemTokens *float64 `json:"systemTokens,omitempty"`
+ // Tool definitions token count at shutdown
+ //
+ // Token count from tool definitions
+ //
+ // Token count from tool definitions at compaction start
+ //
+ // Token count from tool definitions after compaction
+ ToolDefinitionsTokens *float64 `json:"toolDefinitionsTokens,omitempty"`
// Cumulative time spent in API calls during the session, in milliseconds
TotalAPIDurationMS *float64 `json:"totalApiDurationMs,omitempty"`
// Total number of premium API requests used during the session
@@ -435,8 +483,8 @@ type Data struct {
HeadCommit *string `json:"headCommit,omitempty"`
// Hosting platform type of the repository (github or ado)
HostType *HostType `json:"hostType,omitempty"`
- // Current number of tokens in the context window
- CurrentTokens *float64 `json:"currentTokens,omitempty"`
+ // 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,omitempty"`
// Checkpoint snapshot number created for recovery
@@ -481,6 +529,11 @@ type Data struct {
// Request ID of the resolved elicitation request; clients should dismiss any UI for this
// request
//
+ // Unique identifier for this OAuth request; used to respond via
+ // session.respondToMcpOAuth()
+ //
+ // Request ID of the resolved OAuth request
+ //
// Unique identifier for this request; used to respond via session.respondToExternalTool()
//
// Request ID of the resolved external tool request; clients should dismiss any UI for this
@@ -488,6 +541,8 @@ type Data struct {
//
// Unique identifier for this request; used to respond via session.respondToQueuedCommand()
//
+ // Unique identifier; used to respond via session.commands.handlePendingCommand()
+ //
// Request ID of the resolved command request; clients should dismiss any UI for this
// request
//
@@ -498,6 +553,8 @@ type Data struct {
RequestID *string `json:"requestId,omitempty"`
// Whether compaction completed successfully
//
+ // Whether the tool call succeeded. False when validation failed (e.g., invalid arguments)
+ //
// Whether the tool execution completed successfully
//
// Whether the hook completed successfully
@@ -530,9 +587,9 @@ type Data struct {
//
// CAPI interaction ID for correlating this tool execution with upstream telemetry
InteractionID *string `json:"interactionId,omitempty"`
- // Origin of this message, used for timeline filtering and telemetry (e.g., "user",
- // "autopilot", "skill", or "command")
- Source *Source `json:"source,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"`
// Transformed version of the message sent to the model, with XML wrapping, timestamps, and
// other augmentations for prompt caching
TransformedContent *string `json:"transformedContent,omitempty"`
@@ -618,6 +675,12 @@ type Data struct {
//
// Tool call ID of the parent tool invocation that spawned this sub-agent
//
+ // The LLM-assigned tool call ID that triggered this request; used by remote UIs to
+ // correlate responses
+ //
+ // Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id
+ // for remote UIs
+ //
// Tool call ID assigned to this external tool invocation
ToolCallID *string `json:"toolCallId,omitempty"`
// Name of the tool the user wants to invoke
@@ -690,22 +753,49 @@ type Data struct {
Choices []string `json:"choices,omitempty"`
// The question or prompt to present to the user
Question *string `json:"question,omitempty"`
- // Elicitation mode; currently only "form" is supported. Defaults to "form" when absent.
+ // The source that initiated the request (MCP server name, or absent for agent-initiated)
+ ElicitationSource *string `json:"elicitationSource,omitempty"`
+ // Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to
+ // "form" when absent.
Mode *Mode `json:"mode,omitempty"`
- // JSON Schema describing the form fields to present to the user
+ // JSON Schema describing the form fields to present to the user (form mode only)
RequestedSchema *RequestedSchema `json:"requestedSchema,omitempty"`
+ // Display name of the MCP server that requires OAuth
+ //
+ // Name of the MCP server whose status changed
+ ServerName *string `json:"serverName,omitempty"`
+ // URL of the MCP server that requires OAuth
+ ServerURL *string `json:"serverUrl,omitempty"`
+ // Static OAuth client configuration, if the server specifies one
+ StaticClientConfig *StaticClientConfig `json:"staticClientConfig,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"`
// The slash command text to be executed (e.g., /help, /clear)
+ //
+ // The full command text (e.g., /deploy production)
Command *string `json:"command,omitempty"`
+ // Raw argument string after the command name
+ Args *string `json:"args,omitempty"`
+ // Command name without leading /
+ CommandName *string `json:"commandName,omitempty"`
+ // Current list of registered SDK commands
+ Commands []DataCommand `json:"commands,omitempty"`
// Available actions the user can take (e.g., approve, edit, reject)
Actions []string `json:"actions,omitempty"`
// Full content of the plan file
PlanContent *string `json:"planContent,omitempty"`
// The recommended action for the user to take
RecommendedAction *string `json:"recommendedAction,omitempty"`
+ // Array of resolved skill metadata
+ Skills []Skill `json:"skills,omitempty"`
+ // Array of MCP server status summaries
+ Servers []Server `json:"servers,omitempty"`
+ // New connection status: connected, failed, pending, disabled, or not_configured
+ Status *ServerStatus `json:"status,omitempty"`
+ // Array of discovered extensions and their status
+ Extensions []Extension `json:"extensions,omitempty"`
}
// A user message attachment — a file, directory, code selection, blob, or GitHub reference
@@ -822,6 +912,11 @@ type CodeChanges struct {
LinesRemoved float64 `json:"linesRemoved"`
}
+type DataCommand struct {
+ Description *string `json:"description,omitempty"`
+ Name string `json:"name"`
+}
+
// Token usage breakdown for the compaction LLM call
type CompactionTokensUsed struct {
// Cached input tokens reused in the compaction LLM call
@@ -885,6 +980,17 @@ type ErrorClass struct {
Stack *string `json:"stack,omitempty"`
}
+type Extension 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 Source `json:"source"`
+ // Current status: running, disabled, failed, or starting
+ Status ExtensionStatus `json:"status"`
+}
+
// Structured metadata identifying what triggered this notification
type KindClass struct {
// Unique identifier of the background agent
@@ -898,8 +1004,8 @@ type KindClass struct {
// The full prompt given to the background agent
Prompt *string `json:"prompt,omitempty"`
// Whether the agent completed successfully or failed
- Status *Status `json:"status,omitempty"`
- Type KindType `json:"type"`
+ Status *KindStatus `json:"status,omitempty"`
+ Type KindType `json:"type"`
// Exit code of the shell command, if available
ExitCode *float64 `json:"exitCode,omitempty"`
// Unique identifier of the shell session
@@ -964,7 +1070,7 @@ type PermissionRequest struct {
// Whether the UI can offer session-wide approval for this command pattern
CanOfferSessionApproval *bool `json:"canOfferSessionApproval,omitempty"`
// Parsed command identifiers found in the command text
- Commands []CommandElement `json:"commands,omitempty"`
+ Commands []PermissionRequestCommand `json:"commands,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 >>)
@@ -1027,7 +1133,7 @@ type PermissionRequest struct {
ToolArgs interface{} `json:"toolArgs"`
}
-type CommandElement struct {
+type PermissionRequestCommand struct {
// Command identifier (e.g., executable name)
Identifier string `json:"identifier"`
// Whether this command is read-only (no side effects)
@@ -1068,7 +1174,7 @@ type RepositoryClass struct {
Owner string `json:"owner"`
}
-// JSON Schema describing the form fields to present to the user
+// JSON Schema describing the form fields to present to the user (form mode only)
type RequestedSchema struct {
// Form field definitions, keyed by field name
Properties map[string]interface{} `json:"properties"`
@@ -1172,6 +1278,40 @@ type ResourceClass struct {
Blob *string `json:"blob,omitempty"`
}
+type Server 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 *string `json:"source,omitempty"`
+ // Connection status: connected, failed, pending, disabled, or not_configured
+ Status ServerStatus `json:"status"`
+}
+
+type Skill 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"`
+ // 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"`
+}
+
+// Static OAuth client configuration, if the server specifies one
+type StaticClientConfig struct {
+ // OAuth client ID for the server
+ ClientID string `json:"clientId"`
+ // Whether this is a public OAuth client
+ PublicClient *bool `json:"publicClient,omitempty"`
+}
+
// A tool invocation request from the assistant
type ToolRequest struct {
// Arguments to pass to the tool, format depends on the tool
@@ -1193,59 +1333,81 @@ type ToolRequest struct {
type AgentMode string
const (
- AgentModeAutopilot AgentMode = "autopilot"
- AgentModeShell AgentMode = "shell"
- Interactive AgentMode = "interactive"
- Plan AgentMode = "plan"
+ AgentModeShell AgentMode = "shell"
+ AgentModeAutopilot AgentMode = "autopilot"
+ AgentModeInteractive AgentMode = "interactive"
+ AgentModePlan AgentMode = "plan"
)
// Type of GitHub reference
type ReferenceType string
const (
- Discussion ReferenceType = "discussion"
- Issue ReferenceType = "issue"
- PR ReferenceType = "pr"
+ ReferenceTypeDiscussion ReferenceType = "discussion"
+ ReferenceTypeIssue ReferenceType = "issue"
+ ReferenceTypePr ReferenceType = "pr"
)
type AttachmentType string
const (
- Blob AttachmentType = "blob"
- Directory AttachmentType = "directory"
- File AttachmentType = "file"
- GithubReference AttachmentType = "github_reference"
- Selection AttachmentType = "selection"
+ AttachmentTypeBlob AttachmentType = "blob"
+ AttachmentTypeDirectory AttachmentType = "directory"
+ AttachmentTypeFile AttachmentType = "file"
+ AttachmentTypeGithubReference AttachmentType = "github_reference"
+ AttachmentTypeSelection AttachmentType = "selection"
)
// Hosting platform type of the repository (github or ado)
type HostType string
const (
- ADO HostType = "ado"
- Github HostType = "github"
+ HostTypeAdo HostType = "ado"
+ HostTypeGithub HostType = "github"
+)
+
+// Discovery source
+type Source string
+
+const (
+ SourceProject Source = "project"
+ SourceUser Source = "user"
+)
+
+// Current status: running, disabled, failed, or starting
+type ExtensionStatus string
+
+const (
+ ExtensionStatusDisabled ExtensionStatus = "disabled"
+ ExtensionStatusFailed ExtensionStatus = "failed"
+ ExtensionStatusRunning ExtensionStatus = "running"
+ ExtensionStatusStarting ExtensionStatus = "starting"
)
// Whether the agent completed successfully or failed
-type Status string
+type KindStatus string
const (
- Completed Status = "completed"
- Failed Status = "failed"
+ KindStatusCompleted KindStatus = "completed"
+ KindStatusFailed KindStatus = "failed"
)
type KindType string
const (
- AgentCompleted KindType = "agent_completed"
- ShellCompleted KindType = "shell_completed"
- ShellDetachedCompleted KindType = "shell_detached_completed"
+ KindTypeAgentCompleted KindType = "agent_completed"
+ KindTypeAgentIdle KindType = "agent_idle"
+ KindTypeShellCompleted KindType = "shell_completed"
+ KindTypeShellDetachedCompleted KindType = "shell_detached_completed"
)
+// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to
+// "form" when absent.
type Mode string
const (
- Form Mode = "form"
+ ModeForm Mode = "form"
+ ModeURL Mode = "url"
)
// The type of operation performed on the plan file
@@ -1254,99 +1416,95 @@ const (
type Operation string
const (
- Create Operation = "create"
- Delete Operation = "delete"
- Update Operation = "update"
+ OperationCreate Operation = "create"
+ OperationDelete Operation = "delete"
+ OperationUpdate Operation = "update"
)
type PermissionRequestKind string
const (
- CustomTool PermissionRequestKind = "custom-tool"
- Hook PermissionRequestKind = "hook"
- KindShell PermissionRequestKind = "shell"
- MCP PermissionRequestKind = "mcp"
- Memory PermissionRequestKind = "memory"
- Read PermissionRequestKind = "read"
- URL PermissionRequestKind = "url"
- Write PermissionRequestKind = "write"
+ PermissionRequestKindCustomTool PermissionRequestKind = "custom-tool"
+ PermissionRequestKindHook PermissionRequestKind = "hook"
+ PermissionRequestKindShell PermissionRequestKind = "shell"
+ PermissionRequestKindURL PermissionRequestKind = "url"
+ PermissionRequestKindMcp PermissionRequestKind = "mcp"
+ PermissionRequestKindMemory PermissionRequestKind = "memory"
+ PermissionRequestKindRead PermissionRequestKind = "read"
+ PermissionRequestKindWrite PermissionRequestKind = "write"
)
type RequestedSchemaType string
const (
- Object RequestedSchemaType = "object"
+ RequestedSchemaTypeObject RequestedSchemaType = "object"
)
// Theme variant this icon is intended for
type Theme string
const (
- Dark Theme = "dark"
- Light Theme = "light"
+ ThemeDark Theme = "dark"
+ ThemeLight Theme = "light"
)
type ContentType string
const (
- Audio ContentType = "audio"
- Image ContentType = "image"
- Resource ContentType = "resource"
- ResourceLink ContentType = "resource_link"
- Terminal ContentType = "terminal"
- Text ContentType = "text"
+ ContentTypeAudio ContentType = "audio"
+ ContentTypeImage ContentType = "image"
+ ContentTypeResource ContentType = "resource"
+ ContentTypeResourceLink ContentType = "resource_link"
+ ContentTypeTerminal ContentType = "terminal"
+ ContentTypeText ContentType = "text"
)
// The outcome of the permission request
type ResultKind string
const (
- Approved ResultKind = "approved"
- DeniedByContentExclusionPolicy ResultKind = "denied-by-content-exclusion-policy"
- DeniedByRules ResultKind = "denied-by-rules"
- DeniedInteractivelyByUser ResultKind = "denied-interactively-by-user"
- DeniedNoApprovalRuleAndCouldNotRequestFromUser ResultKind = "denied-no-approval-rule-and-could-not-request-from-user"
+ ResultKindApproved ResultKind = "approved"
+ ResultKindDeniedByContentExclusionPolicy ResultKind = "denied-by-content-exclusion-policy"
+ ResultKindDeniedByRules ResultKind = "denied-by-rules"
+ ResultKindDeniedInteractivelyByUser ResultKind = "denied-interactively-by-user"
+ ResultKindDeniedNoApprovalRuleAndCouldNotRequestFromUser ResultKind = "denied-no-approval-rule-and-could-not-request-from-user"
)
// Message role: "system" for system prompts, "developer" for developer-injected instructions
type Role string
const (
- Developer Role = "developer"
- RoleSystem Role = "system"
+ RoleDeveloper Role = "developer"
+ RoleSystem Role = "system"
)
-// Whether the session ended normally ("routine") or due to a crash/fatal error ("error")
-type ShutdownType string
+// Connection status: connected, failed, pending, disabled, or not_configured
+//
+// New connection status: connected, failed, pending, disabled, or not_configured
+type ServerStatus string
const (
- Error ShutdownType = "error"
- Routine ShutdownType = "routine"
+ ServerStatusConnected ServerStatus = "connected"
+ ServerStatusDisabled ServerStatus = "disabled"
+ ServerStatusNotConfigured ServerStatus = "not_configured"
+ ServerStatusPending ServerStatus = "pending"
+ ServerStatusFailed ServerStatus = "failed"
)
-// Origin of this message, used for timeline filtering and telemetry (e.g., "user",
-// "autopilot", "skill", or "command")
-type Source string
+// Whether the session ended normally ("routine") or due to a crash/fatal error ("error")
+type ShutdownType string
const (
- Command Source = "command"
- ImmediatePrompt Source = "immediate-prompt"
- JITInstruction Source = "jit-instruction"
- Other Source = "other"
- Skill Source = "skill"
- SnippyBlocking Source = "snippy-blocking"
- SourceAutopilot Source = "autopilot"
- SourceSystem Source = "system"
- ThinkingExhaustedContinuation Source = "thinking-exhausted-continuation"
- User Source = "user"
+ ShutdownTypeError ShutdownType = "error"
+ ShutdownTypeRoutine ShutdownType = "routine"
)
// Origin type of the session being handed off
type SourceType string
const (
- Local SourceType = "local"
- Remote SourceType = "remote"
+ SourceTypeLocal SourceType = "local"
+ SourceTypeRemote SourceType = "remote"
)
// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool
@@ -1354,74 +1512,82 @@ const (
type ToolRequestType string
const (
- Custom ToolRequestType = "custom"
- Function ToolRequestType = "function"
+ ToolRequestTypeCustom ToolRequestType = "custom"
+ ToolRequestTypeFunction ToolRequestType = "function"
)
type SessionEventType string
const (
- Abort SessionEventType = "abort"
- AssistantIntent SessionEventType = "assistant.intent"
- AssistantMessage SessionEventType = "assistant.message"
- AssistantMessageDelta SessionEventType = "assistant.message_delta"
- AssistantReasoning SessionEventType = "assistant.reasoning"
- AssistantReasoningDelta SessionEventType = "assistant.reasoning_delta"
- AssistantStreamingDelta SessionEventType = "assistant.streaming_delta"
- AssistantTurnEnd SessionEventType = "assistant.turn_end"
- AssistantTurnStart SessionEventType = "assistant.turn_start"
- AssistantUsage SessionEventType = "assistant.usage"
- CommandCompleted SessionEventType = "command.completed"
- CommandQueued SessionEventType = "command.queued"
- ElicitationCompleted SessionEventType = "elicitation.completed"
- ElicitationRequested SessionEventType = "elicitation.requested"
- ExitPlanModeCompleted SessionEventType = "exit_plan_mode.completed"
- ExitPlanModeRequested SessionEventType = "exit_plan_mode.requested"
- ExternalToolCompleted SessionEventType = "external_tool.completed"
- ExternalToolRequested SessionEventType = "external_tool.requested"
- HookEnd SessionEventType = "hook.end"
- HookStart SessionEventType = "hook.start"
- PendingMessagesModified SessionEventType = "pending_messages.modified"
- PermissionCompleted SessionEventType = "permission.completed"
- PermissionRequested SessionEventType = "permission.requested"
- SessionBackgroundTasksChanged SessionEventType = "session.background_tasks_changed"
- SessionCompactionComplete SessionEventType = "session.compaction_complete"
- SessionCompactionStart SessionEventType = "session.compaction_start"
- SessionContextChanged SessionEventType = "session.context_changed"
- SessionError SessionEventType = "session.error"
- SessionHandoff SessionEventType = "session.handoff"
- SessionIdle SessionEventType = "session.idle"
- SessionInfo SessionEventType = "session.info"
- SessionModeChanged SessionEventType = "session.mode_changed"
- SessionModelChange SessionEventType = "session.model_change"
- SessionPlanChanged SessionEventType = "session.plan_changed"
- SessionResume SessionEventType = "session.resume"
- SessionShutdown SessionEventType = "session.shutdown"
- SessionSnapshotRewind SessionEventType = "session.snapshot_rewind"
- SessionStart SessionEventType = "session.start"
- SessionTaskComplete SessionEventType = "session.task_complete"
- SessionTitleChanged SessionEventType = "session.title_changed"
- SessionToolsUpdated SessionEventType = "session.tools_updated"
- SessionTruncation SessionEventType = "session.truncation"
- SessionUsageInfo SessionEventType = "session.usage_info"
- SessionWarning SessionEventType = "session.warning"
- SessionWorkspaceFileChanged SessionEventType = "session.workspace_file_changed"
- SkillInvoked SessionEventType = "skill.invoked"
- SubagentCompleted SessionEventType = "subagent.completed"
- SubagentDeselected SessionEventType = "subagent.deselected"
- SubagentFailed SessionEventType = "subagent.failed"
- SubagentSelected SessionEventType = "subagent.selected"
- SubagentStarted SessionEventType = "subagent.started"
- SystemMessage SessionEventType = "system.message"
- SystemNotification SessionEventType = "system.notification"
- ToolExecutionComplete SessionEventType = "tool.execution_complete"
- ToolExecutionPartialResult SessionEventType = "tool.execution_partial_result"
- ToolExecutionProgress SessionEventType = "tool.execution_progress"
- ToolExecutionStart SessionEventType = "tool.execution_start"
- ToolUserRequested SessionEventType = "tool.user_requested"
- UserInputCompleted SessionEventType = "user_input.completed"
- UserInputRequested SessionEventType = "user_input.requested"
- UserMessage SessionEventType = "user.message"
+ SessionEventTypeAbort SessionEventType = "abort"
+ SessionEventTypeAssistantIntent SessionEventType = "assistant.intent"
+ SessionEventTypeAssistantMessage SessionEventType = "assistant.message"
+ SessionEventTypeAssistantMessageDelta SessionEventType = "assistant.message_delta"
+ SessionEventTypeAssistantReasoning SessionEventType = "assistant.reasoning"
+ SessionEventTypeAssistantReasoningDelta SessionEventType = "assistant.reasoning_delta"
+ SessionEventTypeAssistantStreamingDelta SessionEventType = "assistant.streaming_delta"
+ SessionEventTypeAssistantTurnEnd SessionEventType = "assistant.turn_end"
+ SessionEventTypeAssistantTurnStart SessionEventType = "assistant.turn_start"
+ SessionEventTypeAssistantUsage SessionEventType = "assistant.usage"
+ SessionEventTypeCommandCompleted SessionEventType = "command.completed"
+ SessionEventTypeCommandExecute SessionEventType = "command.execute"
+ SessionEventTypeCommandQueued SessionEventType = "command.queued"
+ SessionEventTypeCommandsChanged SessionEventType = "commands.changed"
+ SessionEventTypeElicitationCompleted SessionEventType = "elicitation.completed"
+ SessionEventTypeElicitationRequested SessionEventType = "elicitation.requested"
+ SessionEventTypeExitPlanModeCompleted SessionEventType = "exit_plan_mode.completed"
+ SessionEventTypeExitPlanModeRequested SessionEventType = "exit_plan_mode.requested"
+ SessionEventTypeExternalToolCompleted SessionEventType = "external_tool.completed"
+ SessionEventTypeExternalToolRequested SessionEventType = "external_tool.requested"
+ SessionEventTypeHookEnd SessionEventType = "hook.end"
+ SessionEventTypeHookStart SessionEventType = "hook.start"
+ SessionEventTypeMcpOauthCompleted SessionEventType = "mcp.oauth_completed"
+ SessionEventTypeMcpOauthRequired SessionEventType = "mcp.oauth_required"
+ SessionEventTypePendingMessagesModified SessionEventType = "pending_messages.modified"
+ SessionEventTypePermissionCompleted SessionEventType = "permission.completed"
+ SessionEventTypePermissionRequested SessionEventType = "permission.requested"
+ SessionEventTypeSessionBackgroundTasksChanged SessionEventType = "session.background_tasks_changed"
+ SessionEventTypeSessionCompactionComplete SessionEventType = "session.compaction_complete"
+ SessionEventTypeSessionCompactionStart SessionEventType = "session.compaction_start"
+ SessionEventTypeSessionContextChanged SessionEventType = "session.context_changed"
+ SessionEventTypeSessionError SessionEventType = "session.error"
+ SessionEventTypeSessionExtensionsLoaded SessionEventType = "session.extensions_loaded"
+ SessionEventTypeSessionHandoff SessionEventType = "session.handoff"
+ SessionEventTypeSessionIdle SessionEventType = "session.idle"
+ SessionEventTypeSessionInfo SessionEventType = "session.info"
+ SessionEventTypeSessionMcpServerStatusChanged SessionEventType = "session.mcp_server_status_changed"
+ SessionEventTypeSessionMcpServersLoaded SessionEventType = "session.mcp_servers_loaded"
+ SessionEventTypeSessionModeChanged SessionEventType = "session.mode_changed"
+ SessionEventTypeSessionModelChange SessionEventType = "session.model_change"
+ SessionEventTypeSessionPlanChanged SessionEventType = "session.plan_changed"
+ SessionEventTypeSessionResume SessionEventType = "session.resume"
+ SessionEventTypeSessionShutdown SessionEventType = "session.shutdown"
+ SessionEventTypeSessionSkillsLoaded SessionEventType = "session.skills_loaded"
+ SessionEventTypeSessionSnapshotRewind SessionEventType = "session.snapshot_rewind"
+ SessionEventTypeSessionStart SessionEventType = "session.start"
+ SessionEventTypeSessionTaskComplete SessionEventType = "session.task_complete"
+ SessionEventTypeSessionTitleChanged SessionEventType = "session.title_changed"
+ SessionEventTypeSessionToolsUpdated SessionEventType = "session.tools_updated"
+ SessionEventTypeSessionTruncation SessionEventType = "session.truncation"
+ SessionEventTypeSessionUsageInfo SessionEventType = "session.usage_info"
+ SessionEventTypeSessionWarning SessionEventType = "session.warning"
+ SessionEventTypeSessionWorkspaceFileChanged SessionEventType = "session.workspace_file_changed"
+ SessionEventTypeSkillInvoked SessionEventType = "skill.invoked"
+ SessionEventTypeSubagentCompleted SessionEventType = "subagent.completed"
+ SessionEventTypeSubagentDeselected SessionEventType = "subagent.deselected"
+ SessionEventTypeSubagentFailed SessionEventType = "subagent.failed"
+ SessionEventTypeSubagentSelected SessionEventType = "subagent.selected"
+ SessionEventTypeSubagentStarted SessionEventType = "subagent.started"
+ SessionEventTypeSystemMessage SessionEventType = "system.message"
+ SessionEventTypeSystemNotification SessionEventType = "system.notification"
+ SessionEventTypeToolExecutionComplete SessionEventType = "tool.execution_complete"
+ SessionEventTypeToolExecutionPartialResult SessionEventType = "tool.execution_partial_result"
+ SessionEventTypeToolExecutionProgress SessionEventType = "tool.execution_progress"
+ SessionEventTypeToolExecutionStart SessionEventType = "tool.execution_start"
+ SessionEventTypeToolUserRequested SessionEventType = "tool.user_requested"
+ SessionEventTypeUserInputCompleted SessionEventType = "user_input.completed"
+ SessionEventTypeUserInputRequested SessionEventType = "user_input.requested"
+ SessionEventTypeUserMessage SessionEventType = "user.message"
)
type ContextUnion struct {
diff --git a/go/internal/e2e/agent_and_compact_rpc_test.go b/go/internal/e2e/agent_and_compact_rpc_test.go
index 338f4da67..cbd52a326 100644
--- a/go/internal/e2e/agent_and_compact_rpc_test.go
+++ b/go/internal/e2e/agent_and_compact_rpc_test.go
@@ -215,7 +215,7 @@ func TestAgentSelectionRpc(t *testing.T) {
}
})
- t.Run("should return empty list when no custom agents configured", func(t *testing.T) {
+ t.Run("should return no custom agents when none configured", func(t *testing.T) {
client := copilot.NewClient(&copilot.ClientOptions{
CLIPath: cliPath,
UseStdio: copilot.Bool(true),
@@ -238,8 +238,13 @@ func TestAgentSelectionRpc(t *testing.T) {
t.Fatalf("Failed to list agents: %v", err)
}
- if len(result.Agents) != 0 {
- t.Errorf("Expected empty agent list, got %d agents", len(result.Agents))
+ // The CLI may return built-in/default agents even when no custom agents
+ // are configured, so just verify none of the known custom agent names appear.
+ customNames := map[string]bool{"test-agent": true, "another-agent": true}
+ for _, agent := range result.Agents {
+ if customNames[agent.Name] {
+ t.Errorf("Expected no custom agents, but found %q", agent.Name)
+ }
}
if err := client.Stop(); err != nil {
diff --git a/go/internal/e2e/compaction_test.go b/go/internal/e2e/compaction_test.go
index aee80704d..888ab2aa9 100644
--- a/go/internal/e2e/compaction_test.go
+++ b/go/internal/e2e/compaction_test.go
@@ -36,10 +36,10 @@ func TestCompaction(t *testing.T) {
var compactionCompleteEvents []copilot.SessionEvent
session.On(func(event copilot.SessionEvent) {
- if event.Type == copilot.SessionCompactionStart {
+ if event.Type == copilot.SessionEventTypeSessionCompactionStart {
compactionStartEvents = append(compactionStartEvents, event)
}
- if event.Type == copilot.SessionCompactionComplete {
+ if event.Type == copilot.SessionEventTypeSessionCompactionComplete {
compactionCompleteEvents = append(compactionCompleteEvents, event)
}
})
@@ -105,7 +105,7 @@ func TestCompaction(t *testing.T) {
var compactionEvents []copilot.SessionEvent
session.On(func(event copilot.SessionEvent) {
- if event.Type == copilot.SessionCompactionStart || event.Type == copilot.SessionCompactionComplete {
+ if event.Type == copilot.SessionEventTypeSessionCompactionStart || event.Type == copilot.SessionEventTypeSessionCompactionComplete {
compactionEvents = append(compactionEvents, event)
}
})
diff --git a/go/internal/e2e/multi_client_test.go b/go/internal/e2e/multi_client_test.go
index 9571ab58e..3c7dc34c3 100644
--- a/go/internal/e2e/multi_client_test.go
+++ b/go/internal/e2e/multi_client_test.go
@@ -79,13 +79,13 @@ func TestMultiClient(t *testing.T) {
client2Completed := make(chan struct{}, 1)
session1.On(func(event copilot.SessionEvent) {
- if event.Type == copilot.ExternalToolRequested {
+ if event.Type == copilot.SessionEventTypeExternalToolRequested {
select {
case client1Requested <- struct{}{}:
default:
}
}
- if event.Type == copilot.ExternalToolCompleted {
+ if event.Type == copilot.SessionEventTypeExternalToolCompleted {
select {
case client1Completed <- struct{}{}:
default:
@@ -93,13 +93,13 @@ func TestMultiClient(t *testing.T) {
}
})
session2.On(func(event copilot.SessionEvent) {
- if event.Type == copilot.ExternalToolRequested {
+ if event.Type == copilot.SessionEventTypeExternalToolRequested {
select {
case client2Requested <- struct{}{}:
default:
}
}
- if event.Type == copilot.ExternalToolCompleted {
+ if event.Type == copilot.SessionEventTypeExternalToolCompleted {
select {
case client2Completed <- struct{}{}:
default:
@@ -120,7 +120,7 @@ func TestMultiClient(t *testing.T) {
}
// Wait for all broadcast events to arrive on both clients
- timeout := time.After(10 * time.Second)
+ timeout := time.After(30 * time.Second)
for _, ch := range []chan struct{}{client1Requested, client2Requested, client1Completed, client2Completed} {
select {
case <-ch:
@@ -197,10 +197,10 @@ func TestMultiClient(t *testing.T) {
// Both clients should have seen permission.requested events
mu1.Lock()
- c1PermRequested := filterEventsByType(client1Events, copilot.PermissionRequested)
+ c1PermRequested := filterEventsByType(client1Events, copilot.SessionEventTypePermissionRequested)
mu1.Unlock()
mu2.Lock()
- c2PermRequested := filterEventsByType(client2Events, copilot.PermissionRequested)
+ c2PermRequested := filterEventsByType(client2Events, copilot.SessionEventTypePermissionRequested)
mu2.Unlock()
if len(c1PermRequested) == 0 {
@@ -212,10 +212,10 @@ func TestMultiClient(t *testing.T) {
// Both clients should have seen permission.completed events with approved result
mu1.Lock()
- c1PermCompleted := filterEventsByType(client1Events, copilot.PermissionCompleted)
+ c1PermCompleted := filterEventsByType(client1Events, copilot.SessionEventTypePermissionCompleted)
mu1.Unlock()
mu2.Lock()
- c2PermCompleted := filterEventsByType(client2Events, copilot.PermissionCompleted)
+ c2PermCompleted := filterEventsByType(client2Events, copilot.SessionEventTypePermissionCompleted)
mu2.Unlock()
if len(c1PermCompleted) == 0 {
@@ -293,10 +293,10 @@ func TestMultiClient(t *testing.T) {
// Both clients should have seen permission.requested events
mu1.Lock()
- c1PermRequested := filterEventsByType(client1Events, copilot.PermissionRequested)
+ c1PermRequested := filterEventsByType(client1Events, copilot.SessionEventTypePermissionRequested)
mu1.Unlock()
mu2.Lock()
- c2PermRequested := filterEventsByType(client2Events, copilot.PermissionRequested)
+ c2PermRequested := filterEventsByType(client2Events, copilot.SessionEventTypePermissionRequested)
mu2.Unlock()
if len(c1PermRequested) == 0 {
@@ -308,10 +308,10 @@ func TestMultiClient(t *testing.T) {
// Both clients should see the denial in the completed event
mu1.Lock()
- c1PermCompleted := filterEventsByType(client1Events, copilot.PermissionCompleted)
+ c1PermCompleted := filterEventsByType(client1Events, copilot.SessionEventTypePermissionCompleted)
mu1.Unlock()
mu2.Lock()
- c2PermCompleted := filterEventsByType(client2Events, copilot.PermissionCompleted)
+ c2PermCompleted := filterEventsByType(client2Events, copilot.SessionEventTypePermissionCompleted)
mu2.Unlock()
if len(c1PermCompleted) == 0 {
diff --git a/go/internal/e2e/permissions_test.go b/go/internal/e2e/permissions_test.go
index 328e7e788..98f620043 100644
--- a/go/internal/e2e/permissions_test.go
+++ b/go/internal/e2e/permissions_test.go
@@ -173,7 +173,7 @@ func TestPermissions(t *testing.T) {
permissionDenied := false
session.On(func(event copilot.SessionEvent) {
- if event.Type == copilot.ToolExecutionComplete &&
+ if event.Type == copilot.SessionEventTypeToolExecutionComplete &&
event.Data.Success != nil && !*event.Data.Success &&
event.Data.Error != nil && event.Data.Error.ErrorClass != nil &&
strings.Contains(event.Data.Error.ErrorClass.Message, "Permission denied") {
@@ -223,7 +223,7 @@ func TestPermissions(t *testing.T) {
permissionDenied := false
session2.On(func(event copilot.SessionEvent) {
- if event.Type == copilot.ToolExecutionComplete &&
+ if event.Type == copilot.SessionEventTypeToolExecutionComplete &&
event.Data.Success != nil && !*event.Data.Success &&
event.Data.Error != nil && event.Data.Error.ErrorClass != nil &&
strings.Contains(event.Data.Error.ErrorClass.Message, "Permission denied") {
diff --git a/go/internal/e2e/rpc_test.go b/go/internal/e2e/rpc_test.go
index ebcbe1130..3d69b97ad 100644
--- a/go/internal/e2e/rpc_test.go
+++ b/go/internal/e2e/rpc_test.go
@@ -219,16 +219,16 @@ func TestSessionRpc(t *testing.T) {
if err != nil {
t.Fatalf("Failed to get mode: %v", err)
}
- if initial.Mode != rpc.Interactive {
+ if initial.Mode != rpc.ModeInteractive {
t.Errorf("Expected initial mode 'interactive', got %q", initial.Mode)
}
// Switch to plan mode
- planResult, err := session.RPC.Mode.Set(t.Context(), &rpc.SessionModeSetParams{Mode: rpc.Plan})
+ planResult, err := session.RPC.Mode.Set(t.Context(), &rpc.SessionModeSetParams{Mode: rpc.ModePlan})
if err != nil {
t.Fatalf("Failed to set mode to plan: %v", err)
}
- if planResult.Mode != rpc.Plan {
+ if planResult.Mode != rpc.ModePlan {
t.Errorf("Expected mode 'plan', got %q", planResult.Mode)
}
@@ -237,16 +237,16 @@ func TestSessionRpc(t *testing.T) {
if err != nil {
t.Fatalf("Failed to get mode after plan: %v", err)
}
- if afterPlan.Mode != rpc.Plan {
+ if afterPlan.Mode != rpc.ModePlan {
t.Errorf("Expected mode 'plan' after set, got %q", afterPlan.Mode)
}
// Switch back to interactive
- interactiveResult, err := session.RPC.Mode.Set(t.Context(), &rpc.SessionModeSetParams{Mode: rpc.Interactive})
+ interactiveResult, err := session.RPC.Mode.Set(t.Context(), &rpc.SessionModeSetParams{Mode: rpc.ModeInteractive})
if err != nil {
t.Fatalf("Failed to set mode to interactive: %v", err)
}
- if interactiveResult.Mode != rpc.Interactive {
+ if interactiveResult.Mode != rpc.ModeInteractive {
t.Errorf("Expected mode 'interactive', got %q", interactiveResult.Mode)
}
})
diff --git a/go/internal/e2e/session_test.go b/go/internal/e2e/session_test.go
index 052ae1580..1eaeacd1e 100644
--- a/go/internal/e2e/session_test.go
+++ b/go/internal/e2e/session_test.go
@@ -506,7 +506,7 @@ func TestSession(t *testing.T) {
toolStartCh := make(chan *copilot.SessionEvent, 1)
toolStartErrCh := make(chan error, 1)
go func() {
- evt, err := testharness.GetNextEventOfType(session, copilot.ToolExecutionStart, 60*time.Second)
+ evt, err := testharness.GetNextEventOfType(session, copilot.SessionEventTypeToolExecutionStart, 60*time.Second)
if err != nil {
toolStartErrCh <- err
} else {
@@ -517,7 +517,7 @@ func TestSession(t *testing.T) {
sessionIdleCh := make(chan *copilot.SessionEvent, 1)
sessionIdleErrCh := make(chan error, 1)
go func() {
- evt, err := testharness.GetNextEventOfType(session, copilot.SessionIdle, 60*time.Second)
+ evt, err := testharness.GetNextEventOfType(session, copilot.SessionEventTypeSessionIdle, 60*time.Second)
if err != nil {
sessionIdleErrCh <- err
} else {
@@ -565,7 +565,7 @@ func TestSession(t *testing.T) {
// Verify messages contain an abort event
hasAbortEvent := false
for _, msg := range messages {
- if msg.Type == copilot.Abort {
+ if msg.Type == copilot.SessionEventTypeAbort {
hasAbortEvent = true
break
}
@@ -913,7 +913,7 @@ func TestSetModelWithReasoningEffort(t *testing.T) {
modelChanged := make(chan copilot.SessionEvent, 1)
session.On(func(event copilot.SessionEvent) {
- if event.Type == copilot.SessionModelChange {
+ if event.Type == copilot.SessionEventTypeSessionModelChange {
select {
case modelChanged <- event:
default:
@@ -964,7 +964,7 @@ func TestSessionBlobAttachment(t *testing.T) {
Prompt: "Describe this image",
Attachments: []copilot.Attachment{
{
- Type: copilot.Blob,
+ Type: copilot.AttachmentTypeBlob,
Data: &data,
MIMEType: &mimeType,
DisplayName: &displayName,
@@ -1028,7 +1028,7 @@ func TestSessionLog(t *testing.T) {
t.Fatalf("Log failed: %v", err)
}
- evt := waitForEvent(t, &mu, &events, copilot.SessionInfo, "Info message", 5*time.Second)
+ evt := waitForEvent(t, &mu, &events, copilot.SessionEventTypeSessionInfo, "Info message", 5*time.Second)
if evt.Data.InfoType == nil || *evt.Data.InfoType != "notification" {
t.Errorf("Expected infoType 'notification', got %v", evt.Data.InfoType)
}
@@ -1038,11 +1038,11 @@ func TestSessionLog(t *testing.T) {
})
t.Run("should log warning message", func(t *testing.T) {
- if err := session.Log(t.Context(), "Warning message", &copilot.LogOptions{Level: rpc.Warning}); err != nil {
+ if err := session.Log(t.Context(), "Warning message", &copilot.LogOptions{Level: rpc.LevelWarning}); err != nil {
t.Fatalf("Log failed: %v", err)
}
- evt := waitForEvent(t, &mu, &events, copilot.SessionWarning, "Warning message", 5*time.Second)
+ evt := waitForEvent(t, &mu, &events, copilot.SessionEventTypeSessionWarning, "Warning message", 5*time.Second)
if evt.Data.WarningType == nil || *evt.Data.WarningType != "notification" {
t.Errorf("Expected warningType 'notification', got %v", evt.Data.WarningType)
}
@@ -1052,11 +1052,11 @@ func TestSessionLog(t *testing.T) {
})
t.Run("should log error message", func(t *testing.T) {
- if err := session.Log(t.Context(), "Error message", &copilot.LogOptions{Level: rpc.Error}); err != nil {
+ if err := session.Log(t.Context(), "Error message", &copilot.LogOptions{Level: rpc.LevelError}); err != nil {
t.Fatalf("Log failed: %v", err)
}
- evt := waitForEvent(t, &mu, &events, copilot.SessionError, "Error message", 5*time.Second)
+ evt := waitForEvent(t, &mu, &events, copilot.SessionEventTypeSessionError, "Error message", 5*time.Second)
if evt.Data.ErrorType == nil || *evt.Data.ErrorType != "notification" {
t.Errorf("Expected errorType 'notification', got %v", evt.Data.ErrorType)
}
@@ -1070,7 +1070,7 @@ func TestSessionLog(t *testing.T) {
t.Fatalf("Log failed: %v", err)
}
- evt := waitForEvent(t, &mu, &events, copilot.SessionInfo, "Ephemeral message", 5*time.Second)
+ evt := waitForEvent(t, &mu, &events, copilot.SessionEventTypeSessionInfo, "Ephemeral message", 5*time.Second)
if evt.Data.InfoType == nil || *evt.Data.InfoType != "notification" {
t.Errorf("Expected infoType 'notification', got %v", evt.Data.InfoType)
}
diff --git a/go/internal/e2e/testharness/helper.go b/go/internal/e2e/testharness/helper.go
index 05947c806..3b521f330 100644
--- a/go/internal/e2e/testharness/helper.go
+++ b/go/internal/e2e/testharness/helper.go
@@ -67,7 +67,7 @@ func GetNextEventOfType(session *copilot.Session, eventType copilot.SessionEvent
case result <- &event:
default:
}
- case copilot.SessionError:
+ case copilot.SessionEventTypeSessionError:
msg := "session error"
if event.Data.Message != nil {
msg = *event.Data.Message
diff --git a/go/rpc/generated_rpc.go b/go/rpc/generated_rpc.go
index 401f38305..b9ba408b5 100644
--- a/go/rpc/generated_rpc.go
+++ b/go/rpc/generated_rpc.go
@@ -223,10 +223,10 @@ type SessionFleetStartParams struct {
// Experimental: SessionAgentListResult is part of an experimental API and may change or be removed.
type SessionAgentListResult struct {
// Available custom agents
- Agents []AgentElement `json:"agents"`
+ Agents []SessionAgentListResultAgent `json:"agents"`
}
-type AgentElement struct {
+type SessionAgentListResultAgent struct {
// Description of the agent's purpose
Description string `json:"description"`
// Human-readable display name
@@ -276,6 +276,161 @@ type SessionAgentSelectParams struct {
type SessionAgentDeselectResult struct {
}
+// Experimental: SessionAgentReloadResult is part of an experimental API and may change or be removed.
+type SessionAgentReloadResult struct {
+ // Reloaded custom agents
+ Agents []SessionAgentReloadResultAgent `json:"agents"`
+}
+
+type SessionAgentReloadResultAgent 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: SessionSkillsListResult is part of an experimental API and may change or be removed.
+type SessionSkillsListResult struct {
+ // Available skills
+ Skills []Skill `json:"skills"`
+}
+
+type Skill 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"`
+ // Absolute path to the skill file
+ Path *string `json:"path,omitempty"`
+ // Source location type (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"`
+}
+
+// Experimental: SessionSkillsEnableResult is part of an experimental API and may change or be removed.
+type SessionSkillsEnableResult struct {
+}
+
+// Experimental: SessionSkillsEnableParams is part of an experimental API and may change or be removed.
+type SessionSkillsEnableParams struct {
+ // Name of the skill to enable
+ Name string `json:"name"`
+}
+
+// Experimental: SessionSkillsDisableResult is part of an experimental API and may change or be removed.
+type SessionSkillsDisableResult struct {
+}
+
+// Experimental: SessionSkillsDisableParams is part of an experimental API and may change or be removed.
+type SessionSkillsDisableParams struct {
+ // Name of the skill to disable
+ Name string `json:"name"`
+}
+
+// Experimental: SessionSkillsReloadResult is part of an experimental API and may change or be removed.
+type SessionSkillsReloadResult struct {
+}
+
+type SessionMCPListResult struct {
+ // Configured MCP servers
+ Servers []Server `json:"servers"`
+}
+
+type Server 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 *string `json:"source,omitempty"`
+ // Connection status: connected, failed, pending, disabled, or not_configured
+ Status ServerStatus `json:"status"`
+}
+
+type SessionMCPEnableResult struct {
+}
+
+type SessionMCPEnableParams struct {
+ // Name of the MCP server to enable
+ ServerName string `json:"serverName"`
+}
+
+type SessionMCPDisableResult struct {
+}
+
+type SessionMCPDisableParams struct {
+ // Name of the MCP server to disable
+ ServerName string `json:"serverName"`
+}
+
+type SessionMCPReloadResult struct {
+}
+
+// Experimental: SessionPluginsListResult is part of an experimental API and may change or be removed.
+type SessionPluginsListResult struct {
+ // Installed plugins
+ Plugins []Plugin `json:"plugins"`
+}
+
+type Plugin 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"`
+}
+
+// Experimental: SessionExtensionsListResult is part of an experimental API and may change or be removed.
+type SessionExtensionsListResult struct {
+ // Discovered extensions and their current status
+ Extensions []Extension `json:"extensions"`
+}
+
+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 Source `json:"source"`
+ // Current status: running, disabled, failed, or starting
+ Status ExtensionStatus `json:"status"`
+}
+
+// Experimental: SessionExtensionsEnableResult is part of an experimental API and may change or be removed.
+type SessionExtensionsEnableResult struct {
+}
+
+// Experimental: SessionExtensionsEnableParams is part of an experimental API and may change or be removed.
+type SessionExtensionsEnableParams struct {
+ // Source-qualified extension ID to enable
+ ID string `json:"id"`
+}
+
+// Experimental: SessionExtensionsDisableResult is part of an experimental API and may change or be removed.
+type SessionExtensionsDisableResult struct {
+}
+
+// Experimental: SessionExtensionsDisableParams is part of an experimental API and may change or be removed.
+type SessionExtensionsDisableParams struct {
+ // Source-qualified extension ID to disable
+ ID string `json:"id"`
+}
+
+// Experimental: SessionExtensionsReloadResult is part of an experimental API and may change or be removed.
+type SessionExtensionsReloadResult struct {
+}
+
// Experimental: SessionCompactionCompactResult is part of an experimental API and may change or be removed.
type SessionCompactionCompactResult struct {
// Number of messages removed during compaction
@@ -304,6 +459,75 @@ type ResultResult struct {
ToolTelemetry map[string]interface{} `json:"toolTelemetry,omitempty"`
}
+type SessionCommandsHandlePendingCommandResult struct {
+ Success bool `json:"success"`
+}
+
+type SessionCommandsHandlePendingCommandParams 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 SessionUIElicitationResult struct {
+ // The user's response: accept (submitted), decline (rejected), or cancel (dismissed)
+ Action Action `json:"action"`
+ // The form values submitted by the user (present when action is 'accept')
+ Content map[string]*Content `json:"content,omitempty"`
+}
+
+type SessionUIElicitationParams struct {
+ // Message describing what information is needed from the user
+ Message string `json:"message"`
+ // JSON Schema describing the form fields to present to the user
+ RequestedSchema RequestedSchema `json:"requestedSchema"`
+}
+
+// JSON Schema describing the form fields to present to the user
+type RequestedSchema struct {
+ // Form field definitions, keyed by field name
+ Properties map[string]Property `json:"properties"`
+ // List of required field names
+ Required []string `json:"required,omitempty"`
+ // Schema type indicator (always 'object')
+ Type RequestedSchemaType `json:"type"`
+}
+
+type Property struct {
+ Default *Content `json:"default"`
+ Description *string `json:"description,omitempty"`
+ Enum []string `json:"enum,omitempty"`
+ EnumNames []string `json:"enumNames,omitempty"`
+ Title *string `json:"title,omitempty"`
+ Type PropertyType `json:"type"`
+ OneOf []OneOf `json:"oneOf,omitempty"`
+ Items *Items `json:"items,omitempty"`
+ MaxItems *float64 `json:"maxItems,omitempty"`
+ MinItems *float64 `json:"minItems,omitempty"`
+ Format *Format `json:"format,omitempty"`
+ MaxLength *float64 `json:"maxLength,omitempty"`
+ MinLength *float64 `json:"minLength,omitempty"`
+ Maximum *float64 `json:"maximum,omitempty"`
+ Minimum *float64 `json:"minimum,omitempty"`
+}
+
+type Items struct {
+ Enum []string `json:"enum,omitempty"`
+ Type *ItemsType `json:"type,omitempty"`
+ AnyOf []AnyOf `json:"anyOf,omitempty"`
+}
+
+type AnyOf struct {
+ Const string `json:"const"`
+ Title string `json:"title"`
+}
+
+type OneOf struct {
+ Const string `json:"const"`
+ Title string `json:"title"`
+}
+
type SessionPermissionsHandlePendingPermissionRequestResult struct {
// Whether the permission request was handled successfully
Success bool `json:"success"`
@@ -335,6 +559,8 @@ type SessionLogParams struct {
Level *Level `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 SessionShellExecResult struct {
@@ -371,19 +597,88 @@ type SessionShellKillParams struct {
type Mode string
const (
- Autopilot Mode = "autopilot"
- Interactive Mode = "interactive"
- Plan Mode = "plan"
+ ModeAutopilot Mode = "autopilot"
+ ModeInteractive Mode = "interactive"
+ ModePlan Mode = "plan"
+)
+
+// Connection status: connected, failed, pending, disabled, or not_configured
+type ServerStatus string
+
+const (
+ ServerStatusConnected ServerStatus = "connected"
+ ServerStatusNotConfigured ServerStatus = "not_configured"
+ ServerStatusPending ServerStatus = "pending"
+ ServerStatusDisabled ServerStatus = "disabled"
+ ServerStatusFailed ServerStatus = "failed"
+)
+
+// Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)
+type Source string
+
+const (
+ SourceProject Source = "project"
+ SourceUser Source = "user"
+)
+
+// Current status: running, disabled, failed, or starting
+type ExtensionStatus string
+
+const (
+ ExtensionStatusDisabled ExtensionStatus = "disabled"
+ ExtensionStatusFailed ExtensionStatus = "failed"
+ ExtensionStatusRunning ExtensionStatus = "running"
+ ExtensionStatusStarting ExtensionStatus = "starting"
+)
+
+// The user's response: accept (submitted), decline (rejected), or cancel (dismissed)
+type Action string
+
+const (
+ ActionAccept Action = "accept"
+ ActionCancel Action = "cancel"
+ ActionDecline Action = "decline"
+)
+
+type Format string
+
+const (
+ FormatDate Format = "date"
+ FormatDateTime Format = "date-time"
+ FormatEmail Format = "email"
+ FormatUri Format = "uri"
+)
+
+type ItemsType string
+
+const (
+ ItemsTypeString ItemsType = "string"
+)
+
+type PropertyType string
+
+const (
+ PropertyTypeArray PropertyType = "array"
+ PropertyTypeBoolean PropertyType = "boolean"
+ PropertyTypeString PropertyType = "string"
+ PropertyTypeInteger PropertyType = "integer"
+ PropertyTypeNumber PropertyType = "number"
+)
+
+type RequestedSchemaType string
+
+const (
+ RequestedSchemaTypeObject RequestedSchemaType = "object"
)
type Kind string
const (
- Approved Kind = "approved"
- DeniedByContentExclusionPolicy Kind = "denied-by-content-exclusion-policy"
- DeniedByRules Kind = "denied-by-rules"
- DeniedInteractivelyByUser Kind = "denied-interactively-by-user"
- DeniedNoApprovalRuleAndCouldNotRequestFromUser Kind = "denied-no-approval-rule-and-could-not-request-from-user"
+ KindApproved Kind = "approved"
+ KindDeniedByContentExclusionPolicy Kind = "denied-by-content-exclusion-policy"
+ KindDeniedByRules Kind = "denied-by-rules"
+ KindDeniedInteractivelyByUser Kind = "denied-interactively-by-user"
+ KindDeniedNoApprovalRuleAndCouldNotRequestFromUser Kind = "denied-no-approval-rule-and-could-not-request-from-user"
)
// Log severity level. Determines how the message is displayed in the timeline. Defaults to
@@ -391,18 +686,18 @@ const (
type Level string
const (
- Error Level = "error"
- Info Level = "info"
- Warning Level = "warning"
+ LevelError Level = "error"
+ LevelInfo Level = "info"
+ LevelWarning Level = "warning"
)
// Signal to send (default: SIGTERM)
type Signal string
const (
- Sigint Signal = "SIGINT"
- Sigkill Signal = "SIGKILL"
- Sigterm Signal = "SIGTERM"
+ SignalSIGINT Signal = "SIGINT"
+ SignalSIGKILL Signal = "SIGKILL"
+ SignalSIGTERM Signal = "SIGTERM"
)
type ResultUnion struct {
@@ -410,6 +705,13 @@ type ResultUnion struct {
String *string
}
+type Content struct {
+ Bool *bool
+ Double *float64
+ String *string
+ StringArray []string
+}
+
type ServerModelsRpcApi struct {
client *jsonrpc2.Client
}
@@ -740,6 +1042,230 @@ func (a *AgentRpcApi) Deselect(ctx context.Context) (*SessionAgentDeselectResult
return &result, nil
}
+func (a *AgentRpcApi) Reload(ctx context.Context) (*SessionAgentReloadResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.agent.reload", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionAgentReloadResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+// Experimental: SkillsRpcApi contains experimental APIs that may change or be removed.
+type SkillsRpcApi struct {
+ client *jsonrpc2.Client
+ sessionID string
+}
+
+func (a *SkillsRpcApi) List(ctx context.Context) (*SessionSkillsListResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.skills.list", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionSkillsListResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *SkillsRpcApi) Enable(ctx context.Context, params *SessionSkillsEnableParams) (*SessionSkillsEnableResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["name"] = params.Name
+ }
+ raw, err := a.client.Request("session.skills.enable", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionSkillsEnableResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *SkillsRpcApi) Disable(ctx context.Context, params *SessionSkillsDisableParams) (*SessionSkillsDisableResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["name"] = params.Name
+ }
+ raw, err := a.client.Request("session.skills.disable", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionSkillsDisableResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *SkillsRpcApi) Reload(ctx context.Context) (*SessionSkillsReloadResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.skills.reload", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionSkillsReloadResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+// Experimental: McpRpcApi contains experimental APIs that may change or be removed.
+type McpRpcApi struct {
+ client *jsonrpc2.Client
+ sessionID string
+}
+
+func (a *McpRpcApi) List(ctx context.Context) (*SessionMCPListResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.mcp.list", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionMCPListResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *McpRpcApi) Enable(ctx context.Context, params *SessionMCPEnableParams) (*SessionMCPEnableResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["serverName"] = params.ServerName
+ }
+ raw, err := a.client.Request("session.mcp.enable", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionMCPEnableResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *McpRpcApi) Disable(ctx context.Context, params *SessionMCPDisableParams) (*SessionMCPDisableResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["serverName"] = params.ServerName
+ }
+ raw, err := a.client.Request("session.mcp.disable", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionMCPDisableResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *McpRpcApi) Reload(ctx context.Context) (*SessionMCPReloadResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.mcp.reload", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionMCPReloadResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+// Experimental: PluginsRpcApi contains experimental APIs that may change or be removed.
+type PluginsRpcApi struct {
+ client *jsonrpc2.Client
+ sessionID string
+}
+
+func (a *PluginsRpcApi) List(ctx context.Context) (*SessionPluginsListResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.plugins.list", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionPluginsListResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+// Experimental: ExtensionsRpcApi contains experimental APIs that may change or be removed.
+type ExtensionsRpcApi struct {
+ client *jsonrpc2.Client
+ sessionID string
+}
+
+func (a *ExtensionsRpcApi) List(ctx context.Context) (*SessionExtensionsListResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.extensions.list", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionExtensionsListResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *ExtensionsRpcApi) Enable(ctx context.Context, params *SessionExtensionsEnableParams) (*SessionExtensionsEnableResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["id"] = params.ID
+ }
+ raw, err := a.client.Request("session.extensions.enable", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionExtensionsEnableResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *ExtensionsRpcApi) Disable(ctx context.Context, params *SessionExtensionsDisableParams) (*SessionExtensionsDisableResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["id"] = params.ID
+ }
+ raw, err := a.client.Request("session.extensions.disable", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionExtensionsDisableResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+func (a *ExtensionsRpcApi) Reload(ctx context.Context) (*SessionExtensionsReloadResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ raw, err := a.client.Request("session.extensions.reload", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionExtensionsReloadResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
// Experimental: CompactionRpcApi contains experimental APIs that may change or be removed.
type CompactionRpcApi struct {
client *jsonrpc2.Client
@@ -786,6 +1312,52 @@ func (a *ToolsRpcApi) HandlePendingToolCall(ctx context.Context, params *Session
return &result, nil
}
+type CommandsRpcApi struct {
+ client *jsonrpc2.Client
+ sessionID string
+}
+
+func (a *CommandsRpcApi) HandlePendingCommand(ctx context.Context, params *SessionCommandsHandlePendingCommandParams) (*SessionCommandsHandlePendingCommandResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["requestId"] = params.RequestID
+ if params.Error != nil {
+ req["error"] = *params.Error
+ }
+ }
+ raw, err := a.client.Request("session.commands.handlePendingCommand", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionCommandsHandlePendingCommandResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+type UiRpcApi struct {
+ client *jsonrpc2.Client
+ sessionID string
+}
+
+func (a *UiRpcApi) Elicitation(ctx context.Context, params *SessionUIElicitationParams) (*SessionUIElicitationResult, error) {
+ req := map[string]interface{}{"sessionId": a.sessionID}
+ if params != nil {
+ req["message"] = params.Message
+ req["requestedSchema"] = params.RequestedSchema
+ }
+ raw, err := a.client.Request("session.ui.elicitation", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionUIElicitationResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
type PermissionsRpcApi struct {
client *jsonrpc2.Client
sessionID string
@@ -864,8 +1436,14 @@ type SessionRpc struct {
Workspace *WorkspaceRpcApi
Fleet *FleetRpcApi
Agent *AgentRpcApi
+ Skills *SkillsRpcApi
+ Mcp *McpRpcApi
+ Plugins *PluginsRpcApi
+ Extensions *ExtensionsRpcApi
Compaction *CompactionRpcApi
Tools *ToolsRpcApi
+ Commands *CommandsRpcApi
+ Ui *UiRpcApi
Permissions *PermissionsRpcApi
Shell *ShellRpcApi
}
@@ -880,6 +1458,9 @@ func (a *SessionRpc) Log(ctx context.Context, params *SessionLogParams) (*Sessio
if params.Ephemeral != nil {
req["ephemeral"] = *params.Ephemeral
}
+ if params.URL != nil {
+ req["url"] = *params.URL
+ }
}
raw, err := a.client.Request("session.log", req)
if err != nil {
@@ -900,8 +1481,14 @@ func NewSessionRpc(client *jsonrpc2.Client, sessionID string) *SessionRpc {
Workspace: &WorkspaceRpcApi{client: client, sessionID: sessionID},
Fleet: &FleetRpcApi{client: client, sessionID: sessionID},
Agent: &AgentRpcApi{client: client, sessionID: sessionID},
+ Skills: &SkillsRpcApi{client: client, sessionID: sessionID},
+ Mcp: &McpRpcApi{client: client, sessionID: sessionID},
+ Plugins: &PluginsRpcApi{client: client, sessionID: sessionID},
+ Extensions: &ExtensionsRpcApi{client: client, sessionID: sessionID},
Compaction: &CompactionRpcApi{client: client, sessionID: sessionID},
Tools: &ToolsRpcApi{client: client, sessionID: sessionID},
+ Commands: &CommandsRpcApi{client: client, sessionID: sessionID},
+ Ui: &UiRpcApi{client: client, sessionID: sessionID},
Permissions: &PermissionsRpcApi{client: client, sessionID: sessionID},
Shell: &ShellRpcApi{client: client, sessionID: sessionID},
}
diff --git a/go/samples/chat.go b/go/samples/chat.go
index f984f758a..4d5e98d7d 100644
--- a/go/samples/chat.go
+++ b/go/samples/chat.go
@@ -35,11 +35,11 @@ func main() {
session.On(func(event copilot.SessionEvent) {
var output string
switch event.Type {
- case copilot.AssistantReasoning:
+ case copilot.SessionEventTypeAssistantReasoning:
if event.Data.Content != nil {
output = fmt.Sprintf("[reasoning: %s]", *event.Data.Content)
}
- case copilot.ToolExecutionStart:
+ case copilot.SessionEventTypeToolExecutionStart:
if event.Data.ToolName != nil {
output = fmt.Sprintf("[tool: %s]", *event.Data.ToolName)
}
diff --git a/go/session.go b/go/session.go
index d2a5785be..107ac9824 100644
--- a/go/session.go
+++ b/go/session.go
@@ -182,17 +182,17 @@ func (s *Session) SendAndWait(ctx context.Context, options MessageOptions) (*Ses
unsubscribe := s.On(func(event SessionEvent) {
switch event.Type {
- case AssistantMessage:
+ case SessionEventTypeAssistantMessage:
mu.Lock()
eventCopy := event
lastAssistantMessage = &eventCopy
mu.Unlock()
- case SessionIdle:
+ case SessionEventTypeSessionIdle:
select {
case idleCh <- struct{}{}:
default:
}
- case SessionError:
+ case SessionEventTypeSessionError:
errMsg := "session error"
if event.Data.Message != nil {
errMsg = *event.Data.Message
@@ -501,7 +501,7 @@ func (s *Session) processEvents() {
// cause RPC deadlocks.
func (s *Session) handleBroadcastEvent(event SessionEvent) {
switch event.Type {
- case ExternalToolRequested:
+ case SessionEventTypeExternalToolRequested:
requestID := event.Data.RequestID
toolName := event.Data.ToolName
if requestID == nil || toolName == nil {
@@ -524,7 +524,7 @@ func (s *Session) handleBroadcastEvent(event SessionEvent) {
}
s.executeToolAndRespond(*requestID, *toolName, toolCallID, event.Data.Arguments, handler, tp, ts)
- case PermissionRequested:
+ case SessionEventTypePermissionRequested:
requestID := event.Data.RequestID
if requestID == nil || event.Data.PermissionRequest == nil {
return
@@ -585,7 +585,7 @@ func (s *Session) executePermissionAndRespond(requestID string, permissionReques
s.RPC.Permissions.HandlePendingPermissionRequest(context.Background(), &rpc.SessionPermissionsHandlePendingPermissionRequestParams{
RequestID: requestID,
Result: rpc.SessionPermissionsHandlePendingPermissionRequestParamsResult{
- Kind: rpc.DeniedNoApprovalRuleAndCouldNotRequestFromUser,
+ Kind: rpc.KindDeniedNoApprovalRuleAndCouldNotRequestFromUser,
},
})
}
@@ -600,7 +600,7 @@ func (s *Session) executePermissionAndRespond(requestID string, permissionReques
s.RPC.Permissions.HandlePendingPermissionRequest(context.Background(), &rpc.SessionPermissionsHandlePendingPermissionRequestParams{
RequestID: requestID,
Result: rpc.SessionPermissionsHandlePendingPermissionRequestParamsResult{
- Kind: rpc.DeniedNoApprovalRuleAndCouldNotRequestFromUser,
+ Kind: rpc.KindDeniedNoApprovalRuleAndCouldNotRequestFromUser,
},
})
return
@@ -770,8 +770,8 @@ func (s *Session) SetModel(ctx context.Context, model string, opts ...SetModelOp
// LogOptions configures optional parameters for [Session.Log].
type LogOptions struct {
- // Level sets the log severity. Valid values are [rpc.Info] (default),
- // [rpc.Warning], and [rpc.Error].
+ // Level sets the log severity. Valid values are [rpc.LevelInfo] (default),
+ // [rpc.LevelWarning], and [rpc.LevelError].
Level rpc.Level
// Ephemeral marks the message as transient so it is not persisted
// to the session event log on disk. When nil the server decides the
@@ -791,7 +791,7 @@ type LogOptions struct {
// session.Log(ctx, "Processing started")
//
// // Warning with options
-// session.Log(ctx, "Rate limit approaching", &copilot.LogOptions{Level: rpc.Warning})
+// session.Log(ctx, "Rate limit approaching", &copilot.LogOptions{Level: rpc.LevelWarning})
//
// // Ephemeral message (not persisted)
// session.Log(ctx, "Working...", &copilot.LogOptions{Ephemeral: copilot.Bool(true)})
diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json
index 0952122f0..fd56aa84b 100644
--- a/nodejs/package-lock.json
+++ b/nodejs/package-lock.json
@@ -9,7 +9,7 @@
"version": "0.1.8",
"license": "MIT",
"dependencies": {
- "@github/copilot": "^1.0.4",
+ "@github/copilot": "^1.0.10-0",
"vscode-jsonrpc": "^8.2.1",
"zod": "^4.3.6"
},
@@ -662,26 +662,26 @@
}
},
"node_modules/@github/copilot": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.4.tgz",
- "integrity": "sha512-IpPg+zYplLu4F4lmatEDdR/1Y/jJ9cGWt89m3K3H4YSfYrZ5Go4UlM28llulYCG7sVdQeIGauQN1/KiBI/Rocg==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.10-0.tgz",
+ "integrity": "sha512-LmVe3yVDamZc4cbZeyprZ6WjTME9Z4UcB5YWnEagtXJ19KP5PBKbBZVG7pZnQHL2/IHZ/dqcZW3IHMgYDoqDvg==",
"license": "SEE LICENSE IN LICENSE.md",
"bin": {
"copilot": "npm-loader.js"
},
"optionalDependencies": {
- "@github/copilot-darwin-arm64": "1.0.4",
- "@github/copilot-darwin-x64": "1.0.4",
- "@github/copilot-linux-arm64": "1.0.4",
- "@github/copilot-linux-x64": "1.0.4",
- "@github/copilot-win32-arm64": "1.0.4",
- "@github/copilot-win32-x64": "1.0.4"
+ "@github/copilot-darwin-arm64": "1.0.10-0",
+ "@github/copilot-darwin-x64": "1.0.10-0",
+ "@github/copilot-linux-arm64": "1.0.10-0",
+ "@github/copilot-linux-x64": "1.0.10-0",
+ "@github/copilot-win32-arm64": "1.0.10-0",
+ "@github/copilot-win32-x64": "1.0.10-0"
}
},
"node_modules/@github/copilot-darwin-arm64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.4.tgz",
- "integrity": "sha512-/YGGhv6cp0ItolsF0HsLq2KmesA4atn0IEYApBs770fzJ8OP2pkOEzrxo3gWU3wc7fHF2uDB1RrJEZ7QSFLdEQ==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.10-0.tgz",
+ "integrity": "sha512-u5CbflcTpvc4E48E0jrqbN3Y5hWzValMs21RR6L+GDjQpPI2pvDeUWAJZ03Y7qQ2Uk3KZ+hOIJWJvje9VHxrDQ==",
"cpu": [
"arm64"
],
@@ -695,9 +695,9 @@
}
},
"node_modules/@github/copilot-darwin-x64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.4.tgz",
- "integrity": "sha512-gwn2QjZbc1SqPVSAtDMesU1NopyHZT8Qsn37xPfznpV9s94KVyX4TTiDZaUwfnI0wr8kVHBL46RPLNz6I8kR9A==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.10-0.tgz",
+ "integrity": "sha512-4y5OXhAfWX+il9slhrq7v8ONzq+Hpw46ktnz7l1fAZKdmn+dzmFVCvr6pJPr5Az78cAKBuN+Gt4eeSNaxuKCmA==",
"cpu": [
"x64"
],
@@ -711,9 +711,9 @@
}
},
"node_modules/@github/copilot-linux-arm64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.4.tgz",
- "integrity": "sha512-92vzHKxN55BpI76sP/5fXIXfat1gzAhsq4bNLqLENGfZyMP/25OiVihCZuQHnvxzXaHBITFGUvtxfdll2kbcng==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.10-0.tgz",
+ "integrity": "sha512-j+Z/ZahEIT5SCblUqOJ2+2glWeIIUPKXXFS5bbu5kFZ9Xyag37FBvTjyxDeB02dpSKKDD4xbMVjcijFbtyr1PA==",
"cpu": [
"arm64"
],
@@ -727,9 +727,9 @@
}
},
"node_modules/@github/copilot-linux-x64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.4.tgz",
- "integrity": "sha512-wQvpwf4/VMTnSmWyYzq07Xg18Vxg7aZ5NVkkXqlLTuXRASW0kvCCb5USEtXHHzR7E6rJztkhCjFRE1bZW8jAGw==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.10-0.tgz",
+ "integrity": "sha512-S8IfuiMZWwnFW1v0vOGHalPIXq/75kL/RpZCYd1sleQA/yztCNNjxH9tNpXsdZnhYrAgU/3hqseWq5hbz8xjxA==",
"cpu": [
"x64"
],
@@ -743,9 +743,9 @@
}
},
"node_modules/@github/copilot-win32-arm64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.4.tgz",
- "integrity": "sha512-zOvD/5GVxDf0ZdlTkK+m55Vs55xuHNmACX50ZO2N23ZGG2dmkdS4mkruL59XB5ISgrOfeqvnqrwTFHbmPZtLfw==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.10-0.tgz",
+ "integrity": "sha512-6HJErp91fLrwIkoXegLK8SXjHzLgbl9GF+QdOtUGqZ915UUfXcchef0tQjN8u35yNLEW82VnAmft/PJ9Ok2UhQ==",
"cpu": [
"arm64"
],
@@ -759,9 +759,9 @@
}
},
"node_modules/@github/copilot-win32-x64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.4.tgz",
- "integrity": "sha512-yQenHMdkV0b77mF6aLM60TuwtNZ592TluptVDF+80Sj2zPfCpLyvrRh2FCIHRtuwTy4BfxETh2hCFHef8E6IOw==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.10-0.tgz",
+ "integrity": "sha512-AQwZYHoarRACbmPUPmH7gPOEomTAtDusCn65ancI3BoWGj9fzAgZEZ5JSaR3N/VUoXWoEbSe+PcH380ZYwsPag==",
"cpu": [
"x64"
],
diff --git a/nodejs/package.json b/nodejs/package.json
index 6b0d30f2c..7d1822a9c 100644
--- a/nodejs/package.json
+++ b/nodejs/package.json
@@ -56,7 +56,7 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
- "@github/copilot": "^1.0.4",
+ "@github/copilot": "^1.0.10-0",
"vscode-jsonrpc": "^8.2.1",
"zod": "^4.3.6"
},
diff --git a/nodejs/samples/package-lock.json b/nodejs/samples/package-lock.json
index 4f93a271c..77daced15 100644
--- a/nodejs/samples/package-lock.json
+++ b/nodejs/samples/package-lock.json
@@ -18,7 +18,7 @@
"version": "0.1.8",
"license": "MIT",
"dependencies": {
- "@github/copilot": "^1.0.4",
+ "@github/copilot": "^1.0.10-0",
"vscode-jsonrpc": "^8.2.1",
"zod": "^4.3.6"
},
diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts
index 16907fdba..dadb9e79d 100644
--- a/nodejs/src/generated/rpc.ts
+++ b/nodejs/src/generated/rpc.ts
@@ -462,6 +462,302 @@ export interface SessionAgentDeselectParams {
sessionId: string;
}
+/** @experimental */
+export interface SessionAgentReloadResult {
+ /**
+ * Reloaded custom agents
+ */
+ agents: {
+ /**
+ * Unique identifier of the custom agent
+ */
+ name: string;
+ /**
+ * Human-readable display name
+ */
+ displayName: string;
+ /**
+ * Description of the agent's purpose
+ */
+ description: string;
+ }[];
+}
+
+/** @experimental */
+export interface SessionAgentReloadParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
+/** @experimental */
+export interface SessionSkillsListResult {
+ /**
+ * Available skills
+ */
+ 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;
+ }[];
+}
+
+/** @experimental */
+export interface SessionSkillsListParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
+/** @experimental */
+export interface SessionSkillsEnableResult {}
+
+/** @experimental */
+export interface SessionSkillsEnableParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Name of the skill to enable
+ */
+ name: string;
+}
+
+/** @experimental */
+export interface SessionSkillsDisableResult {}
+
+/** @experimental */
+export interface SessionSkillsDisableParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Name of the skill to disable
+ */
+ name: string;
+}
+
+/** @experimental */
+export interface SessionSkillsReloadResult {}
+
+/** @experimental */
+export interface SessionSkillsReloadParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
+/** @experimental */
+export interface SessionMcpListResult {
+ /**
+ * Configured MCP servers
+ */
+ servers: {
+ /**
+ * Server name (config key)
+ */
+ name: string;
+ /**
+ * Connection status: connected, failed, pending, disabled, or not_configured
+ */
+ status: "connected" | "failed" | "pending" | "disabled" | "not_configured";
+ /**
+ * Configuration source: user, workspace, plugin, or builtin
+ */
+ source?: string;
+ /**
+ * Error message if the server failed to connect
+ */
+ error?: string;
+ }[];
+}
+
+/** @experimental */
+export interface SessionMcpListParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
+/** @experimental */
+export interface SessionMcpEnableResult {}
+
+/** @experimental */
+export interface SessionMcpEnableParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Name of the MCP server to enable
+ */
+ serverName: string;
+}
+
+/** @experimental */
+export interface SessionMcpDisableResult {}
+
+/** @experimental */
+export interface SessionMcpDisableParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Name of the MCP server to disable
+ */
+ serverName: string;
+}
+
+/** @experimental */
+export interface SessionMcpReloadResult {}
+
+/** @experimental */
+export interface SessionMcpReloadParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
+/** @experimental */
+export interface SessionPluginsListResult {
+ /**
+ * Installed plugins
+ */
+ 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 SessionPluginsListParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
+/** @experimental */
+export interface SessionExtensionsListResult {
+ /**
+ * Discovered extensions and their current status
+ */
+ 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 SessionExtensionsListParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
+/** @experimental */
+export interface SessionExtensionsEnableResult {}
+
+/** @experimental */
+export interface SessionExtensionsEnableParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Source-qualified extension ID to enable
+ */
+ id: string;
+}
+
+/** @experimental */
+export interface SessionExtensionsDisableResult {}
+
+/** @experimental */
+export interface SessionExtensionsDisableParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Source-qualified extension ID to disable
+ */
+ id: string;
+}
+
+/** @experimental */
+export interface SessionExtensionsReloadResult {}
+
+/** @experimental */
+export interface SessionExtensionsReloadParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+}
+
/** @experimental */
export interface SessionCompactionCompactResult {
/**
@@ -512,6 +808,135 @@ export interface SessionToolsHandlePendingToolCallParams {
error?: string;
}
+export interface SessionCommandsHandlePendingCommandResult {
+ success: boolean;
+}
+
+export interface SessionCommandsHandlePendingCommandParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Request ID from the command invocation event
+ */
+ requestId: string;
+ /**
+ * Error message if the command handler failed
+ */
+ error?: string;
+}
+
+export interface SessionUiElicitationResult {
+ /**
+ * The user's response: accept (submitted), decline (rejected), or cancel (dismissed)
+ */
+ action: "accept" | "decline" | "cancel";
+ /**
+ * The form values submitted by the user (present when action is 'accept')
+ */
+ content?: {
+ [k: string]: string | number | boolean | string[];
+ };
+}
+
+export interface SessionUiElicitationParams {
+ /**
+ * Target session identifier
+ */
+ sessionId: string;
+ /**
+ * Message describing what information is needed from the user
+ */
+ message: 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]:
+ | {
+ type: "string";
+ title?: string;
+ description?: string;
+ enum: string[];
+ enumNames?: string[];
+ default?: string;
+ }
+ | {
+ type: "string";
+ title?: string;
+ description?: string;
+ oneOf: {
+ const: string;
+ title: string;
+ }[];
+ default?: string;
+ }
+ | {
+ type: "array";
+ title?: string;
+ description?: string;
+ minItems?: number;
+ maxItems?: number;
+ items: {
+ type: "string";
+ enum: string[];
+ };
+ default?: string[];
+ }
+ | {
+ type: "array";
+ title?: string;
+ description?: string;
+ minItems?: number;
+ maxItems?: number;
+ items: {
+ anyOf: {
+ const: string;
+ title: string;
+ }[];
+ };
+ default?: string[];
+ }
+ | {
+ type: "boolean";
+ title?: string;
+ description?: string;
+ default?: boolean;
+ }
+ | {
+ type: "string";
+ title?: string;
+ description?: string;
+ minLength?: number;
+ maxLength?: number;
+ format?: "email" | "uri" | "date" | "date-time";
+ default?: string;
+ }
+ | {
+ type: "number" | "integer";
+ title?: string;
+ description?: string;
+ minimum?: number;
+ maximum?: number;
+ default?: number;
+ };
+ };
+ /**
+ * List of required field names
+ */
+ required?: string[];
+ };
+}
+
export interface SessionPermissionsHandlePendingPermissionRequestResult {
/**
* Whether the permission request was handled successfully
@@ -571,6 +996,10 @@ export interface SessionLogParams {
* 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;
}
export interface SessionShellExecResult {
@@ -687,6 +1116,46 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin
connection.sendRequest("session.agent.select", { sessionId, ...params }),
deselect: async (): Promise =>
connection.sendRequest("session.agent.deselect", { sessionId }),
+ reload: async (): Promise =>
+ connection.sendRequest("session.agent.reload", { sessionId }),
+ },
+ /** @experimental */
+ skills: {
+ list: async (): Promise =>
+ connection.sendRequest("session.skills.list", { sessionId }),
+ enable: async (params: Omit): Promise =>
+ connection.sendRequest("session.skills.enable", { sessionId, ...params }),
+ disable: async (params: Omit): Promise =>
+ connection.sendRequest("session.skills.disable", { sessionId, ...params }),
+ reload: async (): Promise =>
+ connection.sendRequest("session.skills.reload", { sessionId }),
+ },
+ /** @experimental */
+ mcp: {
+ list: async (): Promise =>
+ connection.sendRequest("session.mcp.list", { sessionId }),
+ enable: async (params: Omit): Promise =>
+ connection.sendRequest("session.mcp.enable", { sessionId, ...params }),
+ disable: async (params: Omit): Promise =>
+ connection.sendRequest("session.mcp.disable", { sessionId, ...params }),
+ reload: async (): Promise =>
+ connection.sendRequest("session.mcp.reload", { sessionId }),
+ },
+ /** @experimental */
+ plugins: {
+ list: async (): Promise =>
+ connection.sendRequest("session.plugins.list", { sessionId }),
+ },
+ /** @experimental */
+ extensions: {
+ list: async (): Promise =>
+ connection.sendRequest("session.extensions.list", { sessionId }),
+ enable: async (params: Omit): Promise =>
+ connection.sendRequest("session.extensions.enable", { sessionId, ...params }),
+ disable: async (params: Omit): Promise =>
+ connection.sendRequest("session.extensions.disable", { sessionId, ...params }),
+ reload: async (): Promise =>
+ connection.sendRequest("session.extensions.reload", { sessionId }),
},
/** @experimental */
compaction: {
@@ -697,6 +1166,14 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin
handlePendingToolCall: async (params: Omit): Promise =>
connection.sendRequest("session.tools.handlePendingToolCall", { sessionId, ...params }),
},
+ commands: {
+ handlePendingCommand: async (params: Omit): Promise =>
+ connection.sendRequest("session.commands.handlePendingCommand", { sessionId, ...params }),
+ },
+ ui: {
+ elicitation: async (params: Omit): Promise =>
+ connection.sendRequest("session.ui.elicitation", { sessionId, ...params }),
+ },
permissions: {
handlePendingPermissionRequest: async (params: Omit): Promise =>
connection.sendRequest("session.permissions.handlePendingPermissionRequest", { sessionId, ...params }),
diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts
index e9d48bc57..9ad6d3c02 100644
--- a/nodejs/src/generated/session-events.ts
+++ b/nodejs/src/generated/session-events.ts
@@ -212,6 +212,10 @@ export type SessionEvent =
* 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;
};
}
| {
@@ -325,6 +329,10 @@ export type SessionEvent =
* 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;
};
}
| {
@@ -357,6 +365,10 @@ export type SessionEvent =
* 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;
};
}
| {
@@ -741,6 +753,22 @@ export type SessionEvent =
* 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;
};
}
| {
@@ -826,6 +854,22 @@ export type SessionEvent =
* 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;
};
}
| {
@@ -847,9 +891,22 @@ export type SessionEvent =
ephemeral?: boolean;
type: "session.compaction_start";
/**
- * Empty payload; the event signals that LLM-powered conversation compaction has begun
+ * Context window breakdown at the start of LLM-powered conversation compaction
*/
- data: {};
+ 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;
+ };
}
| {
/**
@@ -934,6 +991,18 @@ export type SessionEvent =
* 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;
};
}
| {
@@ -955,13 +1024,17 @@ export type SessionEvent =
ephemeral?: boolean;
type: "session.task_complete";
/**
- * Task completion notification with optional summary from the agent
+ * Task completion notification with summary from the agent
*/
data: {
/**
- * Optional summary of the completed task, provided by the agent
+ * 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;
};
}
| {
@@ -982,9 +1055,6 @@ export type SessionEvent =
*/
ephemeral?: boolean;
type: "user.message";
- /**
- * User message content with optional attachments, source information, and interaction metadata
- */
data: {
/**
* The user's message text as displayed in the timeline
@@ -1134,19 +1204,9 @@ export type SessionEvent =
}
)[];
/**
- * Origin of this message, used for timeline filtering and telemetry (e.g., "user", "autopilot", "skill", or "command")
+ * Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user)
*/
- source?:
- | "user"
- | "autopilot"
- | "skill"
- | "system"
- | "command"
- | "immediate-prompt"
- | "jit-instruction"
- | "snippy-blocking"
- | "thinking-exhausted-continuation"
- | "other";
+ source?: string;
/**
* The agent mode that was active when this message was sent
*/
@@ -2434,6 +2494,21 @@ export type SessionEvent =
*/
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";
/**
@@ -2785,6 +2860,10 @@ export type SessionEvent =
* 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;
};
}
| {
@@ -2828,25 +2907,33 @@ export type SessionEvent =
ephemeral: true;
type: "elicitation.requested";
/**
- * Structured form elicitation request with JSON schema definition for form fields
+ * 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; currently only "form" is supported. Defaults to "form" when absent.
+ * Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent.
*/
- mode?: "form";
+ mode?: "form" | "url";
/**
- * JSON Schema describing the form fields to present to the user
+ * JSON Schema describing the form fields to present to the user (form mode only)
*/
- requestedSchema: {
+ requestedSchema?: {
/**
* Schema type indicator (always 'object')
*/
@@ -2862,6 +2949,10 @@ export type SessionEvent =
*/
required?: string[];
};
+ /**
+ * URL to open in the user's browser (url mode only)
+ */
+ url?: string;
[k: string]: unknown;
};
}
@@ -2890,6 +2981,77 @@ export type SessionEvent =
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;
+ 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;
+ 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
@@ -2995,6 +3157,43 @@ export type SessionEvent =
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;
+ 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
@@ -3020,6 +3219,34 @@ export type SessionEvent =
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;
+ 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
@@ -3121,4 +3348,155 @@ export type SessionEvent =
ephemeral: true;
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;
+ 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;
+ type: "session.mcp_servers_loaded";
+ data: {
+ /**
+ * Array of MCP server status summaries
+ */
+ servers: {
+ /**
+ * Server name (config key)
+ */
+ name: string;
+ /**
+ * Connection status: connected, failed, pending, disabled, or not_configured
+ */
+ status: "connected" | "failed" | "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;
+ type: "session.mcp_server_status_changed";
+ data: {
+ /**
+ * Name of the MCP server whose status changed
+ */
+ serverName: string;
+ /**
+ * New connection status: connected, failed, pending, disabled, or not_configured
+ */
+ status: "connected" | "failed" | "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;
+ 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";
+ }[];
+ };
};
diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py
index da6748d79..14ae307d7 100644
--- a/python/copilot/generated/rpc.py
+++ b/python/copilot/generated/rpc.py
@@ -74,6 +74,11 @@ def to_enum(c: type[EnumT], x: Any) -> EnumT:
return x.value
+def from_int(x: Any) -> int:
+ assert isinstance(x, int) and not isinstance(x, bool)
+ return x
+
+
@dataclass
class PingResult:
message: str
@@ -762,7 +767,7 @@ def to_dict(self) -> dict:
@dataclass
-class AgentElement:
+class SessionAgentListResultAgent:
description: str
"""Description of the agent's purpose"""
@@ -773,12 +778,12 @@ class AgentElement:
"""Unique identifier of the custom agent"""
@staticmethod
- def from_dict(obj: Any) -> 'AgentElement':
+ def from_dict(obj: Any) -> 'SessionAgentListResultAgent':
assert isinstance(obj, dict)
description = from_str(obj.get("description"))
display_name = from_str(obj.get("displayName"))
name = from_str(obj.get("name"))
- return AgentElement(description, display_name, name)
+ return SessionAgentListResultAgent(description, display_name, name)
def to_dict(self) -> dict:
result: dict = {}
@@ -791,18 +796,18 @@ def to_dict(self) -> dict:
# Experimental: this type is part of an experimental API and may change or be removed.
@dataclass
class SessionAgentListResult:
- agents: list[AgentElement]
+ agents: list[SessionAgentListResultAgent]
"""Available custom agents"""
@staticmethod
def from_dict(obj: Any) -> 'SessionAgentListResult':
assert isinstance(obj, dict)
- agents = from_list(AgentElement.from_dict, obj.get("agents"))
+ agents = from_list(SessionAgentListResultAgent.from_dict, obj.get("agents"))
return SessionAgentListResult(agents)
def to_dict(self) -> dict:
result: dict = {}
- result["agents"] = from_list(lambda x: to_class(AgentElement, x), self.agents)
+ result["agents"] = from_list(lambda x: to_class(SessionAgentListResultAgent, x), self.agents)
return result
@@ -929,334 +934,1129 @@ def to_dict(self) -> dict:
return result
-# Experimental: this type is part of an experimental API and may change or be removed.
@dataclass
-class SessionCompactionCompactResult:
- messages_removed: float
- """Number of messages removed during compaction"""
+class SessionAgentReloadResultAgent:
+ description: str
+ """Description of the agent's purpose"""
- success: bool
- """Whether compaction completed successfully"""
+ display_name: str
+ """Human-readable display name"""
- tokens_removed: float
- """Number of tokens freed by compaction"""
+ name: str
+ """Unique identifier of the custom agent"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionCompactionCompactResult':
+ def from_dict(obj: Any) -> 'SessionAgentReloadResultAgent':
assert isinstance(obj, dict)
- messages_removed = from_float(obj.get("messagesRemoved"))
- success = from_bool(obj.get("success"))
- tokens_removed = from_float(obj.get("tokensRemoved"))
- return SessionCompactionCompactResult(messages_removed, success, tokens_removed)
+ description = from_str(obj.get("description"))
+ display_name = from_str(obj.get("displayName"))
+ name = from_str(obj.get("name"))
+ return SessionAgentReloadResultAgent(description, display_name, name)
def to_dict(self) -> dict:
result: dict = {}
- result["messagesRemoved"] = to_float(self.messages_removed)
- result["success"] = from_bool(self.success)
- result["tokensRemoved"] = to_float(self.tokens_removed)
+ 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 SessionToolsHandlePendingToolCallResult:
- success: bool
- """Whether the tool call result was handled successfully"""
+class SessionAgentReloadResult:
+ agents: list[SessionAgentReloadResultAgent]
+ """Reloaded custom agents"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionToolsHandlePendingToolCallResult':
+ def from_dict(obj: Any) -> 'SessionAgentReloadResult':
assert isinstance(obj, dict)
- success = from_bool(obj.get("success"))
- return SessionToolsHandlePendingToolCallResult(success)
+ agents = from_list(SessionAgentReloadResultAgent.from_dict, obj.get("agents"))
+ return SessionAgentReloadResult(agents)
def to_dict(self) -> dict:
result: dict = {}
- result["success"] = from_bool(self.success)
+ result["agents"] = from_list(lambda x: to_class(SessionAgentReloadResultAgent, x), self.agents)
return result
@dataclass
-class ResultResult:
- text_result_for_llm: str
- error: str | None = None
- result_type: str | None = None
- tool_telemetry: dict[str, Any] | None = None
+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"""
+
+ source: str
+ """Source location type (e.g., project, personal, plugin)"""
+
+ 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"""
@staticmethod
- def from_dict(obj: Any) -> 'ResultResult':
+ def from_dict(obj: Any) -> 'Skill':
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 ResultResult(text_result_for_llm, error, result_type, tool_telemetry)
+ 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["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["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
+# Experimental: this type is part of an experimental API and may change or be removed.
@dataclass
-class SessionToolsHandlePendingToolCallParams:
- request_id: str
- error: str | None = None
- result: ResultResult | str | None = None
+class SessionSkillsListResult:
+ skills: list[Skill]
+ """Available skills"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionToolsHandlePendingToolCallParams':
+ def from_dict(obj: Any) -> 'SessionSkillsListResult':
assert isinstance(obj, dict)
- request_id = from_str(obj.get("requestId"))
- error = from_union([from_str, from_none], obj.get("error"))
- result = from_union([ResultResult.from_dict, from_str, from_none], obj.get("result"))
- return SessionToolsHandlePendingToolCallParams(request_id, error, result)
+ skills = from_list(Skill.from_dict, obj.get("skills"))
+ return SessionSkillsListResult(skills)
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(ResultResult, x), from_str, from_none], self.result)
+ 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 SessionPermissionsHandlePendingPermissionRequestResult:
- success: bool
- """Whether the permission request was handled successfully"""
-
+class SessionSkillsEnableResult:
@staticmethod
- def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestResult':
+ def from_dict(obj: Any) -> 'SessionSkillsEnableResult':
assert isinstance(obj, dict)
- success = from_bool(obj.get("success"))
- return SessionPermissionsHandlePendingPermissionRequestResult(success)
+ return SessionSkillsEnableResult()
def to_dict(self) -> dict:
result: dict = {}
- result["success"] = from_bool(self.success)
return result
-class Kind(Enum):
- APPROVED = "approved"
- DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy"
- 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"
+# Experimental: this type is part of an experimental API and may change or be removed.
+@dataclass
+class SessionSkillsEnableParams:
+ name: str
+ """Name of the skill to enable"""
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionSkillsEnableParams':
+ assert isinstance(obj, dict)
+ name = from_str(obj.get("name"))
+ return SessionSkillsEnableParams(name)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["name"] = from_str(self.name)
+ return result
-@dataclass
-class SessionPermissionsHandlePendingPermissionRequestParamsResult:
- kind: Kind
- rules: list[Any] | None = None
- feedback: str | None = None
- message: str | None = None
- path: str | None = None
+# Experimental: this type is part of an experimental API and may change or be removed.
+@dataclass
+class SessionSkillsDisableResult:
@staticmethod
- def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestParamsResult':
+ def from_dict(obj: Any) -> 'SessionSkillsDisableResult':
assert isinstance(obj, dict)
- kind = Kind(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"))
- path = from_union([from_str, from_none], obj.get("path"))
- return SessionPermissionsHandlePendingPermissionRequestParamsResult(kind, rules, feedback, message, path)
+ return SessionSkillsDisableResult()
def to_dict(self) -> dict:
result: dict = {}
- result["kind"] = to_enum(Kind, 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:
- result["feedback"] = from_union([from_str, from_none], self.feedback)
- if self.message is not None:
- result["message"] = from_union([from_str, from_none], self.message)
- if self.path is not None:
- result["path"] = from_union([from_str, from_none], self.path)
return result
+# Experimental: this type is part of an experimental API and may change or be removed.
@dataclass
-class SessionPermissionsHandlePendingPermissionRequestParams:
- request_id: str
- result: SessionPermissionsHandlePendingPermissionRequestParamsResult
+class SessionSkillsDisableParams:
+ name: str
+ """Name of the skill to disable"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestParams':
+ def from_dict(obj: Any) -> 'SessionSkillsDisableParams':
assert isinstance(obj, dict)
- request_id = from_str(obj.get("requestId"))
- result = SessionPermissionsHandlePendingPermissionRequestParamsResult.from_dict(obj.get("result"))
- return SessionPermissionsHandlePendingPermissionRequestParams(request_id, result)
+ name = from_str(obj.get("name"))
+ return SessionSkillsDisableParams(name)
def to_dict(self) -> dict:
result: dict = {}
- result["requestId"] = from_str(self.request_id)
- result["result"] = to_class(SessionPermissionsHandlePendingPermissionRequestParamsResult, self.result)
+ 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 SessionLogResult:
- event_id: UUID
- """The unique identifier of the emitted session event"""
-
+class SessionSkillsReloadResult:
@staticmethod
- def from_dict(obj: Any) -> 'SessionLogResult':
+ def from_dict(obj: Any) -> 'SessionSkillsReloadResult':
assert isinstance(obj, dict)
- event_id = UUID(obj.get("eventId"))
- return SessionLogResult(event_id)
+ return SessionSkillsReloadResult()
def to_dict(self) -> dict:
result: dict = {}
- result["eventId"] = str(self.event_id)
return result
-class Level(Enum):
- """Log severity level. Determines how the message is displayed in the timeline. Defaults to
- "info".
- """
- ERROR = "error"
- INFO = "info"
- WARNING = "warning"
+class ServerStatus(Enum):
+ """Connection status: connected, failed, pending, disabled, or not_configured"""
+
+ CONNECTED = "connected"
+ DISABLED = "disabled"
+ FAILED = "failed"
+ NOT_CONFIGURED = "not_configured"
+ PENDING = "pending"
@dataclass
-class SessionLogParams:
- message: str
- """Human-readable message"""
+class Server:
+ name: str
+ """Server name (config key)"""
- ephemeral: bool | None = None
- """When true, the message is transient and not persisted to the session event log on disk"""
+ status: ServerStatus
+ """Connection status: connected, failed, pending, disabled, or not_configured"""
- level: Level | None = None
- """Log severity level. Determines how the message is displayed in the timeline. Defaults to
- "info".
- """
+ error: str | None = None
+ """Error message if the server failed to connect"""
+
+ source: str | None = None
+ """Configuration source: user, workspace, plugin, or builtin"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionLogParams':
+ def from_dict(obj: Any) -> 'Server':
assert isinstance(obj, dict)
- message = from_str(obj.get("message"))
- ephemeral = from_union([from_bool, from_none], obj.get("ephemeral"))
- level = from_union([Level, from_none], obj.get("level"))
- return SessionLogParams(message, ephemeral, level)
+ name = from_str(obj.get("name"))
+ status = ServerStatus(obj.get("status"))
+ error = from_union([from_str, from_none], obj.get("error"))
+ source = from_union([from_str, from_none], obj.get("source"))
+ return Server(name, status, error, source)
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(Level, x), from_none], self.level)
+ result["name"] = from_str(self.name)
+ result["status"] = to_enum(ServerStatus, self.status)
+ if self.error is not None:
+ result["error"] = from_union([from_str, from_none], self.error)
+ if self.source is not None:
+ result["source"] = from_union([from_str, from_none], self.source)
return result
@dataclass
-class SessionShellExecResult:
- process_id: str
- """Unique identifier for tracking streamed output"""
+class SessionMCPListResult:
+ servers: list[Server]
+ """Configured MCP servers"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionShellExecResult':
+ def from_dict(obj: Any) -> 'SessionMCPListResult':
assert isinstance(obj, dict)
- process_id = from_str(obj.get("processId"))
- return SessionShellExecResult(process_id)
+ servers = from_list(Server.from_dict, obj.get("servers"))
+ return SessionMCPListResult(servers)
def to_dict(self) -> dict:
result: dict = {}
- result["processId"] = from_str(self.process_id)
+ result["servers"] = from_list(lambda x: to_class(Server, x), self.servers)
return result
@dataclass
-class SessionShellExecParams:
- command: str
- """Shell command to execute"""
-
- cwd: str | None = None
- """Working directory (defaults to session working directory)"""
-
- timeout: float | None = None
- """Timeout in milliseconds (default: 30000)"""
-
+class SessionMCPEnableResult:
@staticmethod
- def from_dict(obj: Any) -> 'SessionShellExecParams':
+ def from_dict(obj: Any) -> 'SessionMCPEnableResult':
assert isinstance(obj, dict)
- command = from_str(obj.get("command"))
- cwd = from_union([from_str, from_none], obj.get("cwd"))
- timeout = from_union([from_float, from_none], obj.get("timeout"))
- return SessionShellExecParams(command, cwd, timeout)
+ return SessionMCPEnableResult()
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([to_float, from_none], self.timeout)
return result
@dataclass
-class SessionShellKillResult:
- killed: bool
- """Whether the signal was sent successfully"""
+class SessionMCPEnableParams:
+ server_name: str
+ """Name of the MCP server to enable"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionShellKillResult':
+ def from_dict(obj: Any) -> 'SessionMCPEnableParams':
assert isinstance(obj, dict)
- killed = from_bool(obj.get("killed"))
- return SessionShellKillResult(killed)
+ server_name = from_str(obj.get("serverName"))
+ return SessionMCPEnableParams(server_name)
def to_dict(self) -> dict:
result: dict = {}
- result["killed"] = from_bool(self.killed)
+ result["serverName"] = from_str(self.server_name)
return result
-class Signal(Enum):
- """Signal to send (default: SIGTERM)"""
+@dataclass
+class SessionMCPDisableResult:
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionMCPDisableResult':
+ assert isinstance(obj, dict)
+ return SessionMCPDisableResult()
- SIGINT = "SIGINT"
- SIGKILL = "SIGKILL"
- SIGTERM = "SIGTERM"
+ def to_dict(self) -> dict:
+ result: dict = {}
+ return result
@dataclass
-class SessionShellKillParams:
- process_id: str
- """Process identifier returned by shell.exec"""
-
- signal: Signal | None = None
- """Signal to send (default: SIGTERM)"""
+class SessionMCPDisableParams:
+ server_name: str
+ """Name of the MCP server to disable"""
@staticmethod
- def from_dict(obj: Any) -> 'SessionShellKillParams':
+ def from_dict(obj: Any) -> 'SessionMCPDisableParams':
assert isinstance(obj, dict)
- process_id = from_str(obj.get("processId"))
- signal = from_union([Signal, from_none], obj.get("signal"))
- return SessionShellKillParams(process_id, signal)
+ server_name = from_str(obj.get("serverName"))
+ return SessionMCPDisableParams(server_name)
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(Signal, x), from_none], self.signal)
+ result["serverName"] = from_str(self.server_name)
return result
-def ping_result_from_dict(s: Any) -> PingResult:
- return PingResult.from_dict(s)
-
-
+@dataclass
+class SessionMCPReloadResult:
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionMCPReloadResult':
+ assert isinstance(obj, dict)
+ return SessionMCPReloadResult()
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ return result
+
+
+@dataclass
+class Plugin:
+ enabled: bool
+ """Whether the plugin is currently enabled"""
+
+ marketplace: str
+ """Marketplace the plugin came from"""
+
+ name: str
+ """Plugin name"""
+
+ version: str | None = None
+ """Installed version"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Plugin':
+ 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)
+
+ 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)
+ return result
+
+
+# Experimental: this type is part of an experimental API and may change or be removed.
+@dataclass
+class SessionPluginsListResult:
+ plugins: list[Plugin]
+ """Installed plugins"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionPluginsListResult':
+ assert isinstance(obj, dict)
+ plugins = from_list(Plugin.from_dict, obj.get("plugins"))
+ return SessionPluginsListResult(plugins)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["plugins"] = from_list(lambda x: to_class(Plugin, x), self.plugins)
+ return result
+
+
+class Source(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"
+
+
+@dataclass
+class Extension:
+ id: str
+ """Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper')"""
+
+ name: str
+ """Extension name (directory name)"""
+
+ source: Source
+ """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)"""
+
+ status: ExtensionStatus
+ """Current status: running, disabled, failed, or starting"""
+
+ pid: int | None = None
+ """Process ID if the extension is running"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Extension':
+ assert isinstance(obj, dict)
+ id = from_str(obj.get("id"))
+ name = from_str(obj.get("name"))
+ source = Source(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["id"] = from_str(self.id)
+ result["name"] = from_str(self.name)
+ result["source"] = to_enum(Source, 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 SessionExtensionsListResult:
+ extensions: list[Extension]
+ """Discovered extensions and their current status"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionExtensionsListResult':
+ assert isinstance(obj, dict)
+ extensions = from_list(Extension.from_dict, obj.get("extensions"))
+ return SessionExtensionsListResult(extensions)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["extensions"] = from_list(lambda x: to_class(Extension, x), self.extensions)
+ return result
+
+
+# Experimental: this type is part of an experimental API and may change or be removed.
+@dataclass
+class SessionExtensionsEnableResult:
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionExtensionsEnableResult':
+ assert isinstance(obj, dict)
+ return SessionExtensionsEnableResult()
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ return result
+
+
+# Experimental: this type is part of an experimental API and may change or be removed.
+@dataclass
+class SessionExtensionsEnableParams:
+ id: str
+ """Source-qualified extension ID to enable"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionExtensionsEnableParams':
+ assert isinstance(obj, dict)
+ id = from_str(obj.get("id"))
+ return SessionExtensionsEnableParams(id)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ 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 SessionExtensionsDisableResult:
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionExtensionsDisableResult':
+ assert isinstance(obj, dict)
+ return SessionExtensionsDisableResult()
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ return result
+
+
+# Experimental: this type is part of an experimental API and may change or be removed.
+@dataclass
+class SessionExtensionsDisableParams:
+ id: str
+ """Source-qualified extension ID to disable"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionExtensionsDisableParams':
+ assert isinstance(obj, dict)
+ id = from_str(obj.get("id"))
+ return SessionExtensionsDisableParams(id)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ 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 SessionExtensionsReloadResult:
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionExtensionsReloadResult':
+ assert isinstance(obj, dict)
+ return SessionExtensionsReloadResult()
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ return result
+
+
+# Experimental: this type is part of an experimental API and may change or be removed.
+@dataclass
+class SessionCompactionCompactResult:
+ messages_removed: float
+ """Number of messages removed during compaction"""
+
+ success: bool
+ """Whether compaction completed successfully"""
+
+ tokens_removed: float
+ """Number of tokens freed by compaction"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionCompactionCompactResult':
+ assert isinstance(obj, dict)
+ messages_removed = from_float(obj.get("messagesRemoved"))
+ success = from_bool(obj.get("success"))
+ tokens_removed = from_float(obj.get("tokensRemoved"))
+ return SessionCompactionCompactResult(messages_removed, success, tokens_removed)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["messagesRemoved"] = to_float(self.messages_removed)
+ result["success"] = from_bool(self.success)
+ result["tokensRemoved"] = to_float(self.tokens_removed)
+ return result
+
+
+@dataclass
+class SessionToolsHandlePendingToolCallResult:
+ success: bool
+ """Whether the tool call result was handled successfully"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionToolsHandlePendingToolCallResult':
+ assert isinstance(obj, dict)
+ success = from_bool(obj.get("success"))
+ return SessionToolsHandlePendingToolCallResult(success)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["success"] = from_bool(self.success)
+ return result
+
+
+@dataclass
+class ResultResult:
+ text_result_for_llm: str
+ error: str | None = None
+ result_type: str | None = None
+ tool_telemetry: dict[str, Any] | None = None
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'ResultResult':
+ 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 ResultResult(text_result_for_llm, error, result_type, tool_telemetry)
+
+ 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)
+ return result
+
+
+@dataclass
+class SessionToolsHandlePendingToolCallParams:
+ request_id: str
+ error: str | None = None
+ result: ResultResult | str | None = None
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionToolsHandlePendingToolCallParams':
+ assert isinstance(obj, dict)
+ request_id = from_str(obj.get("requestId"))
+ error = from_union([from_str, from_none], obj.get("error"))
+ result = from_union([ResultResult.from_dict, from_str, from_none], obj.get("result"))
+ return SessionToolsHandlePendingToolCallParams(request_id, error, result)
+
+ 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(ResultResult, x), from_str, from_none], self.result)
+ return result
+
+
+@dataclass
+class SessionCommandsHandlePendingCommandResult:
+ success: bool
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionCommandsHandlePendingCommandResult':
+ assert isinstance(obj, dict)
+ success = from_bool(obj.get("success"))
+ return SessionCommandsHandlePendingCommandResult(success)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["success"] = from_bool(self.success)
+ return result
+
+
+@dataclass
+class SessionCommandsHandlePendingCommandParams:
+ 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) -> 'SessionCommandsHandlePendingCommandParams':
+ assert isinstance(obj, dict)
+ request_id = from_str(obj.get("requestId"))
+ error = from_union([from_str, from_none], obj.get("error"))
+ return SessionCommandsHandlePendingCommandParams(request_id, error)
+
+ 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)
+ return result
+
+
+class Action(Enum):
+ """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)"""
+
+ ACCEPT = "accept"
+ CANCEL = "cancel"
+ DECLINE = "decline"
+
+
+@dataclass
+class SessionUIElicitationResult:
+ action: Action
+ """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)"""
+
+ 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) -> 'SessionUIElicitationResult':
+ assert isinstance(obj, dict)
+ action = Action(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 SessionUIElicitationResult(action, content)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["action"] = to_enum(Action, 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
+
+
+class Format(Enum):
+ DATE = "date"
+ DATE_TIME = "date-time"
+ EMAIL = "email"
+ URI = "uri"
+
+
+@dataclass
+class AnyOf:
+ const: str
+ title: str
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'AnyOf':
+ assert isinstance(obj, dict)
+ const = from_str(obj.get("const"))
+ title = from_str(obj.get("title"))
+ return AnyOf(const, title)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["const"] = from_str(self.const)
+ result["title"] = from_str(self.title)
+ return result
+
+
+class ItemsType(Enum):
+ STRING = "string"
+
+
+@dataclass
+class Items:
+ enum: list[str] | None = None
+ type: ItemsType | None = None
+ any_of: list[AnyOf] | None = None
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Items':
+ assert isinstance(obj, dict)
+ enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum"))
+ type = from_union([ItemsType, from_none], obj.get("type"))
+ any_of = from_union([lambda x: from_list(AnyOf.from_dict, x), from_none], obj.get("anyOf"))
+ return Items(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(ItemsType, x), from_none], self.type)
+ if self.any_of is not None:
+ result["anyOf"] = from_union([lambda x: from_list(lambda x: to_class(AnyOf, x), x), from_none], self.any_of)
+ return result
+
+
+@dataclass
+class OneOf:
+ const: str
+ title: str
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'OneOf':
+ assert isinstance(obj, dict)
+ const = from_str(obj.get("const"))
+ title = from_str(obj.get("title"))
+ return OneOf(const, title)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["const"] = from_str(self.const)
+ result["title"] = from_str(self.title)
+ return result
+
+
+class PropertyType(Enum):
+ ARRAY = "array"
+ BOOLEAN = "boolean"
+ INTEGER = "integer"
+ NUMBER = "number"
+ STRING = "string"
+
+
+@dataclass
+class Property:
+ type: PropertyType
+ 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[OneOf] | None = None
+ items: Items | None = None
+ max_items: float | None = None
+ min_items: float | None = None
+ format: Format | None = None
+ max_length: float | None = None
+ min_length: float | None = None
+ maximum: float | None = None
+ minimum: float | None = None
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Property':
+ assert isinstance(obj, dict)
+ type = PropertyType(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(OneOf.from_dict, x), from_none], obj.get("oneOf"))
+ items = from_union([Items.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"))
+ format = from_union([Format, 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"))
+ maximum = from_union([from_float, from_none], obj.get("maximum"))
+ minimum = from_union([from_float, from_none], obj.get("minimum"))
+ return Property(type, default, description, enum, enum_names, title, one_of, items, max_items, min_items, format, max_length, min_length, maximum, minimum)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["type"] = to_enum(PropertyType, 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:
+ result["description"] = from_union([from_str, from_none], self.description)
+ if self.enum is not None:
+ result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum)
+ 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)
+ if self.one_of is not None:
+ result["oneOf"] = from_union([lambda x: from_list(lambda x: to_class(OneOf, x), x), from_none], self.one_of)
+ if self.items is not None:
+ result["items"] = from_union([lambda x: to_class(Items, x), from_none], self.items)
+ 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.format is not None:
+ result["format"] = from_union([lambda x: to_enum(Format, 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.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)
+ return result
+
+
+class RequestedSchemaType(Enum):
+ OBJECT = "object"
+
+
+@dataclass
+class RequestedSchema:
+ """JSON Schema describing the form fields to present to the user"""
+
+ properties: dict[str, Property]
+ """Form field definitions, keyed by field name"""
+
+ type: RequestedSchemaType
+ """Schema type indicator (always 'object')"""
+
+ required: list[str] | None = None
+ """List of required field names"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'RequestedSchema':
+ assert isinstance(obj, dict)
+ properties = from_dict(Property.from_dict, obj.get("properties"))
+ type = RequestedSchemaType(obj.get("type"))
+ required = from_union([lambda x: from_list(from_str, x), from_none], obj.get("required"))
+ return RequestedSchema(properties, type, required)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["properties"] = from_dict(lambda x: to_class(Property, x), self.properties)
+ result["type"] = to_enum(RequestedSchemaType, 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
+
+
+@dataclass
+class SessionUIElicitationParams:
+ message: str
+ """Message describing what information is needed from the user"""
+
+ requested_schema: RequestedSchema
+ """JSON Schema describing the form fields to present to the user"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionUIElicitationParams':
+ assert isinstance(obj, dict)
+ message = from_str(obj.get("message"))
+ requested_schema = RequestedSchema.from_dict(obj.get("requestedSchema"))
+ return SessionUIElicitationParams(message, requested_schema)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["message"] = from_str(self.message)
+ result["requestedSchema"] = to_class(RequestedSchema, self.requested_schema)
+ return result
+
+
+@dataclass
+class SessionPermissionsHandlePendingPermissionRequestResult:
+ success: bool
+ """Whether the permission request was handled successfully"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestResult':
+ assert isinstance(obj, dict)
+ success = from_bool(obj.get("success"))
+ return SessionPermissionsHandlePendingPermissionRequestResult(success)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["success"] = from_bool(self.success)
+ return result
+
+
+class Kind(Enum):
+ APPROVED = "approved"
+ DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy"
+ 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 SessionPermissionsHandlePendingPermissionRequestParamsResult:
+ kind: Kind
+ rules: list[Any] | None = None
+ feedback: str | None = None
+ message: str | None = None
+ path: str | None = None
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestParamsResult':
+ assert isinstance(obj, dict)
+ kind = Kind(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"))
+ path = from_union([from_str, from_none], obj.get("path"))
+ return SessionPermissionsHandlePendingPermissionRequestParamsResult(kind, rules, feedback, message, path)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["kind"] = to_enum(Kind, 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:
+ result["feedback"] = from_union([from_str, from_none], self.feedback)
+ if self.message is not None:
+ result["message"] = from_union([from_str, from_none], self.message)
+ if self.path is not None:
+ result["path"] = from_union([from_str, from_none], self.path)
+ return result
+
+
+@dataclass
+class SessionPermissionsHandlePendingPermissionRequestParams:
+ request_id: str
+ result: SessionPermissionsHandlePendingPermissionRequestParamsResult
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestParams':
+ assert isinstance(obj, dict)
+ request_id = from_str(obj.get("requestId"))
+ result = SessionPermissionsHandlePendingPermissionRequestParamsResult.from_dict(obj.get("result"))
+ return SessionPermissionsHandlePendingPermissionRequestParams(request_id, result)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["requestId"] = from_str(self.request_id)
+ result["result"] = to_class(SessionPermissionsHandlePendingPermissionRequestParamsResult, self.result)
+ return result
+
+
+@dataclass
+class SessionLogResult:
+ event_id: UUID
+ """The unique identifier of the emitted session event"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionLogResult':
+ assert isinstance(obj, dict)
+ event_id = UUID(obj.get("eventId"))
+ return SessionLogResult(event_id)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["eventId"] = str(self.event_id)
+ return result
+
+
+class Level(Enum):
+ """Log severity level. Determines how the message is displayed in the timeline. Defaults to
+ "info".
+ """
+ ERROR = "error"
+ INFO = "info"
+ WARNING = "warning"
+
+
+@dataclass
+class SessionLogParams:
+ message: str
+ """Human-readable message"""
+
+ ephemeral: bool | None = None
+ """When true, the message is transient and not persisted to the session event log on disk"""
+
+ level: Level | 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) -> 'SessionLogParams':
+ assert isinstance(obj, dict)
+ message = from_str(obj.get("message"))
+ ephemeral = from_union([from_bool, from_none], obj.get("ephemeral"))
+ level = from_union([Level, from_none], obj.get("level"))
+ url = from_union([from_str, from_none], obj.get("url"))
+ return SessionLogParams(message, ephemeral, level, url)
+
+ 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(Level, 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 SessionShellExecResult:
+ process_id: str
+ """Unique identifier for tracking streamed output"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionShellExecResult':
+ assert isinstance(obj, dict)
+ process_id = from_str(obj.get("processId"))
+ return SessionShellExecResult(process_id)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["processId"] = from_str(self.process_id)
+ return result
+
+
+@dataclass
+class SessionShellExecParams:
+ command: str
+ """Shell command to execute"""
+
+ cwd: str | None = None
+ """Working directory (defaults to session working directory)"""
+
+ timeout: float | None = None
+ """Timeout in milliseconds (default: 30000)"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionShellExecParams':
+ assert isinstance(obj, dict)
+ command = from_str(obj.get("command"))
+ cwd = from_union([from_str, from_none], obj.get("cwd"))
+ timeout = from_union([from_float, from_none], obj.get("timeout"))
+ return SessionShellExecParams(command, cwd, timeout)
+
+ 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([to_float, from_none], self.timeout)
+ return result
+
+
+@dataclass
+class SessionShellKillResult:
+ killed: bool
+ """Whether the signal was sent successfully"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionShellKillResult':
+ assert isinstance(obj, dict)
+ killed = from_bool(obj.get("killed"))
+ return SessionShellKillResult(killed)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["killed"] = from_bool(self.killed)
+ return result
+
+
+class Signal(Enum):
+ """Signal to send (default: SIGTERM)"""
+
+ SIGINT = "SIGINT"
+ SIGKILL = "SIGKILL"
+ SIGTERM = "SIGTERM"
+
+
+@dataclass
+class SessionShellKillParams:
+ process_id: str
+ """Process identifier returned by shell.exec"""
+
+ signal: Signal | None = None
+ """Signal to send (default: SIGTERM)"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'SessionShellKillParams':
+ assert isinstance(obj, dict)
+ process_id = from_str(obj.get("processId"))
+ signal = from_union([Signal, from_none], obj.get("signal"))
+ return SessionShellKillParams(process_id, signal)
+
+ 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(Signal, x), from_none], self.signal)
+ return result
+
+
+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)
@@ -1477,6 +2277,166 @@ def session_agent_deselect_result_to_dict(x: SessionAgentDeselectResult) -> Any:
return to_class(SessionAgentDeselectResult, x)
+def session_agent_reload_result_from_dict(s: Any) -> SessionAgentReloadResult:
+ return SessionAgentReloadResult.from_dict(s)
+
+
+def session_agent_reload_result_to_dict(x: SessionAgentReloadResult) -> Any:
+ return to_class(SessionAgentReloadResult, x)
+
+
+def session_skills_list_result_from_dict(s: Any) -> SessionSkillsListResult:
+ return SessionSkillsListResult.from_dict(s)
+
+
+def session_skills_list_result_to_dict(x: SessionSkillsListResult) -> Any:
+ return to_class(SessionSkillsListResult, x)
+
+
+def session_skills_enable_result_from_dict(s: Any) -> SessionSkillsEnableResult:
+ return SessionSkillsEnableResult.from_dict(s)
+
+
+def session_skills_enable_result_to_dict(x: SessionSkillsEnableResult) -> Any:
+ return to_class(SessionSkillsEnableResult, x)
+
+
+def session_skills_enable_params_from_dict(s: Any) -> SessionSkillsEnableParams:
+ return SessionSkillsEnableParams.from_dict(s)
+
+
+def session_skills_enable_params_to_dict(x: SessionSkillsEnableParams) -> Any:
+ return to_class(SessionSkillsEnableParams, x)
+
+
+def session_skills_disable_result_from_dict(s: Any) -> SessionSkillsDisableResult:
+ return SessionSkillsDisableResult.from_dict(s)
+
+
+def session_skills_disable_result_to_dict(x: SessionSkillsDisableResult) -> Any:
+ return to_class(SessionSkillsDisableResult, x)
+
+
+def session_skills_disable_params_from_dict(s: Any) -> SessionSkillsDisableParams:
+ return SessionSkillsDisableParams.from_dict(s)
+
+
+def session_skills_disable_params_to_dict(x: SessionSkillsDisableParams) -> Any:
+ return to_class(SessionSkillsDisableParams, x)
+
+
+def session_skills_reload_result_from_dict(s: Any) -> SessionSkillsReloadResult:
+ return SessionSkillsReloadResult.from_dict(s)
+
+
+def session_skills_reload_result_to_dict(x: SessionSkillsReloadResult) -> Any:
+ return to_class(SessionSkillsReloadResult, x)
+
+
+def session_mcp_list_result_from_dict(s: Any) -> SessionMCPListResult:
+ return SessionMCPListResult.from_dict(s)
+
+
+def session_mcp_list_result_to_dict(x: SessionMCPListResult) -> Any:
+ return to_class(SessionMCPListResult, x)
+
+
+def session_mcp_enable_result_from_dict(s: Any) -> SessionMCPEnableResult:
+ return SessionMCPEnableResult.from_dict(s)
+
+
+def session_mcp_enable_result_to_dict(x: SessionMCPEnableResult) -> Any:
+ return to_class(SessionMCPEnableResult, x)
+
+
+def session_mcp_enable_params_from_dict(s: Any) -> SessionMCPEnableParams:
+ return SessionMCPEnableParams.from_dict(s)
+
+
+def session_mcp_enable_params_to_dict(x: SessionMCPEnableParams) -> Any:
+ return to_class(SessionMCPEnableParams, x)
+
+
+def session_mcp_disable_result_from_dict(s: Any) -> SessionMCPDisableResult:
+ return SessionMCPDisableResult.from_dict(s)
+
+
+def session_mcp_disable_result_to_dict(x: SessionMCPDisableResult) -> Any:
+ return to_class(SessionMCPDisableResult, x)
+
+
+def session_mcp_disable_params_from_dict(s: Any) -> SessionMCPDisableParams:
+ return SessionMCPDisableParams.from_dict(s)
+
+
+def session_mcp_disable_params_to_dict(x: SessionMCPDisableParams) -> Any:
+ return to_class(SessionMCPDisableParams, x)
+
+
+def session_mcp_reload_result_from_dict(s: Any) -> SessionMCPReloadResult:
+ return SessionMCPReloadResult.from_dict(s)
+
+
+def session_mcp_reload_result_to_dict(x: SessionMCPReloadResult) -> Any:
+ return to_class(SessionMCPReloadResult, x)
+
+
+def session_plugins_list_result_from_dict(s: Any) -> SessionPluginsListResult:
+ return SessionPluginsListResult.from_dict(s)
+
+
+def session_plugins_list_result_to_dict(x: SessionPluginsListResult) -> Any:
+ return to_class(SessionPluginsListResult, x)
+
+
+def session_extensions_list_result_from_dict(s: Any) -> SessionExtensionsListResult:
+ return SessionExtensionsListResult.from_dict(s)
+
+
+def session_extensions_list_result_to_dict(x: SessionExtensionsListResult) -> Any:
+ return to_class(SessionExtensionsListResult, x)
+
+
+def session_extensions_enable_result_from_dict(s: Any) -> SessionExtensionsEnableResult:
+ return SessionExtensionsEnableResult.from_dict(s)
+
+
+def session_extensions_enable_result_to_dict(x: SessionExtensionsEnableResult) -> Any:
+ return to_class(SessionExtensionsEnableResult, x)
+
+
+def session_extensions_enable_params_from_dict(s: Any) -> SessionExtensionsEnableParams:
+ return SessionExtensionsEnableParams.from_dict(s)
+
+
+def session_extensions_enable_params_to_dict(x: SessionExtensionsEnableParams) -> Any:
+ return to_class(SessionExtensionsEnableParams, x)
+
+
+def session_extensions_disable_result_from_dict(s: Any) -> SessionExtensionsDisableResult:
+ return SessionExtensionsDisableResult.from_dict(s)
+
+
+def session_extensions_disable_result_to_dict(x: SessionExtensionsDisableResult) -> Any:
+ return to_class(SessionExtensionsDisableResult, x)
+
+
+def session_extensions_disable_params_from_dict(s: Any) -> SessionExtensionsDisableParams:
+ return SessionExtensionsDisableParams.from_dict(s)
+
+
+def session_extensions_disable_params_to_dict(x: SessionExtensionsDisableParams) -> Any:
+ return to_class(SessionExtensionsDisableParams, x)
+
+
+def session_extensions_reload_result_from_dict(s: Any) -> SessionExtensionsReloadResult:
+ return SessionExtensionsReloadResult.from_dict(s)
+
+
+def session_extensions_reload_result_to_dict(x: SessionExtensionsReloadResult) -> Any:
+ return to_class(SessionExtensionsReloadResult, x)
+
+
def session_compaction_compact_result_from_dict(s: Any) -> SessionCompactionCompactResult:
return SessionCompactionCompactResult.from_dict(s)
@@ -1501,6 +2461,38 @@ def session_tools_handle_pending_tool_call_params_to_dict(x: SessionToolsHandleP
return to_class(SessionToolsHandlePendingToolCallParams, x)
+def session_commands_handle_pending_command_result_from_dict(s: Any) -> SessionCommandsHandlePendingCommandResult:
+ return SessionCommandsHandlePendingCommandResult.from_dict(s)
+
+
+def session_commands_handle_pending_command_result_to_dict(x: SessionCommandsHandlePendingCommandResult) -> Any:
+ return to_class(SessionCommandsHandlePendingCommandResult, x)
+
+
+def session_commands_handle_pending_command_params_from_dict(s: Any) -> SessionCommandsHandlePendingCommandParams:
+ return SessionCommandsHandlePendingCommandParams.from_dict(s)
+
+
+def session_commands_handle_pending_command_params_to_dict(x: SessionCommandsHandlePendingCommandParams) -> Any:
+ return to_class(SessionCommandsHandlePendingCommandParams, x)
+
+
+def session_ui_elicitation_result_from_dict(s: Any) -> SessionUIElicitationResult:
+ return SessionUIElicitationResult.from_dict(s)
+
+
+def session_ui_elicitation_result_to_dict(x: SessionUIElicitationResult) -> Any:
+ return to_class(SessionUIElicitationResult, x)
+
+
+def session_ui_elicitation_params_from_dict(s: Any) -> SessionUIElicitationParams:
+ return SessionUIElicitationParams.from_dict(s)
+
+
+def session_ui_elicitation_params_to_dict(x: SessionUIElicitationParams) -> Any:
+ return to_class(SessionUIElicitationParams, x)
+
+
def session_permissions_handle_pending_permission_request_result_from_dict(s: Any) -> SessionPermissionsHandlePendingPermissionRequestResult:
return SessionPermissionsHandlePendingPermissionRequestResult.from_dict(s)
@@ -1706,6 +2698,88 @@ async def select(self, params: SessionAgentSelectParams, *, timeout: float | Non
async def deselect(self, *, timeout: float | None = None) -> SessionAgentDeselectResult:
return SessionAgentDeselectResult.from_dict(await self._client.request("session.agent.deselect", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+ async def reload(self, *, timeout: float | None = None) -> SessionAgentReloadResult:
+ return SessionAgentReloadResult.from_dict(await self._client.request("session.agent.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
+
+# Experimental: this API group is experimental and may change or be removed.
+class SkillsApi:
+ def __init__(self, client: "JsonRpcClient", session_id: str):
+ self._client = client
+ self._session_id = session_id
+
+ async def list(self, *, timeout: float | None = None) -> SessionSkillsListResult:
+ return SessionSkillsListResult.from_dict(await self._client.request("session.skills.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
+ async def enable(self, params: SessionSkillsEnableParams, *, timeout: float | None = None) -> SessionSkillsEnableResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionSkillsEnableResult.from_dict(await self._client.request("session.skills.enable", params_dict, **_timeout_kwargs(timeout)))
+
+ async def disable(self, params: SessionSkillsDisableParams, *, timeout: float | None = None) -> SessionSkillsDisableResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionSkillsDisableResult.from_dict(await self._client.request("session.skills.disable", params_dict, **_timeout_kwargs(timeout)))
+
+ async def reload(self, *, timeout: float | None = None) -> SessionSkillsReloadResult:
+ return SessionSkillsReloadResult.from_dict(await self._client.request("session.skills.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
+
+# Experimental: this API group is experimental and may change or be removed.
+class McpApi:
+ def __init__(self, client: "JsonRpcClient", session_id: str):
+ self._client = client
+ self._session_id = session_id
+
+ async def list(self, *, timeout: float | None = None) -> SessionMCPListResult:
+ return SessionMCPListResult.from_dict(await self._client.request("session.mcp.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
+ async def enable(self, params: SessionMCPEnableParams, *, timeout: float | None = None) -> SessionMCPEnableResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionMCPEnableResult.from_dict(await self._client.request("session.mcp.enable", params_dict, **_timeout_kwargs(timeout)))
+
+ async def disable(self, params: SessionMCPDisableParams, *, timeout: float | None = None) -> SessionMCPDisableResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionMCPDisableResult.from_dict(await self._client.request("session.mcp.disable", params_dict, **_timeout_kwargs(timeout)))
+
+ async def reload(self, *, timeout: float | None = None) -> SessionMCPReloadResult:
+ return SessionMCPReloadResult.from_dict(await self._client.request("session.mcp.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
+
+# Experimental: this API group is experimental and may change or be removed.
+class PluginsApi:
+ def __init__(self, client: "JsonRpcClient", session_id: str):
+ self._client = client
+ self._session_id = session_id
+
+ async def list(self, *, timeout: float | None = None) -> SessionPluginsListResult:
+ return SessionPluginsListResult.from_dict(await self._client.request("session.plugins.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
+
+# Experimental: this API group is experimental and may change or be removed.
+class ExtensionsApi:
+ def __init__(self, client: "JsonRpcClient", session_id: str):
+ self._client = client
+ self._session_id = session_id
+
+ async def list(self, *, timeout: float | None = None) -> SessionExtensionsListResult:
+ return SessionExtensionsListResult.from_dict(await self._client.request("session.extensions.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
+ async def enable(self, params: SessionExtensionsEnableParams, *, timeout: float | None = None) -> SessionExtensionsEnableResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionExtensionsEnableResult.from_dict(await self._client.request("session.extensions.enable", params_dict, **_timeout_kwargs(timeout)))
+
+ async def disable(self, params: SessionExtensionsDisableParams, *, timeout: float | None = None) -> SessionExtensionsDisableResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionExtensionsDisableResult.from_dict(await self._client.request("session.extensions.disable", params_dict, **_timeout_kwargs(timeout)))
+
+ async def reload(self, *, timeout: float | None = None) -> SessionExtensionsReloadResult:
+ return SessionExtensionsReloadResult.from_dict(await self._client.request("session.extensions.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)))
+
# Experimental: this API group is experimental and may change or be removed.
class CompactionApi:
@@ -1728,6 +2802,28 @@ async def handle_pending_tool_call(self, params: SessionToolsHandlePendingToolCa
return SessionToolsHandlePendingToolCallResult.from_dict(await self._client.request("session.tools.handlePendingToolCall", params_dict, **_timeout_kwargs(timeout)))
+class CommandsApi:
+ def __init__(self, client: "JsonRpcClient", session_id: str):
+ self._client = client
+ self._session_id = session_id
+
+ async def handle_pending_command(self, params: SessionCommandsHandlePendingCommandParams, *, timeout: float | None = None) -> SessionCommandsHandlePendingCommandResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionCommandsHandlePendingCommandResult.from_dict(await self._client.request("session.commands.handlePendingCommand", params_dict, **_timeout_kwargs(timeout)))
+
+
+class UiApi:
+ def __init__(self, client: "JsonRpcClient", session_id: str):
+ self._client = client
+ self._session_id = session_id
+
+ async def elicitation(self, params: SessionUIElicitationParams, *, timeout: float | None = None) -> SessionUIElicitationResult:
+ params_dict = {k: v for k, v in params.to_dict().items() if v is not None}
+ params_dict["sessionId"] = self._session_id
+ return SessionUIElicitationResult.from_dict(await self._client.request("session.ui.elicitation", params_dict, **_timeout_kwargs(timeout)))
+
+
class PermissionsApi:
def __init__(self, client: "JsonRpcClient", session_id: str):
self._client = client
@@ -1766,8 +2862,14 @@ def __init__(self, client: "JsonRpcClient", session_id: str):
self.workspace = WorkspaceApi(client, session_id)
self.fleet = FleetApi(client, session_id)
self.agent = AgentApi(client, session_id)
+ self.skills = SkillsApi(client, session_id)
+ self.mcp = McpApi(client, session_id)
+ self.plugins = PluginsApi(client, session_id)
+ self.extensions = ExtensionsApi(client, session_id)
self.compaction = CompactionApi(client, session_id)
self.tools = ToolsApi(client, session_id)
+ self.commands = CommandsApi(client, session_id)
+ self.ui = UiApi(client, session_id)
self.permissions = PermissionsApi(client, session_id)
self.shell = ShellApi(client, session_id)
diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py
index 3fc313399..f3970b815 100644
--- a/python/copilot/generated/session_events.py
+++ b/python/copilot/generated/session_events.py
@@ -419,6 +419,26 @@ def to_dict(self) -> dict:
return result
+@dataclass
+class DataCommand:
+ name: str
+ description: str | None = None
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'DataCommand':
+ assert isinstance(obj, dict)
+ name = from_str(obj.get("name"))
+ description = from_union([from_str, from_none], obj.get("description"))
+ return DataCommand(name, description)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["name"] = from_str(self.name)
+ if self.description is not None:
+ result["description"] = from_union([from_str, from_none], self.description)
+ return result
+
+
@dataclass
class CompactionTokensUsed:
"""Token usage breakdown for the compaction LLM call"""
@@ -605,7 +625,55 @@ def to_dict(self) -> dict:
return result
-class Status(Enum):
+class Source(Enum):
+ """Discovery source"""
+
+ PROJECT = "project"
+ USER = "user"
+
+
+class ExtensionStatus(Enum):
+ """Current status: running, disabled, failed, or starting"""
+
+ DISABLED = "disabled"
+ FAILED = "failed"
+ RUNNING = "running"
+ STARTING = "starting"
+
+
+@dataclass
+class Extension:
+ id: str
+ """Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper')"""
+
+ name: str
+ """Extension name (directory name)"""
+
+ source: Source
+ """Discovery source"""
+
+ status: ExtensionStatus
+ """Current status: running, disabled, failed, or starting"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Extension':
+ assert isinstance(obj, dict)
+ id = from_str(obj.get("id"))
+ name = from_str(obj.get("name"))
+ source = Source(obj.get("source"))
+ status = ExtensionStatus(obj.get("status"))
+ return Extension(id, name, source, status)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["id"] = from_str(self.id)
+ result["name"] = from_str(self.name)
+ result["source"] = to_enum(Source, self.source)
+ result["status"] = to_enum(ExtensionStatus, self.status)
+ return result
+
+
+class KindStatus(Enum):
"""Whether the agent completed successfully or failed"""
COMPLETED = "completed"
@@ -614,6 +682,7 @@ class Status(Enum):
class KindType(Enum):
AGENT_COMPLETED = "agent_completed"
+ AGENT_IDLE = "agent_idle"
SHELL_COMPLETED = "shell_completed"
SHELL_DETACHED_COMPLETED = "shell_detached_completed"
@@ -637,7 +706,7 @@ class KindClass:
prompt: str | None = None
"""The full prompt given to the background agent"""
- status: Status | None = None
+ status: KindStatus | None = None
"""Whether the agent completed successfully or failed"""
exit_code: float | None = None
@@ -657,7 +726,7 @@ def from_dict(obj: Any) -> 'KindClass':
agent_type = from_union([from_str, from_none], obj.get("agentType"))
description = from_union([from_str, from_none], obj.get("description"))
prompt = from_union([from_str, from_none], obj.get("prompt"))
- status = from_union([Status, from_none], obj.get("status"))
+ status = from_union([KindStatus, from_none], obj.get("status"))
exit_code = from_union([from_float, from_none], obj.get("exitCode"))
shell_id = from_union([from_str, from_none], obj.get("shellId"))
return KindClass(type, agent_id, agent_type, description, prompt, status, exit_code, shell_id)
@@ -674,7 +743,7 @@ def to_dict(self) -> dict:
if self.prompt is not None:
result["prompt"] = from_union([from_str, from_none], self.prompt)
if self.status is not None:
- result["status"] = from_union([lambda x: to_enum(Status, x), from_none], self.status)
+ result["status"] = from_union([lambda x: to_enum(KindStatus, x), from_none], self.status)
if self.exit_code is not None:
result["exitCode"] = from_union([to_float, from_none], self.exit_code)
if self.shell_id is not None:
@@ -709,7 +778,11 @@ def to_dict(self) -> dict:
class Mode(Enum):
+ """Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to
+ "form" when absent.
+ """
FORM = "form"
+ URL = "url"
@dataclass
@@ -803,7 +876,7 @@ class Operation(Enum):
@dataclass
-class Command:
+class PermissionRequestCommand:
identifier: str
"""Command identifier (e.g., executable name)"""
@@ -811,11 +884,11 @@ class Command:
"""Whether this command is read-only (no side effects)"""
@staticmethod
- def from_dict(obj: Any) -> 'Command':
+ def from_dict(obj: Any) -> 'PermissionRequestCommand':
assert isinstance(obj, dict)
identifier = from_str(obj.get("identifier"))
read_only = from_bool(obj.get("readOnly"))
- return Command(identifier, read_only)
+ return PermissionRequestCommand(identifier, read_only)
def to_dict(self) -> dict:
result: dict = {}
@@ -878,7 +951,7 @@ class PermissionRequest:
can_offer_session_approval: bool | None = None
"""Whether the UI can offer session-wide approval for this command pattern"""
- commands: list[Command] | None = None
+ commands: list[PermissionRequestCommand] | None = None
"""Parsed command identifiers found in the command text"""
full_command_text: str | None = None
@@ -967,7 +1040,7 @@ def from_dict(obj: Any) -> 'PermissionRequest':
assert isinstance(obj, dict)
kind = PermissionRequestKind(obj.get("kind"))
can_offer_session_approval = from_union([from_bool, from_none], obj.get("canOfferSessionApproval"))
- commands = from_union([lambda x: from_list(Command.from_dict, x), from_none], obj.get("commands"))
+ commands = from_union([lambda x: from_list(PermissionRequestCommand.from_dict, x), from_none], obj.get("commands"))
full_command_text = from_union([from_str, from_none], obj.get("fullCommandText"))
has_write_file_redirection = from_union([from_bool, from_none], obj.get("hasWriteFileRedirection"))
intention = from_union([from_str, from_none], obj.get("intention"))
@@ -999,7 +1072,7 @@ def to_dict(self) -> dict:
if self.can_offer_session_approval is not None:
result["canOfferSessionApproval"] = from_union([from_bool, from_none], self.can_offer_session_approval)
if self.commands is not None:
- result["commands"] = from_union([lambda x: from_list(lambda x: to_class(Command, x), x), from_none], self.commands)
+ result["commands"] = from_union([lambda x: from_list(lambda x: to_class(PermissionRequestCommand, x), x), from_none], self.commands)
if self.full_command_text is not None:
result["fullCommandText"] = from_union([from_str, from_none], self.full_command_text)
if self.has_write_file_redirection is not None:
@@ -1138,7 +1211,7 @@ class RequestedSchemaType(Enum):
@dataclass
class RequestedSchema:
- """JSON Schema describing the form fields to present to the user"""
+ """JSON Schema describing the form fields to present to the user (form mode only)"""
properties: dict[str, Any]
"""Form field definitions, keyed by field name"""
@@ -1430,6 +1503,52 @@ class Role(Enum):
SYSTEM = "system"
+class ServerStatus(Enum):
+ """Connection status: connected, failed, pending, disabled, or not_configured
+
+ New connection status: connected, failed, pending, disabled, or not_configured
+ """
+ CONNECTED = "connected"
+ DISABLED = "disabled"
+ FAILED = "failed"
+ NOT_CONFIGURED = "not_configured"
+ PENDING = "pending"
+
+
+@dataclass
+class Server:
+ name: str
+ """Server name (config key)"""
+
+ status: ServerStatus
+ """Connection status: connected, failed, pending, disabled, or not_configured"""
+
+ error: str | None = None
+ """Error message if the server failed to connect"""
+
+ source: str | None = None
+ """Configuration source: user, workspace, plugin, or builtin"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Server':
+ assert isinstance(obj, dict)
+ name = from_str(obj.get("name"))
+ status = ServerStatus(obj.get("status"))
+ error = from_union([from_str, from_none], obj.get("error"))
+ source = from_union([from_str, from_none], obj.get("source"))
+ return Server(name, status, error, source)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["name"] = from_str(self.name)
+ result["status"] = to_enum(ServerStatus, self.status)
+ if self.error is not None:
+ result["error"] = from_union([from_str, from_none], self.error)
+ if self.source is not None:
+ result["source"] = from_union([from_str, from_none], self.source)
+ return result
+
+
class ShutdownType(Enum):
"""Whether the session ended normally ("routine") or due to a crash/fatal error ("error")"""
@@ -1437,20 +1556,47 @@ class ShutdownType(Enum):
ROUTINE = "routine"
-class Source(Enum):
- """Origin of this message, used for timeline filtering and telemetry (e.g., "user",
- "autopilot", "skill", or "command")
- """
- AUTOPILOT = "autopilot"
- COMMAND = "command"
- IMMEDIATE_PROMPT = "immediate-prompt"
- JIT_INSTRUCTION = "jit-instruction"
- OTHER = "other"
- SKILL = "skill"
- SNIPPY_BLOCKING = "snippy-blocking"
- SYSTEM = "system"
- THINKING_EXHAUSTED_CONTINUATION = "thinking-exhausted-continuation"
- USER = "user"
+@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"""
+
+ source: str
+ """Source location type of the skill (e.g., project, personal, plugin)"""
+
+ 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, if available"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'Skill':
+ 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)
+
+ 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)
+ return result
class SourceType(Enum):
@@ -1460,6 +1606,31 @@ class SourceType(Enum):
REMOTE = "remote"
+@dataclass
+class StaticClientConfig:
+ """Static OAuth client configuration, if the server specifies one"""
+
+ client_id: str
+ """OAuth client ID for the server"""
+
+ public_client: bool | None = None
+ """Whether this is a public OAuth client"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'StaticClientConfig':
+ assert isinstance(obj, dict)
+ client_id = from_str(obj.get("clientId"))
+ public_client = from_union([from_bool, from_none], obj.get("publicClient"))
+ return StaticClientConfig(client_id, public_client)
+
+ 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_bool, from_none], self.public_client)
+ return result
+
+
class ToolRequestType(Enum):
"""Tool call type: "function" for standard tool calls, "custom" for grammar-based tool
calls. Defaults to "function" when absent.
@@ -1555,15 +1726,12 @@ class Data:
Current context window usage statistics including token and message counts
- Empty payload; the event signals that LLM-powered conversation compaction has begun
+ Context window breakdown at the start of LLM-powered conversation compaction
Conversation compaction results including success status, metrics, and optional error
details
- Task completion notification with optional summary from the agent
-
- User message content with optional attachments, source information, and interaction
- metadata
+ Task completion notification with summary from the agent
Empty payload; the event signals that the pending message queue has changed
@@ -1629,18 +1797,27 @@ class Data:
User input request completion notification signaling UI dismissal
- Structured form elicitation request with JSON schema definition for form fields
+ Elicitation request; may be form-based (structured input) or URL-based (browser
+ redirect)
Elicitation request completion notification signaling UI dismissal
+ OAuth authentication request for an MCP server
+
+ MCP OAuth request completion notification
+
External tool invocation request for client-side tool execution
External tool completion notification signaling UI dismissal
Queued slash command dispatch request for client execution
+ Registered command dispatch request routed to the owning client
+
Queued command completion notification signaling UI dismissal
+ SDK command registration change notification
+
Plan approval request with plan content and available user actions
Plan mode exit completion notification signaling UI dismissal
@@ -1716,6 +1893,15 @@ class Data:
status_code: int | None = None
"""HTTP status code from the upstream request, if applicable"""
+ url: str | None = None
+ """Optional URL associated with this error that the user can open in a browser
+
+ Optional URL associated with this message that the user can open in a browser
+
+ Optional URL associated with this warning that the user can open in a browser
+
+ URL to open in the user's browser (url mode only)
+ """
background_tasks: BackgroundTasks | None = None
"""Background tasks still running when the agent became idle"""
@@ -1772,7 +1958,7 @@ class Data:
summary: str | None = None
"""Summary of the work done in the source session
- Optional summary of the completed task, provided by the agent
+ Summary of the completed task, provided by the agent
Summary of the plan that was created
"""
@@ -1809,9 +1995,23 @@ class Data:
code_changes: CodeChanges | None = None
"""Aggregate code change metrics for the session"""
+ conversation_tokens: float | None = None
+ """Non-system message token count at shutdown
+
+ Token count from non-system messages (user, assistant, tool)
+
+ Token count from non-system messages (user, assistant, tool) at compaction start
+
+ Token count from non-system messages (user, assistant, tool) after compaction
+ """
current_model: str | None = None
"""Model that was selected at the time of shutdown"""
+ current_tokens: float | None = None
+ """Total tokens in context window at shutdown
+
+ Current number of tokens in the context window
+ """
error_reason: str | None = None
"""Error description when shutdownType is "error\""""
@@ -1824,6 +2024,24 @@ class Data:
shutdown_type: ShutdownType | None = None
"""Whether the session ended normally ("routine") or due to a crash/fatal error ("error")"""
+ system_tokens: float | None = None
+ """System message token count at shutdown
+
+ Token count from system message(s)
+
+ Token count from system message(s) at compaction start
+
+ Token count from system message(s) after compaction
+ """
+ tool_definitions_tokens: float | None = None
+ """Tool definitions token count at shutdown
+
+ Token count from tool definitions
+
+ Token count from tool definitions at compaction start
+
+ Token count from tool definitions after compaction
+ """
total_api_duration_ms: float | None = None
"""Cumulative time spent in API calls during the session, in milliseconds"""
@@ -1848,8 +2066,8 @@ class Data:
host_type: HostType | None = None
"""Hosting platform type of the repository (github or ado)"""
- current_tokens: float | None = None
- """Current number of tokens in the context window"""
+ is_initial: bool | None = None
+ """Whether this is the first usage_info event emitted in this session"""
messages_length: float | None = None
"""Current number of messages in the conversation"""
@@ -1905,6 +2123,11 @@ class Data:
Request ID of the resolved elicitation request; clients should dismiss any UI for this
request
+ Unique identifier for this OAuth request; used to respond via
+ session.respondToMcpOAuth()
+
+ Request ID of the resolved OAuth request
+
Unique identifier for this request; used to respond via session.respondToExternalTool()
Request ID of the resolved external tool request; clients should dismiss any UI for this
@@ -1912,6 +2135,8 @@ class Data:
Unique identifier for this request; used to respond via session.respondToQueuedCommand()
+ Unique identifier; used to respond via session.commands.handlePendingCommand()
+
Request ID of the resolved command request; clients should dismiss any UI for this
request
@@ -1923,6 +2148,8 @@ class Data:
success: bool | None = None
"""Whether compaction completed successfully
+ Whether the tool call succeeded. False when validation failed (e.g., invalid arguments)
+
Whether the tool execution completed successfully
Whether the hook completed successfully
@@ -1961,9 +2188,9 @@ class Data:
CAPI interaction ID for correlating this tool execution with upstream telemetry
"""
- source: Source | None = None
- """Origin of this message, used for timeline filtering and telemetry (e.g., "user",
- "autopilot", "skill", or "command")
+ source: str | None = None
+ """Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected
+ messages that should be hidden from the user)
"""
transformed_content: str | None = None
"""Transformed version of the message sent to the model, with XML wrapping, timestamps, and
@@ -2077,6 +2304,12 @@ class Data:
Tool call ID of the parent tool invocation that spawned this sub-agent
+ The LLM-assigned tool call ID that triggered this request; used by remote UIs to
+ correlate responses
+
+ Tool call ID from the LLM completion; used to correlate with CompletionChunk.toolCall.id
+ for remote UIs
+
Tool call ID assigned to this external tool invocation
"""
tool_name: str | None = None
@@ -2176,11 +2409,26 @@ class Data:
question: str | None = None
"""The question or prompt to present to the user"""
- mode: Mode | None = None
- """Elicitation mode; currently only "form" is supported. Defaults to "form" when absent."""
+ elicitation_source: str | None = None
+ """The source that initiated the request (MCP server name, or absent for agent-initiated)"""
+ mode: Mode | None = None
+ """Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to
+ "form" when absent.
+ """
requested_schema: RequestedSchema | None = None
- """JSON Schema describing the form fields to present to the user"""
+ """JSON Schema describing the form fields to present to the user (form mode only)"""
+
+ server_name: str | None = None
+ """Display name of the MCP server that requires OAuth
+
+ Name of the MCP server whose status changed
+ """
+ server_url: str | None = None
+ """URL of the MCP server that requires OAuth"""
+
+ static_client_config: StaticClientConfig | None = None
+ """Static OAuth client configuration, if the server specifies one"""
traceparent: str | None = None
"""W3C Trace Context traceparent header for the execute_tool span"""
@@ -2189,7 +2437,18 @@ class Data:
"""W3C Trace Context tracestate header for the execute_tool span"""
command: str | None = None
- """The slash command text to be executed (e.g., /help, /clear)"""
+ """The slash command text to be executed (e.g., /help, /clear)
+
+ The full command text (e.g., /deploy production)
+ """
+ args: str | None = None
+ """Raw argument string after the command name"""
+
+ command_name: str | None = None
+ """Command name without leading /"""
+
+ commands: list[DataCommand] | None = None
+ """Current list of registered SDK commands"""
actions: list[str] | None = None
"""Available actions the user can take (e.g., approve, edit, reject)"""
@@ -2200,6 +2459,18 @@ class Data:
recommended_action: str | None = None
"""The recommended action for the user to take"""
+ skills: list[Skill] | None = None
+ """Array of resolved skill metadata"""
+
+ servers: list[Server] | None = None
+ """Array of MCP server status summaries"""
+
+ status: ServerStatus | None = None
+ """New connection status: connected, failed, pending, disabled, or not_configured"""
+
+ extensions: list[Extension] | None = None
+ """Array of discovered extensions and their status"""
+
@staticmethod
def from_dict(obj: Any) -> 'Data':
assert isinstance(obj, dict)
@@ -2219,6 +2490,7 @@ def from_dict(obj: Any) -> 'Data':
provider_call_id = from_union([from_str, from_none], obj.get("providerCallId"))
stack = from_union([from_str, from_none], obj.get("stack"))
status_code = from_union([from_int, from_none], obj.get("statusCode"))
+ url = from_union([from_str, from_none], obj.get("url"))
background_tasks = from_union([BackgroundTasks.from_dict, from_none], obj.get("backgroundTasks"))
title = from_union([from_str, from_none], obj.get("title"))
info_type = from_union([from_str, from_none], obj.get("infoType"))
@@ -2246,11 +2518,15 @@ def from_dict(obj: Any) -> 'Data':
events_removed = from_union([from_float, from_none], obj.get("eventsRemoved"))
up_to_event_id = from_union([from_str, from_none], obj.get("upToEventId"))
code_changes = from_union([CodeChanges.from_dict, from_none], obj.get("codeChanges"))
+ conversation_tokens = from_union([from_float, from_none], obj.get("conversationTokens"))
current_model = from_union([from_str, from_none], obj.get("currentModel"))
+ current_tokens = from_union([from_float, from_none], obj.get("currentTokens"))
error_reason = from_union([from_str, from_none], obj.get("errorReason"))
model_metrics = from_union([lambda x: from_dict(ModelMetric.from_dict, x), from_none], obj.get("modelMetrics"))
session_start_time = from_union([from_float, from_none], obj.get("sessionStartTime"))
shutdown_type = from_union([ShutdownType, from_none], obj.get("shutdownType"))
+ system_tokens = from_union([from_float, from_none], obj.get("systemTokens"))
+ tool_definitions_tokens = from_union([from_float, from_none], obj.get("toolDefinitionsTokens"))
total_api_duration_ms = from_union([from_float, from_none], obj.get("totalApiDurationMs"))
total_premium_requests = from_union([from_float, from_none], obj.get("totalPremiumRequests"))
base_commit = from_union([from_str, from_none], obj.get("baseCommit"))
@@ -2259,7 +2535,7 @@ def from_dict(obj: Any) -> 'Data':
git_root = from_union([from_str, from_none], obj.get("gitRoot"))
head_commit = from_union([from_str, from_none], obj.get("headCommit"))
host_type = from_union([HostType, from_none], obj.get("hostType"))
- current_tokens = from_union([from_float, from_none], obj.get("currentTokens"))
+ is_initial = from_union([from_bool, from_none], obj.get("isInitial"))
messages_length = from_union([from_float, from_none], obj.get("messagesLength"))
checkpoint_number = from_union([from_float, from_none], obj.get("checkpointNumber"))
checkpoint_path = from_union([from_str, from_none], obj.get("checkpointPath"))
@@ -2277,7 +2553,7 @@ def from_dict(obj: Any) -> 'Data':
attachments = from_union([lambda x: from_list(Attachment.from_dict, x), from_none], obj.get("attachments"))
content = from_union([from_str, from_none], obj.get("content"))
interaction_id = from_union([from_str, from_none], obj.get("interactionId"))
- source = from_union([Source, from_none], obj.get("source"))
+ source = from_union([from_str, from_none], obj.get("source"))
transformed_content = from_union([from_str, from_none], obj.get("transformedContent"))
turn_id = from_union([from_str, from_none], obj.get("turnId"))
intent = from_union([from_str, from_none], obj.get("intent"))
@@ -2332,15 +2608,26 @@ def from_dict(obj: Any) -> 'Data':
allow_freeform = from_union([from_bool, from_none], obj.get("allowFreeform"))
choices = from_union([lambda x: from_list(from_str, x), from_none], obj.get("choices"))
question = from_union([from_str, from_none], obj.get("question"))
+ elicitation_source = from_union([from_str, from_none], obj.get("elicitationSource"))
mode = from_union([Mode, from_none], obj.get("mode"))
requested_schema = from_union([RequestedSchema.from_dict, from_none], obj.get("requestedSchema"))
+ server_name = from_union([from_str, from_none], obj.get("serverName"))
+ server_url = from_union([from_str, from_none], obj.get("serverUrl"))
+ static_client_config = from_union([StaticClientConfig.from_dict, from_none], obj.get("staticClientConfig"))
traceparent = from_union([from_str, from_none], obj.get("traceparent"))
tracestate = from_union([from_str, from_none], obj.get("tracestate"))
command = from_union([from_str, from_none], obj.get("command"))
+ args = from_union([from_str, from_none], obj.get("args"))
+ command_name = from_union([from_str, from_none], obj.get("commandName"))
+ commands = from_union([lambda x: from_list(DataCommand.from_dict, x), from_none], obj.get("commands"))
actions = from_union([lambda x: from_list(from_str, x), from_none], obj.get("actions"))
plan_content = from_union([from_str, from_none], obj.get("planContent"))
recommended_action = from_union([from_str, from_none], obj.get("recommendedAction"))
- return Data(already_in_use, context, copilot_version, producer, reasoning_effort, selected_model, session_id, start_time, version, event_count, resume_time, error_type, message, provider_call_id, stack, status_code, background_tasks, title, info_type, warning_type, new_model, previous_model, previous_reasoning_effort, new_mode, previous_mode, operation, path, handoff_time, remote_session_id, repository, source_type, summary, messages_removed_during_truncation, performed_by, post_truncation_messages_length, post_truncation_tokens_in_messages, pre_truncation_messages_length, pre_truncation_tokens_in_messages, token_limit, tokens_removed_during_truncation, events_removed, up_to_event_id, code_changes, current_model, error_reason, model_metrics, session_start_time, shutdown_type, total_api_duration_ms, total_premium_requests, base_commit, branch, cwd, git_root, head_commit, host_type, current_tokens, messages_length, checkpoint_number, checkpoint_path, compaction_tokens_used, error, messages_removed, post_compaction_tokens, pre_compaction_messages_length, pre_compaction_tokens, request_id, success, summary_content, tokens_removed, agent_mode, attachments, content, interaction_id, source, transformed_content, turn_id, intent, reasoning_id, delta_content, total_response_size_bytes, encrypted_content, message_id, output_tokens, parent_tool_call_id, phase, reasoning_opaque, reasoning_text, tool_requests, api_call_id, cache_read_tokens, cache_write_tokens, copilot_usage, cost, duration, initiator, input_tokens, model, quota_snapshots, reason, arguments, tool_call_id, tool_name, mcp_server_name, mcp_tool_name, partial_output, progress_message, is_user_requested, result, tool_telemetry, allowed_tools, name, plugin_name, plugin_version, agent_description, agent_display_name, agent_name, tools, hook_invocation_id, hook_type, input, output, metadata, role, kind, permission_request, allow_freeform, choices, question, mode, requested_schema, traceparent, tracestate, command, actions, plan_content, recommended_action)
+ skills = from_union([lambda x: from_list(Skill.from_dict, x), from_none], obj.get("skills"))
+ servers = from_union([lambda x: from_list(Server.from_dict, x), from_none], obj.get("servers"))
+ status = from_union([ServerStatus, from_none], obj.get("status"))
+ extensions = from_union([lambda x: from_list(Extension.from_dict, x), from_none], obj.get("extensions"))
+ return Data(already_in_use, context, copilot_version, producer, reasoning_effort, selected_model, session_id, start_time, version, event_count, resume_time, error_type, message, provider_call_id, stack, status_code, url, background_tasks, title, info_type, warning_type, new_model, previous_model, previous_reasoning_effort, new_mode, previous_mode, operation, path, handoff_time, remote_session_id, repository, source_type, summary, messages_removed_during_truncation, performed_by, post_truncation_messages_length, post_truncation_tokens_in_messages, pre_truncation_messages_length, pre_truncation_tokens_in_messages, token_limit, tokens_removed_during_truncation, events_removed, up_to_event_id, code_changes, conversation_tokens, current_model, current_tokens, error_reason, model_metrics, session_start_time, shutdown_type, system_tokens, tool_definitions_tokens, total_api_duration_ms, total_premium_requests, base_commit, branch, cwd, git_root, head_commit, host_type, is_initial, messages_length, checkpoint_number, checkpoint_path, compaction_tokens_used, error, messages_removed, post_compaction_tokens, pre_compaction_messages_length, pre_compaction_tokens, request_id, success, summary_content, tokens_removed, agent_mode, attachments, content, interaction_id, source, transformed_content, turn_id, intent, reasoning_id, delta_content, total_response_size_bytes, encrypted_content, message_id, output_tokens, parent_tool_call_id, phase, reasoning_opaque, reasoning_text, tool_requests, api_call_id, cache_read_tokens, cache_write_tokens, copilot_usage, cost, duration, initiator, input_tokens, model, quota_snapshots, reason, arguments, tool_call_id, tool_name, mcp_server_name, mcp_tool_name, partial_output, progress_message, is_user_requested, result, tool_telemetry, allowed_tools, name, plugin_name, plugin_version, agent_description, agent_display_name, agent_name, tools, hook_invocation_id, hook_type, input, output, metadata, role, kind, permission_request, allow_freeform, choices, question, elicitation_source, mode, requested_schema, server_name, server_url, static_client_config, traceparent, tracestate, command, args, command_name, commands, actions, plan_content, recommended_action, skills, servers, status, extensions)
def to_dict(self) -> dict:
result: dict = {}
@@ -2376,6 +2663,8 @@ def to_dict(self) -> dict:
result["stack"] = from_union([from_str, from_none], self.stack)
if self.status_code is not None:
result["statusCode"] = from_union([from_int, from_none], self.status_code)
+ if self.url is not None:
+ result["url"] = from_union([from_str, from_none], self.url)
if self.background_tasks is not None:
result["backgroundTasks"] = from_union([lambda x: to_class(BackgroundTasks, x), from_none], self.background_tasks)
if self.title is not None:
@@ -2430,8 +2719,12 @@ def to_dict(self) -> dict:
result["upToEventId"] = from_union([from_str, from_none], self.up_to_event_id)
if self.code_changes is not None:
result["codeChanges"] = from_union([lambda x: to_class(CodeChanges, x), from_none], self.code_changes)
+ if self.conversation_tokens is not None:
+ result["conversationTokens"] = from_union([to_float, from_none], self.conversation_tokens)
if self.current_model is not None:
result["currentModel"] = from_union([from_str, from_none], self.current_model)
+ if self.current_tokens is not None:
+ result["currentTokens"] = from_union([to_float, from_none], self.current_tokens)
if self.error_reason is not None:
result["errorReason"] = from_union([from_str, from_none], self.error_reason)
if self.model_metrics is not None:
@@ -2440,6 +2733,10 @@ def to_dict(self) -> dict:
result["sessionStartTime"] = from_union([to_float, from_none], self.session_start_time)
if self.shutdown_type is not None:
result["shutdownType"] = from_union([lambda x: to_enum(ShutdownType, x), from_none], self.shutdown_type)
+ if self.system_tokens is not None:
+ result["systemTokens"] = from_union([to_float, from_none], self.system_tokens)
+ if self.tool_definitions_tokens is not None:
+ result["toolDefinitionsTokens"] = from_union([to_float, from_none], self.tool_definitions_tokens)
if self.total_api_duration_ms is not None:
result["totalApiDurationMs"] = from_union([to_float, from_none], self.total_api_duration_ms)
if self.total_premium_requests is not None:
@@ -2456,8 +2753,8 @@ def to_dict(self) -> dict:
result["headCommit"] = from_union([from_str, from_none], self.head_commit)
if self.host_type is not None:
result["hostType"] = from_union([lambda x: to_enum(HostType, x), from_none], self.host_type)
- if self.current_tokens is not None:
- result["currentTokens"] = from_union([to_float, from_none], self.current_tokens)
+ if self.is_initial is not None:
+ result["isInitial"] = from_union([from_bool, from_none], self.is_initial)
if self.messages_length is not None:
result["messagesLength"] = from_union([to_float, from_none], self.messages_length)
if self.checkpoint_number is not None:
@@ -2493,7 +2790,7 @@ def to_dict(self) -> dict:
if self.interaction_id is not None:
result["interactionId"] = from_union([from_str, from_none], self.interaction_id)
if self.source is not None:
- result["source"] = from_union([lambda x: to_enum(Source, x), from_none], self.source)
+ result["source"] = from_union([from_str, from_none], self.source)
if self.transformed_content is not None:
result["transformedContent"] = from_union([from_str, from_none], self.transformed_content)
if self.turn_id is not None:
@@ -2602,22 +2899,44 @@ def to_dict(self) -> dict:
result["choices"] = from_union([lambda x: from_list(from_str, x), from_none], self.choices)
if self.question is not None:
result["question"] = from_union([from_str, from_none], self.question)
+ if self.elicitation_source is not None:
+ result["elicitationSource"] = from_union([from_str, from_none], self.elicitation_source)
if self.mode is not None:
result["mode"] = from_union([lambda x: to_enum(Mode, x), from_none], self.mode)
if self.requested_schema is not None:
result["requestedSchema"] = from_union([lambda x: to_class(RequestedSchema, x), from_none], self.requested_schema)
+ if self.server_name is not None:
+ result["serverName"] = from_union([from_str, from_none], self.server_name)
+ if self.server_url is not None:
+ result["serverUrl"] = from_union([from_str, from_none], self.server_url)
+ if self.static_client_config is not None:
+ result["staticClientConfig"] = from_union([lambda x: to_class(StaticClientConfig, x), from_none], self.static_client_config)
if self.traceparent is not None:
result["traceparent"] = from_union([from_str, from_none], self.traceparent)
if self.tracestate is not None:
result["tracestate"] = from_union([from_str, from_none], self.tracestate)
if self.command is not None:
result["command"] = from_union([from_str, from_none], self.command)
+ if self.args is not None:
+ result["args"] = from_union([from_str, from_none], self.args)
+ if self.command_name is not None:
+ result["commandName"] = from_union([from_str, from_none], self.command_name)
+ if self.commands is not None:
+ result["commands"] = from_union([lambda x: from_list(lambda x: to_class(DataCommand, x), x), from_none], self.commands)
if self.actions is not None:
result["actions"] = from_union([lambda x: from_list(from_str, x), from_none], self.actions)
if self.plan_content is not None:
result["planContent"] = from_union([from_str, from_none], self.plan_content)
if self.recommended_action is not None:
result["recommendedAction"] = from_union([from_str, from_none], self.recommended_action)
+ if self.skills is not None:
+ result["skills"] = from_union([lambda x: from_list(lambda x: to_class(Skill, x), x), from_none], self.skills)
+ if self.servers is not None:
+ result["servers"] = from_union([lambda x: from_list(lambda x: to_class(Server, x), x), from_none], self.servers)
+ if self.status is not None:
+ result["status"] = from_union([lambda x: to_enum(ServerStatus, x), from_none], self.status)
+ if self.extensions is not None:
+ result["extensions"] = from_union([lambda x: from_list(lambda x: to_class(Extension, x), x), from_none], self.extensions)
return result
@@ -2632,7 +2951,9 @@ class SessionEventType(Enum):
ASSISTANT_TURN_END = "assistant.turn_end"
ASSISTANT_TURN_START = "assistant.turn_start"
ASSISTANT_USAGE = "assistant.usage"
+ COMMANDS_CHANGED = "commands.changed"
COMMAND_COMPLETED = "command.completed"
+ COMMAND_EXECUTE = "command.execute"
COMMAND_QUEUED = "command.queued"
ELICITATION_COMPLETED = "elicitation.completed"
ELICITATION_REQUESTED = "elicitation.requested"
@@ -2642,6 +2963,8 @@ class SessionEventType(Enum):
EXTERNAL_TOOL_REQUESTED = "external_tool.requested"
HOOK_END = "hook.end"
HOOK_START = "hook.start"
+ MCP_OAUTH_COMPLETED = "mcp.oauth_completed"
+ MCP_OAUTH_REQUIRED = "mcp.oauth_required"
PENDING_MESSAGES_MODIFIED = "pending_messages.modified"
PERMISSION_COMPLETED = "permission.completed"
PERMISSION_REQUESTED = "permission.requested"
@@ -2650,14 +2973,18 @@ class SessionEventType(Enum):
SESSION_COMPACTION_START = "session.compaction_start"
SESSION_CONTEXT_CHANGED = "session.context_changed"
SESSION_ERROR = "session.error"
+ SESSION_EXTENSIONS_LOADED = "session.extensions_loaded"
SESSION_HANDOFF = "session.handoff"
SESSION_IDLE = "session.idle"
SESSION_INFO = "session.info"
+ SESSION_MCP_SERVERS_LOADED = "session.mcp_servers_loaded"
+ SESSION_MCP_SERVER_STATUS_CHANGED = "session.mcp_server_status_changed"
SESSION_MODEL_CHANGE = "session.model_change"
SESSION_MODE_CHANGED = "session.mode_changed"
SESSION_PLAN_CHANGED = "session.plan_changed"
SESSION_RESUME = "session.resume"
SESSION_SHUTDOWN = "session.shutdown"
+ SESSION_SKILLS_LOADED = "session.skills_loaded"
SESSION_SNAPSHOT_REWIND = "session.snapshot_rewind"
SESSION_START = "session.start"
SESSION_TASK_COMPLETE = "session.task_complete"
@@ -2731,15 +3058,12 @@ class SessionEvent:
Current context window usage statistics including token and message counts
- Empty payload; the event signals that LLM-powered conversation compaction has begun
+ Context window breakdown at the start of LLM-powered conversation compaction
Conversation compaction results including success status, metrics, and optional error
details
- Task completion notification with optional summary from the agent
-
- User message content with optional attachments, source information, and interaction
- metadata
+ Task completion notification with summary from the agent
Empty payload; the event signals that the pending message queue has changed
@@ -2805,18 +3129,27 @@ class SessionEvent:
User input request completion notification signaling UI dismissal
- Structured form elicitation request with JSON schema definition for form fields
+ Elicitation request; may be form-based (structured input) or URL-based (browser
+ redirect)
Elicitation request completion notification signaling UI dismissal
+ OAuth authentication request for an MCP server
+
+ MCP OAuth request completion notification
+
External tool invocation request for client-side tool execution
External tool completion notification signaling UI dismissal
Queued slash command dispatch request for client execution
+ Registered command dispatch request routed to the owning client
+
Queued command completion notification signaling UI dismissal
+ SDK command registration change notification
+
Plan approval request with plan content and available user actions
Plan mode exit completion notification signaling UI dismissal
diff --git a/python/e2e/test_agent_and_compact_rpc.py b/python/e2e/test_agent_and_compact_rpc.py
index 63d3e7322..e82fcc024 100644
--- a/python/e2e/test_agent_and_compact_rpc.py
+++ b/python/e2e/test_agent_and_compact_rpc.py
@@ -147,7 +147,7 @@ async def test_should_deselect_current_agent(self):
@pytest.mark.asyncio
async def test_should_return_empty_list_when_no_custom_agents_configured(self):
- """Test listing agents returns empty when none configured."""
+ """Test listing agents returns no custom agents when none configured."""
client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH, use_stdio=True))
try:
@@ -157,7 +157,13 @@ async def test_should_return_empty_list_when_no_custom_agents_configured(self):
)
result = await session.rpc.agent.list()
- assert result.agents == []
+ # The CLI may return built-in/default agents even when no custom agents
+ # are configured. Verify no custom test agents appear in the list.
+ custom_names = {"test-agent", "another-agent"}
+ for agent in result.agents:
+ assert agent.name not in custom_names, (
+ f"Expected no custom agents, but found {agent.name!r}"
+ )
await session.disconnect()
await client.stop()
diff --git a/scripts/codegen/go.ts b/scripts/codegen/go.ts
index c467761d0..59abee298 100644
--- a/scripts/codegen/go.ts
+++ b/scripts/codegen/go.ts
@@ -45,6 +45,77 @@ function toGoFieldName(jsonName: string): string {
.join("");
}
+/**
+ * Post-process Go enum constants so every constant follows the canonical
+ * Go `TypeNameValue` convention. quicktype disambiguates collisions with
+ * whimsical prefixes (Purple, Fluffy, …) that we replace.
+ */
+function postProcessEnumConstants(code: string): string {
+ const renames = new Map();
+
+ // Match constant declarations inside const ( … ) blocks.
+ const constLineRe = /^\s+(\w+)\s+(\w+)\s*=\s*"([^"]+)"/gm;
+ let m;
+ while ((m = constLineRe.exec(code)) !== null) {
+ const [, constName, typeName, value] = m;
+ if (constName.startsWith(typeName)) continue;
+
+ // Use the same initialism logic as toPascalCase so "url" → "URL", "mcp" → "MCP", etc.
+ const valuePascal = value
+ .split(/[._-]/)
+ .map((w) => goInitialisms.has(w.toLowerCase()) ? w.toUpperCase() : w.charAt(0).toUpperCase() + w.slice(1))
+ .join("");
+ const desired = typeName + valuePascal;
+ if (constName !== desired) {
+ renames.set(constName, desired);
+ }
+ }
+
+ // Replace each const block in place, then fix switch-case references
+ // in marshal/unmarshal functions. This avoids renaming struct fields.
+
+ // Phase 1: Rename inside const ( … ) blocks
+ code = code.replace(/^(const \([\s\S]*?\n\))/gm, (block) => {
+ let b = block;
+ for (const [oldName, newName] of renames) {
+ b = b.replace(new RegExp(`\\b${oldName}\\b`, "g"), newName);
+ }
+ return b;
+ });
+
+ // Phase 2: Rename inside func bodies (marshal/unmarshal helpers use case statements)
+ code = code.replace(/^(func \([\s\S]*?\n\})/gm, (funcBlock) => {
+ let b = funcBlock;
+ for (const [oldName, newName] of renames) {
+ b = b.replace(new RegExp(`\\b${oldName}\\b`, "g"), newName);
+ }
+ return b;
+ });
+
+ return code;
+}
+
+/**
+ * Extract a mapping from (structName, jsonFieldName) → goFieldName
+ * so the wrapper code references the actual quicktype-generated field names.
+ */
+function extractFieldNames(qtCode: string): Map> {
+ const result = new Map>();
+ const structRe = /^type\s+(\w+)\s+struct\s*\{([^}]*)\}/gm;
+ let sm;
+ while ((sm = structRe.exec(qtCode)) !== null) {
+ const [, structName, body] = sm;
+ const fields = new Map();
+ const fieldRe = /^\s+(\w+)\s+[^`\n]+`json:"([^",]+)/gm;
+ let fm;
+ while ((fm = fieldRe.exec(body)) !== null) {
+ fields.set(fm[2], fm[1]);
+ }
+ result.set(structName, fields);
+ }
+ return result;
+}
+
async function formatGoFile(filePath: string): Promise {
try {
await execFileAsync("go", ["fmt", filePath]);
@@ -93,7 +164,7 @@ async function generateSessionEvents(schemaPath?: string): Promise {
`;
- const outPath = await writeGeneratedFile("go/generated_session_events.go", banner + result.lines.join("\n"));
+ const outPath = await writeGeneratedFile("go/generated_session_events.go", banner + postProcessEnumConstants(result.lines.join("\n")));
console.log(` ✓ ${outPath}`);
await formatGoFile(outPath);
@@ -154,22 +225,25 @@ async function generateRpc(schemaPath?: string): Promise {
rendererOptions: { package: "copilot", "just-types": "true" },
});
- // Build method wrappers
- const lines: string[] = [];
- lines.push(`// AUTO-GENERATED FILE - DO NOT EDIT`);
- lines.push(`// Generated from: api.schema.json`);
- lines.push(``);
- lines.push(`package rpc`);
- lines.push(``);
- lines.push(`import (`);
- lines.push(`\t"context"`);
- lines.push(`\t"encoding/json"`);
- lines.push(``);
- lines.push(`\t"github.com/github/copilot-sdk/go/internal/jsonrpc2"`);
- lines.push(`)`);
- lines.push(``);
+ // Post-process quicktype output: fix enum constant names
+ let qtCode = qtResult.lines.filter((l) => !l.startsWith("package ")).join("\n");
+ qtCode = postProcessEnumConstants(qtCode);
+ // Strip trailing whitespace from quicktype output (gofmt requirement)
+ qtCode = qtCode.replace(/[ \t]+$/gm, "");
- // Add quicktype-generated types (skip package line), annotating experimental types
+ // Extract actual type names generated by quicktype (may differ from toPascalCase)
+ const actualTypeNames = new Map();
+ const structRe = /^type\s+(\w+)\s+struct\b/gm;
+ let sm;
+ while ((sm = structRe.exec(qtCode)) !== null) {
+ actualTypeNames.set(sm[1].toLowerCase(), sm[1]);
+ }
+ const resolveType = (name: string): string => actualTypeNames.get(name.toLowerCase()) ?? name;
+
+ // Extract field name mappings (quicktype may rename fields to avoid Go keyword conflicts)
+ const fieldNames = extractFieldNames(qtCode);
+
+ // Annotate experimental data types
const experimentalTypeNames = new Set();
for (const method of allMethods) {
if (method.stability !== "experimental") continue;
@@ -179,9 +253,6 @@ async function generateRpc(schemaPath?: string): Promise {
experimentalTypeNames.add(baseName + "Params");
}
}
- let qtCode = qtResult.lines.filter((l) => !l.startsWith("package ")).join("\n");
- // Strip trailing whitespace from quicktype output (gofmt requirement)
- qtCode = qtCode.replace(/[ \t]+$/gm, "");
for (const typeName of experimentalTypeNames) {
qtCode = qtCode.replace(
new RegExp(`^(type ${typeName} struct)`, "m"),
@@ -190,17 +261,33 @@ async function generateRpc(schemaPath?: string): Promise {
}
// Remove trailing blank lines from quicktype output before appending
qtCode = qtCode.replace(/\n+$/, "");
+
+ // Build method wrappers
+ const lines: string[] = [];
+ lines.push(`// AUTO-GENERATED FILE - DO NOT EDIT`);
+ lines.push(`// Generated from: api.schema.json`);
+ lines.push(``);
+ lines.push(`package rpc`);
+ lines.push(``);
+ lines.push(`import (`);
+ lines.push(`\t"context"`);
+ lines.push(`\t"encoding/json"`);
+ lines.push(``);
+ lines.push(`\t"github.com/github/copilot-sdk/go/internal/jsonrpc2"`);
+ lines.push(`)`);
+ lines.push(``);
+
lines.push(qtCode);
lines.push(``);
// Emit ServerRpc
if (schema.server) {
- emitRpcWrapper(lines, schema.server, false);
+ emitRpcWrapper(lines, schema.server, false, resolveType, fieldNames);
}
// Emit SessionRpc
if (schema.session) {
- emitRpcWrapper(lines, schema.session, true);
+ emitRpcWrapper(lines, schema.session, true, resolveType, fieldNames);
}
const outPath = await writeGeneratedFile("go/rpc/generated_rpc.go", lines.join("\n"));
@@ -209,7 +296,7 @@ async function generateRpc(schemaPath?: string): Promise {
await formatGoFile(outPath);
}
-function emitRpcWrapper(lines: string[], node: Record, isSession: boolean): void {
+function emitRpcWrapper(lines: string[], node: Record, isSession: boolean, resolveType: (name: string) => string, fieldNames: Map>): void {
const groups = Object.entries(node).filter(([, v]) => typeof v === "object" && v !== null && !isRpcMethod(v));
const topLevelMethods = Object.entries(node).filter(([, v]) => isRpcMethod(v));
@@ -235,7 +322,7 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio
lines.push(``);
for (const [key, value] of Object.entries(groupNode as Record)) {
if (!isRpcMethod(value)) continue;
- emitMethod(lines, apiName, key, value, isSession, groupExperimental);
+ emitMethod(lines, apiName, key, value, isSession, resolveType, fieldNames, groupExperimental);
}
}
@@ -260,7 +347,7 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio
// Top-level methods (server only)
for (const [key, value] of topLevelMethods) {
if (!isRpcMethod(value)) continue;
- emitMethod(lines, wrapperName, key, value, isSession, false);
+ emitMethod(lines, wrapperName, key, value, isSession, resolveType, fieldNames, false);
}
// Compute key alignment for constructor composite literal (gofmt aligns key: value)
@@ -284,15 +371,15 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio
lines.push(``);
}
-function emitMethod(lines: string[], receiver: string, name: string, method: RpcMethod, isSession: boolean, groupExperimental = false): void {
+function emitMethod(lines: string[], receiver: string, name: string, method: RpcMethod, isSession: boolean, resolveType: (name: string) => string, fieldNames: Map>, groupExperimental = false): void {
const methodName = toPascalCase(name);
- const resultType = toPascalCase(method.rpcMethod) + "Result";
+ const resultType = resolveType(toPascalCase(method.rpcMethod) + "Result");
const paramProps = method.params?.properties || {};
const requiredParams = new Set(method.params?.required || []);
const nonSessionParams = Object.keys(paramProps).filter((k) => k !== "sessionId");
const hasParams = isSession ? nonSessionParams.length > 0 : Object.keys(paramProps).length > 0;
- const paramsType = hasParams ? toPascalCase(method.rpcMethod) + "Params" : "";
+ const paramsType = hasParams ? resolveType(toPascalCase(method.rpcMethod) + "Params") : "";
if (method.stability === "experimental" && !groupExperimental) {
lines.push(`// Experimental: ${methodName} is an experimental API and may change or be removed in future versions.`);
@@ -308,7 +395,7 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc
if (hasParams) {
lines.push(`\tif params != nil {`);
for (const pName of nonSessionParams) {
- const goField = toGoFieldName(pName);
+ const goField = fieldNames.get(paramsType)?.get(pName) ?? toGoFieldName(pName);
const isOptional = !requiredParams.has(pName);
if (isOptional) {
// Optional fields are pointers - only add when non-nil and dereference
diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts
index cbbc3df38..0340cf1f1 100644
--- a/scripts/codegen/python.ts
+++ b/scripts/codegen/python.ts
@@ -32,12 +32,37 @@ import {
* - Callable from collections.abc instead of typing
* - Clean up unused typing imports
*/
+function replaceBalancedBrackets(code: string, prefix: string, replacer: (inner: string) => string): string {
+ let result = "";
+ let i = 0;
+ while (i < code.length) {
+ const idx = code.indexOf(prefix + "[", i);
+ if (idx === -1) {
+ result += code.slice(i);
+ break;
+ }
+ result += code.slice(i, idx);
+ const start = idx + prefix.length + 1; // after '['
+ let depth = 1;
+ let j = start;
+ while (j < code.length && depth > 0) {
+ if (code[j] === "[") depth++;
+ else if (code[j] === "]") depth--;
+ j++;
+ }
+ const inner = code.slice(start, j - 1);
+ result += replacer(inner);
+ i = j;
+ }
+ return result;
+}
+
function modernizePython(code: string): string {
- // Replace Optional[X] with X | None (handles nested brackets)
- code = code.replace(/Optional\[([^\[\]]*(?:\[[^\[\]]*\])*[^\[\]]*)\]/g, "$1 | None");
+ // Replace Optional[X] with X | None (handles arbitrarily nested brackets)
+ code = replaceBalancedBrackets(code, "Optional", (inner) => `${inner} | None`);
// Replace Union[X, Y] with X | Y
- code = code.replace(/Union\[([^\[\]]*(?:\[[^\[\]]*\])*[^\[\]]*)\]/g, (_match, inner: string) => {
+ code = replaceBalancedBrackets(code, "Union", (inner) => {
return inner.split(",").map((s: string) => s.trim()).join(" | ");
});
@@ -234,6 +259,16 @@ async function generateRpc(schemaPath?: string): Promise {
);
}
+ // Extract actual class names generated by quicktype (may differ from toPascalCase,
+ // e.g. quicktype produces "SessionMCPList" not "SessionMcpList")
+ const actualTypeNames = new Map();
+ const classRe = /^class\s+(\w+)\b/gm;
+ let cm;
+ while ((cm = classRe.exec(typesCode)) !== null) {
+ actualTypeNames.set(cm[1].toLowerCase(), cm[1]);
+ }
+ const resolveType = (name: string): string => actualTypeNames.get(name.toLowerCase()) ?? name;
+
const lines: string[] = [];
lines.push(`"""
AUTO-GENERATED FILE - DO NOT EDIT
@@ -258,17 +293,17 @@ def _timeout_kwargs(timeout: float | None) -> dict:
// Emit RPC wrapper classes
if (schema.server) {
- emitRpcWrapper(lines, schema.server, false);
+ emitRpcWrapper(lines, schema.server, false, resolveType);
}
if (schema.session) {
- emitRpcWrapper(lines, schema.session, true);
+ emitRpcWrapper(lines, schema.session, true, resolveType);
}
const outPath = await writeGeneratedFile("python/copilot/generated/rpc.py", lines.join("\n"));
console.log(` ✓ ${outPath}`);
}
-function emitRpcWrapper(lines: string[], node: Record, isSession: boolean): void {
+function emitRpcWrapper(lines: string[], node: Record, isSession: boolean, resolveType: (name: string) => string): void {
const groups = Object.entries(node).filter(([, v]) => typeof v === "object" && v !== null && !isRpcMethod(v));
const topLevelMethods = Object.entries(node).filter(([, v]) => isRpcMethod(v));
@@ -298,7 +333,7 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio
lines.push(``);
for (const [key, value] of Object.entries(groupNode as Record)) {
if (!isRpcMethod(value)) continue;
- emitMethod(lines, key, value, isSession, groupExperimental);
+ emitMethod(lines, key, value, isSession, resolveType, groupExperimental);
}
lines.push(``);
}
@@ -327,19 +362,19 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio
// Top-level methods
for (const [key, value] of topLevelMethods) {
if (!isRpcMethod(value)) continue;
- emitMethod(lines, key, value, isSession, false);
+ emitMethod(lines, key, value, isSession, resolveType, false);
}
lines.push(``);
}
-function emitMethod(lines: string[], name: string, method: RpcMethod, isSession: boolean, groupExperimental = false): void {
+function emitMethod(lines: string[], name: string, method: RpcMethod, isSession: boolean, resolveType: (name: string) => string, groupExperimental = false): void {
const methodName = toSnakeCase(name);
- const resultType = toPascalCase(method.rpcMethod) + "Result";
+ const resultType = resolveType(toPascalCase(method.rpcMethod) + "Result");
const paramProps = method.params?.properties || {};
const nonSessionParams = Object.keys(paramProps).filter((k) => k !== "sessionId");
const hasParams = isSession ? nonSessionParams.length > 0 : Object.keys(paramProps).length > 0;
- const paramsType = toPascalCase(method.rpcMethod) + "Params";
+ const paramsType = resolveType(toPascalCase(method.rpcMethod) + "Params");
// Build signature with typed params + optional timeout
const sig = hasParams
diff --git a/test/harness/package-lock.json b/test/harness/package-lock.json
index bf9564d9a..c8ec038fb 100644
--- a/test/harness/package-lock.json
+++ b/test/harness/package-lock.json
@@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
- "@github/copilot": "^1.0.4",
+ "@github/copilot": "^1.0.10-0",
"@modelcontextprotocol/sdk": "^1.26.0",
"@types/node": "^25.3.3",
"openai": "^6.17.0",
@@ -462,27 +462,27 @@
}
},
"node_modules/@github/copilot": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.4.tgz",
- "integrity": "sha512-IpPg+zYplLu4F4lmatEDdR/1Y/jJ9cGWt89m3K3H4YSfYrZ5Go4UlM28llulYCG7sVdQeIGauQN1/KiBI/Rocg==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.10-0.tgz",
+ "integrity": "sha512-LmVe3yVDamZc4cbZeyprZ6WjTME9Z4UcB5YWnEagtXJ19KP5PBKbBZVG7pZnQHL2/IHZ/dqcZW3IHMgYDoqDvg==",
"dev": true,
"license": "SEE LICENSE IN LICENSE.md",
"bin": {
"copilot": "npm-loader.js"
},
"optionalDependencies": {
- "@github/copilot-darwin-arm64": "1.0.4",
- "@github/copilot-darwin-x64": "1.0.4",
- "@github/copilot-linux-arm64": "1.0.4",
- "@github/copilot-linux-x64": "1.0.4",
- "@github/copilot-win32-arm64": "1.0.4",
- "@github/copilot-win32-x64": "1.0.4"
+ "@github/copilot-darwin-arm64": "1.0.10-0",
+ "@github/copilot-darwin-x64": "1.0.10-0",
+ "@github/copilot-linux-arm64": "1.0.10-0",
+ "@github/copilot-linux-x64": "1.0.10-0",
+ "@github/copilot-win32-arm64": "1.0.10-0",
+ "@github/copilot-win32-x64": "1.0.10-0"
}
},
"node_modules/@github/copilot-darwin-arm64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.4.tgz",
- "integrity": "sha512-/YGGhv6cp0ItolsF0HsLq2KmesA4atn0IEYApBs770fzJ8OP2pkOEzrxo3gWU3wc7fHF2uDB1RrJEZ7QSFLdEQ==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.10-0.tgz",
+ "integrity": "sha512-u5CbflcTpvc4E48E0jrqbN3Y5hWzValMs21RR6L+GDjQpPI2pvDeUWAJZ03Y7qQ2Uk3KZ+hOIJWJvje9VHxrDQ==",
"cpu": [
"arm64"
],
@@ -497,9 +497,9 @@
}
},
"node_modules/@github/copilot-darwin-x64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.4.tgz",
- "integrity": "sha512-gwn2QjZbc1SqPVSAtDMesU1NopyHZT8Qsn37xPfznpV9s94KVyX4TTiDZaUwfnI0wr8kVHBL46RPLNz6I8kR9A==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.10-0.tgz",
+ "integrity": "sha512-4y5OXhAfWX+il9slhrq7v8ONzq+Hpw46ktnz7l1fAZKdmn+dzmFVCvr6pJPr5Az78cAKBuN+Gt4eeSNaxuKCmA==",
"cpu": [
"x64"
],
@@ -514,9 +514,9 @@
}
},
"node_modules/@github/copilot-linux-arm64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.4.tgz",
- "integrity": "sha512-92vzHKxN55BpI76sP/5fXIXfat1gzAhsq4bNLqLENGfZyMP/25OiVihCZuQHnvxzXaHBITFGUvtxfdll2kbcng==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.10-0.tgz",
+ "integrity": "sha512-j+Z/ZahEIT5SCblUqOJ2+2glWeIIUPKXXFS5bbu5kFZ9Xyag37FBvTjyxDeB02dpSKKDD4xbMVjcijFbtyr1PA==",
"cpu": [
"arm64"
],
@@ -531,9 +531,9 @@
}
},
"node_modules/@github/copilot-linux-x64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.4.tgz",
- "integrity": "sha512-wQvpwf4/VMTnSmWyYzq07Xg18Vxg7aZ5NVkkXqlLTuXRASW0kvCCb5USEtXHHzR7E6rJztkhCjFRE1bZW8jAGw==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.10-0.tgz",
+ "integrity": "sha512-S8IfuiMZWwnFW1v0vOGHalPIXq/75kL/RpZCYd1sleQA/yztCNNjxH9tNpXsdZnhYrAgU/3hqseWq5hbz8xjxA==",
"cpu": [
"x64"
],
@@ -548,9 +548,9 @@
}
},
"node_modules/@github/copilot-win32-arm64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.4.tgz",
- "integrity": "sha512-zOvD/5GVxDf0ZdlTkK+m55Vs55xuHNmACX50ZO2N23ZGG2dmkdS4mkruL59XB5ISgrOfeqvnqrwTFHbmPZtLfw==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.10-0.tgz",
+ "integrity": "sha512-6HJErp91fLrwIkoXegLK8SXjHzLgbl9GF+QdOtUGqZ915UUfXcchef0tQjN8u35yNLEW82VnAmft/PJ9Ok2UhQ==",
"cpu": [
"arm64"
],
@@ -565,9 +565,9 @@
}
},
"node_modules/@github/copilot-win32-x64": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.4.tgz",
- "integrity": "sha512-yQenHMdkV0b77mF6aLM60TuwtNZ592TluptVDF+80Sj2zPfCpLyvrRh2FCIHRtuwTy4BfxETh2hCFHef8E6IOw==",
+ "version": "1.0.10-0",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.10-0.tgz",
+ "integrity": "sha512-AQwZYHoarRACbmPUPmH7gPOEomTAtDusCn65ancI3BoWGj9fzAgZEZ5JSaR3N/VUoXWoEbSe+PcH380ZYwsPag==",
"cpu": [
"x64"
],
diff --git a/test/harness/package.json b/test/harness/package.json
index 9f336dfd4..25117cac9 100644
--- a/test/harness/package.json
+++ b/test/harness/package.json
@@ -11,7 +11,7 @@
"test": "vitest run"
},
"devDependencies": {
- "@github/copilot": "^1.0.4",
+ "@github/copilot": "^1.0.10-0",
"@modelcontextprotocol/sdk": "^1.26.0",
"@types/node": "^25.3.3",
"openai": "^6.17.0",
diff --git a/test/scenarios/prompts/attachments/README.md b/test/scenarios/prompts/attachments/README.md
index d61a26e57..76b76751d 100644
--- a/test/scenarios/prompts/attachments/README.md
+++ b/test/scenarios/prompts/attachments/README.md
@@ -39,7 +39,7 @@ Demonstrates sending **file attachments** alongside a prompt using the Copilot S
|----------|------------------------|
| TypeScript | `attachments: [{ type: "blob", data: base64Data, mimeType: "image/png" }]` |
| Python | `"attachments": [{"type": "blob", "data": base64_data, "mimeType": "image/png"}]` |
-| Go | `Attachments: []copilot.Attachment{{Type: copilot.Blob, Data: &data, MIMEType: &mime}}` |
+| Go | `Attachments: []copilot.Attachment{{Type: copilot.AttachmentTypeBlob, Data: &data, MIMEType: &mime}}` |
## Sample Data