From 786e6188320f3a492d04402824898fb5f15c8304 Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 13:05:36 +0200 Subject: [PATCH 1/9] =?UTF-8?q?chore(schema):=20bump=20copilot=20CLI=20sch?= =?UTF-8?q?ema=201.0.55-1=20=E2=86=92=201.0.56-1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerated wire layer (event_specs.clj, coerce.clj) for upstream tags v1.0.0-beta.9 and v1.0.0-beta.10. Schema diff surfaces: - contextTier ("long_context" | "default" | nil) on session.start, session.resume, session.model_change event data. - workingDirectory on external_tool.requested event data. - Three new session event types: hook.progress, session.autopilot_objective_changed, session.permissions_changed. - Autopilot objective status enum widened to include "active", "paused", "cap_reached", "completed". - Many new SessionConfigBase fields (mcpOAuthTokenStorage, embeddingCacheStorage, pluginDirectories, multitenancy flags, reasoningSummary, contextTier, displayPrompt, agentMode, etc.) — exposed on the public API in a follow-up commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .copilot-schema-version | 2 +- schemas/README.md | 2 +- schemas/api.schema.json | 1351 ++++++++++++++--- schemas/session-events.schema.json | 317 +++- .../copilot_sdk/generated/event_specs.clj | 40 +- 5 files changed, 1480 insertions(+), 232 deletions(-) diff --git a/.copilot-schema-version b/.copilot-schema-version index 1dc08bd..8e17bf1 100644 --- a/.copilot-schema-version +++ b/.copilot-schema-version @@ -1 +1 @@ -1.0.55-1 +1.0.56-1 diff --git a/schemas/README.md b/schemas/README.md index 29a817c..f904ea6 100644 --- a/schemas/README.md +++ b/schemas/README.md @@ -4,4 +4,4 @@ These files are fetched verbatim from the `@github/copilot` npm package at the v **Do not edit by hand.** To update, run `bb schemas:fetch` after bumping `.copilot-schema-version`. -Currently pinned version: `1.0.55-1` +Currently pinned version: `1.0.56-1` diff --git a/schemas/api.schema.json b/schemas/api.schema.json index 314b857..d4d59e2 100644 --- a/schemas/api.schema.json +++ b/schemas/api.schema.json @@ -149,6 +149,14 @@ "result": { "type": "null" } + }, + "reload": { + "rpcMethod": "mcp.config.reload", + "description": "Drops this runtime process's in-memory MCP server-definition cache so the next MCP config read observes disk.", + "params": null, + "result": { + "type": "null" + } } }, "discover": { @@ -191,6 +199,18 @@ } } }, + "user": { + "settings": { + "reload": { + "rpcMethod": "user.settings.reload", + "description": "Drops this runtime process's in-memory user settings cache so the next settings read observes disk.", + "params": null, + "result": { + "type": "null" + } + } + } + }, "sessionFs": { "setProvider": { "rpcMethod": "sessionFs.setProvider", @@ -237,7 +257,7 @@ "description": "Lists persisted sessions, optionally filtered by working-directory context.", "params": { "$ref": "#/definitions/SessionsListRequest", - "description": "Optional metadata-load limit and context filter applied to the returned sessions." + "description": "Optional metadata-load limit and filters applied to the returned sessions." }, "result": { "$ref": "#/definitions/SessionList", @@ -450,6 +470,21 @@ }, "stability": "experimental" } + }, + "agentRegistry": { + "spawn": { + "rpcMethod": "agentRegistry.spawn", + "description": "Spawns a managed-server child with the supplied configuration and returns a discriminated-union result. The caller (typically the CLI controller) is responsible for attaching to the spawned child and sending any follow-up prompt. When the controller-local spawn gate is closed the server returns JSON-RPC MethodNotFound.", + "params": { + "$ref": "#/definitions/AgentRegistrySpawnRequest", + "description": "Inputs to spawn a managed-server child via the controller's spawn delegate." + }, + "result": { + "$ref": "#/definitions/AgentRegistrySpawnResult", + "description": "Outcome of an agentRegistry.spawn call." + }, + "stability": "experimental" + } } }, "session": { @@ -789,43 +824,45 @@ }, "stability": "experimental" }, - "invokeAction": { - "rpcMethod": "session.canvas.invokeAction", - "description": "Invokes an action on an open canvas instance.", - "params": { - "type": "object", - "properties": { - "sessionId": { - "type": "string", - "description": "Target session identifier" - }, - "instanceId": { - "type": "string", - "description": "Open canvas instance identifier" - }, - "actionName": { - "type": "string", - "description": "Action name to invoke" + "action": { + "invoke": { + "rpcMethod": "session.canvas.action.invoke", + "description": "Invokes an action on an open canvas instance.", + "params": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + }, + "instanceId": { + "type": "string", + "description": "Open canvas instance identifier" + }, + "actionName": { + "type": "string", + "description": "Action name to invoke" + }, + "input": { + "description": "Action input", + "x-opaque-json": true + } }, - "input": { - "description": "Action input", - "x-opaque-json": true - } + "required": [ + "sessionId", + "instanceId", + "actionName" + ], + "additionalProperties": false, + "description": "Canvas action invocation parameters.", + "title": "CanvasActionInvokeRequest" }, - "required": [ - "sessionId", - "instanceId", - "actionName" - ], - "additionalProperties": false, - "description": "Canvas action invocation parameters.", - "title": "CanvasInvokeActionRequest" - }, - "result": { - "$ref": "#/definitions/CanvasInvokeActionResult", - "description": "Canvas action invocation result." - }, - "stability": "experimental" + "result": { + "$ref": "#/definitions/CanvasActionInvokeResult", + "description": "Canvas action invocation result." + }, + "stability": "experimental" + } } }, "model": { @@ -877,6 +914,25 @@ "modelCapabilities": { "$ref": "#/definitions/ModelCapabilitiesOverride", "description": "Override individual model capabilities resolved by the runtime" + }, + "contextTier": { + "anyOf": [ + { + "type": "string", + "enum": [ + "default", + "long_context" + ], + "x-enumDescriptions": { + "default": "Use the model's default context window.", + "long_context": "Pin the session to the long-context tier when supported." + } + }, + { + "type": "null" + } + ], + "description": "Explicit context tier for the selected model. `\"default\"` / `\"long_context\"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched." } }, "required": [ @@ -884,7 +940,7 @@ "modelId" ], "additionalProperties": false, - "description": "Target model identifier and optional reasoning effort, summary, and capability overrides.", + "description": "Target model identifier and optional reasoning effort, summary, capability overrides, and context tier.", "title": "ModelSwitchToRequest" }, "result": { @@ -921,6 +977,43 @@ "description": "Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns." }, "stability": "experimental" + }, + "list": { + "rpcMethod": "session.model.list", + "description": "Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's.", + "params": { + "anyOf": [ + { + "not": {} + }, + { + "type": "object", + "properties": { + "skipCache": { + "type": "boolean", + "description": "If true, bypasses the per-session model list cache and re-fetches from CAPI." + } + }, + "additionalProperties": false + } + ], + "description": "Optional listing options.", + "title": "ModelListRequest", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + } + }, + "required": [ + "sessionId" + ] + }, + "result": { + "$ref": "#/definitions/SessionModelList", + "description": "The list of models available to this session." + }, + "stability": "experimental" } }, "mode": { @@ -2582,6 +2675,10 @@ }, "description": "Denylist of tool names for this session." }, + "toolFilterPrecedence": { + "$ref": "#/definitions/OptionsUpdateToolFilterPrecedence", + "description": "Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set." + }, "enableScriptSafety": { "type": "boolean", "description": "Whether shell-script safety heuristics are enabled." @@ -2701,6 +2798,30 @@ "manageScheduleEnabled": { "type": "boolean", "description": "Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users)." + }, + "skipEmbeddingRetrieval": { + "type": "boolean", + "description": "Whether to skip embedding retrieval pipeline initialization and execution." + }, + "organizationCustomInstructions": { + "type": "string", + "description": "Organization-level custom instructions to inject into the system prompt." + }, + "enableFileHooks": { + "type": "boolean", + "description": "Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism." + }, + "enableHostGitOperations": { + "type": "boolean", + "description": "Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt)." + }, + "enableSessionStore": { + "type": "boolean", + "description": "Whether to enable cross-session store writes and reads." + }, + "enableSkills": { + "type": "boolean", + "description": "Whether to enable skill directory scanning and loading. Falls back to enableConfigDiscovery when unset." } }, "additionalProperties": false, @@ -2917,6 +3038,29 @@ "description": "Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation." }, "stability": "experimental" + }, + "getCurrentMetadata": { + "rpcMethod": "session.tools.getCurrentMetadata", + "description": "Returns lightweight metadata for the session's currently initialized tools.", + "params": { + "type": "object", + "description": "Identifies the target session.", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "result": { + "$ref": "#/definitions/ToolsGetCurrentMetadataResult", + "description": "Current lightweight tool metadata snapshot for the session." + }, + "stability": "experimental" } }, "commands": { @@ -3562,6 +3706,63 @@ }, "stability": "experimental" }, + "setAllowAll": { + "rpcMethod": "session.permissions.setAllowAll", + "description": "Enables or disables full allow-all permissions (tools, paths, and URLs) for the session. Used by attach-mode clients (e.g. LocalRpcSession's `/allow-all` forwarder) to flip the target session's permission state. Unlike `setApproveAll`, this swaps in the unrestricted path and URL managers and emits `session.permissions_changed` on transition. The result returns the authoritative post-mutation state so callers can update their local mirrors without racing the `session.permissions_changed` notification on the same wire.", + "params": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + }, + "enabled": { + "type": "boolean", + "description": "Whether to enable full allow-all permissions" + }, + "source": { + "$ref": "#/definitions/PermissionsSetAllowAllSource", + "description": "Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers." + } + }, + "required": [ + "sessionId", + "enabled" + ], + "additionalProperties": false, + "description": "Whether to enable full allow-all permissions for the session.", + "title": "PermissionsSetAllowAllRequest" + }, + "result": { + "$ref": "#/definitions/AllowAllPermissionSetResult", + "description": "Indicates whether the operation succeeded and reports the post-mutation state." + }, + "stability": "experimental" + }, + "getAllowAll": { + "rpcMethod": "session.permissions.getAllowAll", + "description": "Returns whether full allow-all permissions are currently active for the session.", + "params": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + } + }, + "additionalProperties": false, + "description": "No parameters.", + "title": "PermissionsGetAllowAllRequest", + "required": [ + "sessionId" + ] + }, + "result": { + "$ref": "#/definitions/AllowAllPermissionState", + "description": "Current full allow-all permission state." + }, + "stability": "experimental" + }, "modifyRules": { "rpcMethod": "session.permissions.modifyRules", "description": "Adds or removes session-scoped or location-scoped permission rules.", @@ -5296,6 +5497,10 @@ "host": { "$ref": "#/definitions/CanvasHostContext", "description": "Host context supplied by the runtime." + }, + "session": { + "$ref": "#/definitions/CanvasSessionContext", + "description": "Session context supplied by the runtime." } }, "required": [ @@ -5339,6 +5544,10 @@ "host": { "$ref": "#/definitions/CanvasHostContext", "description": "Host context supplied by the runtime." + }, + "session": { + "$ref": "#/definitions/CanvasSessionContext", + "description": "Session context supplied by the runtime." } }, "required": [ @@ -5356,57 +5565,63 @@ }, "stability": "experimental" }, - "invokeAction": { - "rpcMethod": "canvas.invokeAction", - "description": "Invokes an action on an open canvas instance via the provider.", - "params": { - "type": "object", - "properties": { - "sessionId": { - "type": "string", - "description": "Target session identifier" - }, - "extensionId": { - "type": "string", - "description": "Owning provider identifier" - }, - "canvasId": { - "type": "string", - "description": "Provider-local canvas identifier" - }, - "instanceId": { - "type": "string", - "description": "Canvas instance identifier" - }, - "actionName": { - "type": "string", - "description": "Action name to invoke" - }, - "input": { - "description": "Action input", - "x-opaque-json": true + "action": { + "invoke": { + "rpcMethod": "canvas.action.invoke", + "description": "Invokes an action on an open canvas instance via the provider.", + "params": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + }, + "extensionId": { + "type": "string", + "description": "Owning provider identifier" + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + }, + "instanceId": { + "type": "string", + "description": "Canvas instance identifier" + }, + "actionName": { + "type": "string", + "description": "Action name to invoke" + }, + "input": { + "description": "Action input", + "x-opaque-json": true + }, + "host": { + "$ref": "#/definitions/CanvasHostContext", + "description": "Host context supplied by the runtime." + }, + "session": { + "$ref": "#/definitions/CanvasSessionContext", + "description": "Session context supplied by the runtime." + } }, - "host": { - "$ref": "#/definitions/CanvasHostContext", - "description": "Host context supplied by the runtime." - } + "required": [ + "sessionId", + "extensionId", + "canvasId", + "instanceId", + "actionName" + ], + "additionalProperties": false, + "description": "Canvas action invocation parameters sent to the provider.", + "title": "CanvasProviderInvokeActionRequest" }, - "required": [ - "sessionId", - "extensionId", - "canvasId", - "instanceId", - "actionName" - ], - "additionalProperties": false, - "description": "Canvas action invocation parameters sent to the provider.", - "title": "CanvasProviderInvokeActionRequest" - }, - "result": { - "description": "Provider-supplied action result.", - "x-opaque-json": true - }, - "stability": "experimental" + "result": { + "description": "Provider-supplied action result.", + "x-opaque-json": true + }, + "stability": "experimental" + } } } }, @@ -5669,23 +5884,445 @@ "description": "Custom agents available to the session.", "title": "AgentList" }, - "AgentReloadResult": { + "AgentRegistryLiveTargetEntry": { "type": "object", "properties": { - "agents": { - "type": "array", - "items": { - "$ref": "#/definitions/AgentInfo" - }, - "description": "Reloaded custom agents" - } - }, - "required": [ - "agents" - ], - "additionalProperties": false, - "description": "Custom agents available to the session after reloading definitions from disk.", - "title": "AgentReloadResult" + "schemaVersion": { + "type": "integer", + "description": "Registry entry schema version (1 = ui-server, 2 = managed-server)" + }, + "kind": { + "$ref": "#/definitions/AgentRegistryLiveTargetEntryKind", + "description": "Process kind tag for the registry entry" + }, + "pid": { + "type": "integer", + "description": "Operating-system pid of the process owning this entry" + }, + "host": { + "type": "string", + "description": "Bind host for the entry's JSON-RPC server" + }, + "port": { + "type": "integer", + "description": "TCP port the entry's JSON-RPC server is listening on" + }, + "token": { + "type": [ + "string", + "null" + ], + "description": "Connection token (null when the target is unauthenticated)", + "visibility": "internal" + }, + "sessionId": { + "type": "string", + "description": "Session ID of the foreground session for this entry" + }, + "sessionName": { + "type": "string", + "description": "Friendly session name (when set)" + }, + "cwd": { + "type": "string", + "description": "Working directory of the session (when known)" + }, + "branch": { + "type": "string", + "description": "Git branch of the session (when known)" + }, + "model": { + "type": "string", + "description": "Model identifier currently selected for the session" + }, + "status": { + "$ref": "#/definitions/AgentRegistryLiveTargetEntryStatus", + "description": "Coarse lifecycle status of the foreground session" + }, + "attentionKind": { + "$ref": "#/definitions/AgentRegistryLiveTargetEntryAttentionKind", + "description": "Kind of attention required when status === \"attention\". Meaningful only when status === \"attention\"." + }, + "statusRevision": { + "type": "integer", + "minimum": 0, + "description": "Monotonic per-publisher revision counter incremented on every status update. Lets watchers detect transient flips." + }, + "lastTerminalEvent": { + "$ref": "#/definitions/AgentRegistryLiveTargetEntryLastTerminalEvent", + "description": "How the most recent turn ended (clean vs aborted). Lets the renderer distinguish done from done_cancelled." + }, + "startedAt": { + "type": "string", + "description": "ISO 8601 timestamp captured at registration" + }, + "copilotVersion": { + "type": "string", + "description": "Copilot CLI version that wrote the entry" + }, + "lastSeenMs": { + "type": "integer", + "description": "Wall-clock milliseconds since the watcher last observed this entry (heartbeat freshness)" + } + }, + "required": [ + "schemaVersion", + "kind", + "pid", + "host", + "port", + "startedAt", + "copilotVersion", + "lastSeenMs" + ], + "additionalProperties": false, + "description": "Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window).", + "title": "AgentRegistryLiveTargetEntry" + }, + "AgentRegistryLiveTargetEntryAttentionKind": { + "type": "string", + "enum": [ + "error", + "permission", + "exit_plan", + "elicitation", + "user_input" + ], + "description": "Kind of attention required when status === \"attention\". Meaningful only when status === \"attention\".", + "title": "AgentRegistryLiveTargetEntryAttentionKind", + "x-enumDescriptions": { + "error": "Session is blocked on an unrecoverable error", + "permission": "Session is waiting for a tool-permission decision", + "exit_plan": "Session is waiting for the user to approve or reject a plan", + "elicitation": "Session is waiting on an elicitation prompt", + "user_input": "Session is waiting for free-form user input" + } + }, + "AgentRegistryLiveTargetEntryKind": { + "type": "string", + "enum": [ + "ui-server", + "managed-server" + ], + "description": "Process kind tag for the registry entry", + "title": "AgentRegistryLiveTargetEntryKind", + "x-enumDescriptions": { + "ui-server": "Interactive Copilot CLI exposing a UI server (legacy/normal CLI process)", + "managed-server": "Headless `--server --managed-server` child spawned by a controller" + } + }, + "AgentRegistryLiveTargetEntryLastTerminalEvent": { + "type": "string", + "enum": [ + "turn_end", + "abort" + ], + "description": "How the most recent turn ended (clean vs aborted). Lets the renderer distinguish done from done_cancelled.", + "title": "AgentRegistryLiveTargetEntryLastTerminalEvent", + "x-enumDescriptions": { + "turn_end": "Last turn ended cleanly (model returned a final assistant message)", + "abort": "Last turn was aborted (e.g. user interrupted)" + } + }, + "AgentRegistryLiveTargetEntryStatus": { + "type": "string", + "enum": [ + "working", + "waiting", + "done", + "attention" + ], + "description": "Coarse lifecycle status of the foreground session", + "title": "AgentRegistryLiveTargetEntryStatus", + "x-enumDescriptions": { + "working": "Session is actively processing a turn", + "waiting": "Session is idle, waiting for input", + "done": "Last turn completed successfully", + "attention": "Session needs user attention (see attentionKind for the specific reason)" + } + }, + "AgentRegistryLogCapture": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether per-spawn log capture is on (false when env-disabled or open failed)" + }, + "path": { + "type": "string", + "description": "Absolute path to the per-spawn log file (only set when enabled)" + }, + "openError": { + "type": "string", + "description": "Human-readable open failure message (only set when enabled === false AND the env-disable opt-out was NOT used)" + }, + "openErrorReason": { + "$ref": "#/definitions/AgentRegistryLogCaptureOpenErrorReason", + "description": "Categorized reason for log-open failure" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false, + "description": "Per-spawn log-capture outcome; populated from spawnLiveTarget.", + "title": "AgentRegistryLogCapture" + }, + "AgentRegistryLogCaptureOpenErrorReason": { + "type": "string", + "enum": [ + "permission", + "disk_full", + "other" + ], + "description": "Categorized reason for log-open failure", + "title": "AgentRegistryLogCaptureOpenErrorReason", + "x-enumDescriptions": { + "permission": "Filesystem permission denied opening the log file", + "disk_full": "No space left on device", + "other": "Other / uncategorized open failure" + } + }, + "AgentRegistrySpawnError": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "spawn-error", + "description": "Discriminator: child_process.spawn itself failed" + }, + "message": { + "type": "string", + "description": "Human-readable error message" + }, + "code": { + "type": "string", + "description": "Underlying errno code (e.g. ENOENT, EACCES) when available" + } + }, + "required": [ + "kind", + "message" + ], + "additionalProperties": false, + "description": "`child_process.spawn` itself failed before the child entered the registry.", + "title": "AgentRegistrySpawnError" + }, + "AgentRegistrySpawnPermissionMode": { + "type": "string", + "enum": [ + "default", + "yolo" + ], + "description": "Permission posture for the new session. 'yolo' requires the controller-local session to currently be in allow-all mode.", + "title": "AgentRegistrySpawnPermissionMode", + "x-enumDescriptions": { + "default": "Standard permission posture (prompts for each request)", + "yolo": "Full allow-all (requires the controller-local session to currently be in allow-all mode)" + } + }, + "AgentRegistrySpawnRegistryTimeout": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "registry-timeout", + "description": "Discriminator: spawn succeeded but child never registered" + }, + "childPid": { + "type": "integer", + "description": "Process ID of the orphaned child (so the caller can offer 'kill the pid' guidance)" + }, + "logCapture": { + "$ref": "#/definitions/AgentRegistryLogCapture", + "description": "Per-spawn log-capture outcome; populated from spawnLiveTarget." + } + }, + "required": [ + "kind", + "childPid" + ], + "additionalProperties": false, + "description": "Spawn succeeded but the child did not publish a matching managed-server entry within the timeout.", + "title": "AgentRegistrySpawnRegistryTimeout" + }, + "AgentRegistrySpawnRequest": { + "type": "object", + "properties": { + "cwd": { + "type": "string", + "description": "Working directory for the spawned child (must be an existing directory)" + }, + "agentName": { + "type": "string", + "description": "Custom or built-in agent name (e.g. 'explore'). When omitted, the child uses its own default." + }, + "model": { + "type": "string", + "description": "Model identifier to apply to the new session" + }, + "name": { + "type": "string", + "description": "Friendly session name. Must satisfy validateSessionName: non-empty, no leading/trailing whitespace, <=100 chars, no control chars, no double quotes." + }, + "permissionMode": { + "$ref": "#/definitions/AgentRegistrySpawnPermissionMode", + "description": "Permission posture for the new session. 'yolo' requires the controller-local session to currently be in allow-all mode." + }, + "initialPrompt": { + "type": "string", + "description": "Optional first user message. Forwarded to the caller (the CLI's spawn wrapper sends it post-attach via the standard LocalRpcSession.send path)." + } + }, + "required": [ + "cwd" + ], + "additionalProperties": false, + "description": "Inputs to spawn a managed-server child via the controller's spawn delegate.", + "title": "AgentRegistrySpawnRequest" + }, + "AgentRegistrySpawnResult": { + "anyOf": [ + { + "$ref": "#/definitions/AgentRegistrySpawnSpawned", + "description": "Managed-server child was spawned and registered successfully." + }, + { + "$ref": "#/definitions/AgentRegistrySpawnError", + "description": "`child_process.spawn` itself failed before the child entered the registry." + }, + { + "$ref": "#/definitions/AgentRegistrySpawnRegistryTimeout", + "description": "Spawn succeeded but the child did not publish a matching managed-server entry within the timeout." + }, + { + "$ref": "#/definitions/AgentRegistrySpawnValidationError", + "description": "Synchronous pre-validation rejected the spawn request." + } + ], + "description": "Outcome of an agentRegistry.spawn call.", + "title": "AgentRegistrySpawnResult" + }, + "AgentRegistrySpawnSpawned": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "spawned", + "description": "Discriminator: managed-server child spawned successfully" + }, + "entry": { + "$ref": "#/definitions/AgentRegistryLiveTargetEntry", + "description": "Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window)." + }, + "initialPromptSent": { + "type": "boolean", + "description": "Whether the delegate already sent the initial prompt. Always omitted in the current wiring: the controller sends the prompt post-attach via the standard LocalRpcSession.send path." + }, + "initialPromptError": { + "type": "string", + "description": "If the delegate attempted to send the initial prompt and failed, the categorized error message." + }, + "logCapture": { + "$ref": "#/definitions/AgentRegistryLogCapture", + "description": "Per-spawn log-capture outcome; populated from spawnLiveTarget." + } + }, + "required": [ + "kind", + "entry" + ], + "additionalProperties": false, + "description": "Managed-server child was spawned and registered successfully.", + "title": "AgentRegistrySpawnSpawned" + }, + "AgentRegistrySpawnValidationError": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "validation-error", + "description": "Discriminator: synchronous pre-validation rejected the request" + }, + "reason": { + "$ref": "#/definitions/AgentRegistrySpawnValidationErrorReason", + "description": "Categorized reason for the rejection. Low-cardinality enum so telemetry can aggregate by reason without leaking raw paths or agent/model names." + }, + "field": { + "$ref": "#/definitions/AgentRegistrySpawnValidationErrorField", + "description": "Which parameter field was invalid. Omitted when the rejection is not field-specific." + }, + "message": { + "type": "string", + "description": "Human-readable explanation; safe to surface in the UI banner. Never logged to unrestricted telemetry." + } + }, + "required": [ + "kind", + "reason", + "message" + ], + "additionalProperties": false, + "description": "Synchronous pre-validation rejected the spawn request.", + "title": "AgentRegistrySpawnValidationError" + }, + "AgentRegistrySpawnValidationErrorField": { + "type": "string", + "enum": [ + "cwd", + "name", + "agentName", + "model", + "permissionMode" + ], + "description": "Which parameter field was invalid. Omitted when the rejection is not field-specific.", + "title": "AgentRegistrySpawnValidationErrorField", + "x-enumDescriptions": { + "cwd": "The cwd parameter", + "name": "The session name parameter", + "agentName": "The agentName parameter", + "model": "The model parameter", + "permissionMode": "The permissionMode parameter" + } + }, + "AgentRegistrySpawnValidationErrorReason": { + "type": "string", + "enum": [ + "cwd-not-found", + "cwd-not-directory", + "invalid-name", + "unknown-agent", + "unknown-model", + "yolo-not-allowed" + ], + "description": "Categorized reason for the rejection. Low-cardinality enum so telemetry can aggregate by reason without leaking raw paths or agent/model names.", + "title": "AgentRegistrySpawnValidationErrorReason", + "x-enumDescriptions": { + "cwd-not-found": "Provided cwd does not exist on disk", + "cwd-not-directory": "Provided cwd exists but is not a directory", + "invalid-name": "Session name failed validateSessionName", + "unknown-agent": "Requested agent name was not found in builtin or custom agents", + "unknown-model": "Requested model is not available to this session", + "yolo-not-allowed": "Caller asked for permissionMode='yolo' but the controller is not currently in allow-all mode" + } + }, + "AgentReloadResult": { + "type": "object", + "properties": { + "agents": { + "type": "array", + "items": { + "$ref": "#/definitions/AgentInfo" + }, + "description": "Reloaded custom agents" + } + }, + "required": [ + "agents" + ], + "additionalProperties": false, + "description": "Custom agents available to the session after reloading definitions from disk.", + "title": "AgentReloadResult" }, "AgentSelectRequest": { "type": "object", @@ -5717,6 +6354,41 @@ "description": "The newly selected custom agent.", "title": "AgentSelectResult" }, + "AllowAllPermissionSetResult": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "enabled": { + "type": "boolean", + "description": "Authoritative allow-all state after the mutation" + } + }, + "required": [ + "success", + "enabled" + ], + "additionalProperties": false, + "description": "Indicates whether the operation succeeded and reports the post-mutation state.", + "title": "AllowAllPermissionSetResult" + }, + "AllowAllPermissionState": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether full allow-all permissions are currently active" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false, + "description": "Current full allow-all permission state.", + "title": "AllowAllPermissionState" + }, "ApiKeyAuthInfo": { "type": "object", "properties": { @@ -5820,93 +6492,93 @@ "description": "Canvas action that the agent or host can invoke. To discover the input schema for a particular action, call the list_canvas_capabilities tool.", "title": "CanvasAction" }, - "CanvasCloseRequest": { + "CanvasActionInvokeRequest": { "type": "object", "properties": { "instanceId": { "type": "string", "description": "Open canvas instance identifier" + }, + "actionName": { + "type": "string", + "description": "Action name to invoke" + }, + "input": { + "description": "Action input", + "x-opaque-json": true } }, "required": [ - "instanceId" + "instanceId", + "actionName" ], "additionalProperties": false, - "description": "Canvas close parameters.", - "title": "CanvasCloseRequest" + "description": "Canvas action invocation parameters.", + "title": "CanvasActionInvokeRequest" }, - "CanvasHostContext": { + "CanvasActionInvokeResult": { "type": "object", "properties": { - "capabilities": { - "$ref": "#/definitions/CanvasHostContextCapabilities", - "description": "Host capabilities" + "result": { + "description": "Provider-supplied action result", + "x-opaque-json": true } }, "additionalProperties": false, - "description": "Host context supplied by the runtime.", - "title": "CanvasHostContext" + "description": "Canvas action invocation result.", + "title": "CanvasActionInvokeResult" }, - "CanvasHostContextCapabilities": { + "CanvasCloseRequest": { "type": "object", "properties": { - "canvases": { - "type": "boolean", - "description": "Whether canvas rendering is supported" + "instanceId": { + "type": "string", + "description": "Open canvas instance identifier" } }, - "additionalProperties": false, - "description": "Host capabilities", - "title": "CanvasHostContextCapabilities" - }, - "CanvasInstanceAvailability": { - "type": "string", - "enum": [ - "ready", - "stale" + "required": [ + "instanceId" ], - "description": "Runtime-controlled routing state for an open canvas instance.", - "title": "CanvasInstanceAvailability", - "x-enumDescriptions": { - "ready": "The owning provider is currently connected and routing calls will be dispatched normally.", - "stale": "The owning provider is not currently connected. Routing calls fail with canvas_provider_unavailable until the agent re-issues open_canvas (which rehydrates via a fresh canvas.open) or the provider reconnects." - } + "additionalProperties": false, + "description": "Canvas close parameters.", + "title": "CanvasCloseRequest" }, - "CanvasInvokeActionRequest": { + "CanvasHostContext": { "type": "object", "properties": { - "instanceId": { - "type": "string", - "description": "Open canvas instance identifier" - }, - "actionName": { - "type": "string", - "description": "Action name to invoke" - }, - "input": { - "description": "Action input", - "x-opaque-json": true + "capabilities": { + "$ref": "#/definitions/CanvasHostContextCapabilities", + "description": "Host capabilities" } }, - "required": [ - "instanceId", - "actionName" - ], "additionalProperties": false, - "description": "Canvas action invocation parameters.", - "title": "CanvasInvokeActionRequest" + "description": "Host context supplied by the runtime.", + "title": "CanvasHostContext" }, - "CanvasInvokeActionResult": { + "CanvasHostContextCapabilities": { "type": "object", "properties": { - "result": { - "description": "Provider-supplied action result", - "x-opaque-json": true + "canvases": { + "type": "boolean", + "description": "Whether canvas rendering is supported" } }, "additionalProperties": false, - "description": "Canvas action invocation result.", - "title": "CanvasInvokeActionResult" + "description": "Host capabilities", + "title": "CanvasHostContextCapabilities" + }, + "CanvasInstanceAvailability": { + "type": "string", + "enum": [ + "ready", + "stale" + ], + "description": "Runtime-controlled routing state for an open canvas instance.", + "title": "CanvasInstanceAvailability", + "x-enumDescriptions": { + "ready": "The owning provider is currently connected and routing calls will be dispatched normally.", + "stale": "The owning provider is not currently connected. Routing calls fail with canvas_provider_unavailable until the agent re-issues open_canvas (which rehydrates via a fresh canvas.open) or the provider reconnects." + } }, "CanvasJsonSchema": { "description": "JSON Schema for canvas open input", @@ -5997,6 +6669,10 @@ "host": { "$ref": "#/definitions/CanvasHostContext", "description": "Host context supplied by the runtime." + }, + "session": { + "$ref": "#/definitions/CanvasSessionContext", + "description": "Session context supplied by the runtime." } }, "required": [ @@ -6034,6 +6710,10 @@ "host": { "$ref": "#/definitions/CanvasHostContext", "description": "Host context supplied by the runtime." + }, + "session": { + "$ref": "#/definitions/CanvasSessionContext", + "description": "Session context supplied by the runtime." } }, "required": [ @@ -6068,6 +6748,10 @@ "host": { "$ref": "#/definitions/CanvasHostContext", "description": "Host context supplied by the runtime." + }, + "session": { + "$ref": "#/definitions/CanvasSessionContext", + "description": "Session context supplied by the runtime." } }, "required": [ @@ -6099,6 +6783,18 @@ "description": "Canvas open result returned by the provider.", "title": "CanvasProviderOpenResult" }, + "CanvasSessionContext": { + "type": "object", + "properties": { + "workingDirectory": { + "type": "string", + "description": "Active session working directory, when known." + } + }, + "additionalProperties": false, + "description": "Session context supplied by the runtime.", + "title": "CanvasSessionContext" + }, "CommandList": { "type": "object", "properties": { @@ -6846,6 +7542,49 @@ "description": "The currently selected model and reasoning effort for the session.", "title": "CurrentModel" }, + "CurrentToolMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Model-facing tool name" + }, + "namespacedName": { + "type": "string", + "description": "Optional MCP/config namespaced tool name" + }, + "mcpServerName": { + "type": "string", + "description": "MCP server name for MCP-backed tools" + }, + "mcpToolName": { + "type": "string", + "description": "Raw MCP tool name for MCP-backed tools" + }, + "description": { + "type": "string", + "description": "Tool description" + }, + "input_schema": { + "type": "object", + "additionalProperties": { + "x-opaque-json": true + }, + "description": "JSON Schema for tool input" + }, + "deferLoading": { + "type": "boolean", + "description": "Whether the tool is loaded on demand via tool search" + } + }, + "required": [ + "name", + "description" + ], + "additionalProperties": false, + "description": "Lightweight metadata for a currently initialized session tool", + "title": "CurrentToolMetadata" + }, "DiscoveredCanvas": { "type": "object", "properties": { @@ -9283,6 +10022,34 @@ "title": "McpServer", "description": "Schema for the `McpServer` type." }, + "McpServerAuthConfig": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/McpServerAuthConfigRedirectPort", + "description": "Authentication settings with optional redirect port configuration." + } + ], + "description": "Set to `true` to use defaults, or provide an object with additional auth or OIDC settings.", + "title": "McpServerAuthConfig", + "x-opaque-json": true + }, + "McpServerAuthConfigRedirectPort": { + "type": "object", + "properties": { + "redirectPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "Fixed port for the OAuth redirect callback server." + } + }, + "additionalProperties": true, + "description": "Authentication settings with optional redirect port configuration.", + "title": "McpServerAuthConfigRedirectPort" + }, "McpServerConfig": { "anyOf": [ { @@ -9328,12 +10095,12 @@ "format": "duration" }, "oidc": { - "$ref": "#/definitions/McpServerConfigHttpOidc", - "description": "OIDC token configuration. When truthy, a token is automatically gathered." + "$ref": "#/definitions/McpServerAuthConfig", + "description": "Set to `true` to use defaults, or provide an object with additional auth or OIDC settings." }, "auth": { - "$ref": "#/definitions/McpServerConfigHttpAuth", - "description": "Additional authentication configuration for this server." + "$ref": "#/definitions/McpServerAuthConfig", + "description": "Set to `true` to use defaults, or provide an object with additional auth or OIDC settings." }, "url": { "type": "string", @@ -9367,20 +10134,6 @@ "description": "Remote MCP server configuration accessed over HTTP or SSE.", "title": "McpServerConfigHttp" }, - "McpServerConfigHttpAuth": { - "type": "object", - "properties": { - "redirectPort": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "Fixed port for the OAuth redirect callback server." - } - }, - "additionalProperties": true, - "description": "Additional authentication configuration for this server.", - "title": "McpServerConfigHttpAuth" - }, "McpServerConfigHttpOauthGrantType": { "type": "string", "enum": [ @@ -9394,20 +10147,6 @@ "client_credentials": "Headless client credentials flow using the configured OAuth client." } }, - "McpServerConfigHttpOidc": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "additionalProperties": {} - } - ], - "description": "OIDC token configuration. When truthy, a token is automatically gathered.", - "title": "McpServerConfigHttpOidc", - "x-opaque-json": true - }, "McpServerConfigHttpType": { "type": "string", "enum": [ @@ -9448,12 +10187,12 @@ "format": "duration" }, "oidc": { - "$ref": "#/definitions/McpServerConfigStdioOidc", - "description": "OIDC token configuration. When truthy, a token is automatically gathered." + "$ref": "#/definitions/McpServerAuthConfig", + "description": "Set to `true` to use defaults, or provide an object with additional auth or OIDC settings." }, "auth": { - "$ref": "#/definitions/McpServerConfigStdioAuth", - "description": "Authentication configuration for this server." + "$ref": "#/definitions/McpServerAuthConfig", + "description": "Set to `true` to use defaults, or provide an object with additional auth or OIDC settings." }, "command": { "type": "string", @@ -9486,34 +10225,6 @@ "description": "Stdio MCP server configuration launched as a child process.", "title": "McpServerConfigStdio" }, - "McpServerConfigStdioAuth": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "additionalProperties": {} - } - ], - "description": "Authentication configuration for this server.", - "title": "McpServerConfigStdioAuth", - "x-opaque-json": true - }, - "McpServerConfigStdioOidc": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "additionalProperties": {} - } - ], - "description": "OIDC token configuration. When truthy, a token is automatically gathered.", - "title": "McpServerConfigStdioOidc", - "x-opaque-json": true - }, "McpServerList": { "type": "object", "properties": { @@ -10169,6 +10880,25 @@ "description": "List of Copilot models available to the resolved user, including capabilities and billing metadata.", "title": "ModelList" }, + "ModelListRequest": { + "anyOf": [ + { + "not": {} + }, + { + "type": "object", + "properties": { + "skipCache": { + "type": "boolean", + "description": "If true, bypasses the per-session model list cache and re-fetches from CAPI." + } + }, + "additionalProperties": false + } + ], + "description": "Optional listing options.", + "title": "ModelListRequest" + }, "ModelPickerCategory": { "type": "string", "enum": [ @@ -10302,13 +11032,32 @@ "modelCapabilities": { "$ref": "#/definitions/ModelCapabilitiesOverride", "description": "Override individual model capabilities resolved by the runtime" + }, + "contextTier": { + "anyOf": [ + { + "type": "string", + "enum": [ + "default", + "long_context" + ], + "x-enumDescriptions": { + "default": "Use the model's default context window.", + "long_context": "Pin the session to the long-context tier when supported." + } + }, + { + "type": "null" + } + ], + "description": "Explicit context tier for the selected model. `\"default\"` / `\"long_context\"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched." } }, "required": [ "modelId" ], "additionalProperties": false, - "description": "Target model identifier and optional reasoning effort, summary, and capability overrides.", + "description": "Target model identifier and optional reasoning effort, summary, capability overrides, and context tier.", "title": "ModelSwitchToRequest" }, "ModelSwitchToResult": { @@ -10471,6 +11220,19 @@ "indirect": "Resolve MCP server environment values from host-side references." } }, + "OptionsUpdateToolFilterPrecedence": { + "type": "string", + "enum": [ + "available", + "excluded" + ], + "description": "Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set.", + "title": "OptionsUpdateToolFilterPrecedence", + "x-enumDescriptions": { + "available": "If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default.", + "excluded": "A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists." + } + }, "PendingPermissionRequest": { "type": "object", "properties": { @@ -11841,6 +12603,13 @@ "description": "Indicates whether the operation succeeded.", "title": "PermissionsFolderTrustAddTrustedResult" }, + "PermissionsGetAllowAllRequest": { + "type": "object", + "properties": {}, + "additionalProperties": false, + "description": "No parameters.", + "title": "PermissionsGetAllowAllRequest" + }, "PermissionsLocationsAddToolApprovalDetails": { "anyOf": [ { @@ -12215,6 +12984,42 @@ "description": "Indicates whether the operation succeeded.", "title": "PermissionsResetSessionApprovalsResult" }, + "PermissionsSetAllowAllRequest": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether to enable full allow-all permissions" + }, + "source": { + "$ref": "#/definitions/PermissionsSetAllowAllSource", + "description": "Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers." + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false, + "description": "Whether to enable full allow-all permissions for the session.", + "title": "PermissionsSetAllowAllRequest" + }, + "PermissionsSetAllowAllSource": { + "type": "string", + "enum": [ + "cli_flag", + "slash_command", + "autopilot_confirmation", + "rpc" + ], + "description": "Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.", + "title": "PermissionsSetAllowAllSource", + "x-enumDescriptions": { + "cli_flag": "Allow-all was enabled from a CLI command-line flag.", + "slash_command": "Allow-all was enabled by a slash command.", + "autopilot_confirmation": "Allow-all was enabled by confirming autopilot behavior.", + "rpc": "Allow-all was enabled through an RPC caller." + } + }, "PermissionsSetApproveAllRequest": { "type": "object", "properties": { @@ -13470,6 +14275,11 @@ "minimum": 0, "description": "Tokens consumed by tool definitions sent to the model (excludes deferred tools)" }, + "mcpToolsTokens": { + "type": "integer", + "minimum": 0, + "description": "Tokens consumed by MCP tool definitions (subset of toolDefinitionsTokens, excludes deferred tools)" + }, "totalTokens": { "type": "integer", "minimum": 0, @@ -13501,6 +14311,7 @@ "systemTokens", "conversationTokens", "toolDefinitionsTokens", + "mcpToolsTokens", "totalTokens", "promptTokenLimit", "compactionThreshold", @@ -14327,10 +15138,18 @@ "type": "string", "description": "Optional human-friendly name set via /rename" }, + "clientName": { + "type": "string", + "description": "Runtime client name that created/last resumed this session" + }, "isRemote": { "type": "boolean", "description": "True for remote (GitHub) sessions; false for local" }, + "isDetached": { + "type": "boolean", + "description": "True for detached maintenance sessions that should be hidden from normal resume lists." + }, "context": { "$ref": "#/definitions/SessionContext", "description": "Schema for the `SessionContext` type." @@ -14386,6 +15205,10 @@ "type": "string", "description": "User-provided name supplied at session construction (via `--name`), if any. Immutable after construction." }, + "clientName": { + "type": "string", + "description": "Runtime client name associated with the session (telemetry identifier)." + }, "remoteMetadata": { "$ref": "#/definitions/MetadataSnapshotRemoteMetadata", "description": "Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session." @@ -14441,6 +15264,31 @@ "autopilot": "The agent is working autonomously toward task completion." } }, + "SessionModelList": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "x-opaque-json": true + }, + "description": "Available models, ordered with the most preferred default first." + }, + "quotaSnapshots": { + "type": "object", + "additionalProperties": { + "x-opaque-json": true + }, + "description": "Per-quota snapshots returned alongside the model list, keyed by quota type." + } + }, + "required": [ + "list" + ], + "additionalProperties": false, + "description": "The list of models available to this session.", + "title": "SessionModelList" + }, "SessionPruneResult": { "type": "object", "properties": { @@ -14819,13 +15667,17 @@ "filter": { "$ref": "#/definitions/SessionListFilter", "description": "Optional filter applied to the returned sessions" + }, + "includeDetached": { + "type": "boolean", + "description": "When true, include detached maintenance sessions. Defaults to false for user-facing session lists." } }, "additionalProperties": false, - "description": "Optional metadata-load limit and context filter applied to the returned sessions." + "description": "Optional metadata-load limit and filters applied to the returned sessions." } ], - "description": "Optional metadata-load limit and context filter applied to the returned sessions.", + "description": "Optional metadata-load limit and filters applied to the returned sessions.", "title": "SessionsListRequest" }, "SessionsLoadDeferredRepoHooksRequest": { @@ -15026,6 +15878,10 @@ }, "description": "Denylist of tool names for this session." }, + "toolFilterPrecedence": { + "$ref": "#/definitions/OptionsUpdateToolFilterPrecedence", + "description": "Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set." + }, "enableScriptSafety": { "type": "boolean", "description": "Whether shell-script safety heuristics are enabled." @@ -15145,6 +16001,30 @@ "manageScheduleEnabled": { "type": "boolean", "description": "Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users)." + }, + "skipEmbeddingRetrieval": { + "type": "boolean", + "description": "Whether to skip embedding retrieval pipeline initialization and execution." + }, + "organizationCustomInstructions": { + "type": "string", + "description": "Organization-level custom instructions to inject into the system prompt." + }, + "enableFileHooks": { + "type": "boolean", + "description": "Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism." + }, + "enableHostGitOperations": { + "type": "boolean", + "description": "Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt)." + }, + "enableSessionStore": { + "type": "boolean", + "description": "Whether to enable cross-session store writes and reads." + }, + "enableSkills": { + "type": "boolean", + "description": "Whether to enable skill directory scanning and loading. Falls back to enableConfigDiscovery when unset." } }, "additionalProperties": false, @@ -16534,6 +17414,32 @@ "description": "Built-in tools available for the requested model, with their parameters and instructions.", "title": "ToolList" }, + "ToolsGetCurrentMetadataResult": { + "type": "object", + "properties": { + "tools": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/definitions/CurrentToolMetadata", + "description": "Lightweight metadata for a currently initialized session tool" + } + }, + { + "type": "null" + } + ], + "description": "Current tool metadata, or null when tools have not been initialized yet" + } + }, + "required": [ + "tools" + ], + "additionalProperties": false, + "description": "Current lightweight tool metadata snapshot for the session.", + "title": "ToolsGetCurrentMetadataResult" + }, "ToolsInitializeAndValidateResult": { "type": "object", "properties": {}, @@ -18004,6 +18910,9 @@ "name": { "type": "string" }, + "client_name": { + "type": "string" + }, "user_named": { "type": "boolean" }, diff --git a/schemas/session-events.schema.json b/schemas/session-events.schema.json index 90977be..7e74166 100644 --- a/schemas/session-events.schema.json +++ b/schemas/session-events.schema.json @@ -925,7 +925,7 @@ "properties": { "batchSize": { "type": "integer", - "exclusiveMinimum": 0, + "minimum": 0, "description": "Number of tokens in this billing batch" }, "costPerBatch": { @@ -1349,6 +1349,116 @@ "no": "Do not switch models." } }, + "AutopilotObjectiveChangedData": { + "type": "object", + "properties": { + "operation": { + "$ref": "#/definitions/AutopilotObjectiveChangedOperation", + "description": "The type of operation performed on the autopilot objective state file" + }, + "id": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Current autopilot objective id, if one exists" + }, + "status": { + "$ref": "#/definitions/AutopilotObjectiveChangedStatus", + "description": "Current autopilot objective status, if one exists" + } + }, + "required": [ + "operation" + ], + "additionalProperties": false, + "description": "Autopilot objective state file operation details indicating what changed", + "title": "AutopilotObjectiveChangedData" + }, + "AutopilotObjectiveChangedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique event identifier (UUID v4), generated when the event is emitted" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the event was created" + }, + "parentId": { + "anyOf": [ + { + "type": "string", + "format": "uuid" + }, + { + "type": "null" + } + ], + "description": "ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event." + }, + "ephemeral": { + "type": "boolean", + "description": "When true, the event is transient and not persisted to the session event log on disk" + }, + "agentId": { + "type": "string", + "description": "Sub-agent instance identifier. Absent for events from the root/main agent and session-level events." + }, + "type": { + "type": "string", + "const": "session.autopilot_objective_changed", + "description": "Type discriminator. Always \"session.autopilot_objective_changed\"." + }, + "data": { + "$ref": "#/definitions/AutopilotObjectiveChangedData", + "description": "Autopilot objective state file operation details indicating what changed" + } + }, + "required": [ + "id", + "timestamp", + "parentId", + "type", + "data" + ], + "additionalProperties": false, + "description": "Session event \"session.autopilot_objective_changed\". Autopilot objective state file operation details indicating what changed", + "title": "AutopilotObjectiveChangedEvent" + }, + "AutopilotObjectiveChangedOperation": { + "type": "string", + "enum": [ + "create", + "update", + "delete" + ], + "description": "The type of operation performed on the autopilot objective state file", + "title": "AutopilotObjectiveChangedOperation", + "x-enumDescriptions": { + "create": "Autopilot objective state file was created for a new objective.", + "update": "Autopilot objective state file was updated for an existing objective.", + "delete": "Autopilot objective state file was deleted or cleared." + } + }, + "AutopilotObjectiveChangedStatus": { + "type": "string", + "enum": [ + "active", + "paused", + "cap_reached", + "completed" + ], + "description": "Current autopilot objective status, if one exists", + "title": "AutopilotObjectiveChangedStatus", + "x-enumDescriptions": { + "active": "Objective is active and can drive autopilot continuations.", + "paused": "Objective is paused and will not drive autopilot continuations.", + "cap_reached": "Legacy objective state indicating the previous continuation cap was reached.", + "completed": "Objective was completed by the agent." + } + }, "BackgroundTasksChangedData": { "type": "object", "properties": {}, @@ -2170,7 +2280,7 @@ "properties": { "batchSize": { "type": "integer", - "exclusiveMinimum": 0, + "minimum": 0, "description": "Number of tokens in this billing batch" }, "costPerBatch": { @@ -3585,6 +3695,10 @@ "description": "Arguments to pass to the external tool", "x-opaque-json": true }, + "workingDirectory": { + "type": "string", + "description": "Active session working directory, when known." + }, "traceparent": { "type": "string", "description": "W3C Trace Context traceparent header for the execute_tool span" @@ -3896,6 +4010,77 @@ "description": "Session event \"hook.end\". Hook invocation completion details including output, success status, and error information", "title": "HookEndEvent" }, + "HookProgressData": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Human-readable progress message from the hook process" + } + }, + "required": [ + "message" + ], + "additionalProperties": false, + "description": "Ephemeral progress update from a running hook process", + "title": "HookProgressData" + }, + "HookProgressEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique event identifier (UUID v4), generated when the event is emitted" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the event was created" + }, + "parentId": { + "anyOf": [ + { + "type": "string", + "format": "uuid" + }, + { + "type": "null" + } + ], + "description": "ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event." + }, + "ephemeral": { + "type": "boolean", + "const": true, + "description": "Always true for events that are transient and not persisted to the session event log on disk." + }, + "agentId": { + "type": "string", + "description": "Sub-agent instance identifier. Absent for events from the root/main agent and session-level events." + }, + "type": { + "type": "string", + "const": "hook.progress", + "description": "Type discriminator. Always \"hook.progress\"." + }, + "data": { + "$ref": "#/definitions/HookProgressData", + "description": "Ephemeral progress update from a running hook process" + } + }, + "required": [ + "id", + "timestamp", + "parentId", + "ephemeral", + "type", + "data" + ], + "additionalProperties": false, + "description": "Session event \"hook.progress\". Ephemeral progress update from a running hook process", + "title": "HookProgressEvent" + }, "HookStartData": { "type": "object", "properties": { @@ -6460,6 +6645,80 @@ "title": "PermissionRule", "description": "Schema for the `PermissionRule` type." }, + "PermissionsChangedData": { + "type": "object", + "properties": { + "previousAllowAllPermissions": { + "type": "boolean", + "description": "Aggregate allow-all flag before the change" + }, + "allowAllPermissions": { + "type": "boolean", + "description": "Aggregate allow-all flag after the change" + } + }, + "required": [ + "previousAllowAllPermissions", + "allowAllPermissions" + ], + "additionalProperties": false, + "description": "Permissions change details carrying the aggregate allow-all boolean transition.", + "title": "PermissionsChangedData" + }, + "PermissionsChangedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique event identifier (UUID v4), generated when the event is emitted" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the event was created" + }, + "parentId": { + "anyOf": [ + { + "type": "string", + "format": "uuid" + }, + { + "type": "null" + } + ], + "description": "ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event." + }, + "ephemeral": { + "type": "boolean", + "description": "When true, the event is transient and not persisted to the session event log on disk" + }, + "agentId": { + "type": "string", + "description": "Sub-agent instance identifier. Absent for events from the root/main agent and session-level events." + }, + "type": { + "type": "string", + "const": "session.permissions_changed", + "description": "Type discriminator. Always \"session.permissions_changed\"." + }, + "data": { + "$ref": "#/definitions/PermissionsChangedData", + "description": "Permissions change details carrying the aggregate allow-all boolean transition." + } + }, + "required": [ + "id", + "timestamp", + "parentId", + "type", + "data" + ], + "additionalProperties": false, + "description": "Session event \"session.permissions_changed\". Permissions change details carrying the aggregate allow-all boolean transition.", + "title": "PermissionsChangedEvent" + }, "PlanChangedData": { "type": "object", "properties": { @@ -6653,6 +6912,25 @@ "$ref": "#/definitions/ReasoningSummary", "description": "Reasoning summary mode used for model calls, if applicable (e.g. \"none\", \"concise\", \"detailed\")" }, + "contextTier": { + "anyOf": [ + { + "type": "string", + "enum": [ + "default", + "long_context" + ], + "x-enumDescriptions": { + "default": "Default context tier with standard context window size.", + "long_context": "Extended context tier with a larger context window." + } + }, + { + "type": "null" + } + ], + "description": "Context tier currently selected at resume time; null when no tier is active" + }, "context": { "$ref": "#/definitions/WorkingDirectoryContext", "description": "Updated working directory and git context at resume time" @@ -7086,6 +7364,10 @@ "$ref": "#/definitions/ScheduleCancelledEvent", "description": "Session event \"session.schedule_cancelled\". Scheduled prompt cancelled from the schedule manager dialog" }, + { + "$ref": "#/definitions/AutopilotObjectiveChangedEvent", + "description": "Session event \"session.autopilot_objective_changed\". Autopilot objective state file operation details indicating what changed" + }, { "$ref": "#/definitions/InfoEvent", "description": "Session event \"session.info\". Informational message for timeline display with categorization" @@ -7102,6 +7384,10 @@ "$ref": "#/definitions/ModeChangedEvent", "description": "Session event \"session.mode_changed\". Agent mode change details including previous and new modes" }, + { + "$ref": "#/definitions/PermissionsChangedEvent", + "description": "Session event \"session.permissions_changed\". Permissions change details carrying the aggregate allow-all boolean transition." + }, { "$ref": "#/definitions/PlanChangedEvent", "description": "Session event \"session.plan_changed\". Plan file operation details indicating what changed" @@ -7254,6 +7540,10 @@ "$ref": "#/definitions/HookEndEvent", "description": "Session event \"hook.end\". Hook invocation completion details including output, success status, and error information" }, + { + "$ref": "#/definitions/HookProgressEvent", + "description": "Session event \"hook.progress\". Ephemeral progress update from a running hook process" + }, { "$ref": "#/definitions/SystemMessageEvent", "description": "Session event \"system.message\". System/developer instruction content with role and optional template metadata" @@ -8087,6 +8377,25 @@ "$ref": "#/definitions/ReasoningSummary", "description": "Reasoning summary mode used for model calls, if applicable (e.g. \"none\", \"concise\", \"detailed\")" }, + "contextTier": { + "anyOf": [ + { + "type": "string", + "enum": [ + "default", + "long_context" + ], + "x-enumDescriptions": { + "default": "Default context tier with standard context window size.", + "long_context": "Extended context tier with a larger context window." + } + }, + { + "type": "null" + } + ], + "description": "Context tier selected at session creation time for models with tiered context pricing; null when no tier is selected (e.g., non-tiered model)" + }, "context": { "$ref": "#/definitions/WorkingDirectoryContext", "description": "Working directory and git context at session start" @@ -9996,6 +10305,10 @@ "type": "string", "description": "Identifier for the agent loop turn this tool was invoked in, matching the corresponding assistant.turn_start event" }, + "displayVerbatim": { + "type": "boolean", + "description": "When true, the tool output should be displayed expanded (verbatim) in the CLI timeline" + }, "parentToolCallId": { "type": "string", "description": "Tool call ID of the parent tool invocation when this event originates from a sub-agent", diff --git a/src/github/copilot_sdk/generated/event_specs.clj b/src/github/copilot_sdk/generated/event_specs.clj index f389489..4878499 100644 --- a/src/github/copilot_sdk/generated/event_specs.clj +++ b/src/github/copilot_sdk/generated/event_specs.clj @@ -21,6 +21,8 @@ (s/def :github.copilot-sdk.generated.event-specs/agents (s/coll-of clojure.core/map?)) +(s/def :github.copilot-sdk.generated.event-specs/allow-all-permissions clojure.core/boolean?) + (s/def :github.copilot-sdk.generated.event-specs/allow-freeform clojure.core/boolean?) (s/def :github.copilot-sdk.generated.event-specs/allowed-tools (s/coll-of clojure.core/string?)) @@ -113,6 +115,8 @@ (s/def :github.copilot-sdk.generated.event-specs/display-prompt clojure.core/string?) +(s/def :github.copilot-sdk.generated.event-specs/display-verbatim clojure.core/boolean?) + (s/def :github.copilot-sdk.generated.event-specs/duration clojure.core/integer?) (s/def :github.copilot-sdk.generated.event-specs/duration-ms (s/spec (fn [v939] (or (s/valid? clojure.core/integer? v939) (s/valid? clojure.core/number? v939))))) @@ -267,6 +271,8 @@ (s/def :github.copilot-sdk.generated.event-specs/pre-truncation-tokens-in-messages clojure.core/integer?) +(s/def :github.copilot-sdk.generated.event-specs/previous-allow-all-permissions clojure.core/boolean?) + (s/def :github.copilot-sdk.generated.event-specs/previous-mode #{"interactive" "autopilot" "plan"}) (s/def :github.copilot-sdk.generated.event-specs/previous-model clojure.core/string?) @@ -367,7 +373,7 @@ (s/def :github.copilot-sdk.generated.event-specs/static-client-config clojure.core/map?) -(s/def :github.copilot-sdk.generated.event-specs/status (s/spec (fn [v945] (or (s/valid? #{"failed" "not_configured" "needs-auth" "connected" "disabled" "pending"} v945) (s/valid? clojure.core/string? v945))))) +(s/def :github.copilot-sdk.generated.event-specs/status (s/spec (fn [v945] (or (s/valid? #{"cap_reached" "completed" "paused" "active"} v945) (s/valid? #{"failed" "not_configured" "needs-auth" "connected" "disabled" "pending"} v945) (s/valid? clojure.core/string? v945))))) (s/def :github.copilot-sdk.generated.event-specs/status-code clojure.core/integer?) @@ -437,7 +443,7 @@ (s/def :github.copilot-sdk.generated.event-specs/turn-id clojure.core/string?) -(s/def :github.copilot-sdk.generated.event-specs/type (s/spec (fn [v949] (or (s/valid? #{"session.start"} v949) (s/valid? #{"session.resume"} v949) (s/valid? #{"session.remote_steerable_changed"} v949) (s/valid? #{"session.error"} v949) (s/valid? #{"session.idle"} v949) (s/valid? #{"session.title_changed"} v949) (s/valid? #{"session.schedule_created"} v949) (s/valid? #{"session.schedule_cancelled"} v949) (s/valid? #{"session.info"} v949) (s/valid? #{"session.warning"} v949) (s/valid? #{"session.model_change"} v949) (s/valid? #{"session.mode_changed"} v949) (s/valid? #{"session.plan_changed"} v949) (s/valid? #{"session.workspace_file_changed"} v949) (s/valid? #{"session.handoff"} v949) (s/valid? #{"session.truncation"} v949) (s/valid? #{"session.snapshot_rewind"} v949) (s/valid? #{"session.shutdown"} v949) (s/valid? #{"session.context_changed"} v949) (s/valid? #{"session.usage_info"} v949) (s/valid? #{"session.compaction_start"} v949) (s/valid? #{"session.compaction_complete"} v949) (s/valid? #{"session.task_complete"} v949) (s/valid? #{"user.message"} v949) (s/valid? #{"pending_messages.modified"} v949) (s/valid? #{"assistant.turn_start"} v949) (s/valid? #{"assistant.intent"} v949) (s/valid? #{"assistant.reasoning"} v949) (s/valid? #{"assistant.reasoning_delta"} v949) (s/valid? #{"assistant.streaming_delta"} v949) (s/valid? #{"assistant.message"} v949) (s/valid? #{"assistant.message_start"} v949) (s/valid? #{"assistant.message_delta"} v949) (s/valid? #{"assistant.turn_end"} v949) (s/valid? #{"assistant.usage"} v949) (s/valid? #{"model.call_failure"} v949) (s/valid? #{"abort"} v949) (s/valid? #{"tool.user_requested"} v949) (s/valid? #{"tool.execution_start"} v949) (s/valid? #{"tool.execution_partial_result"} v949) (s/valid? #{"tool.execution_progress"} v949) (s/valid? #{"tool.execution_complete"} v949) (s/valid? #{"skill.invoked"} v949) (s/valid? #{"subagent.started"} v949) (s/valid? #{"subagent.completed"} v949) (s/valid? #{"subagent.failed"} v949) (s/valid? #{"subagent.selected"} v949) (s/valid? #{"subagent.deselected"} v949) (s/valid? #{"hook.start"} v949) (s/valid? #{"hook.end"} v949) (s/valid? #{"system.message"} v949) (s/valid? #{"system.notification"} v949) (s/valid? #{"permission.requested"} v949) (s/valid? #{"permission.completed"} v949) (s/valid? #{"user_input.requested"} v949) (s/valid? #{"user_input.completed"} v949) (s/valid? #{"elicitation.requested"} v949) (s/valid? #{"elicitation.completed"} v949) (s/valid? #{"sampling.requested"} v949) (s/valid? #{"sampling.completed"} v949) (s/valid? #{"mcp.oauth_required"} v949) (s/valid? #{"mcp.oauth_completed"} v949) (s/valid? #{"session.custom_notification"} v949) (s/valid? #{"external_tool.requested"} v949) (s/valid? #{"external_tool.completed"} v949) (s/valid? #{"command.queued"} v949) (s/valid? #{"command.execute"} v949) (s/valid? #{"command.completed"} v949) (s/valid? #{"auto_mode_switch.requested"} v949) (s/valid? #{"auto_mode_switch.completed"} v949) (s/valid? #{"commands.changed"} v949) (s/valid? #{"capabilities.changed"} v949) (s/valid? #{"exit_plan_mode.requested"} v949) (s/valid? #{"exit_plan_mode.completed"} v949) (s/valid? #{"session.tools_updated"} v949) (s/valid? #{"session.background_tasks_changed"} v949) (s/valid? #{"session.skills_loaded"} v949) (s/valid? #{"session.custom_agents_updated"} v949) (s/valid? #{"session.mcp_servers_loaded"} v949) (s/valid? #{"session.mcp_server_status_changed"} v949) (s/valid? #{"session.extensions_loaded"} v949) (s/valid? #{"session.canvas.opened"} v949) (s/valid? #{"session.canvas.registry_changed"} v949) (s/valid? #{"mcp_app.tool_call_complete"} v949))))) +(s/def :github.copilot-sdk.generated.event-specs/type (s/spec (fn [v949] (or (s/valid? #{"session.start"} v949) (s/valid? #{"session.resume"} v949) (s/valid? #{"session.remote_steerable_changed"} v949) (s/valid? #{"session.error"} v949) (s/valid? #{"session.idle"} v949) (s/valid? #{"session.title_changed"} v949) (s/valid? #{"session.schedule_created"} v949) (s/valid? #{"session.schedule_cancelled"} v949) (s/valid? #{"session.autopilot_objective_changed"} v949) (s/valid? #{"session.info"} v949) (s/valid? #{"session.warning"} v949) (s/valid? #{"session.model_change"} v949) (s/valid? #{"session.mode_changed"} v949) (s/valid? #{"session.permissions_changed"} v949) (s/valid? #{"session.plan_changed"} v949) (s/valid? #{"session.workspace_file_changed"} v949) (s/valid? #{"session.handoff"} v949) (s/valid? #{"session.truncation"} v949) (s/valid? #{"session.snapshot_rewind"} v949) (s/valid? #{"session.shutdown"} v949) (s/valid? #{"session.context_changed"} v949) (s/valid? #{"session.usage_info"} v949) (s/valid? #{"session.compaction_start"} v949) (s/valid? #{"session.compaction_complete"} v949) (s/valid? #{"session.task_complete"} v949) (s/valid? #{"user.message"} v949) (s/valid? #{"pending_messages.modified"} v949) (s/valid? #{"assistant.turn_start"} v949) (s/valid? #{"assistant.intent"} v949) (s/valid? #{"assistant.reasoning"} v949) (s/valid? #{"assistant.reasoning_delta"} v949) (s/valid? #{"assistant.streaming_delta"} v949) (s/valid? #{"assistant.message"} v949) (s/valid? #{"assistant.message_start"} v949) (s/valid? #{"assistant.message_delta"} v949) (s/valid? #{"assistant.turn_end"} v949) (s/valid? #{"assistant.usage"} v949) (s/valid? #{"model.call_failure"} v949) (s/valid? #{"abort"} v949) (s/valid? #{"tool.user_requested"} v949) (s/valid? #{"tool.execution_start"} v949) (s/valid? #{"tool.execution_partial_result"} v949) (s/valid? #{"tool.execution_progress"} v949) (s/valid? #{"tool.execution_complete"} v949) (s/valid? #{"skill.invoked"} v949) (s/valid? #{"subagent.started"} v949) (s/valid? #{"subagent.completed"} v949) (s/valid? #{"subagent.failed"} v949) (s/valid? #{"subagent.selected"} v949) (s/valid? #{"subagent.deselected"} v949) (s/valid? #{"hook.start"} v949) (s/valid? #{"hook.end"} v949) (s/valid? #{"hook.progress"} v949) (s/valid? #{"system.message"} v949) (s/valid? #{"system.notification"} v949) (s/valid? #{"permission.requested"} v949) (s/valid? #{"permission.completed"} v949) (s/valid? #{"user_input.requested"} v949) (s/valid? #{"user_input.completed"} v949) (s/valid? #{"elicitation.requested"} v949) (s/valid? #{"elicitation.completed"} v949) (s/valid? #{"sampling.requested"} v949) (s/valid? #{"sampling.completed"} v949) (s/valid? #{"mcp.oauth_required"} v949) (s/valid? #{"mcp.oauth_completed"} v949) (s/valid? #{"session.custom_notification"} v949) (s/valid? #{"external_tool.requested"} v949) (s/valid? #{"external_tool.completed"} v949) (s/valid? #{"command.queued"} v949) (s/valid? #{"command.execute"} v949) (s/valid? #{"command.completed"} v949) (s/valid? #{"auto_mode_switch.requested"} v949) (s/valid? #{"auto_mode_switch.completed"} v949) (s/valid? #{"commands.changed"} v949) (s/valid? #{"capabilities.changed"} v949) (s/valid? #{"exit_plan_mode.requested"} v949) (s/valid? #{"exit_plan_mode.completed"} v949) (s/valid? #{"session.tools_updated"} v949) (s/valid? #{"session.background_tasks_changed"} v949) (s/valid? #{"session.skills_loaded"} v949) (s/valid? #{"session.custom_agents_updated"} v949) (s/valid? #{"session.mcp_servers_loaded"} v949) (s/valid? #{"session.mcp_server_status_changed"} v949) (s/valid? #{"session.extensions_loaded"} v949) (s/valid? #{"session.canvas.opened"} v949) (s/valid? #{"session.canvas.registry_changed"} v949) (s/valid? #{"mcp_app.tool_call_complete"} v949))))) (s/def :github.copilot-sdk.generated.event-specs/ui clojure.core/map?) @@ -453,6 +459,8 @@ (s/def :github.copilot-sdk.generated.event-specs/was-freeform clojure.core/boolean?) +(s/def :github.copilot-sdk.generated.event-specs/working-directory clojure.core/string?) + (s/def :github.copilot-sdk.generated.event-specs/abort-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/reason])) (s/def :github.copilot-sdk.generated.event-specs/assistant.intent-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/intent])) @@ -499,10 +507,12 @@ (s/def :github.copilot-sdk.generated.event-specs/external_tool.completed-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/request-id])) -(s/def :github.copilot-sdk.generated.event-specs/external_tool.requested-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/request-id :github.copilot-sdk.generated.event-specs/session-id :github.copilot-sdk.generated.event-specs/tool-call-id :github.copilot-sdk.generated.event-specs/tool-name] :opt-un [:github.copilot-sdk.generated.event-specs/arguments :github.copilot-sdk.generated.event-specs/traceparent :github.copilot-sdk.generated.event-specs/tracestate])) +(s/def :github.copilot-sdk.generated.event-specs/external_tool.requested-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/request-id :github.copilot-sdk.generated.event-specs/session-id :github.copilot-sdk.generated.event-specs/tool-call-id :github.copilot-sdk.generated.event-specs/tool-name] :opt-un [:github.copilot-sdk.generated.event-specs/arguments :github.copilot-sdk.generated.event-specs/traceparent :github.copilot-sdk.generated.event-specs/tracestate :github.copilot-sdk.generated.event-specs/working-directory])) (s/def :github.copilot-sdk.generated.event-specs/hook.end-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/hook-invocation-id :github.copilot-sdk.generated.event-specs/hook-type :github.copilot-sdk.generated.event-specs/success] :opt-un [:github.copilot-sdk.generated.event-specs/error :github.copilot-sdk.generated.event-specs/output])) +(s/def :github.copilot-sdk.generated.event-specs/hook.progress-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/message])) + (s/def :github.copilot-sdk.generated.event-specs/hook.start-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/hook-invocation-id :github.copilot-sdk.generated.event-specs/hook-type] :opt-un [:github.copilot-sdk.generated.event-specs/input])) (s/def :github.copilot-sdk.generated.event-specs/mcp.oauth_completed-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/request-id])) @@ -523,6 +533,8 @@ (s/def :github.copilot-sdk.generated.event-specs/sampling.requested-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/mcp-request-id :github.copilot-sdk.generated.event-specs/request-id :github.copilot-sdk.generated.event-specs/server-name])) +(s/def :github.copilot-sdk.generated.event-specs/session.autopilot_objective_changed-data (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/operation] :opt-un [:github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/status]) (fn [data] (or (not (contains? data :id)) (s/valid? clojure.core/integer? (:id data)))))) + (s/def :github.copilot-sdk.generated.event-specs/session.background_tasks_changed-data (s/keys)) (s/def :github.copilot-sdk.generated.event-specs/session.canvas.opened-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/availability :github.copilot-sdk.generated.event-specs/canvas-id :github.copilot-sdk.generated.event-specs/extension-id :github.copilot-sdk.generated.event-specs/instance-id :github.copilot-sdk.generated.event-specs/reopen] :opt-un [:github.copilot-sdk.generated.event-specs/extension-name :github.copilot-sdk.generated.event-specs/input :github.copilot-sdk.generated.event-specs/status :github.copilot-sdk.generated.event-specs/title :github.copilot-sdk.generated.event-specs/url])) @@ -557,11 +569,13 @@ (s/def :github.copilot-sdk.generated.event-specs/session.model_change-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/new-model] :opt-un [:github.copilot-sdk.generated.event-specs/cause :github.copilot-sdk.generated.event-specs/context-tier :github.copilot-sdk.generated.event-specs/previous-model :github.copilot-sdk.generated.event-specs/previous-reasoning-effort :github.copilot-sdk.generated.event-specs/previous-reasoning-summary :github.copilot-sdk.generated.event-specs/reasoning-effort :github.copilot-sdk.generated.event-specs/reasoning-summary])) +(s/def :github.copilot-sdk.generated.event-specs/session.permissions_changed-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/allow-all-permissions :github.copilot-sdk.generated.event-specs/previous-allow-all-permissions])) + (s/def :github.copilot-sdk.generated.event-specs/session.plan_changed-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/operation])) (s/def :github.copilot-sdk.generated.event-specs/session.remote_steerable_changed-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/remote-steerable])) -(s/def :github.copilot-sdk.generated.event-specs/session.resume-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/event-count :github.copilot-sdk.generated.event-specs/resume-time] :opt-un [:github.copilot-sdk.generated.event-specs/already-in-use :github.copilot-sdk.generated.event-specs/context :github.copilot-sdk.generated.event-specs/continue-pending-work :github.copilot-sdk.generated.event-specs/reasoning-effort :github.copilot-sdk.generated.event-specs/reasoning-summary :github.copilot-sdk.generated.event-specs/remote-steerable :github.copilot-sdk.generated.event-specs/selected-model :github.copilot-sdk.generated.event-specs/session-was-active])) +(s/def :github.copilot-sdk.generated.event-specs/session.resume-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/event-count :github.copilot-sdk.generated.event-specs/resume-time] :opt-un [:github.copilot-sdk.generated.event-specs/already-in-use :github.copilot-sdk.generated.event-specs/context :github.copilot-sdk.generated.event-specs/context-tier :github.copilot-sdk.generated.event-specs/continue-pending-work :github.copilot-sdk.generated.event-specs/reasoning-effort :github.copilot-sdk.generated.event-specs/reasoning-summary :github.copilot-sdk.generated.event-specs/remote-steerable :github.copilot-sdk.generated.event-specs/selected-model :github.copilot-sdk.generated.event-specs/session-was-active])) (s/def :github.copilot-sdk.generated.event-specs/session.schedule_cancelled-data (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/id]) (fn [data] (s/valid? clojure.core/integer? (:id data))))) @@ -573,7 +587,7 @@ (s/def :github.copilot-sdk.generated.event-specs/session.snapshot_rewind-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/events-removed :github.copilot-sdk.generated.event-specs/up-to-event-id])) -(s/def :github.copilot-sdk.generated.event-specs/session.start-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/copilot-version :github.copilot-sdk.generated.event-specs/producer :github.copilot-sdk.generated.event-specs/session-id :github.copilot-sdk.generated.event-specs/start-time :github.copilot-sdk.generated.event-specs/version] :opt-un [:github.copilot-sdk.generated.event-specs/already-in-use :github.copilot-sdk.generated.event-specs/context :github.copilot-sdk.generated.event-specs/detached-from-spawning-parent-session-id :github.copilot-sdk.generated.event-specs/reasoning-effort :github.copilot-sdk.generated.event-specs/reasoning-summary :github.copilot-sdk.generated.event-specs/remote-steerable :github.copilot-sdk.generated.event-specs/selected-model])) +(s/def :github.copilot-sdk.generated.event-specs/session.start-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/copilot-version :github.copilot-sdk.generated.event-specs/producer :github.copilot-sdk.generated.event-specs/session-id :github.copilot-sdk.generated.event-specs/start-time :github.copilot-sdk.generated.event-specs/version] :opt-un [:github.copilot-sdk.generated.event-specs/already-in-use :github.copilot-sdk.generated.event-specs/context :github.copilot-sdk.generated.event-specs/context-tier :github.copilot-sdk.generated.event-specs/detached-from-spawning-parent-session-id :github.copilot-sdk.generated.event-specs/reasoning-effort :github.copilot-sdk.generated.event-specs/reasoning-summary :github.copilot-sdk.generated.event-specs/remote-steerable :github.copilot-sdk.generated.event-specs/selected-model])) (s/def :github.copilot-sdk.generated.event-specs/session.task_complete-data (s/keys :opt-un [:github.copilot-sdk.generated.event-specs/success :github.copilot-sdk.generated.event-specs/summary])) @@ -611,7 +625,7 @@ (s/def :github.copilot-sdk.generated.event-specs/tool.execution_progress-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/progress-message :github.copilot-sdk.generated.event-specs/tool-call-id])) -(s/def :github.copilot-sdk.generated.event-specs/tool.execution_start-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/tool-call-id :github.copilot-sdk.generated.event-specs/tool-name] :opt-un [:github.copilot-sdk.generated.event-specs/arguments :github.copilot-sdk.generated.event-specs/mcp-server-name :github.copilot-sdk.generated.event-specs/mcp-tool-name :github.copilot-sdk.generated.event-specs/parent-tool-call-id :github.copilot-sdk.generated.event-specs/turn-id])) +(s/def :github.copilot-sdk.generated.event-specs/tool.execution_start-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/tool-call-id :github.copilot-sdk.generated.event-specs/tool-name] :opt-un [:github.copilot-sdk.generated.event-specs/arguments :github.copilot-sdk.generated.event-specs/display-verbatim :github.copilot-sdk.generated.event-specs/mcp-server-name :github.copilot-sdk.generated.event-specs/mcp-tool-name :github.copilot-sdk.generated.event-specs/parent-tool-call-id :github.copilot-sdk.generated.event-specs/turn-id])) (s/def :github.copilot-sdk.generated.event-specs/tool.user_requested-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/tool-call-id :github.copilot-sdk.generated.event-specs/tool-name] :opt-un [:github.copilot-sdk.generated.event-specs/arguments])) @@ -671,6 +685,8 @@ (s/def :github.copilot-sdk.generated.event-specs/hook.end (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id :github.copilot-sdk.generated.event-specs/ephemeral]) (fn [event] (clojure.core/= "hook.end" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/hook.end-data (:data event))))) +(s/def :github.copilot-sdk.generated.event-specs/hook.progress (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/ephemeral :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id]) (fn [event] (clojure.core/= true (:ephemeral event))) (fn [event] (clojure.core/= "hook.progress" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/hook.progress-data (:data event))))) + (s/def :github.copilot-sdk.generated.event-specs/hook.start (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id :github.copilot-sdk.generated.event-specs/ephemeral]) (fn [event] (clojure.core/= "hook.start" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/hook.start-data (:data event))))) (s/def :github.copilot-sdk.generated.event-specs/mcp.oauth_completed (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/ephemeral :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id]) (fn [event] (clojure.core/= true (:ephemeral event))) (fn [event] (clojure.core/= "mcp.oauth_completed" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/mcp.oauth_completed-data (:data event))))) @@ -691,6 +707,8 @@ (s/def :github.copilot-sdk.generated.event-specs/sampling.requested (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/ephemeral :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id]) (fn [event] (clojure.core/= true (:ephemeral event))) (fn [event] (clojure.core/= "sampling.requested" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/sampling.requested-data (:data event))))) +(s/def :github.copilot-sdk.generated.event-specs/session.autopilot_objective_changed (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id :github.copilot-sdk.generated.event-specs/ephemeral]) (fn [event] (clojure.core/= "session.autopilot_objective_changed" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.autopilot_objective_changed-data (:data event))))) + (s/def :github.copilot-sdk.generated.event-specs/session.background_tasks_changed (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/ephemeral :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id]) (fn [event] (clojure.core/= true (:ephemeral event))) (fn [event] (clojure.core/= "session.background_tasks_changed" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.background_tasks_changed-data (:data event))))) (s/def :github.copilot-sdk.generated.event-specs/session.canvas.opened (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/ephemeral :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id]) (fn [event] (clojure.core/= true (:ephemeral event))) (fn [event] (clojure.core/= "session.canvas.opened" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.canvas.opened-data (:data event))))) @@ -725,6 +743,8 @@ (s/def :github.copilot-sdk.generated.event-specs/session.model_change (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id :github.copilot-sdk.generated.event-specs/ephemeral]) (fn [event] (clojure.core/= "session.model_change" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.model_change-data (:data event))))) +(s/def :github.copilot-sdk.generated.event-specs/session.permissions_changed (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id :github.copilot-sdk.generated.event-specs/ephemeral]) (fn [event] (clojure.core/= "session.permissions_changed" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.permissions_changed-data (:data event))))) + (s/def :github.copilot-sdk.generated.event-specs/session.plan_changed (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id :github.copilot-sdk.generated.event-specs/ephemeral]) (fn [event] (clojure.core/= "session.plan_changed" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.plan_changed-data (:data event))))) (s/def :github.copilot-sdk.generated.event-specs/session.remote_steerable_changed (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id :github.copilot-sdk.generated.event-specs/ephemeral]) (fn [event] (clojure.core/= "session.remote_steerable_changed" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.remote_steerable_changed-data (:data event))))) @@ -789,7 +809,7 @@ (s/def :github.copilot-sdk.generated.event-specs/user_input.requested (s/and (s/keys :req-un [:github.copilot-sdk.generated.event-specs/data :github.copilot-sdk.generated.event-specs/ephemeral :github.copilot-sdk.generated.event-specs/id :github.copilot-sdk.generated.event-specs/parent-id :github.copilot-sdk.generated.event-specs/timestamp :github.copilot-sdk.generated.event-specs/type] :opt-un [:github.copilot-sdk.generated.event-specs/agent-id]) (fn [event] (clojure.core/= true (:ephemeral event))) (fn [event] (clojure.core/= "user_input.requested" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/user_input.requested-data (:data event))))) -(def event-types "Set of all event-type strings known to the schema." #{"abort" "assistant.intent" "assistant.message" "assistant.message_delta" "assistant.message_start" "assistant.reasoning" "assistant.reasoning_delta" "assistant.streaming_delta" "assistant.turn_end" "assistant.turn_start" "assistant.usage" "auto_mode_switch.completed" "auto_mode_switch.requested" "capabilities.changed" "command.completed" "command.execute" "command.queued" "commands.changed" "elicitation.completed" "elicitation.requested" "exit_plan_mode.completed" "exit_plan_mode.requested" "external_tool.completed" "external_tool.requested" "hook.end" "hook.start" "mcp.oauth_completed" "mcp.oauth_required" "mcp_app.tool_call_complete" "model.call_failure" "pending_messages.modified" "permission.completed" "permission.requested" "sampling.completed" "sampling.requested" "session.background_tasks_changed" "session.canvas.opened" "session.canvas.registry_changed" "session.compaction_complete" "session.compaction_start" "session.context_changed" "session.custom_agents_updated" "session.custom_notification" "session.error" "session.extensions_loaded" "session.handoff" "session.idle" "session.info" "session.mcp_server_status_changed" "session.mcp_servers_loaded" "session.mode_changed" "session.model_change" "session.plan_changed" "session.remote_steerable_changed" "session.resume" "session.schedule_cancelled" "session.schedule_created" "session.shutdown" "session.skills_loaded" "session.snapshot_rewind" "session.start" "session.task_complete" "session.title_changed" "session.tools_updated" "session.truncation" "session.usage_info" "session.warning" "session.workspace_file_changed" "skill.invoked" "subagent.completed" "subagent.deselected" "subagent.failed" "subagent.selected" "subagent.started" "system.message" "system.notification" "tool.execution_complete" "tool.execution_partial_result" "tool.execution_progress" "tool.execution_start" "tool.user_requested" "user.message" "user_input.completed" "user_input.requested"}) +(def event-types "Set of all event-type strings known to the schema." #{"abort" "assistant.intent" "assistant.message" "assistant.message_delta" "assistant.message_start" "assistant.reasoning" "assistant.reasoning_delta" "assistant.streaming_delta" "assistant.turn_end" "assistant.turn_start" "assistant.usage" "auto_mode_switch.completed" "auto_mode_switch.requested" "capabilities.changed" "command.completed" "command.execute" "command.queued" "commands.changed" "elicitation.completed" "elicitation.requested" "exit_plan_mode.completed" "exit_plan_mode.requested" "external_tool.completed" "external_tool.requested" "hook.end" "hook.progress" "hook.start" "mcp.oauth_completed" "mcp.oauth_required" "mcp_app.tool_call_complete" "model.call_failure" "pending_messages.modified" "permission.completed" "permission.requested" "sampling.completed" "sampling.requested" "session.autopilot_objective_changed" "session.background_tasks_changed" "session.canvas.opened" "session.canvas.registry_changed" "session.compaction_complete" "session.compaction_start" "session.context_changed" "session.custom_agents_updated" "session.custom_notification" "session.error" "session.extensions_loaded" "session.handoff" "session.idle" "session.info" "session.mcp_server_status_changed" "session.mcp_servers_loaded" "session.mode_changed" "session.model_change" "session.permissions_changed" "session.plan_changed" "session.remote_steerable_changed" "session.resume" "session.schedule_cancelled" "session.schedule_created" "session.shutdown" "session.skills_loaded" "session.snapshot_rewind" "session.start" "session.task_complete" "session.title_changed" "session.tools_updated" "session.truncation" "session.usage_info" "session.warning" "session.workspace_file_changed" "skill.invoked" "subagent.completed" "subagent.deselected" "subagent.failed" "subagent.selected" "subagent.started" "system.message" "system.notification" "tool.execution_complete" "tool.execution_partial_result" "tool.execution_progress" "tool.execution_start" "tool.user_requested" "user.message" "user_input.completed" "user_input.requested"}) (defmulti event-mm :type) @@ -843,6 +863,8 @@ (defmethod event-mm "hook.end" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/hook.end)) +(defmethod event-mm "hook.progress" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/hook.progress)) + (defmethod event-mm "hook.start" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/hook.start)) (defmethod event-mm "mcp.oauth_completed" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/mcp.oauth_completed)) @@ -863,6 +885,8 @@ (defmethod event-mm "sampling.requested" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/sampling.requested)) +(defmethod event-mm "session.autopilot_objective_changed" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.autopilot_objective_changed)) + (defmethod event-mm "session.background_tasks_changed" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.background_tasks_changed)) (defmethod event-mm "session.canvas.opened" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.canvas.opened)) @@ -897,6 +921,8 @@ (defmethod event-mm "session.model_change" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.model_change)) +(defmethod event-mm "session.permissions_changed" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.permissions_changed)) + (defmethod event-mm "session.plan_changed" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.plan_changed)) (defmethod event-mm "session.remote_steerable_changed" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.remote_steerable_changed)) From f702818a457e09d37552a59e76efe01cf0c75a52 Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 13:05:43 +0200 Subject: [PATCH 2/9] feat(events): expose 3 new round-6 event types on the public API - :copilot/hook.progress (ephemeral progress from long-running hooks) - :copilot/session.autopilot_objective_changed - :copilot/session.permissions_changed Added to the public event-types and session-events sets, plus fixture entries in codegen_test for the two with hand-written curated data specs (added in the follow-up specs commit). Curated specs land in specs.clj so they're not re-generated when the schema is regenerated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/github/copilot_sdk.clj | 13 +++++++++++-- test/github/copilot_sdk/codegen_test.clj | 10 +++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/github/copilot_sdk.clj b/src/github/copilot_sdk.clj index 990241e..8838977 100644 --- a/src/github/copilot_sdk.clj +++ b/src/github/copilot_sdk.clj @@ -122,7 +122,13 @@ :copilot/session.remote_steerable_changed :copilot/capabilities.changed ;; MCP Apps tool-call complete (upstream schema 1.0.52-4, SEP-1865) - :copilot/mcp_app.tool_call_complete}) + :copilot/mcp_app.tool_call_complete + ;; Round 6 (upstream schema 1.0.56-1, post-v1.0.0-beta.4): autopilot + ;; objective lifecycle, allow-all-permissions mode toggles, and an + ;; ephemeral hook-progress event. + :copilot/session.autopilot_objective_changed + :copilot/session.permissions_changed + :copilot/hook.progress}) (def session-events "Session lifecycle and state management events." @@ -157,7 +163,10 @@ :copilot/session.custom_agents_updated :copilot/session.custom_notification :copilot/session.remote_steerable_changed - :copilot/capabilities.changed}) + :copilot/capabilities.changed + ;; Round 6 additions (upstream schema 1.0.56-1). + :copilot/session.autopilot_objective_changed + :copilot/session.permissions_changed}) (def assistant-events "Assistant response events." diff --git a/test/github/copilot_sdk/codegen_test.clj b/test/github/copilot_sdk/codegen_test.clj index 3c1b57e..ea239c9 100644 --- a/test/github/copilot_sdk/codegen_test.clj +++ b/test/github/copilot_sdk/codegen_test.clj @@ -240,7 +240,15 @@ :name "doc.opened" :payload {:path "/tmp/x"} :subject {:doc "foo"} - :version 1}}) + :version 1} + + ;; Round 6 additions (upstream schema 1.0.56-1). + "session.permissions_changed" + {:allow-all-permissions true + :previous-allow-all-permissions false} + + "hook.progress" + {:message "extracting..."}}) (defn- envelope "Wrap a data payload in a minimal valid envelope of the given type. Honours From c20f5a97f2f1ee21a379199cd82b6e7b1e80656e Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 13:05:51 +0200 Subject: [PATCH 3/9] feat(protocol): add inline-response callback on send-request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an optional {:on-response-inline (fn [result])} option to send-request and send-request!. The callback is invoked synchronously in the JSON-RPC reader thread, before the response is delivered to the result channel and before the next inbound message is dispatched. This is the building block for upstream PR #1479 (server-assigned sessionId for cloud sessions): the SDK uses this callback to register the session under the server-returned id atomically with respect to session-scoped notifications that may arrive immediately after the response on the wire. The callback runs in a try/catch so any exception is logged and the result is still delivered to the caller. Callers must keep the callback fast and non-blocking — it executes on the single reader thread. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/github/copilot_sdk/protocol.clj | 71 ++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/src/github/copilot_sdk/protocol.clj b/src/github/copilot_sdk/protocol.clj index b69ea11..d727a88 100644 --- a/src/github/copilot_sdk/protocol.clj +++ b/src/github/copilot_sdk/protocol.clj @@ -127,21 +127,34 @@ ;; ----------------------------------------------------------------------------- (defn- handle-response! - "Handle an incoming response message. Delivers to pending channel." + "Handle an incoming response message. Delivers to pending channel. + + If the original `send-request` call supplied an `:on-response-inline` + callback, invoke it synchronously **before** delivering the result to + the response channel. This callback runs in the reader thread, so any + work it performs (e.g. session registration after a server-assigned + sessionId) is guaranteed to complete before the next inbound message + is dispatched. Used by `client/create-session` for the cloud-no-id + flow (upstream PR #1479)." [state-atom msg] (let [id (:id msg) pending-requests (:pending-requests (conn-state state-atom))] (log/debug "Received response for id=" id) - (when-let [{:keys [ch]} (get pending-requests id)] + (when-let [{:keys [ch on-response-inline]} (get pending-requests id)] (update-conn! state-atom update :pending-requests dissoc id) (if-let [error (:error msg)] (do (log/debug "Response error: " error) (put! ch {:error error}) (close! ch)) - (do + (let [result (:result msg)] (log/debug "Response success for id=" id) - (put! ch {:result (:result msg)}) + (when on-response-inline + (try + (on-response-inline result) + (catch Throwable t + (log/error t "on-response-inline callback threw for id=" id)))) + (put! ch {:result result}) (close! ch)))))) (defn- preserve-outgoing-opaque-fields @@ -530,20 +543,31 @@ (defn send-request "Send a JSON-RPC request and return a channel for the response. - The channel delivers a single {:result ...} or {:error ...} map, then closes." - [conn method params] - (let [state-atom (:state-atom conn) - id (str (java.util.UUID/randomUUID)) - ch (chan 1) - wire-params (when params (util/clj->wire params)) - msg {:jsonrpc "2.0" - :id id - :method method - :params wire-params}] - (log/debug "Sending request: method=" method " id=" id) - (swap! state-atom assoc-in [:connection :pending-requests id] {:ch ch :method method}) - (put! (:outgoing-ch conn) msg) - ch)) + The channel delivers a single {:result ...} or {:error ...} map, then closes. + + Optional `opts` map: + - `:on-response-inline` — 1-arg fn `(fn [result])` invoked synchronously + in the read thread, **before** the result is delivered to the response + channel, on success only. Use this when you need to mutate shared + state (e.g. register a session under a server-assigned id) before + any later inbound message can be dispatched. See upstream PR #1479." + ([conn method params] + (send-request conn method params {})) + ([conn method params {:keys [on-response-inline] :as _opts}] + (let [state-atom (:state-atom conn) + id (str (java.util.UUID/randomUUID)) + ch (chan 1) + wire-params (when params (util/clj->wire params)) + msg {:jsonrpc "2.0" + :id id + :method method + :params wire-params} + entry (cond-> {:ch ch :method method} + on-response-inline (assoc :on-response-inline on-response-inline))] + (log/debug "Sending request: method=" method " id=" id) + (swap! state-atom assoc-in [:connection :pending-requests id] entry) + (put! (:outgoing-ch conn) msg) + ch))) (defn- remove-pending-by-chan! "Remove a pending request entry by channel identity." @@ -559,12 +583,17 @@ (defn send-request! "Send a JSON-RPC request and block for the response. - Returns result or throws on error." + Returns result or throws on error. + + The 4- and 5-arity forms accept an `opts` map forwarded to + `send-request` (see its docstring for supported keys)." ([conn method params] - (send-request! conn method params 60000)) + (send-request! conn method params 60000 {})) ([conn method params timeout-ms] + (send-request! conn method params timeout-ms {})) + ([conn method params timeout-ms opts] (let [state-atom (:state-atom conn) - response-ch (send-request conn method params) + response-ch (send-request conn method params opts) timeout-ch (async/timeout timeout-ms) [result port] (async/alts!! [response-ch timeout-ch])] (cond From e37980873b0d11f0dea37be3d6eeb6ea4c920f0c Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 13:05:57 +0200 Subject: [PATCH 4/9] feat(session): forward :agent-mode and :display-prompt on send! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - :agent-mode — keyword in #{:interactive :plan :autopilot :shell}, wire-encoded as agentMode. Per-message agent mode (upstream PR #1438). - :display-prompt — string shown in the timeline UI instead of the model-facing :prompt. Wire-encoded as displayPrompt (upstream PR #1470). Applied to both send! and --- src/github/copilot_sdk/session.clj | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/github/copilot_sdk/session.clj b/src/github/copilot_sdk/session.clj index 207c0ee..c350529 100644 --- a/src/github/copilot_sdk/session.clj +++ b/src/github/copilot_sdk/session.clj @@ -908,6 +908,13 @@ - :prompt - The message text (required) - :attachments - Vector of attachments (file/directory/selection) - :mode - :enqueue (default) or :immediate + - :agent-mode - **Optional**. One of :interactive (default), :plan, + :autopilot, or :shell. Selects the agent mode for + this turn (upstream PR #1438). + - :display-prompt - **Optional**. String shown in the session timeline + instead of the model `:prompt` (e.g., when the model + prompt is augmented with internal context that should + not be shown to end users). (upstream PR #1470) - :request-headers - Optional map of HTTP headers forwarded to the upstream LLM on this send (upstream PR #1094). Keys and values must both be strings (do not use @@ -935,6 +942,8 @@ trace-ctx (merge trace-ctx) wire-attachments (assoc :attachments wire-attachments) (:mode opts) (assoc :mode (name (:mode opts))) + (:agent-mode opts) (assoc :agent-mode (name (:agent-mode opts))) + (some? (:display-prompt opts)) (assoc :display-prompt (:display-prompt opts)) (:request-headers opts) (assoc :request-headers (:request-headers opts))) result (proto/send-request! conn "session.send" params) msg-id (:message-id result)] @@ -1142,6 +1151,8 @@ trace-ctx (merge trace-ctx) wire-attachments (assoc :attachments wire-attachments) (:mode opts) (assoc :mode (name (:mode opts))) + (:agent-mode opts) (assoc :agent-mode (name (:agent-mode opts))) + (some? (:display-prompt opts)) (assoc :display-prompt (:display-prompt opts)) (:request-headers opts) (assoc :request-headers (:request-headers opts))) response-ch (proto/send-request conn "session.send" params) [result port] (if deadline-ch From 76f3d7867cf0bf83efb6721e35dd5e5704269d2c Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 13:06:12 +0200 Subject: [PATCH 5/9] feat(client): port round 6 session config + cloud-no-id (PR #1479) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session config additions, all optional, accepted on both create and resume unless noted (closes pre-existing parity gaps from earlier upstream releases as well): - :mcp-oauth-token-storage — #{:persistent :in-memory}. Wire-encoded as the string key "mcpOAuthTokenStorage" (bypassing the default kebab→camel converter, which would lower-case OAuth). (upstream PR #1326) - :embedding-cache-storage, :skip-embedding-retrieval, :organization-custom-instructions, :enable-on-demand-instruction-discovery, :enable-file-hooks, :enable-host-git-operations, :enable-session-store, :enable-skills — per-session multitenancy granular flags. (upstream PR #1474) - :plugin-directories — extra plugin dirs loaded even when :enable-config-discovery is false. (upstream PR #1482) - :reasoning-summary — #{:none :concise :detailed} (parity gap). - :context-tier — #{:default :long-context}, wire-encoded as contextTier with values "default"/"long_context" via an explicit case table (parity gap). - :large-output on resume — was already accepted on create; now also forwarded on resume to match upstream client.ts:1308 (parity gap). PR #1479 — server-assigned sessionId for cloud sessions: When :cloud is set and :session-id is omitted from create-session / --- src/github/copilot_sdk/client.clj | 374 ++++++++++++---- src/github/copilot_sdk/specs.clj | 167 ++++++- test/github/copilot_sdk/integration_test.clj | 440 +++++++++++++++++++ 3 files changed, 890 insertions(+), 91 deletions(-) diff --git a/src/github/copilot_sdk/client.clj b/src/github/copilot_sdk/client.clj index 6b317b3..5f6e536 100644 --- a/src/github/copilot_sdk/client.clj +++ b/src/github/copilot_sdk/client.clj @@ -1436,6 +1436,27 @@ (assoc :maxPromptTokens (:maxInputTokens wire))) wire))) +(defn- context-tier->wire + "Convert a Clojure :context-tier keyword to the wire string value. + The CLI expects \"default\" / \"long_context\" (underscore), so csk + camelCasing would produce the wrong value — we map explicitly." + [tier] + (case tier + :default "default" + :long-context "long_context" + nil nil + (throw (ex-info "Invalid :context-tier value (expected :default or :long-context)" + {:context-tier tier})))) + +(defn- large-output->wire + "Convert a :large-output config map to wire shape, accepting both the + pre-existing `:output-dir` key and the upstream-aligned alias + `:output-directory` (the wire field stays `outputDir`)." + [lo] + (let [dir (or (:output-directory lo) (:output-dir lo))] + (cond-> (dissoc lo :output-directory) + dir (assoc :output-dir dir)))) + (defn- build-create-session-params "Build wire params for session.create from config." [config] @@ -1468,7 +1489,9 @@ (cond-> {:name (:name c)} (some? (:description c)) (assoc :description (:description c)))) - cmds))] + cmds)) + config-dir (or (:config-directory config) (:config-dir config)) + wire-large-output (some-> (:large-output config) large-output->wire)] (cond-> {} (:session-id config) (assoc :session-id (:session-id config)) (:client-name config) (assoc :client-name (:client-name config)) @@ -1485,14 +1508,18 @@ wire-mcp-servers (assoc :mcp-servers wire-mcp-servers) wire-custom-agents (assoc :custom-agents wire-custom-agents) wire-default-agent (assoc :default-agent wire-default-agent) - (:config-dir config) (assoc :config-dir (:config-dir config)) + config-dir (assoc :config-dir config-dir) (:skill-directories config) (assoc :skill-directories (:skill-directories config)) (:instruction-directories config) (assoc :instruction-directories (:instruction-directories config)) (:disabled-skills config) (assoc :disabled-skills (:disabled-skills config)) - (:large-output config) (assoc :large-output (:large-output config)) + (:plugin-directories config) (assoc :plugin-directories (:plugin-directories config)) + wire-large-output (assoc :large-output wire-large-output) (:working-directory config) (assoc :working-directory (:working-directory config)) wire-infinite-sessions (assoc :infinite-sessions wire-infinite-sessions) (:reasoning-effort config) (assoc :reasoning-effort (:reasoning-effort config)) + (:reasoning-summary config) (assoc :reasoning-summary (:reasoning-summary config)) + (contains? config :context-tier) + (assoc :context-tier (context-tier->wire (:context-tier config))) (:agent config) (assoc :agent (:agent config)) true (assoc :request-user-input (boolean (:on-user-input-request config))) true (assoc :request-elicitation (boolean (:on-elicitation-request config))) @@ -1509,6 +1536,32 @@ (assoc :cloud (util/clj->wire (:cloud config))) (:model-capabilities config) (assoc :model-capabilities (util/clj->wire (:model-capabilities config))) + ;; Round 6 (upstream schema 1.0.56-1): MCP OAuth token storage mode and + ;; embedding cache storage mode are hyphen-preserving string enums + ;; (`"persistent"` / `"in-memory"`). The wire key for the first is + ;; `mcpOAuthTokenStorage` (capital `OA` in `OAuth`) — csk on + ;; `:mcp-oauth-token-storage` would emit `mcpOauthTokenStorage` instead, + ;; so we forward via a string key to bypass key conversion. The value + ;; uses `(name kw)` so `:in-memory` survives as `"in-memory"` + ;; (csk would mangle it to `"inMemory"`). + (:mcp-oauth-token-storage config) + (assoc "mcpOAuthTokenStorage" (name (:mcp-oauth-token-storage config))) + (:embedding-cache-storage config) + (assoc :embedding-cache-storage (name (:embedding-cache-storage config))) + (some? (:skip-embedding-retrieval config)) + (assoc :skip-embedding-retrieval (:skip-embedding-retrieval config)) + (:organization-custom-instructions config) + (assoc :organization-custom-instructions (:organization-custom-instructions config)) + (some? (:enable-on-demand-instruction-discovery config)) + (assoc :enable-on-demand-instruction-discovery (:enable-on-demand-instruction-discovery config)) + (some? (:enable-file-hooks config)) + (assoc :enable-file-hooks (:enable-file-hooks config)) + (some? (:enable-host-git-operations config)) + (assoc :enable-host-git-operations (:enable-host-git-operations config)) + (some? (:enable-session-store config)) + (assoc :enable-session-store (:enable-session-store config)) + (some? (:enable-skills config)) + (assoc :enable-skills (:enable-skills config)) true (assoc :include-sub-agent-streaming-events (if (some? (:include-sub-agent-streaming-events? config)) (:include-sub-agent-streaming-events? config) @@ -1547,7 +1600,9 @@ (cond-> {:name (:name c)} (some? (:description c)) (assoc :description (:description c)))) - cmds))] + cmds)) + config-dir (or (:config-directory config) (:config-dir config)) + wire-large-output (some-> (:large-output config) large-output->wire)] (cond-> {:session-id session-id} (:client-name config) (assoc :client-name (:client-name config)) (:model config) (assoc :model (:model config)) @@ -1565,12 +1620,17 @@ wire-mcp-servers (assoc :mcp-servers wire-mcp-servers) wire-custom-agents (assoc :custom-agents wire-custom-agents) wire-default-agent (assoc :default-agent wire-default-agent) - (:config-dir config) (assoc :config-dir (:config-dir config)) + config-dir (assoc :config-dir config-dir) (:skill-directories config) (assoc :skill-directories (:skill-directories config)) (:instruction-directories config) (assoc :instruction-directories (:instruction-directories config)) (:disabled-skills config) (assoc :disabled-skills (:disabled-skills config)) + (:plugin-directories config) (assoc :plugin-directories (:plugin-directories config)) + wire-large-output (assoc :large-output wire-large-output) wire-infinite-sessions (assoc :infinite-sessions wire-infinite-sessions) (:reasoning-effort config) (assoc :reasoning-effort (:reasoning-effort config)) + (:reasoning-summary config) (assoc :reasoning-summary (:reasoning-summary config)) + (contains? config :context-tier) + (assoc :context-tier (context-tier->wire (:context-tier config))) (:agent config) (assoc :agent (:agent config)) true (assoc :request-user-input (boolean (:on-user-input-request config))) true (assoc :request-elicitation (boolean (:on-elicitation-request config))) @@ -1589,6 +1649,28 @@ (assoc :remote-session (name (:remote-session config))) (:model-capabilities config) (assoc :model-capabilities (util/clj->wire (:model-capabilities config))) + ;; Round 6 (upstream schema 1.0.56-1) per-session multitenancy / + ;; storage knobs — mirror the set forwarded on session.create. The + ;; `mcpOAuthTokenStorage` wire key (capital `OA`) bypasses csk via + ;; a string key (see `build-create-session-params` for rationale). + (:mcp-oauth-token-storage config) + (assoc "mcpOAuthTokenStorage" (name (:mcp-oauth-token-storage config))) + (:embedding-cache-storage config) + (assoc :embedding-cache-storage (name (:embedding-cache-storage config))) + (some? (:skip-embedding-retrieval config)) + (assoc :skip-embedding-retrieval (:skip-embedding-retrieval config)) + (:organization-custom-instructions config) + (assoc :organization-custom-instructions (:organization-custom-instructions config)) + (some? (:enable-on-demand-instruction-discovery config)) + (assoc :enable-on-demand-instruction-discovery (:enable-on-demand-instruction-discovery config)) + (some? (:enable-file-hooks config)) + (assoc :enable-file-hooks (:enable-file-hooks config)) + (some? (:enable-host-git-operations config)) + (assoc :enable-host-git-operations (:enable-host-git-operations config)) + (some? (:enable-session-store config)) + (assoc :enable-session-store (:enable-session-store config)) + (some? (:enable-skills config)) + (assoc :enable-skills (:enable-skills config)) true (assoc :include-sub-agent-streaming-events (if (some? (:include-sub-agent-streaming-events? config)) (:include-sub-agent-streaming-events? config) @@ -1612,6 +1694,67 @@ :on-event (:on-event config) :config config})) +(defn- ensure-session-fs-handler-factory! + "When the client has sessionFs enabled, validate that the config provides + `:create-session-fs-handler` (which builds the per-session handler). + Throws fail-fast with a clear message; allows the cloud-no-id flow to + bail out BEFORE issuing the RPC instead of inside the reader-thread + callback." + [client config] + (when (:session-fs client) + (when-not (:create-session-fs-handler config) + (throw (ex-info (str ":create-session-fs-handler is required in session config " + "when :session-fs is enabled in client options.") + {:config config}))))) + +(defn- install-session-fs-handler! + "Construct and install the per-session sessionFs handler. Caller is + responsible for sessionFs validation (use `ensure-session-fs-handler-factory!` + before calling). No-op when sessionFs is disabled on the client." + [client session-id session config] + (when (:session-fs client) + (when-let [factory (:create-session-fs-handler config)] + (session/set-session-fs-handler! client session-id + (session/adapt-session-fs-handler (factory session)))))) + +(defn- make-create-session-inline-callback + "Build the inline-response callback used by the cloud-no-id session + creation path. The callback runs in the JSON-RPC reader thread; keep + it minimal and non-blocking. On any failure it removes any partially + registered session and delivers the error to `result-promise`; on + success it delivers the live session. + + Note: `install-session-fs-handler!` invokes a user-supplied + `:create-session-fs-handler` factory. Document and rely on the + convention that the factory is a fast, non-blocking constructor — + if it issues another RPC it will deadlock the reader thread. + `ensure-session-fs-handler-factory!` is called BEFORE the RPC so a + missing factory cannot reach the callback." + [client config transform-callbacks result-promise] + (let [registered-id (atom nil) + deliver-error! + (fn [ex] + (when-let [sid @registered-id] + (try + (session/remove-session! client sid) + (catch Throwable cleanup-t + (log/warn cleanup-t "Failed to remove partially registered session " sid)))) + (deliver result-promise ex))] + (fn [result] + (try + (let [assigned-id (:session-id result)] + (if (or (not (string? assigned-id)) (str/blank? assigned-id)) + (deliver-error! + (ex-info "session.create response did not include a sessionId for cloud session" + {:result result})) + (let [session (pre-register-session client assigned-id config)] + (reset! registered-id assigned-id) + (session/register-transform-callbacks! client assigned-id transform-callbacks) + (install-session-fs-handler! client assigned-id session config) + (deliver result-promise session)))) + (catch Throwable t + (deliver-error! t)))))) + (defn create-session "Create a new conversation session. @@ -1688,38 +1831,75 @@ repository: `{:repository {:owner \"...\" :name \"...\" :branch \"...\"}}`. `:branch` is optional. Forwarded as `cloud` on session.create. (upstream PR #1306) + + When `:cloud` is set and no `:session-id` is provided, the server + assigns a sessionId and the SDK registers the session under that + id; the session is registered synchronously before any subsequent + server-initiated requests can be dispatched (upstream PR #1479). Returns a CopilotSession." [client config] (log/debug "Creating session with config: " (select-keys config [:model :session-id])) (validate-session-config! config) (ensure-connected! client) + (ensure-session-fs-handler-factory! client config) (let [{:keys [connection-io]} @(:state client) - session-id (or (:session-id config) (str (java.util.UUID/randomUUID))) trace-ctx (get-trace-context (:on-get-trace-context client)) {:keys [transform-callbacks]} (extract-transform-callbacks (:system-message config)) - params (merge trace-ctx (assoc (build-create-session-params config) :session-id session-id)) - ;; Pre-register session before RPC so early events are captured - session (pre-register-session client session-id config)] - ;; Register transform callbacks on session before RPC - (session/register-transform-callbacks! client session-id transform-callbacks) - (try - ;; Attach sessionFs handler if sessionFs is configured - (when (:session-fs client) - (if-let [factory (:create-session-fs-handler config)] - (session/set-session-fs-handler! client session-id - (session/adapt-session-fs-handler (factory session))) - (throw (ex-info (str ":create-session-fs-handler is required in session config " - "when :session-fs is enabled in client options.") - {:config config})))) - (let [result (proto/send-request! connection-io "session.create" params)] - (session/set-workspace-path! client session-id (:workspace-path result)) - (session/set-capabilities! client session-id (:capabilities result)) - (log/info "Session created: " session-id) - session) - (catch Throwable t - (session/remove-session! client session-id) - (throw t))))) + cloud? (some? (:cloud config)) + caller-session-id (:session-id config) + defer-session-id? (and cloud? (not caller-session-id))] + (if defer-session-id? + ;; Cloud session without a caller-supplied id (upstream PR #1479): omit + ;; `sessionId` from the wire params and let the server assign one. The + ;; SDK registers the session under the server-returned id inside an + ;; inline-response callback so any session-scoped notifications that + ;; arrive after the response are routed to the correct session. + (let [params (merge trace-ctx (build-create-session-params config)) + session-promise (promise) + on-inline (make-create-session-inline-callback + client config transform-callbacks session-promise) + result (proto/send-request! connection-io "session.create" params 60000 + {:on-response-inline on-inline}) + registered (deref session-promise 0 :not-delivered)] + (cond + (= registered :not-delivered) + (throw (ex-info "Internal error: inline-response callback did not run for session.create" + {:result result})) + + (instance? Throwable registered) + (throw registered) + + :else + (let [session registered + session-id (:session-id session)] + (session/set-workspace-path! client session-id (:workspace-path result)) + (session/set-capabilities! client session-id (:capabilities result)) + (log/info "Session created (cloud, server-assigned id): " session-id) + session))) + ;; Standard path: client supplies (or generates) the sessionId up front. + (let [session-id (or caller-session-id (str (java.util.UUID/randomUUID))) + params (merge trace-ctx (assoc (build-create-session-params config) :session-id session-id)) + ;; Pre-register session before RPC so early events are captured + session (pre-register-session client session-id config)] + ;; Register transform callbacks on session before RPC + (session/register-transform-callbacks! client session-id transform-callbacks) + (try + (install-session-fs-handler! client session-id session config) + (let [result (proto/send-request! connection-io "session.create" params) + returned-id (:session-id result)] + (when (and (string? returned-id) + (not (str/blank? returned-id)) + (not= returned-id session-id)) + (throw (ex-info "session.create returned a sessionId that differs from the caller-supplied id" + {:requested session-id :returned returned-id}))) + (session/set-workspace-path! client session-id (:workspace-path result)) + (session/set-capabilities! client session-id (:capabilities result)) + (log/info "Session created: " session-id) + session) + (catch Throwable t + (session/remove-session! client session-id) + (throw t))))))) (defn resume-session "Resume an existing session by ID. @@ -1777,6 +1957,7 @@ (throw (ex-info "Invalid session config: :model is required when :provider (BYOK) is specified" {:config config}))) (ensure-connected! client) + (ensure-session-fs-handler-factory! client config) (let [{:keys [connection-io]} @(:state client) trace-ctx (get-trace-context (:on-get-trace-context client)) {:keys [transform-callbacks]} (extract-transform-callbacks (:system-message config)) @@ -1786,14 +1967,7 @@ ;; Register transform callbacks on session before RPC (session/register-transform-callbacks! client session-id transform-callbacks) (try - ;; Attach sessionFs handler if sessionFs is configured - (when (:session-fs client) - (if-let [factory (:create-session-fs-handler config)] - (session/set-session-fs-handler! client session-id - (session/adapt-session-fs-handler (factory session))) - (throw (ex-info (str ":create-session-fs-handler is required in session config " - "when :session-fs is enabled in client options.") - {:config config})))) + (install-session-fs-handler! client session-id session config) (let [result (proto/send-request! connection-io "session.resume" params)] (session/set-workspace-path! client session-id (:workspace-path result)) (session/set-capabilities! client session-id (:capabilities result)) @@ -1825,43 +1999,93 @@ (log/debug "Creating session (async) with config: " (select-keys config [:model :session-id])) (validate-session-config! config) (ensure-connected! client) + (ensure-session-fs-handler-factory! client config) (let [{:keys [connection-io]} @(:state client) - session-id (or (:session-id config) (str (java.util.UUID/randomUUID))) trace-ctx (get-trace-context (:on-get-trace-context client)) {:keys [transform-callbacks]} (extract-transform-callbacks (:system-message config)) - params (merge trace-ctx (assoc (build-create-session-params config) :session-id session-id)) - ;; Pre-register session before RPC so early events are captured - session (pre-register-session client session-id config) - _ (session/register-transform-callbacks! client session-id transform-callbacks) - ;; Attach sessionFs handler if sessionFs is configured (synchronously, before RPC) - _ (try - (when (:session-fs client) - (if-let [factory (:create-session-fs-handler config)] - (session/set-session-fs-handler! client session-id - (session/adapt-session-fs-handler (factory session))) - (throw (ex-info (str ":create-session-fs-handler is required in session config " - "when :session-fs is enabled in client options.") - {:config config})))) - (catch Throwable t - (session/remove-session! client session-id) - (throw t))) - rpc-ch (proto/send-request connection-io "session.create" params)] - (go - (let [response ( — same shape as ::model-capabilities since all fields are already optional. +;; ----------------------------------------------------------------------------- +;; Round 6 (post-v1.0.0-beta.4) SessionConfigBase additions +;; ----------------------------------------------------------------------------- + +;; mcpOAuthTokenStorage (PR #1326): controls where MCP OAuth tokens are stored +;; on disk vs in process memory. Idiom uses keywords; wire emits the original +;; hyphenated string (NOT camel-cased — csk would wrongly produce "inMemory"). +;; embeddingCacheStorage (PR #1474) shares the same enum. +(s/def ::storage-mode #{:persistent :in-memory}) +(s/def ::mcp-oauth-token-storage ::storage-mode) +(s/def ::embedding-cache-storage ::storage-mode) + +;; Multitenancy hardening flags (upstream PR #1474). All optional, plain +;; booleans/strings. Application-mode behavior is driven by Client Mode +;; (upstream PR #1428), which has been deferred to a dedicated future round. +(s/def ::skip-embedding-retrieval boolean?) +(s/def ::organization-custom-instructions string?) +(s/def ::enable-on-demand-instruction-discovery boolean?) +(s/def ::enable-file-hooks boolean?) +(s/def ::enable-host-git-operations boolean?) +(s/def ::enable-session-store boolean?) +(s/def ::enable-skills boolean?) + +;; Reasoning summary mode (upstream PR #813 - pre-existing parity gap). +;; Wire enum: "none" | "concise" | "detailed". Mirrors upstream's ReasoningSummary type. +(s/def ::reasoning-summary #{"none" "concise" "detailed"}) + +;; Explicit context tier for the selected model (upstream — pre-existing parity gap). +;; Idiom uses keywords; wire emits the underscored enum: "default" | "long_context". +;; nil clears the previous explicit choice; missing leaves it untouched. +(s/def ::context-tier (s/nilable #{:default :long-context})) + (def session-config-keys #{:session-id :client-name :model :tools :commands :system-message :available-tools :excluded-tools :provider :on-permission-request :streaming? :mcp-servers - :custom-agents :default-agent :config-dir :skill-directories + :custom-agents :default-agent + ;; Directory rename (PR #1482): :config-directory is the new spelling; + ;; :config-dir is accepted as a deprecated alias. + :config-dir :config-directory + :skill-directories :instruction-directories + :plugin-directories :disabled-skills :large-output :infinite-sessions - :reasoning-effort :on-user-input-request :on-elicitation-request :hooks + :reasoning-effort :reasoning-summary :context-tier + :on-user-input-request :on-elicitation-request :hooks :on-exit-plan-mode :on-auto-mode-switch :working-directory :agent :on-event :create-session-fs-handler :enable-config-discovery :model-capabilities :github-token :enable-session-telemetry? :remote-session :cloud + :mcp-oauth-token-storage + :embedding-cache-storage + :skip-embedding-retrieval + :organization-custom-instructions + :enable-on-demand-instruction-discovery + :enable-file-hooks + :enable-host-git-operations + :enable-session-store + :enable-skills :include-sub-agent-streaming-events?}) (s/def ::session-config @@ -600,31 +659,57 @@ ::session-id ::client-name ::model ::tools ::commands ::system-message ::available-tools ::excluded-tools ::provider ::streaming? ::mcp-servers - ::custom-agents ::default-agent ::config-dir ::skill-directories + ::custom-agents ::default-agent + ::config-dir ::config-directory + ::skill-directories ::instruction-directories + ::plugin-directories ::disabled-skills ::large-output ::infinite-sessions - ::reasoning-effort ::on-user-input-request ::on-elicitation-request ::hooks + ::reasoning-effort ::reasoning-summary ::context-tier + ::on-user-input-request ::on-elicitation-request ::hooks ::on-exit-plan-mode ::on-auto-mode-switch ::working-directory ::agent ::on-event ::create-session-fs-handler ::enable-config-discovery ::model-capabilities ::github-token ::enable-session-telemetry? ::remote-session ::cloud + ::mcp-oauth-token-storage + ::embedding-cache-storage + ::skip-embedding-retrieval + ::organization-custom-instructions + ::enable-on-demand-instruction-discovery + ::enable-file-hooks + ::enable-host-git-operations + ::enable-session-store + ::enable-skills ::include-sub-agent-streaming-events?]) session-config-keys)) (def ^:private resume-session-config-keys #{:client-name :model :tools :commands :system-message :available-tools :excluded-tools :provider :streaming? :on-permission-request - :mcp-servers :custom-agents :default-agent :config-dir :skill-directories + :mcp-servers :custom-agents :default-agent + :config-dir :config-directory + :skill-directories :instruction-directories - :disabled-skills :infinite-sessions :reasoning-effort + :plugin-directories + :disabled-skills :large-output :infinite-sessions + :reasoning-effort :reasoning-summary :context-tier :on-user-input-request :on-elicitation-request :hooks :working-directory :disable-resume? :agent :on-event :on-exit-plan-mode :on-auto-mode-switch :continue-pending-work? :create-session-fs-handler :enable-config-discovery :model-capabilities :github-token :enable-session-telemetry? :remote-session + :mcp-oauth-token-storage + :embedding-cache-storage + :skip-embedding-retrieval + :organization-custom-instructions + :enable-on-demand-instruction-discovery + :enable-file-hooks + :enable-host-git-operations + :enable-session-store + :enable-skills :include-sub-agent-streaming-events?}) (s/def ::resume-session-config @@ -633,9 +718,13 @@ (s/keys :opt-un [::on-permission-request ::client-name ::model ::tools ::commands ::system-message ::available-tools ::excluded-tools ::provider ::streaming? - ::mcp-servers ::custom-agents ::default-agent ::config-dir ::skill-directories + ::mcp-servers ::custom-agents ::default-agent + ::config-dir ::config-directory + ::skill-directories ::instruction-directories - ::disabled-skills ::infinite-sessions ::reasoning-effort + ::plugin-directories + ::disabled-skills ::large-output ::infinite-sessions + ::reasoning-effort ::reasoning-summary ::context-tier ::on-user-input-request ::on-elicitation-request ::hooks ::working-directory ::disable-resume? ::agent ::on-exit-plan-mode ::on-auto-mode-switch ::on-event ::create-session-fs-handler @@ -643,6 +732,15 @@ ::continue-pending-work? ::enable-session-telemetry? ::remote-session + ::mcp-oauth-token-storage + ::embedding-cache-storage + ::skip-embedding-retrieval + ::organization-custom-instructions + ::enable-on-demand-instruction-discovery + ::enable-file-hooks + ::enable-host-git-operations + ::enable-session-store + ::enable-skills ::include-sub-agent-streaming-events?]) resume-session-config-keys)) @@ -653,9 +751,13 @@ (s/keys :opt-un [::on-permission-request ::client-name ::model ::tools ::commands ::system-message ::available-tools ::excluded-tools ::provider ::streaming? - ::mcp-servers ::custom-agents ::default-agent ::config-dir ::skill-directories + ::mcp-servers ::custom-agents ::default-agent + ::config-dir ::config-directory + ::skill-directories ::instruction-directories - ::disabled-skills ::infinite-sessions ::reasoning-effort + ::plugin-directories + ::disabled-skills ::large-output ::infinite-sessions + ::reasoning-effort ::reasoning-summary ::context-tier ::on-user-input-request ::on-elicitation-request ::hooks ::working-directory ::disable-resume? ::agent ::on-exit-plan-mode ::on-auto-mode-switch ::on-event ::create-session-fs-handler @@ -663,6 +765,15 @@ ::continue-pending-work? ::enable-session-telemetry? ::remote-session + ::mcp-oauth-token-storage + ::embedding-cache-storage + ::skip-embedding-retrieval + ::organization-custom-instructions + ::enable-on-demand-instruction-discovery + ::enable-file-hooks + ::enable-host-git-operations + ::enable-session-store + ::enable-skills ::include-sub-agent-streaming-events?]) resume-session-config-keys)) @@ -754,9 +865,19 @@ ;; Map of header name → value, merged with any provider-level headers. (s/def ::request-headers (s/map-of string? string?)) +;; UI agent mode for this turn (upstream PR #1438, post-v1.0.0-beta.4). +;; Wire enum: "interactive" | "plan" | "autopilot" | "shell". Defaults to the +;; session's current mode when omitted. +(s/def ::agent-mode #{:interactive :plan :autopilot :shell}) + +;; Display-only prompt shown in the timeline instead of the model :prompt +;; (upstream PR #1470, post-v1.0.0-beta.4). +(s/def ::display-prompt string?) + (s/def ::send-options (s/keys :req-un [::prompt] - :opt-un [::attachments ::mode ::timeout-ms ::request-headers])) + :opt-un [::attachments ::mode ::timeout-ms ::request-headers + ::agent-mode ::display-prompt])) ;; :timeout-ms as used in option maps for send-async / Date: Sat, 30 May 2026 13:06:21 +0200 Subject: [PATCH 6/9] docs: round 6 changelog and API reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHANGELOG: round 6 [Unreleased] entries for MessageOptions additions (agentMode, displayPrompt), mcpOAuthTokenStorage, multitenancy flags, pluginDirectories, cloud-no-id (PR #1479), reasoningSummary / contextTier / resume largeOutput parity gaps, three new event types, and the schema bump. Deferred items called out: PR #1428 (multitenancy client mode), the configDir → configDirectory rename (PR #1482), Canvas runtime, MCP Apps enableMcpApps. doc/reference/API.md: new session-config options table entries with wire-key annotations and upstream PR references; new event types in the event-type table; cloud-no-id behaviour noted on :cloud; resume table mentions :large-output forwarded on session.resume; send! options table gains :agent-mode and :display-prompt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 92 ++++++++++++++++++++++++++++++++++++++++++++ doc/reference/API.md | 20 +++++++++- 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be64f34..f64a2bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,98 @@ All notable changes to this project will be documented in this file. This change ## [Unreleased] +### Added (post-v1.0.0-beta.4 sync, round 6) +- **`:agent-mode` and `:display-prompt` send options** — `session/send!` + (and async/streaming variants) now accept: + - `:agent-mode` — keyword in `#{:interactive :plan :autopilot :shell}`, + wire-encoded as `agentMode`. Lets the model run with different agent + behaviours per message. (upstream PR #1438) + - `:display-prompt` — string shown in the timeline UI instead of the + model-facing `:prompt`. Useful when the model prompt contains + machinery or context that should not be surfaced to the end user. + Wire-encoded as `displayPrompt`. (upstream PR #1470) +- **`:mcp-oauth-token-storage` config option** — Controls where MCP OAuth + tokens are persisted. Enum `#{:persistent :in-memory}`, defaulting to + the server's default (persistent disk-backed). Set to `:in-memory` in + multi-tenant hosts that must not leak tokens to disk. Wire-encoded as + `mcpOAuthTokenStorage` (the wire key is set directly to bypass the + default kebab-camel converter which would mangle `OAuth`). Accepted on + both create and resume. (upstream PR #1326) +- **Multitenancy per-session granular flags** — All optional, accepted on + both `create-session` and `resume-session`: + - `:embedding-cache-storage` (`#{:persistent :in-memory}`, wire + `embeddingCacheStorage`) + - `:skip-embedding-retrieval` (boolean) + - `:organization-custom-instructions` (string) + - `:enable-on-demand-instruction-discovery` (boolean) + - `:enable-file-hooks` (boolean) + - `:enable-host-git-operations` (boolean) + - `:enable-session-store` (boolean) + - `:enable-skills` (boolean) + + Lets multi-tenant hosts opt individual sessions out of disk-backed + caches, host git, hooks, sessions store, and skills discovery without + switching to a separate client. (upstream PR #1474) +- **`:plugin-directories` config option** — `[string]` of extra plugin + directories. Wire-encoded as `pluginDirectories`. Loaded even when + `:enable-config-discovery` is `false`, so multi-tenant hosts can + inject a curated plugin set without enabling general discovery. + Accepted on both create and resume. (upstream PR #1482) +- **Cloud sessions can defer `sessionId` to the server** — When + `:cloud` is set and `:session-id` is omitted from `create-session` / + ` :interval-ms :prompt "..."}` (upstream schema 1.0.42) | | `:copilot/session.schedule_cancelled` | Scheduled prompt cancelled from the schedule manager dialog; data: `{:id }` (upstream schema 1.0.42) | +| `:copilot/session.autopilot_objective_changed` | Autopilot objective added/updated/removed; data: `{:operation "..." :objective {...}}` (upstream schema 1.0.56). The `:status` enum for autopilot objectives is widened to include `"active"`, `"paused"`, `"cap_reached"`, `"completed"`. | +| `:copilot/session.permissions_changed` | Per-session permission flags changed; data: `{:allow-all-permissions boolean :disable-permissions boolean}` (upstream schema 1.0.56). | | `:copilot/skill.invoked` | Skill invocation triggered; data includes :name, :path, :content, optional :description, :plugin-name, :plugin-version | | `:copilot/user.message` | User message added | | `:copilot/pending_messages.modified` | Pending message queue updated | @@ -1404,6 +1421,7 @@ Convert an unqualified event keyword to a namespace-qualified `:copilot/` keywor | `:copilot/subagent.selected` | Subagent selected | | `:copilot/subagent.deselected` | Subagent deselected | | `:copilot/hook.start` | Hook invocation started | +| `:copilot/hook.progress` | Ephemeral progress update from a long-running hook; data: `{:message "..."}` (upstream schema 1.0.56). | | `:copilot/hook.end` | Hook invocation finished | | `:copilot/system.message` | System message emitted | | `:copilot/system.notification` | System notification with structured `:kind` discriminator (e.g. `agent_completed`, `shell_completed`, `shell_detached_completed`) | From fdf1c83496737de3e9e08931fac328297a9975b0 Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 22:49:54 +0200 Subject: [PATCH 7/9] fix(docs+tests): address Copilot Code Review feedback round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs(reasoning-summary): correct CHANGELOG/API.md from keyword-enum to string enum (#{"none" "concise" "detailed"}) — matches the actual spec and tests, and the existing :reasoning-effort string pattern. - docs(event-payloads): correct session.autopilot_objective_changed data (:operation #{"create" "update" "delete"} required, :id integer optional, :status optional — no :objective field) and session.permissions_changed data (:allow-all-permissions plus :previous-allow-all-permissions — no :disable-permissions field) to match the actual schema/specs. - docs(hook.progress): clarify that the curated ::hook.progress-data spec is just :message — :session-id/:timestamp are envelope fields, not data fields. - docs(config-directory aliases): the :config-directory and :output-directory aliases ARE added in this release (non-breaking); moved from Deferred to a new Added bullet. Deferred now scoped to the future breaking removal of the legacy spellings. - test(codegen fixture): add session.autopilot_objective_changed fixture so generated-data-specs-accept-wire-payloads exercises the new required :operation and optional :id/:status shape. - test(context-tier): rewrite the false-confidence test-spec-session-resume-data-context-tier — the curated ::session.resume-data does not declare :context-tier, so the prior assertion passed trivially. Rewritten as test-generated-session-resume-data-context-tier asserting against the generated wire spec (the layer that actually carries the field as nilable "default"/"long_context" string). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 35 ++++++++++++-------- doc/reference/API.md | 6 ++-- test/github/copilot_sdk/codegen_test.clj | 5 +++ test/github/copilot_sdk/integration_test.clj | 29 ++++++++++++---- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f64a2bb..5edcd97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,26 +55,35 @@ All notable changes to this project will be documented in this file. This change - **Config parity additions** — Existed in upstream `SessionConfigBase` prior to this window; added to close pre-existing parity gaps. All optional, accepted on both create and resume: - - `:reasoning-summary` (`#{:none :concise :detailed}`, wire + - `:reasoning-summary` (`#{"none" "concise" "detailed"}`, wire `reasoningSummary`) — controls inclusion/granularity of reasoning - summaries in assistant turns. + summaries in assistant turns. String-valued for consistency with + the existing `:reasoning-effort` option. - `:context-tier` (`#{:default :long-context}`, wire `contextTier` as `"default"` / `"long_context"`) — selects long-context model variants. - `:large-output` on `resume-session` — already accepted on create; now also forwarded on resume (wire `largeOutput`). +- **`:config-directory` and `:output-directory` option aliases** — + Non-breaking aliases for `:config-dir` and `:output-dir` + (`:output-directory` is inside the `:large-output` map). Wire keys + stay `configDir` / `outputDir`. When both old and new keys are + supplied, the new key wins. (upstream PR #1482 source-side rename) - **New event types** — Added to the public `event-types` set and picked up automatically by the generated wire spec: - `:copilot/hook.progress` — ephemeral progress updates from long-running hooks. Curated `::hook.progress-data` spec exposes - `:message` (string) plus the standard `:session-id`/`:timestamp`. + `:message` (non-blank string); `:session-id` / `:timestamp` live on + the envelope. - `:copilot/session.autopilot_objective_changed` — autopilot - objective updates. Generated spec carries `:operation` and - `:objective` data; the `:status` enum is widened to include - `"active"`, `"paused"`, `"cap_reached"`, `"completed"`. + objective lifecycle events. Generated wire spec carries + `:operation` (required, one of `"create"` / `"update"` / + `"delete"`), with optional `:id` (integer) and `:status`. The + `:status` enum is widened to include `"active"`, `"paused"`, + `"cap_reached"`, `"completed"`. - `:copilot/session.permissions_changed` — emitted when per-session permission flags change. Curated `::session.permissions_changed-data` - spec exposes `:allow-all-permissions` and `:disable-permissions` - booleans. + spec requires `:allow-all-permissions` and + `:previous-allow-all-permissions` (both booleans). - **Schema bump** — `.copilot-schema-version` advanced from `1.0.55-1` to `1.0.56-1`, covering upstream tags `v1.0.0-beta.9` and `v1.0.0-beta.10`. Schema regen picks up several new optional event @@ -87,11 +96,11 @@ All notable changes to this project will be documented in this file. This change public API surface (`mode = "empty" | "copilot-cli"`, `ToolSet`, `toolFilterPrecedence`, ambient flags via `session.options.update`). Tracked for a dedicated future sync round with its own plan. -- **`configDir` → `configDirectory` and `outputDir` → `outputDirectory` - rename (upstream PR #1482)** — Wire keys stay `configDir`/`outputDir`. - Renaming the Clojure-side option keys would be breaking; tracked - alongside the other rename PRs (#1357 etc.) for a coordinated - breaking-rename release. +- **Removal of the legacy `:config-dir` / `:output-dir` option keys + (upstream PR #1482 follow-up)** — The new `:config-directory` / + `:output-directory` aliases ship in this release (see Added). The + breaking removal of the older spellings is tracked alongside the + other rename PRs (#1357 etc.) for a coordinated rename release. - **Canvas runtime, MCP Apps `enableMcpApps`** — Continue to defer as experimental coupled surfaces. diff --git a/doc/reference/API.md b/doc/reference/API.md index 8c38bf7..0c52cfe 100644 --- a/doc/reference/API.md +++ b/doc/reference/API.md @@ -277,7 +277,7 @@ Create a client and session together, ensuring both are cleaned up on exit. | `:enable-session-store` | boolean | Enable the disk-backed session store. (upstream PR #1474) | | `:enable-skills` | boolean | Enable skills discovery and loading. (upstream PR #1474) | | `:plugin-directories` | vector | Extra plugin directories loaded even when `:enable-config-discovery` is `false`. Wire-encoded as `pluginDirectories`. (upstream PR #1482) | -| `:reasoning-summary` | keyword | `#{:none :concise :detailed}`. Controls inclusion/granularity of reasoning summaries on assistant turns. Wire-encoded as `reasoningSummary`. | +| `:reasoning-summary` | string | `"none"` / `"concise"` / `"detailed"`. Controls inclusion/granularity of reasoning summaries on assistant turns. Wire-encoded as `reasoningSummary`. String-valued for consistency with `:reasoning-effort`. | | `:context-tier` | keyword | `#{:default :long-context}`. Selects the long-context model variant. Wire-encoded as `contextTier` with values `"default"` / `"long_context"`. | #### `resume-session` @@ -1395,8 +1395,8 @@ Convert an unqualified event keyword to a namespace-qualified `:copilot/` keywor | `:copilot/session.task_complete` | Task completed by the session agent; data: `{:summary "..." :aborted? false}` (both optional) | | `:copilot/session.schedule_created` | Scheduled prompt registered via `/every`; data: `{:id :interval-ms :prompt "..."}` (upstream schema 1.0.42) | | `:copilot/session.schedule_cancelled` | Scheduled prompt cancelled from the schedule manager dialog; data: `{:id }` (upstream schema 1.0.42) | -| `:copilot/session.autopilot_objective_changed` | Autopilot objective added/updated/removed; data: `{:operation "..." :objective {...}}` (upstream schema 1.0.56). The `:status` enum for autopilot objectives is widened to include `"active"`, `"paused"`, `"cap_reached"`, `"completed"`. | -| `:copilot/session.permissions_changed` | Per-session permission flags changed; data: `{:allow-all-permissions boolean :disable-permissions boolean}` (upstream schema 1.0.56). | +| `:copilot/session.autopilot_objective_changed` | Autopilot objective lifecycle events; data: `{:operation #{"create" "update" "delete"}}` (required) with optional `:id` (integer) and `:status` (upstream schema 1.0.56). The `:status` enum is widened to include `"active"`, `"paused"`, `"cap_reached"`, `"completed"`. | +| `:copilot/session.permissions_changed` | Per-session permission flags changed; data: `{:allow-all-permissions boolean :previous-allow-all-permissions boolean}` (upstream schema 1.0.56). | | `:copilot/skill.invoked` | Skill invocation triggered; data includes :name, :path, :content, optional :description, :plugin-name, :plugin-version | | `:copilot/user.message` | User message added | | `:copilot/pending_messages.modified` | Pending message queue updated | diff --git a/test/github/copilot_sdk/codegen_test.clj b/test/github/copilot_sdk/codegen_test.clj index ea239c9..25cda25 100644 --- a/test/github/copilot_sdk/codegen_test.clj +++ b/test/github/copilot_sdk/codegen_test.clj @@ -247,6 +247,11 @@ {:allow-all-permissions true :previous-allow-all-permissions false} + "session.autopilot_objective_changed" + {:operation "create" + :id 7 + :status "active"} + "hook.progress" {:message "extracting..."}}) diff --git a/test/github/copilot_sdk/integration_test.clj b/test/github/copilot_sdk/integration_test.clj index ce74e38..04be1a6 100644 --- a/test/github/copilot_sdk/integration_test.clj +++ b/test/github/copilot_sdk/integration_test.clj @@ -5260,12 +5260,29 @@ (is (not (s/valid? :github.copilot-sdk.specs/hook.progress-data {:message 42}))))) -(deftest test-spec-session-resume-data-context-tier - (testing "::session.resume-data accepts :context-tier (round-5 consistency)" - (is (s/valid? :github.copilot-sdk.specs/session.resume-data - {:resume-time (java.time.Instant/parse "2026-05-01T00:00:00Z") - :event-count 0 - :context-tier :long-context})))) +(deftest test-generated-session-resume-data-context-tier + (testing "generated session.resume-data accepts wire :context-tier values" + ;; The curated ::specs/session.resume-data deliberately does NOT lift + ;; :context-tier into the idiom layer (matches the round-5 pattern for + ;; ::session.model_change-data: event payloads carry the wire string). + ;; The generated wire spec is the source of truth for the field shape. + (let [spec :github.copilot-sdk.generated.event-specs/session.resume-data] + (is (s/valid? spec + {:resume-time "2026-05-01T00:00:00Z" + :event-count 0 + :context-tier "long_context"})) + (is (s/valid? spec + {:resume-time "2026-05-01T00:00:00Z" + :event-count 0 + :context-tier "default"})) + (is (s/valid? spec + {:resume-time "2026-05-01T00:00:00Z" + :event-count 0 + :context-tier nil})) + (is (not (s/valid? spec + {:resume-time "2026-05-01T00:00:00Z" + :event-count 0 + :context-tier "bogus"})))))) ;; --- Cloud session: defer sessionId to server (PR #1479) ------------------- From 9a791d0bc9f0633346151a719c0a1bdbb59530bf Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 23:03:41 +0200 Subject: [PATCH 8/9] fix(docs+errors): address Copilot Code Review feedback round 2 - API.md :context-tier row: document nil case for explicit clearing, distinct from omitting the key (matches spec at specs.clj:620 which is (s/nilable #{:default :long-context})). - client.clj session.create id-mismatch error: reword from 'caller-supplied' to 'requested' so the message is accurate for both the standard caller-supplied path and the SDK-generated path (sync site at L1894 and async site at L2082). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- doc/reference/API.md | 2 +- src/github/copilot_sdk/client.clj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/reference/API.md b/doc/reference/API.md index 0c52cfe..c50d75c 100644 --- a/doc/reference/API.md +++ b/doc/reference/API.md @@ -278,7 +278,7 @@ Create a client and session together, ensuring both are cleaned up on exit. | `:enable-skills` | boolean | Enable skills discovery and loading. (upstream PR #1474) | | `:plugin-directories` | vector | Extra plugin directories loaded even when `:enable-config-discovery` is `false`. Wire-encoded as `pluginDirectories`. (upstream PR #1482) | | `:reasoning-summary` | string | `"none"` / `"concise"` / `"detailed"`. Controls inclusion/granularity of reasoning summaries on assistant turns. Wire-encoded as `reasoningSummary`. String-valued for consistency with `:reasoning-effort`. | -| `:context-tier` | keyword | `#{:default :long-context}`. Selects the long-context model variant. Wire-encoded as `contextTier` with values `"default"` / `"long_context"`. | +| `:context-tier` | keyword \| `nil` | `#{:default :long-context}` selects the long-context model variant; `nil` explicitly clears any prior tier (wire-encoded as JSON `null`). Omit the key entirely to leave the current setting untouched. Wire-encoded as `contextTier` with values `"default"` / `"long_context"`. | #### `resume-session` diff --git a/src/github/copilot_sdk/client.clj b/src/github/copilot_sdk/client.clj index 5f6e536..9ec42d6 100644 --- a/src/github/copilot_sdk/client.clj +++ b/src/github/copilot_sdk/client.clj @@ -1891,7 +1891,7 @@ (when (and (string? returned-id) (not (str/blank? returned-id)) (not= returned-id session-id)) - (throw (ex-info "session.create returned a sessionId that differs from the caller-supplied id" + (throw (ex-info "session.create returned a sessionId that differs from the requested id" {:requested session-id :returned returned-id}))) (session/set-workspace-path! client session-id (:workspace-path result)) (session/set-capabilities! client session-id (:capabilities result)) @@ -2079,7 +2079,7 @@ (not (str/blank? returned-id)) (not= returned-id session-id)) (do (session/remove-session! client session-id) - (ex-info "session.create returned a sessionId that differs from the caller-supplied id" + (ex-info "session.create returned a sessionId that differs from the requested id" {:requested session-id :returned returned-id})) (do (session/set-workspace-path! client session-id (:workspace-path result)) From 9d93bed247a2ee0815766c34872f0f489dd3a658 Mon Sep 17 00:00:00 2001 From: Karl Krukow Date: Sat, 30 May 2026 23:15:38 +0200 Subject: [PATCH 9/9] fix(specs): dedup ::agent-mode definition Round 6's PR #1438 port added a second ::agent-mode s/def at the ::send-options site, but ::agent-mode already exists from PR #1286 for ::user.message-data. The two defs were identical sets, so behaviour was unchanged, but the duplicate would drift if upstream widens or narrows the enum. Keep the single def alongside the surrounding turn-options block and broaden the comment to cover both uses (per-turn send option AND inbound user.message echo). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/github/copilot_sdk/specs.clj | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/github/copilot_sdk/specs.clj b/src/github/copilot_sdk/specs.clj index 106872a..fe24244 100644 --- a/src/github/copilot_sdk/specs.clj +++ b/src/github/copilot_sdk/specs.clj @@ -865,9 +865,10 @@ ;; Map of header name → value, merged with any provider-level headers. (s/def ::request-headers (s/map-of string? string?)) -;; UI agent mode for this turn (upstream PR #1438, post-v1.0.0-beta.4). -;; Wire enum: "interactive" | "plan" | "autopilot" | "shell". Defaults to the -;; session's current mode when omitted. +;; UI agent mode (upstream PR #1438, post-v1.0.0-beta.4). +;; Wire enum: "interactive" | "plan" | "autopilot" | "shell". Used for both +;; per-turn ::send-options (defaults to the session's current mode when +;; omitted on send) and inbound ::user.message-data echoes. (s/def ::agent-mode #{:interactive :plan :autopilot :shell}) ;; Display-only prompt shown in the timeline instead of the model :prompt @@ -1099,8 +1100,6 @@ (or (not (contains? m :mode)) (s/valid? ::remote-session-mode (:mode m)))))) -(s/def ::agent-mode #{:interactive :plan :autopilot :shell}) - ;; Cloud session config (upstream PR #1306). When supplied to create-session, ;; creates a remote session in the cloud instead of a local session. Optional ;; :repository associates the cloud session with a GitHub repository.