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/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/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/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/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/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/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/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:
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",