From ac552877ca8decac4dbdf4f495df616eed7d1d2e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 17:40:08 +0000 Subject: [PATCH 1/2] Update @github/copilot to 1.0.17 - Updated nodejs and test harness dependencies - Re-ran code generators - Formatted generated code --- dotnet/src/Generated/SessionEvents.cs | 15 +++++- go/generated_session_events.go | 8 +++- go/rpc/generated_rpc.go | 12 +++-- nodejs/package-lock.json | 56 +++++++++++----------- nodejs/package.json | 2 +- nodejs/samples/package-lock.json | 3 +- nodejs/src/generated/rpc.ts | 5 ++ nodejs/src/generated/session-events.ts | 13 ++++- python/copilot/generated/rpc.py | 7 ++- python/copilot/generated/session_events.py | 20 ++++++-- test/harness/package-lock.json | 56 +++++++++++----------- test/harness/package.json | 2 +- 12 files changed, 127 insertions(+), 72 deletions(-) diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs index c01d1ddcd..8b5c0a5f1 100644 --- a/dotnet/src/Generated/SessionEvents.cs +++ b/dotnet/src/Generated/SessionEvents.cs @@ -1180,7 +1180,7 @@ public partial class SessionRemoteSteerableChangedData /// Error details for timeline display including message and optional diagnostic information. public partial class SessionErrorData { - /// Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "query"). + /// Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query"). [JsonPropertyName("errorType")] public required string ErrorType { get; set; } @@ -2267,6 +2267,11 @@ public partial class PermissionRequestedData /// Details of the permission being requested. [JsonPropertyName("permissionRequest")] public required PermissionRequest PermissionRequest { get; set; } + + /// When true, this permission was already resolved by a permissionRequest hook and requires no client action. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resolvedByHook")] + public bool? ResolvedByHook { get; set; } } /// Permission request completion notification signaling UI dismissal. @@ -2998,6 +3003,11 @@ public partial class AssistantMessageDataToolRequestsItem [JsonPropertyName("toolTitle")] public string? ToolTitle { get; set; } + /// Name of the MCP server hosting this tool, when the tool is an MCP tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mcpServerName")] + public string? McpServerName { get; set; } + /// Resolved intention summary describing what this specific call does. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("intentionSummary")] @@ -3989,6 +3999,9 @@ public enum PermissionCompletedDataResultKind /// The denied-by-content-exclusion-policy variant. [JsonStringEnumMemberName("denied-by-content-exclusion-policy")] DeniedByContentExclusionPolicy, + /// The denied-by-permission-request-hook variant. + [JsonStringEnumMemberName("denied-by-permission-request-hook")] + DeniedByPermissionRequestHook, } /// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. diff --git a/go/generated_session_events.go b/go/generated_session_events.go index 4799aca91..e3b6fa71e 100644 --- a/go/generated_session_events.go +++ b/go/generated_session_events.go @@ -358,7 +358,7 @@ type Data struct { // ISO 8601 timestamp when the session was resumed ResumeTime *time.Time `json:"resumeTime,omitempty"` // Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", - // "query") + // "context_limit", "query") ErrorType *string `json:"errorType,omitempty"` // Human-readable error message // @@ -801,6 +801,9 @@ type Data struct { Kind *KindClass `json:"kind,omitempty"` // Details of the permission being requested PermissionRequest *PermissionRequest `json:"permissionRequest,omitempty"` + // When true, this permission was already resolved by a permissionRequest hook and requires + // no client action + ResolvedByHook *bool `json:"resolvedByHook,omitempty"` // Whether the user can provide a free-form text response in addition to predefined choices AllowFreeform *bool `json:"allowFreeform,omitempty"` // Predefined choices for the user to select from, if applicable @@ -1403,6 +1406,8 @@ type ToolRequest struct { Arguments interface{} `json:"arguments"` // Resolved intention summary describing what this specific call does IntentionSummary *string `json:"intentionSummary"` + // Name of the MCP server hosting this tool, when the tool is an MCP tool + MCPServerName *string `json:"mcpServerName,omitempty"` // Name of the tool being invoked Name string `json:"name"` // Unique identifier for this tool call @@ -1556,6 +1561,7 @@ type ResultKind string const ( ResultKindApproved ResultKind = "approved" ResultKindDeniedByContentExclusionPolicy ResultKind = "denied-by-content-exclusion-policy" + ResultKindDeniedByPermissionRequestHook ResultKind = "denied-by-permission-request-hook" ResultKindDeniedByRules ResultKind = "denied-by-rules" ResultKindDeniedInteractivelyByUser ResultKind = "denied-interactively-by-user" ResultKindDeniedNoApprovalRuleAndCouldNotRequestFromUser ResultKind = "denied-no-approval-rule-and-could-not-request-from-user" diff --git a/go/rpc/generated_rpc.go b/go/rpc/generated_rpc.go index f6011d900..3e7b336b7 100644 --- a/go/rpc/generated_rpc.go +++ b/go/rpc/generated_rpc.go @@ -652,11 +652,12 @@ type SessionPermissionsHandlePendingPermissionRequestParams struct { } type SessionPermissionsHandlePendingPermissionRequestParamsResult struct { - Kind Kind `json:"kind"` - Rules []any `json:"rules,omitempty"` - Feedback *string `json:"feedback,omitempty"` - Message *string `json:"message,omitempty"` - Path *string `json:"path,omitempty"` + Kind Kind `json:"kind"` + Rules []any `json:"rules,omitempty"` + Feedback *string `json:"feedback,omitempty"` + Message *string `json:"message,omitempty"` + Path *string `json:"path,omitempty"` + Interrupt *bool `json:"interrupt,omitempty"` } type SessionLogResult struct { @@ -815,6 +816,7 @@ type Kind string const ( KindApproved Kind = "approved" KindDeniedByContentExclusionPolicy Kind = "denied-by-content-exclusion-policy" + KindDeniedByPermissionRequestHook Kind = "denied-by-permission-request-hook" KindDeniedByRules Kind = "denied-by-rules" KindDeniedInteractivelyByUser Kind = "denied-interactively-by-user" KindDeniedNoApprovalRuleAndCouldNotRequestFromUser Kind = "denied-no-approval-rule-and-could-not-request-from-user" diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 1af6e76c6..98ed1f0c7 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.8", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.15-2", + "@github/copilot": "^1.0.17", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, @@ -663,26 +663,26 @@ } }, "node_modules/@github/copilot": { - "version": "1.0.15-2", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.15-2.tgz", - "integrity": "sha512-ZVwGAH9u55CbGsM2fbZr9yL7oML5NZxfMbATBU9hWY8yEjiaSj+9WkRPxCSxGsd2cu4tw3OcHhFkDvxvWd2QpQ==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.17.tgz", + "integrity": "sha512-RTJ+kEKOdidjuOs8ozsoBdz+94g7tFJIEu5kz1P2iwJhsL+iIA5rtn9/jXOF0hAI3CLSXKZoSd66cqHrn4rb1A==", "license": "SEE LICENSE IN LICENSE.md", "bin": { "copilot": "npm-loader.js" }, "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.15-2", - "@github/copilot-darwin-x64": "1.0.15-2", - "@github/copilot-linux-arm64": "1.0.15-2", - "@github/copilot-linux-x64": "1.0.15-2", - "@github/copilot-win32-arm64": "1.0.15-2", - "@github/copilot-win32-x64": "1.0.15-2" + "@github/copilot-darwin-arm64": "1.0.17", + "@github/copilot-darwin-x64": "1.0.17", + "@github/copilot-linux-arm64": "1.0.17", + "@github/copilot-linux-x64": "1.0.17", + "@github/copilot-win32-arm64": "1.0.17", + "@github/copilot-win32-x64": "1.0.17" } }, "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.15-2", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.15-2.tgz", - "integrity": "sha512-J2kvPBbNC636z3YdFdg2uK8YAF0o1ktss4Cmz+WVi5+5rNzscty3GmUoWBgw1AtPRNSeFT8amMVZ9xBvkpzA/A==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.17.tgz", + "integrity": "sha512-LSv66P8611y/UjTESnaHLYqLl9kA9yBYsaocZPQoOsvMgCmktgaBgUWq+KMpLMicaFN0jBAE5F0Ve7dW6N9X3A==", "cpu": [ "arm64" ], @@ -696,9 +696,9 @@ } }, "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.15-2", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.15-2.tgz", - "integrity": "sha512-utoHP7RyJXasNVQtpAhkDfp4jTLiNwJf5ZFjOkb9XMASre0+i4CfsokuXb1yPXczXFnrLcreVWQ2wtSuRiyV3A==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.17.tgz", + "integrity": "sha512-yqRS0/8kYTGl4VvfJ/QOtHTeYF+DnAWNUReZgt2U0AEP3zgj4z4hxSH7D2PsO/488L4KsBmmcnJr13HmBGiT/w==", "cpu": [ "x64" ], @@ -712,9 +712,9 @@ } }, "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.15-2", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.15-2.tgz", - "integrity": "sha512-tkqt6W+3VhZRvTMQoNj80s5JWNu5TXPYnNQkrPzAviqTsd8BRXOSGnqcIL7DvU+Y0z4pY5IS0ZECByB0IsRSHw==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.17.tgz", + "integrity": "sha512-TOK0ma0A24zmQJslkGxUk+KnMFpiqquWEXB5sIv/5Ci45Qi7s0BRWTnqtiJ8Vahwb/wkja6KarHkLA27+ETGUA==", "cpu": [ "arm64" ], @@ -728,9 +728,9 @@ } }, "node_modules/@github/copilot-linux-x64": { - "version": "1.0.15-2", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.15-2.tgz", - "integrity": "sha512-svGfox/x8pNzrxcTAkpbqyWzaeQiJaRj6ZuQzzGJGi5+G6kAok3iqIInO+QYNB6fozW8oLnR8QJigAoj8Ldzbw==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.17.tgz", + "integrity": "sha512-4Yum3uaAuTM/SiNtzchsO/G/144Bi/Z4FEcearW6WsGDvS6cRwSJeudOM0y4aoy4BHcv8+yw7YuXH5BHC3SAiA==", "cpu": [ "x64" ], @@ -744,9 +744,9 @@ } }, "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.15-2", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.15-2.tgz", - "integrity": "sha512-ZM/cmICtOOknMLkN42OvCRaLp5qJPBN9GAKkwTWCrhBmFpAIjC9O679AQA6KiCNj4OUzL6Hi5mSl9ufdUzPwkw==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.17.tgz", + "integrity": "sha512-I1ferbfQ0aS149WyEUw6XS1sFixwTUUm13BPBQ3yMzD8G2SaoxTsdYdlhZpkVfkfh/rUYyvMKKi9VNxoVYOlDA==", "cpu": [ "arm64" ], @@ -760,9 +760,9 @@ } }, "node_modules/@github/copilot-win32-x64": { - "version": "1.0.15-2", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.15-2.tgz", - "integrity": "sha512-tAyd3Fzta6XJoH5MZ3yaw4H8i92C6k0zVkLKzL5zhrm4YEGWyQMcGB7NlLcvcmKewx49smCjbWtO/TIcVWJrrA==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.17.tgz", + "integrity": "sha512-kjiOxY9ibS+rPp9XFpPdfdYzluEL3SHN8R5/fnA7RO+kZEJ4FDKWJjAiec3tgVkEHQT3UwNuVa/u3TdfYNF15w==", "cpu": [ "x64" ], diff --git a/nodejs/package.json b/nodejs/package.json index ce8d99a86..99681ec3f 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -56,7 +56,7 @@ "author": "GitHub", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.15-2", + "@github/copilot": "^1.0.17", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, diff --git a/nodejs/samples/package-lock.json b/nodejs/samples/package-lock.json index cd2ce2305..c0749ee6c 100644 --- a/nodejs/samples/package-lock.json +++ b/nodejs/samples/package-lock.json @@ -18,11 +18,12 @@ "version": "0.1.8", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.11", + "@github/copilot": "^1.0.17", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, "devDependencies": { + "@platformatic/vfs": "^0.3.0", "@types/node": "^25.2.0", "@typescript-eslint/eslint-plugin": "^8.54.0", "@typescript-eslint/parser": "^8.54.0", diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 845d49129..4f87c14f2 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -1185,6 +1185,11 @@ export interface SessionPermissionsHandlePendingPermissionRequestParams { kind: "denied-by-content-exclusion-policy"; path: string; message: string; + } + | { + kind: "denied-by-permission-request-hook"; + message?: string; + interrupt?: boolean; }; } diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index 137c474f2..642c933cd 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -229,7 +229,7 @@ export type SessionEvent = */ data: { /** - * Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "query") + * Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") */ errorType: string; /** @@ -1480,6 +1480,10 @@ export type SessionEvent = * Human-readable display title for the tool */ toolTitle?: string; + /** + * Name of the MCP server hosting this tool, when the tool is an MCP tool + */ + mcpServerName?: string; /** * Resolved intention summary describing what this specific call does */ @@ -2872,6 +2876,10 @@ export type SessionEvent = */ hookMessage?: string; }; + /** + * When true, this permission was already resolved by a permissionRequest hook and requires no client action + */ + resolvedByHook?: boolean; }; } | { @@ -2909,7 +2917,8 @@ export type SessionEvent = | "denied-by-rules" | "denied-no-approval-rule-and-could-not-request-from-user" | "denied-interactively-by-user" - | "denied-by-content-exclusion-policy"; + | "denied-by-content-exclusion-policy" + | "denied-by-permission-request-hook"; }; }; } diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 39e20a05d..7852d9984 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -2257,6 +2257,7 @@ def to_dict(self) -> dict: class Kind(Enum): APPROVED = "approved" DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" + DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" DENIED_BY_RULES = "denied-by-rules" DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" @@ -2269,6 +2270,7 @@ class SessionPermissionsHandlePendingPermissionRequestParamsResult: feedback: str | None = None message: str | None = None path: str | None = None + interrupt: bool | None = None @staticmethod def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestParamsResult': @@ -2278,7 +2280,8 @@ def from_dict(obj: Any) -> 'SessionPermissionsHandlePendingPermissionRequestPara feedback = from_union([from_str, from_none], obj.get("feedback")) message = from_union([from_str, from_none], obj.get("message")) path = from_union([from_str, from_none], obj.get("path")) - return SessionPermissionsHandlePendingPermissionRequestParamsResult(kind, rules, feedback, message, path) + interrupt = from_union([from_bool, from_none], obj.get("interrupt")) + return SessionPermissionsHandlePendingPermissionRequestParamsResult(kind, rules, feedback, message, path, interrupt) def to_dict(self) -> dict: result: dict = {} @@ -2291,6 +2294,8 @@ def to_dict(self) -> dict: result["message"] = from_union([from_str, from_none], self.message) if self.path is not None: result["path"] = from_union([from_str, from_none], self.path) + if self.interrupt is not None: + result["interrupt"] = from_union([from_bool, from_none], self.interrupt) return result diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index 2c3acba81..9b4267829 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -1500,6 +1500,7 @@ class ResultKind(Enum): APPROVED = "approved" DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" + DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" DENIED_BY_RULES = "denied-by-rules" DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" @@ -1708,6 +1709,9 @@ class ToolRequest: intention_summary: str | None = None """Resolved intention summary describing what this specific call does""" + mcp_server_name: str | None = None + """Name of the MCP server hosting this tool, when the tool is an MCP tool""" + tool_title: str | None = None """Human-readable display title for the tool""" @@ -1723,9 +1727,10 @@ def from_dict(obj: Any) -> 'ToolRequest': tool_call_id = from_str(obj.get("toolCallId")) arguments = obj.get("arguments") intention_summary = from_union([from_none, from_str], obj.get("intentionSummary")) + mcp_server_name = from_union([from_str, from_none], obj.get("mcpServerName")) tool_title = from_union([from_str, from_none], obj.get("toolTitle")) type = from_union([ToolRequestType, from_none], obj.get("type")) - return ToolRequest(name, tool_call_id, arguments, intention_summary, tool_title, type) + return ToolRequest(name, tool_call_id, arguments, intention_summary, mcp_server_name, tool_title, type) def to_dict(self) -> dict: result: dict = {} @@ -1735,6 +1740,8 @@ def to_dict(self) -> dict: result["arguments"] = self.arguments if self.intention_summary is not None: result["intentionSummary"] = from_union([from_none, from_str], self.intention_summary) + if self.mcp_server_name is not None: + result["mcpServerName"] = from_union([from_str, from_none], self.mcp_server_name) if self.tool_title is not None: result["toolTitle"] = from_union([from_str, from_none], self.tool_title) if self.type is not None: @@ -1957,7 +1964,7 @@ class Data: error_type: str | None = None """Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", - "query") + "context_limit", "query") """ message: str | None = None """Human-readable error message @@ -2527,6 +2534,10 @@ class Data: permission_request: PermissionRequest | None = None """Details of the permission being requested""" + resolved_by_hook: bool | None = None + """When true, this permission was already resolved by a permissionRequest hook and requires + no client action + """ allow_freeform: bool | None = None """Whether the user can provide a free-form text response in addition to predefined choices""" @@ -2758,6 +2769,7 @@ def from_dict(obj: Any) -> 'Data': role = from_union([Role, from_none], obj.get("role")) kind = from_union([KindClass.from_dict, from_none], obj.get("kind")) permission_request = from_union([PermissionRequest.from_dict, from_none], obj.get("permissionRequest")) + resolved_by_hook = from_union([from_bool, from_none], obj.get("resolvedByHook")) allow_freeform = from_union([from_bool, from_none], obj.get("allowFreeform")) choices = from_union([lambda x: from_list(from_str, x), from_none], obj.get("choices")) question = from_union([from_str, from_none], obj.get("question")) @@ -2785,7 +2797,7 @@ def from_dict(obj: Any) -> 'Data': servers = from_union([lambda x: from_list(Server.from_dict, x), from_none], obj.get("servers")) status = from_union([ServerStatus, from_none], obj.get("status")) extensions = from_union([lambda x: from_list(Extension.from_dict, x), from_none], obj.get("extensions")) - return Data(already_in_use, context, copilot_version, producer, reasoning_effort, remote_steerable, selected_model, session_id, start_time, version, event_count, resume_time, error_type, message, provider_call_id, stack, status_code, url, aborted, background_tasks, title, info_type, warning_type, new_model, previous_model, previous_reasoning_effort, new_mode, previous_mode, operation, path, handoff_time, host, remote_session_id, repository, source_type, summary, messages_removed_during_truncation, performed_by, post_truncation_messages_length, post_truncation_tokens_in_messages, pre_truncation_messages_length, pre_truncation_tokens_in_messages, token_limit, tokens_removed_during_truncation, events_removed, up_to_event_id, code_changes, conversation_tokens, current_model, current_tokens, error_reason, model_metrics, session_start_time, shutdown_type, system_tokens, tool_definitions_tokens, total_api_duration_ms, total_premium_requests, base_commit, branch, cwd, git_root, head_commit, host_type, is_initial, messages_length, checkpoint_number, checkpoint_path, compaction_tokens_used, error, messages_removed, post_compaction_tokens, pre_compaction_messages_length, pre_compaction_tokens, request_id, success, summary_content, tokens_removed, agent_mode, attachments, content, interaction_id, source, transformed_content, turn_id, intent, reasoning_id, delta_content, total_response_size_bytes, encrypted_content, message_id, output_tokens, parent_tool_call_id, phase, reasoning_opaque, reasoning_text, tool_requests, api_call_id, cache_read_tokens, cache_write_tokens, copilot_usage, cost, duration, initiator, input_tokens, inter_token_latency_ms, model, quota_snapshots, ttft_ms, reason, arguments, tool_call_id, tool_name, mcp_server_name, mcp_tool_name, partial_output, progress_message, is_user_requested, result, tool_telemetry, allowed_tools, description, name, plugin_name, plugin_version, agent_description, agent_display_name, agent_name, duration_ms, total_tokens, total_tool_calls, tools, hook_invocation_id, hook_type, input, output, metadata, role, kind, permission_request, allow_freeform, choices, question, elicitation_source, mode, requested_schema, mcp_request_id, server_name, server_url, static_client_config, traceparent, tracestate, command, args, command_name, commands, ui, actions, plan_content, recommended_action, skills, agents, errors, warnings, servers, status, extensions) + return Data(already_in_use, context, copilot_version, producer, reasoning_effort, remote_steerable, selected_model, session_id, start_time, version, event_count, resume_time, error_type, message, provider_call_id, stack, status_code, url, aborted, background_tasks, title, info_type, warning_type, new_model, previous_model, previous_reasoning_effort, new_mode, previous_mode, operation, path, handoff_time, host, remote_session_id, repository, source_type, summary, messages_removed_during_truncation, performed_by, post_truncation_messages_length, post_truncation_tokens_in_messages, pre_truncation_messages_length, pre_truncation_tokens_in_messages, token_limit, tokens_removed_during_truncation, events_removed, up_to_event_id, code_changes, conversation_tokens, current_model, current_tokens, error_reason, model_metrics, session_start_time, shutdown_type, system_tokens, tool_definitions_tokens, total_api_duration_ms, total_premium_requests, base_commit, branch, cwd, git_root, head_commit, host_type, is_initial, messages_length, checkpoint_number, checkpoint_path, compaction_tokens_used, error, messages_removed, post_compaction_tokens, pre_compaction_messages_length, pre_compaction_tokens, request_id, success, summary_content, tokens_removed, agent_mode, attachments, content, interaction_id, source, transformed_content, turn_id, intent, reasoning_id, delta_content, total_response_size_bytes, encrypted_content, message_id, output_tokens, parent_tool_call_id, phase, reasoning_opaque, reasoning_text, tool_requests, api_call_id, cache_read_tokens, cache_write_tokens, copilot_usage, cost, duration, initiator, input_tokens, inter_token_latency_ms, model, quota_snapshots, ttft_ms, reason, arguments, tool_call_id, tool_name, mcp_server_name, mcp_tool_name, partial_output, progress_message, is_user_requested, result, tool_telemetry, allowed_tools, description, name, plugin_name, plugin_version, agent_description, agent_display_name, agent_name, duration_ms, total_tokens, total_tool_calls, tools, hook_invocation_id, hook_type, input, output, metadata, role, kind, permission_request, resolved_by_hook, allow_freeform, choices, question, elicitation_source, mode, requested_schema, mcp_request_id, server_name, server_url, static_client_config, traceparent, tracestate, command, args, command_name, commands, ui, actions, plan_content, recommended_action, skills, agents, errors, warnings, servers, status, extensions) def to_dict(self) -> dict: result: dict = {} @@ -3069,6 +3081,8 @@ def to_dict(self) -> dict: result["kind"] = from_union([lambda x: to_class(KindClass, x), from_none], self.kind) if self.permission_request is not None: result["permissionRequest"] = from_union([lambda x: to_class(PermissionRequest, x), from_none], self.permission_request) + if self.resolved_by_hook is not None: + result["resolvedByHook"] = from_union([from_bool, from_none], self.resolved_by_hook) if self.allow_freeform is not None: result["allowFreeform"] = from_union([from_bool, from_none], self.allow_freeform) if self.choices is not None: diff --git a/test/harness/package-lock.json b/test/harness/package-lock.json index d1ee2fa24..5d055e680 100644 --- a/test/harness/package-lock.json +++ b/test/harness/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "@github/copilot": "^1.0.14-0", + "@github/copilot": "^1.0.17", "@modelcontextprotocol/sdk": "^1.26.0", "@types/node": "^25.3.3", "openai": "^6.17.0", @@ -462,27 +462,27 @@ } }, "node_modules/@github/copilot": { - "version": "1.0.14-0", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.14-0.tgz", - "integrity": "sha512-9eA5sFbvx69OtQnVoeik/8boFqHgGAhylLeUjEACc3kB70aaH1E/cHgxNzSMyYgZDjpXov0/IBXjtx2otpfHBw==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.17.tgz", + "integrity": "sha512-RTJ+kEKOdidjuOs8ozsoBdz+94g7tFJIEu5kz1P2iwJhsL+iIA5rtn9/jXOF0hAI3CLSXKZoSd66cqHrn4rb1A==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "bin": { "copilot": "npm-loader.js" }, "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.14-0", - "@github/copilot-darwin-x64": "1.0.14-0", - "@github/copilot-linux-arm64": "1.0.14-0", - "@github/copilot-linux-x64": "1.0.14-0", - "@github/copilot-win32-arm64": "1.0.14-0", - "@github/copilot-win32-x64": "1.0.14-0" + "@github/copilot-darwin-arm64": "1.0.17", + "@github/copilot-darwin-x64": "1.0.17", + "@github/copilot-linux-arm64": "1.0.17", + "@github/copilot-linux-x64": "1.0.17", + "@github/copilot-win32-arm64": "1.0.17", + "@github/copilot-win32-x64": "1.0.17" } }, "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.14-0", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.14-0.tgz", - "integrity": "sha512-w11Eqmfnu0ihrvgLysTd5Tkq8LuQa9eW63CNTQ/k5copnG1AMCdvd3K/78MxE2DdFJPq2L95KGS5cs9jH1dlIw==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.17.tgz", + "integrity": "sha512-LSv66P8611y/UjTESnaHLYqLl9kA9yBYsaocZPQoOsvMgCmktgaBgUWq+KMpLMicaFN0jBAE5F0Ve7dW6N9X3A==", "cpu": [ "arm64" ], @@ -497,9 +497,9 @@ } }, "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.14-0", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.14-0.tgz", - "integrity": "sha512-4X/dMSPxCE/rvL6N1tgnwFxBg2uXnPrN63GGgS/FqK/fNi3TtcuojDVv8K1yjmEYpF8PXdkQttDlp6bKc+Nonw==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.17.tgz", + "integrity": "sha512-yqRS0/8kYTGl4VvfJ/QOtHTeYF+DnAWNUReZgt2U0AEP3zgj4z4hxSH7D2PsO/488L4KsBmmcnJr13HmBGiT/w==", "cpu": [ "x64" ], @@ -514,9 +514,9 @@ } }, "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.14-0", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.14-0.tgz", - "integrity": "sha512-A4thcLUoErEvfBO3Hsl/hJASibn44qwZm1ZSeVBPCa1FkpowBwo8fT1eV9EwN/ftKsyks3QkndNFvHkVzjUfxA==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.17.tgz", + "integrity": "sha512-TOK0ma0A24zmQJslkGxUk+KnMFpiqquWEXB5sIv/5Ci45Qi7s0BRWTnqtiJ8Vahwb/wkja6KarHkLA27+ETGUA==", "cpu": [ "arm64" ], @@ -531,9 +531,9 @@ } }, "node_modules/@github/copilot-linux-x64": { - "version": "1.0.14-0", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.14-0.tgz", - "integrity": "sha512-Kwn+Qn8/BqWRKa2DewZipH7rPIO8nDRWzpVy/ZLcRWBAvnIU+6BLWfhnYEU44DsqkD2VeWhKVfQlNmDX23xKKg==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.17.tgz", + "integrity": "sha512-4Yum3uaAuTM/SiNtzchsO/G/144Bi/Z4FEcearW6WsGDvS6cRwSJeudOM0y4aoy4BHcv8+yw7YuXH5BHC3SAiA==", "cpu": [ "x64" ], @@ -548,9 +548,9 @@ } }, "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.14-0", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.14-0.tgz", - "integrity": "sha512-8P5kxcb8YVWSS+Ihs+ykyy8jov1WwQ8GKV4d7mJN268Jpd8y5VI8Peb7uE2VO0lRLgq5c2VcXuZDsLG/1Wgnlw==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.17.tgz", + "integrity": "sha512-I1ferbfQ0aS149WyEUw6XS1sFixwTUUm13BPBQ3yMzD8G2SaoxTsdYdlhZpkVfkfh/rUYyvMKKi9VNxoVYOlDA==", "cpu": [ "arm64" ], @@ -565,9 +565,9 @@ } }, "node_modules/@github/copilot-win32-x64": { - "version": "1.0.14-0", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.14-0.tgz", - "integrity": "sha512-JWxp08j5o/PUkRZtZVagNYJLjH+KCURCyZRb7BfnC0A3vLeqcJQ70JC5qlYEAlcRnb4uCUJnmnpbWLLOJ+ObrA==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.17.tgz", + "integrity": "sha512-kjiOxY9ibS+rPp9XFpPdfdYzluEL3SHN8R5/fnA7RO+kZEJ4FDKWJjAiec3tgVkEHQT3UwNuVa/u3TdfYNF15w==", "cpu": [ "x64" ], diff --git a/test/harness/package.json b/test/harness/package.json index f8fe732e4..257caf35c 100644 --- a/test/harness/package.json +++ b/test/harness/package.json @@ -11,7 +11,7 @@ "test": "vitest run" }, "devDependencies": { - "@github/copilot": "^1.0.14-0", + "@github/copilot": "^1.0.17", "@modelcontextprotocol/sdk": "^1.26.0", "@types/node": "^25.3.3", "openai": "^6.17.0", From 8638ca6dabee86fb76a36cc3b4fb91d1f0e4c92c Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Fri, 3 Apr 2026 11:19:34 -0700 Subject: [PATCH 2/2] Skip permission RPC response when resolvedByHook is true When the runtime resolves a permission request via a permissionRequest hook, it sets resolvedByHook=true on the broadcast event. The SDK broadcast handlers were unconditionally invoking the permission handler and sending an RPC response, causing duplicate/invalid responses. Add a guard in all four SDKs (Node, Python, Go, .NET) to skip the permission handler and RPC response when resolvedByHook is set, while still allowing event subscribers to observe the event. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- dotnet/src/Session.cs | 3 +++ go/session.go | 3 +++ nodejs/src/session.ts | 6 +++++- python/copilot/session.py | 4 ++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs index ae3d0c85b..3468e9b52 100644 --- a/dotnet/src/Session.cs +++ b/dotnet/src/Session.cs @@ -456,6 +456,9 @@ private async Task HandleBroadcastEventAsync(SessionEvent sessionEvent) if (string.IsNullOrEmpty(data.RequestId) || data.PermissionRequest is null) return; + if (data.ResolvedByHook == true) + return; // Already resolved by a permissionRequest hook; no client action needed. + var handler = _permissionHandler; if (handler is null) return; // This client doesn't handle permissions; another client will. diff --git a/go/session.go b/go/session.go index 04c1a05b0..225f2bf5e 100644 --- a/go/session.go +++ b/go/session.go @@ -915,6 +915,9 @@ func (s *Session) handleBroadcastEvent(event SessionEvent) { if requestID == nil || event.Data.PermissionRequest == nil { return } + if event.Data.ResolvedByHook != nil && *event.Data.ResolvedByHook { + return // Already resolved by a permissionRequest hook; no client action needed. + } handler := s.getPermissionHandler() if handler == nil { return diff --git a/nodejs/src/session.ts b/nodejs/src/session.ts index 50f094e5a..0bd5ad7b8 100644 --- a/nodejs/src/session.ts +++ b/nodejs/src/session.ts @@ -408,10 +408,14 @@ export class CopilotSession { ); } } else if (event.type === "permission.requested") { - const { requestId, permissionRequest } = event.data as { + const { requestId, permissionRequest, resolvedByHook } = event.data as { requestId: string; permissionRequest: PermissionRequest; + resolvedByHook?: boolean; }; + if (resolvedByHook) { + return; // Already resolved by a permissionRequest hook; no client action needed. + } if (this.permissionHandler) { void this._executePermissionAndRespond(requestId, permissionRequest); } diff --git a/python/copilot/session.py b/python/copilot/session.py index 96bb4730b..9bf384fbe 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -1224,6 +1224,10 @@ def _handle_broadcast_event(self, event: SessionEvent) -> None: if not request_id or not permission_request: return + resolved_by_hook = getattr(event.data, "resolved_by_hook", None) + if resolved_by_hook: + return # Already resolved by a permissionRequest hook; no client action needed. + with self._permission_handler_lock: perm_handler = self._permission_handler if not perm_handler: