diff --git a/.copilot-schema-version b/.copilot-schema-version index 46354d7..1dc08bd 100644 --- a/.copilot-schema-version +++ b/.copilot-schema-version @@ -1 +1 @@ -1.0.52 +1.0.55-1 diff --git a/CHANGELOG.md b/CHANGELOG.md index ce76e0e..be64f34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. This change ## [Unreleased] ### Added (post-v1.0.0-beta.4 sync, round 5) +- **`:on-post-tool-use-failure` hook** — New lifecycle hook in the + `:hooks` map. Fires after a tool execution whose result was `"failure"`; + `:on-post-tool-use` only fires for successful results, so register this + handler to observe or react to failed tool outcomes. Note: `"rejected"`, + `"denied"`, and `"timeout"` results do not currently trigger this hook — + only `"failure"` does. Handler input has `:tool-name`, `:tool-args`, + `:error` (string), plus the base hook fields (`:session-id`, + `:timestamp`, `:cwd`). Optional return value: + `{:additional-context "..."}` is appended as hidden guidance to the + model alongside the failed tool result. (upstream PR #1421) - **`:runtime-instructions` system message section** — New section recognized by the SDK's `:system-message` `:customize` mode. Wire-encoded as `"runtime_instructions"` and accepted by `::specs/system-prompt-section`. @@ -32,10 +42,19 @@ All notable changes to this project will be documented in this file. This change on `:skill.invoked` data. - `:tool-description` and `:ui-resource` on `:tool.execution_complete` data. - **Schema bump** — `.copilot-schema-version` advanced from `1.0.52-1` to - `1.0.52` (stable). Picked up the 1.0.52-4 pre-release (upstream PR #1393) - and then advanced to the 1.0.52 stable release (upstream PR #1405); the - shipped JSON Schemas are byte-identical between 1.0.52-4 and 1.0.52, so - no additional schema-driven changes were required. + `1.0.55-1`. Picked up the 1.0.52-4 pre-release (upstream PR #1393), the + 1.0.52 stable release (upstream PR #1405), the 1.0.53-2 pre-release + (upstream PR #1408), and the 1.0.53 / 1.0.54 / 1.0.55-0 / 1.0.55-1 + schema bumps (upstream PRs #1410, #1411, #1412, #1432). Schema regen + surfaces new wire-only canvas event types (`session.canvas.opened`, + `session.canvas.registry_changed`) and their field set in the + generated `event-specs` namespace. The canvas runtime (extension + manifests, `requestCanvasRenderer`, `openCanvases`, etc. — upstream + PRs #1401, #1413) is **not yet exposed** on the public Clojure API, + including the curated `event-types` set. Canvas runtime support + (including opaque-field preservation for `data.input` and nested + `inputSchema` payloads on canvas events) will land in a dedicated + future sync round. ### Changed (post-v1.0.0-beta.4 sync, round 5) - **BREAKING: Minimum supported protocol version raised from 2 to 3.** The diff --git a/doc/reference/API.md b/doc/reference/API.md index efdd179..bc6a35a 100644 --- a/doc/reference/API.md +++ b/doc/reference/API.md @@ -2258,11 +2258,30 @@ Lifecycle hooks allow custom logic at various points during the session: :on-post-tool-use (fn [input invocation] - ;; Called after each tool execution - ;; input contains {:tool-name "..." :result {...}} + ;; Called after each *successful* tool execution + ;; input contains {:tool-name "..." :tool-args {...} :tool-result {...}} + ;; For failed tool calls, register :on-post-tool-use-failure below. (println "Tool completed:" (:tool-name input)) nil) + :on-post-tool-use-failure + (fn [input invocation] + ;; Called after a tool execution whose result was `"failure"` + ;; (upstream PR #1421). :on-post-tool-use only fires for + ;; successful results, so register this handler to observe + ;; failed tool outcomes. Note: `"rejected"`, `"denied"`, and + ;; `"timeout"` results do NOT currently trigger this hook — + ;; only `"failure"` does. + ;; input contains {:tool-name "..." :tool-args {...} + ;; :error "failure message string" + ;; :session-id "..." :timestamp 12345} + ;; Optional return: {:additional-context "..."} is appended as + ;; hidden guidance to the model alongside the failed result. + ;; Other fields (e.g. :modified-result, :suppress-output) are + ;; not honored for failure hooks. + (println "Tool failed:" (:tool-name input) (:error input)) + {:additional-context "Tip: try `ls` first to see available files."}) + :on-pre-mcp-tool-call (fn [input invocation] ;; Called before each MCP tool call is dispatched (upstream PR #1366). diff --git a/schemas/README.md b/schemas/README.md index 360fa59..29a817c 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.52` +Currently pinned version: `1.0.55-1` diff --git a/schemas/api.schema.json b/schemas/api.schema.json index 8d82d86..314b857 100644 --- a/schemas/api.schema.json +++ b/schemas/api.schema.json @@ -407,7 +407,7 @@ }, "result": { "$ref": "#/definitions/SessionEnrichMetadataResult", - "description": "The same metadata records, with summary and context fields backfilled where available." + "description": "The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted." }, "stability": "experimental" }, @@ -672,6 +672,162 @@ "stability": "experimental" } }, + "canvas": { + "list": { + "rpcMethod": "session.canvas.list", + "description": "Lists canvases declared for the session.", + "params": { + "type": "object", + "description": "Identifies the target session.", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "result": { + "$ref": "#/definitions/CanvasList", + "description": "Declared canvases available in this session." + }, + "stability": "experimental" + }, + "listOpen": { + "rpcMethod": "session.canvas.listOpen", + "description": "Lists currently open canvas instances for the live session.", + "params": { + "type": "object", + "description": "Identifies the target session.", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + } + }, + "required": [ + "sessionId" + ], + "additionalProperties": false + }, + "result": { + "$ref": "#/definitions/CanvasListOpenResult", + "description": "Live open-canvas snapshot." + }, + "stability": "experimental" + }, + "open": { + "rpcMethod": "session.canvas.open", + "description": "Opens or focuses a canvas instance.", + "params": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + }, + "extensionId": { + "type": "string", + "description": "Owning provider identifier. Optional when the canvasId is unique across providers; required to disambiguate when multiple providers register the same canvasId." + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + }, + "instanceId": { + "type": "string", + "description": "Caller-supplied stable instance identifier" + }, + "input": { + "description": "Canvas open input", + "x-opaque-json": true + } + }, + "required": [ + "sessionId", + "canvasId", + "instanceId" + ], + "additionalProperties": false, + "description": "Canvas open parameters.", + "title": "CanvasOpenRequest" + }, + "result": { + "$ref": "#/definitions/OpenCanvasInstance", + "description": "Open canvas instance snapshot." + }, + "stability": "experimental" + }, + "close": { + "rpcMethod": "session.canvas.close", + "description": "Closes an open canvas instance.", + "params": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + }, + "instanceId": { + "type": "string", + "description": "Open canvas instance identifier" + } + }, + "required": [ + "sessionId", + "instanceId" + ], + "additionalProperties": false, + "description": "Canvas close parameters.", + "title": "CanvasCloseRequest" + }, + "result": { + "type": "null" + }, + "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" + }, + "input": { + "description": "Action input", + "x-opaque-json": true + } + }, + "required": [ + "sessionId", + "instanceId", + "actionName" + ], + "additionalProperties": false, + "description": "Canvas action invocation parameters.", + "title": "CanvasInvokeActionRequest" + }, + "result": { + "$ref": "#/definitions/CanvasInvokeActionResult", + "description": "Canvas action invocation result." + }, + "stability": "experimental" + } + }, "model": { "getCurrent": { "rpcMethod": "session.model.getCurrent", @@ -1169,6 +1325,35 @@ "description": "Descriptor for the saved paste file, or null when the workspace is unavailable." }, "stability": "experimental" + }, + "diff": { + "rpcMethod": "session.workspaces.diff", + "description": "Computes a diff for the session workspace.", + "params": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Target session identifier" + }, + "mode": { + "$ref": "#/definitions/WorkspaceDiffMode", + "description": "Diff mode requested by the client." + } + }, + "required": [ + "sessionId", + "mode" + ], + "additionalProperties": false, + "description": "Parameters for computing a workspace diff.", + "title": "WorkspacesDiffRequest" + }, + "result": { + "$ref": "#/definitions/WorkspaceDiffResult", + "description": "Workspace diff result for the requested mode." + }, + "stability": "experimental" } }, "instructions": { @@ -4665,7 +4850,8 @@ "result": { "$ref": "#/definitions/SessionFsReadFileResult", "description": "File content as a UTF-8 string, or a filesystem error if the read failed." - } + }, + "stability": "experimental" }, "writeFile": { "rpcMethod": "sessionFs.writeFile", @@ -4711,7 +4897,8 @@ } ], "description": "Describes a filesystem error." - } + }, + "stability": "experimental" }, "appendFile": { "rpcMethod": "sessionFs.appendFile", @@ -4757,7 +4944,8 @@ } ], "description": "Describes a filesystem error." - } + }, + "stability": "experimental" }, "exists": { "rpcMethod": "sessionFs.exists", @@ -4785,7 +4973,8 @@ "result": { "$ref": "#/definitions/SessionFsExistsResult", "description": "Indicates whether the requested path exists in the client-provided session filesystem." - } + }, + "stability": "experimental" }, "stat": { "rpcMethod": "sessionFs.stat", @@ -4813,7 +5002,8 @@ "result": { "$ref": "#/definitions/SessionFsStatResult", "description": "Filesystem metadata for the requested path, or a filesystem error if the stat failed." - } + }, + "stability": "experimental" }, "mkdir": { "rpcMethod": "sessionFs.mkdir", @@ -4858,7 +5048,8 @@ } ], "description": "Describes a filesystem error." - } + }, + "stability": "experimental" }, "readdir": { "rpcMethod": "sessionFs.readdir", @@ -4886,7 +5077,8 @@ "result": { "$ref": "#/definitions/SessionFsReaddirResult", "description": "Names of entries in the requested directory, or a filesystem error if the read failed." - } + }, + "stability": "experimental" }, "readdirWithTypes": { "rpcMethod": "sessionFs.readdirWithTypes", @@ -4914,7 +5106,8 @@ "result": { "$ref": "#/definitions/SessionFsReaddirWithTypesResult", "description": "Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed." - } + }, + "stability": "experimental" }, "rm": { "rpcMethod": "sessionFs.rm", @@ -4958,7 +5151,8 @@ } ], "description": "Describes a filesystem error." - } + }, + "stability": "experimental" }, "rename": { "rpcMethod": "sessionFs.rename", @@ -4999,7 +5193,8 @@ } ], "description": "Describes a filesystem error." - } + }, + "stability": "experimental" }, "sqliteQuery": { "rpcMethod": "sessionFs.sqliteQuery", @@ -5044,7 +5239,8 @@ "result": { "$ref": "#/definitions/SessionFsSqliteQueryResult", "description": "Query results including rows, columns, and rows affected, or a filesystem error if execution failed." - } + }, + "stability": "experimental" }, "sqliteExists": { "rpcMethod": "sessionFs.sqliteExists", @@ -5066,7 +5262,151 @@ "result": { "$ref": "#/definitions/SessionFsSqliteExistsResult", "description": "Indicates whether the per-session SQLite database already exists." - } + }, + "stability": "experimental" + } + }, + "canvas": { + "open": { + "rpcMethod": "canvas.open", + "description": "Opens a canvas instance on 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": "Stable caller-supplied canvas instance identifier" + }, + "input": { + "description": "Canvas open input", + "x-opaque-json": true + }, + "host": { + "$ref": "#/definitions/CanvasHostContext", + "description": "Host context supplied by the runtime." + } + }, + "required": [ + "sessionId", + "extensionId", + "canvasId", + "instanceId" + ], + "additionalProperties": false, + "description": "Canvas open parameters sent to the provider.", + "title": "CanvasProviderOpenRequest" + }, + "result": { + "$ref": "#/definitions/CanvasProviderOpenResult", + "description": "Canvas open result returned by the provider." + }, + "stability": "experimental" + }, + "close": { + "rpcMethod": "canvas.close", + "description": "Closes a canvas instance on 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" + }, + "host": { + "$ref": "#/definitions/CanvasHostContext", + "description": "Host context supplied by the runtime." + } + }, + "required": [ + "sessionId", + "extensionId", + "canvasId", + "instanceId" + ], + "additionalProperties": false, + "description": "Canvas close parameters sent to the provider.", + "title": "CanvasProviderCloseRequest" + }, + "result": { + "type": "null" + }, + "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 + }, + "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" + }, + "result": { + "description": "Provider-supplied action result.", + "x-opaque-json": true + }, + "stability": "experimental" } } }, @@ -5371,91 +5711,393 @@ } }, "required": [ - "agent" + "agent" + ], + "additionalProperties": false, + "description": "The newly selected custom agent.", + "title": "AgentSelectResult" + }, + "ApiKeyAuthInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "api-key", + "description": "API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style)." + }, + "apiKey": { + "type": "string", + "description": "The API key. Treat as a secret." + }, + "host": { + "type": "string", + "description": "Authentication host." + }, + "copilotUser": { + "$ref": "#/definitions/CopilotUserResponse", + "description": "Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set." + } + }, + "required": [ + "type", + "apiKey", + "host" + ], + "additionalProperties": false, + "title": "ApiKeyAuthInfo", + "description": "Schema for the `ApiKeyAuthInfo` type." + }, + "AuthInfo": { + "anyOf": [ + { + "$ref": "#/definitions/HMACAuthInfo" + }, + { + "$ref": "#/definitions/EnvAuthInfo" + }, + { + "$ref": "#/definitions/TokenAuthInfo" + }, + { + "$ref": "#/definitions/CopilotApiTokenAuthInfo" + }, + { + "$ref": "#/definitions/UserAuthInfo" + }, + { + "$ref": "#/definitions/GhCliAuthInfo" + }, + { + "$ref": "#/definitions/ApiKeyAuthInfo" + } + ], + "description": "The new auth credentials to install on the session. When omitted or `undefined`, the call is a no-op and the session's existing credentials are preserved. The runtime stores the value verbatim and uses it for outbound model/API requests; it does NOT re-validate or re-fetch the associated Copilot user response. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit.", + "title": "AuthInfo" + }, + "AuthInfoType": { + "type": "string", + "enum": [ + "hmac", + "env", + "user", + "gh-cli", + "api-key", + "token", + "copilot-api-token" + ], + "description": "Authentication type", + "title": "AuthInfoType", + "x-enumDescriptions": { + "hmac": "Authentication provided by a GitHub App HMAC credential.", + "env": "Authentication resolved from environment-provided credentials.", + "user": "Authentication from an interactive user sign-in.", + "gh-cli": "Authentication delegated to the GitHub CLI.", + "api-key": "Authentication from an API key credential.", + "token": "Authentication from a GitHub token.", + "copilot-api-token": "Authentication from a Copilot API token." + } + }, + "CanvasAction": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Action name exposed by the canvas provider" + }, + "description": { + "type": "string", + "description": "Description of the action" + }, + "inputSchema": { + "$ref": "#/definitions/CanvasJsonSchema", + "description": "JSON Schema for the action input" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "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": { + "type": "object", + "properties": { + "instanceId": { + "type": "string", + "description": "Open canvas instance identifier" + } + }, + "required": [ + "instanceId" + ], + "additionalProperties": false, + "description": "Canvas close parameters.", + "title": "CanvasCloseRequest" + }, + "CanvasHostContext": { + "type": "object", + "properties": { + "capabilities": { + "$ref": "#/definitions/CanvasHostContextCapabilities", + "description": "Host capabilities" + } + }, + "additionalProperties": false, + "description": "Host context supplied by the runtime.", + "title": "CanvasHostContext" + }, + "CanvasHostContextCapabilities": { + "type": "object", + "properties": { + "canvases": { + "type": "boolean", + "description": "Whether canvas rendering is supported" + } + }, + "additionalProperties": false, + "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." + } + }, + "CanvasInvokeActionRequest": { + "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", + "actionName" + ], + "additionalProperties": false, + "description": "Canvas action invocation parameters.", + "title": "CanvasInvokeActionRequest" + }, + "CanvasInvokeActionResult": { + "type": "object", + "properties": { + "result": { + "description": "Provider-supplied action result", + "x-opaque-json": true + } + }, + "additionalProperties": false, + "description": "Canvas action invocation result.", + "title": "CanvasInvokeActionResult" + }, + "CanvasJsonSchema": { + "description": "JSON Schema for canvas open input", + "title": "CanvasJsonSchema", + "x-opaque-json": true + }, + "CanvasList": { + "type": "object", + "properties": { + "canvases": { + "type": "array", + "items": { + "$ref": "#/definitions/DiscoveredCanvas", + "description": "Canvas available in the current session." + }, + "description": "Declared canvases available in this session" + } + }, + "required": [ + "canvases" + ], + "additionalProperties": false, + "description": "Declared canvases available in this session.", + "title": "CanvasList" + }, + "CanvasListOpenResult": { + "type": "object", + "properties": { + "openCanvases": { + "type": "array", + "items": { + "$ref": "#/definitions/OpenCanvasInstance", + "description": "Open canvas instance snapshot." + }, + "description": "Currently open canvas instances" + } + }, + "required": [ + "openCanvases" + ], + "additionalProperties": false, + "description": "Live open-canvas snapshot.", + "title": "CanvasListOpenResult" + }, + "CanvasOpenRequest": { + "type": "object", + "properties": { + "extensionId": { + "type": "string", + "description": "Owning provider identifier. Optional when the canvasId is unique across providers; required to disambiguate when multiple providers register the same canvasId." + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + }, + "instanceId": { + "type": "string", + "description": "Caller-supplied stable instance identifier" + }, + "input": { + "description": "Canvas open input", + "x-opaque-json": true + } + }, + "required": [ + "canvasId", + "instanceId" + ], + "additionalProperties": false, + "description": "Canvas open parameters.", + "title": "CanvasOpenRequest" + }, + "CanvasProviderCloseRequest": { + "type": "object", + "properties": { + "extensionId": { + "type": "string", + "description": "Owning provider identifier" + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + }, + "instanceId": { + "type": "string", + "description": "Canvas instance identifier" + }, + "host": { + "$ref": "#/definitions/CanvasHostContext", + "description": "Host context supplied by the runtime." + } + }, + "required": [ + "extensionId", + "canvasId", + "instanceId" ], "additionalProperties": false, - "description": "The newly selected custom agent.", - "title": "AgentSelectResult" + "description": "Canvas close parameters sent to the provider.", + "title": "CanvasProviderCloseRequest" }, - "ApiKeyAuthInfo": { + "CanvasProviderInvokeActionRequest": { "type": "object", "properties": { - "type": { + "extensionId": { "type": "string", - "const": "api-key", - "description": "API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style)." + "description": "Owning provider identifier" }, - "apiKey": { + "canvasId": { "type": "string", - "description": "The API key. Treat as a secret." + "description": "Provider-local canvas identifier" }, - "host": { + "instanceId": { "type": "string", - "description": "Authentication host." + "description": "Canvas instance identifier" }, - "copilotUser": { - "$ref": "#/definitions/CopilotUserResponse", - "description": "Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set." + "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." } }, "required": [ - "type", - "apiKey", - "host" + "extensionId", + "canvasId", + "instanceId", + "actionName" ], "additionalProperties": false, - "title": "ApiKeyAuthInfo", - "description": "Schema for the `ApiKeyAuthInfo` type." + "description": "Canvas action invocation parameters sent to the provider.", + "title": "CanvasProviderInvokeActionRequest" }, - "AuthInfo": { - "anyOf": [ - { - "$ref": "#/definitions/HMACAuthInfo" - }, - { - "$ref": "#/definitions/EnvAuthInfo" - }, - { - "$ref": "#/definitions/TokenAuthInfo" + "CanvasProviderOpenRequest": { + "type": "object", + "properties": { + "extensionId": { + "type": "string", + "description": "Owning provider identifier" }, - { - "$ref": "#/definitions/CopilotApiTokenAuthInfo" + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" }, - { - "$ref": "#/definitions/UserAuthInfo" + "instanceId": { + "type": "string", + "description": "Stable caller-supplied canvas instance identifier" }, - { - "$ref": "#/definitions/GhCliAuthInfo" + "input": { + "description": "Canvas open input", + "x-opaque-json": true }, - { - "$ref": "#/definitions/ApiKeyAuthInfo" + "host": { + "$ref": "#/definitions/CanvasHostContext", + "description": "Host context supplied by the runtime." } + }, + "required": [ + "extensionId", + "canvasId", + "instanceId" ], - "description": "The new auth credentials to install on the session. When omitted or `undefined`, the call is a no-op and the session's existing credentials are preserved. The runtime stores the value verbatim and uses it for outbound model/API requests; it does NOT re-validate or re-fetch the associated Copilot user response. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit.", - "title": "AuthInfo" + "additionalProperties": false, + "description": "Canvas open parameters sent to the provider.", + "title": "CanvasProviderOpenRequest" }, - "AuthInfoType": { - "type": "string", - "enum": [ - "hmac", - "env", - "user", - "gh-cli", - "api-key", - "token", - "copilot-api-token" - ], - "description": "Authentication type", - "title": "AuthInfoType", - "x-enumDescriptions": { - "hmac": "Authentication provided by a GitHub App HMAC credential.", - "env": "Authentication resolved from environment-provided credentials.", - "user": "Authentication from an interactive user sign-in.", - "gh-cli": "Authentication delegated to the GitHub CLI.", - "api-key": "Authentication from an API key credential.", - "token": "Authentication from a GitHub token.", - "copilot-api-token": "Authentication from a Copilot API token." - } + "CanvasProviderOpenResult": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL for web-rendered canvases" + }, + "title": { + "type": "string", + "description": "Provider-supplied title" + }, + "status": { + "type": "string", + "description": "Provider-supplied status text" + } + }, + "additionalProperties": false, + "description": "Canvas open result returned by the provider.", + "title": "CanvasProviderOpenResult" }, "CommandList": { "type": "object", @@ -6204,6 +6846,53 @@ "description": "The currently selected model and reasoning effort for the session.", "title": "CurrentModel" }, + "DiscoveredCanvas": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Human-readable canvas name" + }, + "description": { + "type": "string", + "minLength": 1, + "description": "Short, single-sentence description shown to the agent in canvas catalogs." + }, + "inputSchema": { + "$ref": "#/definitions/CanvasJsonSchema", + "description": "JSON Schema for canvas open input" + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/definitions/CanvasAction", + "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." + }, + "description": "Actions the agent or host may invoke on an open instance" + }, + "extensionId": { + "type": "string", + "description": "Owning provider identifier" + }, + "extensionName": { + "type": "string", + "description": "Owning extension display name, when available" + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + } + }, + "required": [ + "displayName", + "description", + "extensionId", + "canvasId" + ], + "additionalProperties": false, + "description": "Canvas available in the current session.", + "title": "DiscoveredCanvas" + }, "DiscoveredMcpServer": { "type": "object", "properties": { @@ -8638,6 +9327,14 @@ "description": "Timeout in milliseconds for tool calls to this server.", "format": "duration" }, + "oidc": { + "$ref": "#/definitions/McpServerConfigHttpOidc", + "description": "OIDC token configuration. When truthy, a token is automatically gathered." + }, + "auth": { + "$ref": "#/definitions/McpServerConfigHttpAuth", + "description": "Additional authentication configuration for this server." + }, "url": { "type": "string", "format": "uri", @@ -8661,10 +9358,6 @@ "oauthGrantType": { "$ref": "#/definitions/McpServerConfigHttpOauthGrantType", "description": "OAuth grant type to use when authenticating to the remote MCP server." - }, - "auth": { - "$ref": "#/definitions/McpServerConfigHttpAuth", - "description": "Additional authentication configuration for this server." } }, "required": [ @@ -8684,7 +9377,7 @@ "description": "Fixed port for the OAuth redirect callback server." } }, - "additionalProperties": false, + "additionalProperties": true, "description": "Additional authentication configuration for this server.", "title": "McpServerConfigHttpAuth" }, @@ -8701,6 +9394,20 @@ "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": [ @@ -8740,6 +9447,14 @@ "description": "Timeout in milliseconds for tool calls to this server.", "format": "duration" }, + "oidc": { + "$ref": "#/definitions/McpServerConfigStdioOidc", + "description": "OIDC token configuration. When truthy, a token is automatically gathered." + }, + "auth": { + "$ref": "#/definitions/McpServerConfigStdioAuth", + "description": "Authentication configuration for this server." + }, "command": { "type": "string", "description": "Executable command used to start the Stdio MCP server process." @@ -8771,6 +9486,34 @@ "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": { @@ -9660,6 +10403,61 @@ "description": "New friendly name to apply to the session.", "title": "NameSetRequest" }, + "OpenCanvasInstance": { + "type": "object", + "properties": { + "instanceId": { + "type": "string", + "description": "Stable caller-supplied canvas instance identifier" + }, + "extensionId": { + "type": "string", + "description": "Owning provider identifier" + }, + "extensionName": { + "type": "string", + "description": "Owning extension display name, when available" + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + }, + "title": { + "type": "string", + "description": "Rendered title" + }, + "status": { + "type": "string", + "description": "Provider-supplied status text" + }, + "url": { + "type": "string", + "description": "URL for web-rendered canvases" + }, + "input": { + "description": "Input supplied when the instance was opened", + "x-opaque-json": true + }, + "reopen": { + "type": "boolean", + "description": "Whether this snapshot came from an idempotent reopen" + }, + "availability": { + "$ref": "#/definitions/CanvasInstanceAvailability", + "description": "Runtime-controlled routing state for an open canvas instance." + } + }, + "required": [ + "instanceId", + "extensionId", + "canvasId", + "reopen", + "availability" + ], + "additionalProperties": false, + "description": "Open canvas instance snapshot.", + "title": "OpenCanvasInstance" + }, "OptionsUpdateEnvValueMode": { "type": "string", "enum": [ @@ -12727,14 +13525,14 @@ "items": { "$ref": "#/definitions/SessionMetadata" }, - "description": "Same records, with summary and context backfilled" + "description": "Enriched records, with summary and context backfilled. Sessions confirmed empty and unnamed may be omitted." } }, "required": [ "sessions" ], "additionalProperties": false, - "description": "The same metadata records, with summary and context fields backfilled where available.", + "description": "The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted.", "title": "SessionEnrichMetadataResult" }, "SessionFsAppendFileRequest": { @@ -17013,6 +17811,107 @@ "title": "UserToolSessionApprovalWrite", "description": "Schema for the `UserToolSessionApprovalWrite` type." }, + "WorkspaceDiffFileChange": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Path to the changed file, relative to the workspace root." + }, + "diff": { + "type": "string", + "description": "Unified diff content for the file. Empty when the diff was truncated." + }, + "changeType": { + "$ref": "#/definitions/WorkspaceDiffFileChangeType", + "description": "Type of change represented by this file diff." + }, + "oldPath": { + "type": "string", + "description": "Original file path for renamed files." + }, + "isTruncated": { + "type": "boolean", + "description": "Whether the diff content was omitted because it exceeded the per-file size limit." + } + }, + "required": [ + "path", + "diff", + "changeType" + ], + "additionalProperties": false, + "description": "A single changed file and its unified diff.", + "title": "WorkspaceDiffFileChange" + }, + "WorkspaceDiffFileChangeType": { + "type": "string", + "enum": [ + "added", + "modified", + "deleted", + "renamed" + ], + "description": "Type of change represented by this file diff.", + "title": "WorkspaceDiffFileChangeType", + "x-enumDescriptions": { + "added": "The file was added.", + "modified": "The file was modified.", + "deleted": "The file was deleted.", + "renamed": "The file was renamed." + } + }, + "WorkspaceDiffMode": { + "type": "string", + "enum": [ + "unstaged", + "branch" + ], + "description": "Diff mode requested by the client.", + "title": "WorkspaceDiffMode", + "x-enumDescriptions": { + "unstaged": "Return staged, unstaged, and untracked working tree changes.", + "branch": "Return changes compared with the default branch." + } + }, + "WorkspaceDiffResult": { + "type": "object", + "properties": { + "requestedMode": { + "$ref": "#/definitions/WorkspaceDiffMode", + "description": "Diff mode requested by the client." + }, + "mode": { + "$ref": "#/definitions/WorkspaceDiffMode", + "description": "Effective mode used for the returned changes." + }, + "changes": { + "type": "array", + "items": { + "$ref": "#/definitions/WorkspaceDiffFileChange", + "description": "A single changed file and its unified diff." + }, + "description": "Changed files and their unified diffs." + }, + "baseBranch": { + "type": "string", + "description": "Default branch used for a branch diff, when branch mode was requested." + }, + "isFallback": { + "type": "boolean", + "description": "Whether a requested branch diff fell back to unstaged changes because branch diff failed." + } + }, + "required": [ + "requestedMode", + "mode", + "changes", + "isFallback" + ], + "additionalProperties": false, + "description": "Workspace diff result for the requested mode.", + "title": "WorkspaceDiffResult" + }, "WorkspacesCheckpoints": { "type": "object", "properties": { @@ -17059,6 +17958,21 @@ "description": "Relative path and UTF-8 content for the workspace file to create or overwrite.", "title": "WorkspacesCreateFileRequest" }, + "WorkspacesDiffRequest": { + "type": "object", + "properties": { + "mode": { + "$ref": "#/definitions/WorkspaceDiffMode", + "description": "Diff mode requested by the client." + } + }, + "required": [ + "mode" + ], + "additionalProperties": false, + "description": "Parameters for computing a workspace diff.", + "title": "WorkspacesDiffRequest" + }, "WorkspacesGetWorkspaceResult": { "type": "object", "properties": { diff --git a/schemas/session-events.schema.json b/schemas/session-events.schema.json index 88fb105..90977be 100644 --- a/schemas/session-events.schema.json +++ b/schemas/session-events.schema.json @@ -1412,6 +1412,277 @@ "description": "Session event \"session.background_tasks_changed\".", "title": "BackgroundTasksChangedEvent" }, + "CanvasOpenedAvailability": { + "type": "string", + "enum": [ + "ready", + "stale" + ], + "description": "Runtime-controlled routing state for the instance. \"ready\" when the provider connection is live; \"stale\" when the provider has gone away and the instance is awaiting rebinding.", + "title": "CanvasOpenedAvailability", + "x-enumDescriptions": { + "ready": "Provider connection is live; actions can be invoked.", + "stale": "Provider has gone away; the instance is awaiting rebinding." + } + }, + "CanvasOpenedData": { + "type": "object", + "properties": { + "instanceId": { + "type": "string", + "description": "Stable caller-supplied canvas instance identifier" + }, + "extensionId": { + "type": "string", + "description": "Owning provider identifier" + }, + "extensionName": { + "type": "string", + "description": "Owning extension display name, when available" + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + }, + "title": { + "type": "string", + "description": "Rendered title" + }, + "status": { + "type": "string", + "description": "Provider-supplied status text" + }, + "url": { + "type": "string", + "description": "URL for web-rendered canvases" + }, + "input": { + "description": "Input supplied when the instance was opened", + "x-opaque-json": true + }, + "reopen": { + "type": "boolean", + "description": "Whether this notification represents an idempotent reopen" + }, + "availability": { + "$ref": "#/definitions/CanvasOpenedAvailability", + "description": "Runtime-controlled routing state for the instance. \"ready\" when the provider connection is live; \"stale\" when the provider has gone away and the instance is awaiting rebinding." + } + }, + "required": [ + "instanceId", + "extensionId", + "canvasId", + "reopen", + "availability" + ], + "additionalProperties": false, + "title": "CanvasOpenedData", + "description": "Schema for the `CanvasOpenedData` type." + }, + "CanvasOpenedEvent": { + "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": "session.canvas.opened", + "description": "Type discriminator. Always \"session.canvas.opened\"." + }, + "data": { + "$ref": "#/definitions/CanvasOpenedData", + "description": "Schema for the `CanvasOpenedData` type." + } + }, + "required": [ + "id", + "timestamp", + "parentId", + "ephemeral", + "type", + "data" + ], + "additionalProperties": false, + "description": "Session event \"session.canvas.opened\".", + "title": "CanvasOpenedEvent" + }, + "CanvasRegistryChangedCanvas": { + "type": "object", + "properties": { + "extensionId": { + "type": "string", + "description": "Owning provider identifier" + }, + "extensionName": { + "type": "string", + "description": "Owning extension display name, when available" + }, + "canvasId": { + "type": "string", + "description": "Provider-local canvas identifier" + }, + "displayName": { + "type": "string", + "description": "Human-readable canvas name" + }, + "description": { + "type": "string", + "minLength": 1, + "description": "Short, single-sentence description shown to the agent in canvas catalogs." + }, + "inputSchema": { + "type": "object", + "additionalProperties": {}, + "description": "JSON Schema for canvas open input", + "x-opaque-json": true + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/definitions/CanvasRegistryChangedCanvasAction" + }, + "description": "Actions the agent or host may invoke" + } + }, + "required": [ + "extensionId", + "canvasId", + "displayName", + "description" + ], + "additionalProperties": false, + "title": "CanvasRegistryChangedCanvas", + "description": "Schema for the `CanvasRegistryChangedCanvas` type." + }, + "CanvasRegistryChangedCanvasAction": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Action name" + }, + "description": { + "type": "string", + "description": "Action description" + }, + "inputSchema": { + "type": "object", + "additionalProperties": {}, + "description": "JSON Schema for action input", + "x-opaque-json": true + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "title": "CanvasRegistryChangedCanvasAction", + "description": "Schema for the `CanvasRegistryChangedCanvasAction` type." + }, + "CanvasRegistryChangedData": { + "type": "object", + "properties": { + "canvases": { + "type": "array", + "items": { + "$ref": "#/definitions/CanvasRegistryChangedCanvas" + }, + "description": "Canvas declarations currently available" + } + }, + "required": [ + "canvases" + ], + "additionalProperties": false, + "title": "CanvasRegistryChangedData", + "description": "Schema for the `CanvasRegistryChangedData` type." + }, + "CanvasRegistryChangedEvent": { + "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": "session.canvas.registry_changed", + "description": "Type discriminator. Always \"session.canvas.registry_changed\"." + }, + "data": { + "$ref": "#/definitions/CanvasRegistryChangedData", + "description": "Schema for the `CanvasRegistryChangedData` type." + } + }, + "required": [ + "id", + "timestamp", + "parentId", + "ephemeral", + "type", + "data" + ], + "additionalProperties": false, + "description": "Session event \"session.canvas.registry_changed\".", + "title": "CanvasRegistryChangedEvent" + }, "CapabilitiesChangedData": { "type": "object", "properties": { @@ -1490,6 +1761,10 @@ "mcpApps": { "type": "boolean", "description": "Whether MCP Apps (SEP-1865) UI passthrough is now supported" + }, + "canvases": { + "type": "boolean", + "description": "Whether canvas rendering is now supported" } }, "additionalProperties": false, @@ -7103,6 +7378,14 @@ "$ref": "#/definitions/ExtensionsLoadedEvent", "description": "Session event \"session.extensions_loaded\"." }, + { + "$ref": "#/definitions/CanvasOpenedEvent", + "description": "Session event \"session.canvas.opened\"." + }, + { + "$ref": "#/definitions/CanvasRegistryChangedEvent", + "description": "Session event \"session.canvas.registry_changed\"." + }, { "$ref": "#/definitions/McpAppToolCallCompleteEvent", "description": "Session event \"mcp_app.tool_call_complete\". MCP App view called a tool on a connected MCP server (SEP-1865)" diff --git a/src/github/copilot_sdk/client.clj b/src/github/copilot_sdk/client.clj index 29e6a1f..6b317b3 100644 --- a/src/github/copilot_sdk/client.clj +++ b/src/github/copilot_sdk/client.clj @@ -1655,7 +1655,8 @@ :elicitation-source, :url. Returns an ElicitationResult map. - :hooks - Lifecycle hooks map (PR #269): {:on-pre-tool-use, :on-pre-mcp-tool-call, - :on-post-tool-use, :on-user-prompt-submitted, + :on-post-tool-use, :on-post-tool-use-failure, + :on-user-prompt-submitted, :on-session-start, :on-session-end, :on-error-occurred} See `doc/reference/API.md` for hook input/output shapes. `:on-pre-mcp-tool-call` (upstream PR #1366) fires before @@ -1663,6 +1664,12 @@ `{:meta-to-use {...}}` replaces the request `_meta`, `{:meta-to-use nil}` removes it, and an empty / missing `:meta-to-use` preserves the existing `_meta`. + `:on-post-tool-use-failure` (upstream PR #1421) fires + after a tool execution whose `:result-type` was + `\"failure\"`; `:on-post-tool-use` only fires for + successful results. Handler input has `:tool-name`, + `:tool-args`, `:error` (string), plus base hook fields. + Optional output: `{:additional-context \"...\"}`. - :on-event - Event handler (1-arg fn) registered before the RPC call. Guarantees early events like session.start are not missed. - :enable-config-discovery - Boolean. Auto-discover .mcp.json, .vscode/mcp.json, skills, etc. diff --git a/src/github/copilot_sdk/generated/event_specs.clj b/src/github/copilot_sdk/generated/event_specs.clj index 567e35a..f389489 100644 --- a/src/github/copilot_sdk/generated/event_specs.clj +++ b/src/github/copilot_sdk/generated/event_specs.clj @@ -41,12 +41,14 @@ (s/def :github.copilot-sdk.generated.event-specs/args clojure.core/string?) -(s/def :github.copilot-sdk.generated.event-specs/arguments (s/spec (fn [v948] (or (s/valid? clojure.core/any? v948) (s/valid? clojure.core/map? v948))))) +(s/def :github.copilot-sdk.generated.event-specs/arguments (s/spec (fn [v950] (or (s/valid? clojure.core/any? v950) (s/valid? clojure.core/map? v950))))) (s/def :github.copilot-sdk.generated.event-specs/attachments (s/coll-of (s/or :branch-0 clojure.core/map? :branch-1 clojure.core/map? :branch-2 clojure.core/map? :branch-3 clojure.core/map? :branch-4 clojure.core/map?))) (s/def :github.copilot-sdk.generated.event-specs/auto-approve-edits clojure.core/boolean?) +(s/def :github.copilot-sdk.generated.event-specs/availability #{"ready" "stale"}) + (s/def :github.copilot-sdk.generated.event-specs/base-commit clojure.core/string?) (s/def :github.copilot-sdk.generated.event-specs/branch clojure.core/string?) @@ -55,6 +57,10 @@ (s/def :github.copilot-sdk.generated.event-specs/cache-write-tokens clojure.core/integer?) +(s/def :github.copilot-sdk.generated.event-specs/canvas-id clojure.core/string?) + +(s/def :github.copilot-sdk.generated.event-specs/canvases (s/coll-of clojure.core/map?)) + (s/def :github.copilot-sdk.generated.event-specs/cause clojure.core/string?) (s/def :github.copilot-sdk.generated.event-specs/checkpoint-number clojure.core/integer?) @@ -73,9 +79,9 @@ (s/def :github.copilot-sdk.generated.event-specs/compaction-tokens-used clojure.core/map?) -(s/def :github.copilot-sdk.generated.event-specs/content (s/spec (fn [v945] (or (s/valid? clojure.core/string? v945) (s/valid? clojure.core/map? v945))))) +(s/def :github.copilot-sdk.generated.event-specs/content (s/spec (fn [v947] (or (s/valid? clojure.core/string? v947) (s/valid? clojure.core/map? v947))))) -(s/def :github.copilot-sdk.generated.event-specs/context (s/spec (fn [v943] (or (s/valid? clojure.core/map? v943) (s/valid? clojure.core/string? v943))))) +(s/def :github.copilot-sdk.generated.event-specs/context (s/spec (fn [v944] (or (s/valid? clojure.core/map? v944) (s/valid? clojure.core/string? v944))))) (s/def :github.copilot-sdk.generated.event-specs/context-tier (s/nilable #{"long_context" "default"})) @@ -109,7 +115,7 @@ (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 [v938] (or (s/valid? clojure.core/integer? v938) (s/valid? clojure.core/number? v938))))) +(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))))) (s/def :github.copilot-sdk.generated.event-specs/elicitation-source clojure.core/string?) @@ -119,7 +125,7 @@ (s/def :github.copilot-sdk.generated.event-specs/ephemeral clojure.core/boolean?) -(s/def :github.copilot-sdk.generated.event-specs/error (s/spec (fn [v940] (or (s/valid? clojure.core/string? v940) (s/valid? clojure.core/map? v940))))) +(s/def :github.copilot-sdk.generated.event-specs/error (s/spec (fn [v941] (or (s/valid? clojure.core/string? v941) (s/valid? clojure.core/map? v941))))) (s/def :github.copilot-sdk.generated.event-specs/error-code clojure.core/string?) @@ -135,6 +141,10 @@ (s/def :github.copilot-sdk.generated.event-specs/events-removed clojure.core/integer?) +(s/def :github.copilot-sdk.generated.event-specs/extension-id clojure.core/string?) + +(s/def :github.copilot-sdk.generated.event-specs/extension-name clojure.core/string?) + (s/def :github.copilot-sdk.generated.event-specs/extensions (s/coll-of clojure.core/map?)) (s/def :github.copilot-sdk.generated.event-specs/feedback clojure.core/string?) @@ -153,7 +163,7 @@ (s/def :github.copilot-sdk.generated.event-specs/host-type #{"github" "ado"}) -(s/def :github.copilot-sdk.generated.event-specs/id (s/spec (fn [v941] (or (s/valid? clojure.core/string? v941) (s/valid? clojure.core/integer? v941))))) +(s/def :github.copilot-sdk.generated.event-specs/id (s/spec (fn [v942] (or (s/valid? clojure.core/string? v942) (s/valid? clojure.core/integer? v942))))) (s/def :github.copilot-sdk.generated.event-specs/info-type clojure.core/string?) @@ -163,6 +173,8 @@ (s/def :github.copilot-sdk.generated.event-specs/input-tokens clojure.core/integer?) +(s/def :github.copilot-sdk.generated.event-specs/instance-id clojure.core/string?) + (s/def :github.copilot-sdk.generated.event-specs/intent clojure.core/string?) (s/def :github.copilot-sdk.generated.event-specs/inter-token-latency-ms clojure.core/number?) @@ -211,7 +223,7 @@ (s/def :github.copilot-sdk.generated.event-specs/new-model clojure.core/string?) -(s/def :github.copilot-sdk.generated.event-specs/operation (s/spec (fn [v944] (or (s/valid? #{"delete" "update" "create"} v944) (s/valid? #{"update" "create"} v944))))) +(s/def :github.copilot-sdk.generated.event-specs/operation (s/spec (fn [v946] (or (s/valid? #{"delete" "update" "create"} v946) (s/valid? #{"update" "create"} v946))))) (s/def :github.copilot-sdk.generated.event-specs/output clojure.core/any?) @@ -279,7 +291,7 @@ (s/def :github.copilot-sdk.generated.event-specs/reason #{"user_abort" "remote_command" "user_initiated"}) -(s/def :github.copilot-sdk.generated.event-specs/reasoning-effort (s/spec (fn [v942] (or (s/valid? clojure.core/string? v942) (s/valid? clojure.core/any? v942))))) +(s/def :github.copilot-sdk.generated.event-specs/reasoning-effort (s/spec (fn [v943] (or (s/valid? clojure.core/string? v943) (s/valid? clojure.core/any? v943))))) (s/def :github.copilot-sdk.generated.event-specs/reasoning-id clojure.core/string?) @@ -299,7 +311,9 @@ (s/def :github.copilot-sdk.generated.event-specs/remote-steerable clojure.core/boolean?) -(s/def :github.copilot-sdk.generated.event-specs/repository (s/spec (fn [v939] (or (s/valid? clojure.core/map? v939) (s/valid? clojure.core/string? v939))))) +(s/def :github.copilot-sdk.generated.event-specs/reopen clojure.core/boolean?) + +(s/def :github.copilot-sdk.generated.event-specs/repository (s/spec (fn [v940] (or (s/valid? clojure.core/map? v940) (s/valid? clojure.core/string? v940))))) (s/def :github.copilot-sdk.generated.event-specs/repository-host clojure.core/string?) @@ -311,7 +325,7 @@ (s/def :github.copilot-sdk.generated.event-specs/response #{"yes_always" "yes" "no"}) -(s/def :github.copilot-sdk.generated.event-specs/result (s/spec (fn [v949] (or (s/valid? clojure.core/map? v949) (s/valid? (s/or :branch-0 clojure.core/map? :branch-1 clojure.core/map? :branch-2 clojure.core/map? :branch-3 clojure.core/map? :branch-4 clojure.core/map? :branch-5 clojure.core/map? :branch-6 clojure.core/map? :branch-7 clojure.core/map? :branch-8 clojure.core/map?) v949))))) +(s/def :github.copilot-sdk.generated.event-specs/result (s/spec (fn [v951] (or (s/valid? clojure.core/map? v951) (s/valid? (s/or :branch-0 clojure.core/map? :branch-1 clojure.core/map? :branch-2 clojure.core/map? :branch-3 clojure.core/map? :branch-4 clojure.core/map? :branch-5 clojure.core/map? :branch-6 clojure.core/map? :branch-7 clojure.core/map? :branch-8 clojure.core/map?) v951))))) (s/def :github.copilot-sdk.generated.event-specs/resume-time clojure.core/string?) @@ -343,7 +357,7 @@ (s/def :github.copilot-sdk.generated.event-specs/skills (s/coll-of clojure.core/map?)) -(s/def :github.copilot-sdk.generated.event-specs/source (s/spec (fn [v946] (or (s/valid? clojure.core/string? v946) (s/valid? #{"top_level" "subagent" "mcp_sampling"} v946))))) +(s/def :github.copilot-sdk.generated.event-specs/source (s/spec (fn [v948] (or (s/valid? clojure.core/string? v948) (s/valid? #{"top_level" "subagent" "mcp_sampling"} v948))))) (s/def :github.copilot-sdk.generated.event-specs/source-type #{"remote" "local"}) @@ -353,7 +367,7 @@ (s/def :github.copilot-sdk.generated.event-specs/static-client-config clojure.core/map?) -(s/def :github.copilot-sdk.generated.event-specs/status #{"failed" "not_configured" "needs-auth" "connected" "disabled" "pending"}) +(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-code clojure.core/integer?) @@ -423,7 +437,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 [v947] (or (s/valid? #{"session.start"} v947) (s/valid? #{"session.resume"} v947) (s/valid? #{"session.remote_steerable_changed"} v947) (s/valid? #{"session.error"} v947) (s/valid? #{"session.idle"} v947) (s/valid? #{"session.title_changed"} v947) (s/valid? #{"session.schedule_created"} v947) (s/valid? #{"session.schedule_cancelled"} v947) (s/valid? #{"session.info"} v947) (s/valid? #{"session.warning"} v947) (s/valid? #{"session.model_change"} v947) (s/valid? #{"session.mode_changed"} v947) (s/valid? #{"session.plan_changed"} v947) (s/valid? #{"session.workspace_file_changed"} v947) (s/valid? #{"session.handoff"} v947) (s/valid? #{"session.truncation"} v947) (s/valid? #{"session.snapshot_rewind"} v947) (s/valid? #{"session.shutdown"} v947) (s/valid? #{"session.context_changed"} v947) (s/valid? #{"session.usage_info"} v947) (s/valid? #{"session.compaction_start"} v947) (s/valid? #{"session.compaction_complete"} v947) (s/valid? #{"session.task_complete"} v947) (s/valid? #{"user.message"} v947) (s/valid? #{"pending_messages.modified"} v947) (s/valid? #{"assistant.turn_start"} v947) (s/valid? #{"assistant.intent"} v947) (s/valid? #{"assistant.reasoning"} v947) (s/valid? #{"assistant.reasoning_delta"} v947) (s/valid? #{"assistant.streaming_delta"} v947) (s/valid? #{"assistant.message"} v947) (s/valid? #{"assistant.message_start"} v947) (s/valid? #{"assistant.message_delta"} v947) (s/valid? #{"assistant.turn_end"} v947) (s/valid? #{"assistant.usage"} v947) (s/valid? #{"model.call_failure"} v947) (s/valid? #{"abort"} v947) (s/valid? #{"tool.user_requested"} v947) (s/valid? #{"tool.execution_start"} v947) (s/valid? #{"tool.execution_partial_result"} v947) (s/valid? #{"tool.execution_progress"} v947) (s/valid? #{"tool.execution_complete"} v947) (s/valid? #{"skill.invoked"} v947) (s/valid? #{"subagent.started"} v947) (s/valid? #{"subagent.completed"} v947) (s/valid? #{"subagent.failed"} v947) (s/valid? #{"subagent.selected"} v947) (s/valid? #{"subagent.deselected"} v947) (s/valid? #{"hook.start"} v947) (s/valid? #{"hook.end"} v947) (s/valid? #{"system.message"} v947) (s/valid? #{"system.notification"} v947) (s/valid? #{"permission.requested"} v947) (s/valid? #{"permission.completed"} v947) (s/valid? #{"user_input.requested"} v947) (s/valid? #{"user_input.completed"} v947) (s/valid? #{"elicitation.requested"} v947) (s/valid? #{"elicitation.completed"} v947) (s/valid? #{"sampling.requested"} v947) (s/valid? #{"sampling.completed"} v947) (s/valid? #{"mcp.oauth_required"} v947) (s/valid? #{"mcp.oauth_completed"} v947) (s/valid? #{"session.custom_notification"} v947) (s/valid? #{"external_tool.requested"} v947) (s/valid? #{"external_tool.completed"} v947) (s/valid? #{"command.queued"} v947) (s/valid? #{"command.execute"} v947) (s/valid? #{"command.completed"} v947) (s/valid? #{"auto_mode_switch.requested"} v947) (s/valid? #{"auto_mode_switch.completed"} v947) (s/valid? #{"commands.changed"} v947) (s/valid? #{"capabilities.changed"} v947) (s/valid? #{"exit_plan_mode.requested"} v947) (s/valid? #{"exit_plan_mode.completed"} v947) (s/valid? #{"session.tools_updated"} v947) (s/valid? #{"session.background_tasks_changed"} v947) (s/valid? #{"session.skills_loaded"} v947) (s/valid? #{"session.custom_agents_updated"} v947) (s/valid? #{"session.mcp_servers_loaded"} v947) (s/valid? #{"session.mcp_server_status_changed"} v947) (s/valid? #{"session.extensions_loaded"} v947) (s/valid? #{"mcp_app.tool_call_complete"} v947))))) +(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/ui clojure.core/map?) @@ -511,6 +525,10 @@ (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])) + +(s/def :github.copilot-sdk.generated.event-specs/session.canvas.registry_changed-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/canvases])) + (s/def :github.copilot-sdk.generated.event-specs/session.compaction_complete-data (s/keys :req-un [:github.copilot-sdk.generated.event-specs/success] :opt-un [:github.copilot-sdk.generated.event-specs/checkpoint-number :github.copilot-sdk.generated.event-specs/checkpoint-path :github.copilot-sdk.generated.event-specs/compaction-tokens-used :github.copilot-sdk.generated.event-specs/conversation-tokens :github.copilot-sdk.generated.event-specs/custom-instructions :github.copilot-sdk.generated.event-specs/error :github.copilot-sdk.generated.event-specs/messages-removed :github.copilot-sdk.generated.event-specs/post-compaction-tokens :github.copilot-sdk.generated.event-specs/pre-compaction-messages-length :github.copilot-sdk.generated.event-specs/pre-compaction-tokens :github.copilot-sdk.generated.event-specs/request-id :github.copilot-sdk.generated.event-specs/service-request-id :github.copilot-sdk.generated.event-specs/summary-content :github.copilot-sdk.generated.event-specs/system-tokens :github.copilot-sdk.generated.event-specs/tokens-removed :github.copilot-sdk.generated.event-specs/tool-definitions-tokens])) (s/def :github.copilot-sdk.generated.event-specs/session.compaction_start-data (s/keys :opt-un [:github.copilot-sdk.generated.event-specs/conversation-tokens :github.copilot-sdk.generated.event-specs/system-tokens :github.copilot-sdk.generated.event-specs/tool-definitions-tokens])) @@ -675,6 +693,10 @@ (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))))) + +(s/def :github.copilot-sdk.generated.event-specs/session.canvas.registry_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.canvas.registry_changed" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.canvas.registry_changed-data (:data event))))) + (s/def :github.copilot-sdk.generated.event-specs/session.compaction_complete (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.compaction_complete" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.compaction_complete-data (:data event))))) (s/def :github.copilot-sdk.generated.event-specs/session.compaction_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/= "session.compaction_start" (:type event))) (fn [event] (s/valid? clojure.core/string? (:id event))) (fn [event] (s/valid? :github.copilot-sdk.generated.event-specs/session.compaction_start-data (:data event))))) @@ -767,7 +789,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.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.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"}) (defmulti event-mm :type) @@ -843,6 +865,10 @@ (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)) + +(defmethod event-mm "session.canvas.registry_changed" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.canvas.registry_changed)) + (defmethod event-mm "session.compaction_complete" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.compaction_complete)) (defmethod event-mm "session.compaction_start" [_] (s/get-spec :github.copilot-sdk.generated.event-specs/session.compaction_start)) diff --git a/src/github/copilot_sdk/session.clj b/src/github/copilot_sdk/session.clj index 14f8eed..207c0ee 100644 --- a/src/github/copilot_sdk/session.clj +++ b/src/github/copilot_sdk/session.clj @@ -695,6 +695,7 @@ "preToolUse" :on-pre-tool-use "preMcpToolCall" :on-pre-mcp-tool-call "postToolUse" :on-post-tool-use + "postToolUseFailure" :on-post-tool-use-failure "userPromptSubmitted" :on-user-prompt-submitted "sessionStart" :on-session-start "sessionEnd" :on-session-end diff --git a/src/github/copilot_sdk/specs.clj b/src/github/copilot_sdk/specs.clj index 4a2b70e..1c63450 100644 --- a/src/github/copilot_sdk/specs.clj +++ b/src/github/copilot_sdk/specs.clj @@ -453,12 +453,14 @@ (s/def ::on-pre-tool-use fn?) (s/def ::on-pre-mcp-tool-call fn?) (s/def ::on-post-tool-use fn?) +(s/def ::on-post-tool-use-failure fn?) (s/def ::on-user-prompt-submitted fn?) (s/def ::on-session-start fn?) (s/def ::on-session-end fn?) (s/def ::on-error-occurred fn?) (s/def ::hooks (s/keys :opt-un [::on-pre-tool-use ::on-pre-mcp-tool-call ::on-post-tool-use + ::on-post-tool-use-failure ::on-user-prompt-submitted ::on-session-start ::on-session-end ::on-error-occurred])) diff --git a/test/github/copilot_sdk/integration_test.clj b/test/github/copilot_sdk/integration_test.clj index 860c20c..5dee98c 100644 --- a/test/github/copilot_sdk/integration_test.clj +++ b/test/github/copilot_sdk/integration_test.clj @@ -2999,6 +2999,50 @@ ;; Handler returned nil, so result is nil (is (nil? (:result response)))))) +(deftest test-hooks-post-tool-use-failure + (testing "hooks.invoke postToolUseFailure calls registered handler (upstream PR #1421)" + (let [handler-called (atom nil) + session (sdk/create-session *test-client* + {:on-permission-request sdk/approve-all + :hooks {:on-post-tool-use-failure + (fn [input ctx] + (reset! handler-called {:input input :ctx ctx}) + {:additional-context "noted"})}}) + session-id (sdk/session-id session) + response (mock/send-rpc-request! *mock-server* + "hooks.invoke" + {:sessionId session-id + :hookType "postToolUseFailure" + :input {:toolName "bash" + :toolArgs {:command "false"} + :error "command exited 1" + :timestamp 12345 + :cwd "/workspace"}})] + (is (some? @handler-called)) + (is (= "bash" (get-in @handler-called [:input :tool-name]))) + (is (= "command exited 1" (get-in @handler-called [:input :error]))) + (is (= session-id (get-in @handler-called [:input :session-id]))) + (is (= "noted" (get-in response [:result :additionalContext])))))) + +(deftest test-hooks-post-tool-use-failure-no-handler + (testing "hooks.invoke postToolUseFailure with no handler returns nil result" + (let [session (sdk/create-session *test-client* + {:on-permission-request sdk/approve-all + ;; Only success hook registered; failure should pass through as nil. + :hooks {:on-post-tool-use + (fn [_ _] nil)}}) + session-id (sdk/session-id session) + response (mock/send-rpc-request! *mock-server* + "hooks.invoke" + {:sessionId session-id + :hookType "postToolUseFailure" + :input {:toolName "bash" + :toolArgs {} + :error "boom" + :timestamp 12345 + :cwd "/workspace"}})] + (is (nil? (:result response)))))) + (deftest test-hooks-session-start (testing "hooks.invoke sessionStart calls registered handler" (let [handler-called (atom nil)