diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs
index d5ef13d53..48a694a37 100644
--- a/dotnet/src/Generated/SessionEvents.cs
+++ b/dotnet/src/Generated/SessionEvents.cs
@@ -49,6 +49,7 @@ namespace GitHub.Copilot.SDK;
[JsonDerivedType(typeof(SessionCompactionCompleteEvent), "session.compaction_complete")]
[JsonDerivedType(typeof(SessionCompactionStartEvent), "session.compaction_start")]
[JsonDerivedType(typeof(SessionContextChangedEvent), "session.context_changed")]
+[JsonDerivedType(typeof(SessionCustomAgentsUpdatedEvent), "session.custom_agents_updated")]
[JsonDerivedType(typeof(SessionErrorEvent), "session.error")]
[JsonDerivedType(typeof(SessionExtensionsLoadedEvent), "session.extensions_loaded")]
[JsonDerivedType(typeof(SessionHandoffEvent), "session.handoff")]
@@ -978,6 +979,18 @@ public partial class SessionSkillsLoadedEvent : SessionEvent
public required SessionSkillsLoadedData Data { get; set; }
}
+/// Represents the session.custom_agents_updated event.
+public partial class SessionCustomAgentsUpdatedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "session.custom_agents_updated";
+
+ /// The session.custom_agents_updated event payload.
+ [JsonPropertyName("data")]
+ public required SessionCustomAgentsUpdatedData Data { get; set; }
+}
+
/// Represents the session.mcp_servers_loaded event.
public partial class SessionMcpServersLoadedEvent : SessionEvent
{
@@ -1954,6 +1967,11 @@ public partial class SkillInvokedData
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("pluginVersion")]
public string? PluginVersion { get; set; }
+
+ /// Description of the skill from its SKILL.md frontmatter.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("description")]
+ public string? Description { get; set; }
}
/// Sub-agent startup details including parent tool call and agent information.
@@ -1990,6 +2008,26 @@ public partial class SubagentCompletedData
/// Human-readable display name of the sub-agent.
[JsonPropertyName("agentDisplayName")]
public required string AgentDisplayName { get; set; }
+
+ /// Model used by the sub-agent.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
+ /// Total number of tool calls made by the sub-agent.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("totalToolCalls")]
+ public double? TotalToolCalls { get; set; }
+
+ /// Total tokens (input + output) consumed by the sub-agent.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("totalTokens")]
+ public double? TotalTokens { get; set; }
+
+ /// Wall-clock duration of the sub-agent execution in milliseconds.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("durationMs")]
+ public double? DurationMs { get; set; }
}
/// Sub-agent failure details including error message and agent information.
@@ -2010,6 +2048,26 @@ public partial class SubagentFailedData
/// Error message describing why the sub-agent failed.
[JsonPropertyName("error")]
public required string Error { get; set; }
+
+ /// Model used by the sub-agent (if any model calls succeeded before failure).
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
+ /// Total number of tool calls made before the sub-agent failed.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("totalToolCalls")]
+ public double? TotalToolCalls { get; set; }
+
+ /// Total tokens (input + output) consumed before the sub-agent failed.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("totalTokens")]
+ public double? TotalTokens { get; set; }
+
+ /// Wall-clock duration of the sub-agent execution in milliseconds.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("durationMs")]
+ public double? DurationMs { get; set; }
}
/// Custom agent selection details including name and available tools.
@@ -2387,6 +2445,22 @@ public partial class SessionSkillsLoadedData
public required SessionSkillsLoadedDataSkillsItem[] Skills { get; set; }
}
+/// Event payload for .
+public partial class SessionCustomAgentsUpdatedData
+{
+ /// Array of loaded custom agent metadata.
+ [JsonPropertyName("agents")]
+ public required SessionCustomAgentsUpdatedDataAgentsItem[] Agents { get; set; }
+
+ /// Non-fatal warnings from agent loading.
+ [JsonPropertyName("warnings")]
+ public required string[] Warnings { get; set; }
+
+ /// Fatal errors from agent loading.
+ [JsonPropertyName("errors")]
+ public required string[] Errors { get; set; }
+}
+
/// Event payload for .
public partial class SessionMcpServersLoadedData
{
@@ -3541,6 +3615,43 @@ public partial class SessionSkillsLoadedDataSkillsItem
public string? Path { get; set; }
}
+/// Nested data type for SessionCustomAgentsUpdatedDataAgentsItem.
+public partial class SessionCustomAgentsUpdatedDataAgentsItem
+{
+ /// Unique identifier for the agent.
+ [JsonPropertyName("id")]
+ public required string Id { get; set; }
+
+ /// Internal name of the agent.
+ [JsonPropertyName("name")]
+ public required string Name { get; set; }
+
+ /// Human-readable display name.
+ [JsonPropertyName("displayName")]
+ public required string DisplayName { get; set; }
+
+ /// Description of what the agent does.
+ [JsonPropertyName("description")]
+ public required string Description { get; set; }
+
+ /// Source location: user, project, inherited, remote, or plugin.
+ [JsonPropertyName("source")]
+ public required string Source { get; set; }
+
+ /// List of tool names available to this agent.
+ [JsonPropertyName("tools")]
+ public required string[] Tools { get; set; }
+
+ /// Whether the agent can be selected by the user.
+ [JsonPropertyName("userInvocable")]
+ public required bool UserInvocable { get; set; }
+
+ /// Model override for this agent, if set.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+}
+
/// Nested data type for SessionMcpServersLoadedDataServersItem.
public partial class SessionMcpServersLoadedDataServersItem
{
@@ -3898,6 +4009,9 @@ public enum SessionExtensionsLoadedDataExtensionsItemStatus
[JsonSerializable(typeof(SessionCompactionStartEvent))]
[JsonSerializable(typeof(SessionContextChangedData))]
[JsonSerializable(typeof(SessionContextChangedEvent))]
+[JsonSerializable(typeof(SessionCustomAgentsUpdatedData))]
+[JsonSerializable(typeof(SessionCustomAgentsUpdatedDataAgentsItem))]
+[JsonSerializable(typeof(SessionCustomAgentsUpdatedEvent))]
[JsonSerializable(typeof(SessionErrorData))]
[JsonSerializable(typeof(SessionErrorEvent))]
[JsonSerializable(typeof(SessionEvent))]
diff --git a/go/generated_session_events.go b/go/generated_session_events.go
index 591ff53af..b9cdbab47 100644
--- a/go/generated_session_events.go
+++ b/go/generated_session_events.go
@@ -657,6 +657,10 @@ type Data struct {
// Model identifier used for this API call
//
// Model identifier that generated this tool call
+ //
+ // Model used by the sub-agent
+ //
+ // Model used by the sub-agent (if any model calls succeeded before failure)
Model *string `json:"model,omitempty"`
// Per-quota resource usage snapshots, keyed by quota identifier
QuotaSnapshots map[string]QuotaSnapshot `json:"quotaSnapshots,omitempty"`
@@ -710,6 +714,8 @@ type Data struct {
ToolTelemetry map[string]interface{} `json:"toolTelemetry,omitempty"`
// Tool names that should be auto-approved when this skill is active
AllowedTools []string `json:"allowedTools,omitempty"`
+ // Description of the skill from its SKILL.md frontmatter
+ Description *string `json:"description,omitempty"`
// Name of the invoked skill
//
// Optional name identifier for the message source
@@ -728,6 +734,16 @@ type Data struct {
//
// Internal name of the selected custom agent
AgentName *string `json:"agentName,omitempty"`
+ // Wall-clock duration of the sub-agent execution in milliseconds
+ DurationMS *float64 `json:"durationMs,omitempty"`
+ // Total tokens (input + output) consumed by the sub-agent
+ //
+ // Total tokens (input + output) consumed before the sub-agent failed
+ TotalTokens *float64 `json:"totalTokens,omitempty"`
+ // Total number of tool calls made by the sub-agent
+ //
+ // Total number of tool calls made before the sub-agent failed
+ TotalToolCalls *float64 `json:"totalToolCalls,omitempty"`
// List of tool names available to this agent, or null for all tools
Tools []string `json:"tools"`
// Unique identifier for this hook invocation
@@ -793,6 +809,12 @@ type Data struct {
RecommendedAction *string `json:"recommendedAction,omitempty"`
// Array of resolved skill metadata
Skills []Skill `json:"skills,omitempty"`
+ // Array of loaded custom agent metadata
+ Agents []DataAgent `json:"agents,omitempty"`
+ // Fatal errors from agent loading
+ Errors []string `json:"errors,omitempty"`
+ // Non-fatal warnings from agent loading
+ Warnings []string `json:"warnings,omitempty"`
// Array of MCP server status summaries
Servers []Server `json:"servers,omitempty"`
// New connection status: connected, failed, pending, disabled, or not_configured
@@ -801,6 +823,25 @@ type Data struct {
Extensions []Extension `json:"extensions,omitempty"`
}
+type DataAgent struct {
+ // Description of what the agent does
+ Description string `json:"description"`
+ // Human-readable display name
+ DisplayName string `json:"displayName"`
+ // Unique identifier for the agent
+ ID string `json:"id"`
+ // Model override for this agent, if set
+ Model *string `json:"model,omitempty"`
+ // Internal name of the agent
+ Name string `json:"name"`
+ // Source location: user, project, inherited, remote, or plugin
+ Source string `json:"source"`
+ // List of tool names available to this agent
+ Tools []string `json:"tools"`
+ // Whether the agent can be selected by the user
+ UserInvocable bool `json:"userInvocable"`
+}
+
// A user message attachment — a file, directory, code selection, blob, or GitHub reference
//
// # File attachment
@@ -882,13 +923,13 @@ type Start struct {
// Background tasks still running when the agent became idle
type BackgroundTasks struct {
// Currently running background agents
- Agents []Agent `json:"agents"`
+ Agents []BackgroundTasksAgent `json:"agents"`
// Currently running background shell commands
Shells []Shell `json:"shells"`
}
// A background agent task
-type Agent struct {
+type BackgroundTasksAgent struct {
// Unique identifier of the background agent
AgentID string `json:"agentId"`
// Type of the background agent
@@ -1553,6 +1594,7 @@ const (
SessionEventTypeSessionCompactionComplete SessionEventType = "session.compaction_complete"
SessionEventTypeSessionCompactionStart SessionEventType = "session.compaction_start"
SessionEventTypeSessionContextChanged SessionEventType = "session.context_changed"
+ SessionEventTypeSessionCustomAgentsUpdated SessionEventType = "session.custom_agents_updated"
SessionEventTypeSessionError SessionEventType = "session.error"
SessionEventTypeSessionExtensionsLoaded SessionEventType = "session.extensions_loaded"
SessionEventTypeSessionHandoff SessionEventType = "session.handoff"
diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json
index d0d1398b2..42d9b6fb6 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.11-1",
+ "@github/copilot": "^1.0.11",
"vscode-jsonrpc": "^8.2.1",
"zod": "^4.3.6"
},
@@ -662,26 +662,26 @@
}
},
"node_modules/@github/copilot": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.11-1.tgz",
- "integrity": "sha512-W34C5TLJxE3SvB/TTt//LBNUbxNZV0tuobWUjBG7TnKQ4HHuJSzvQDE9dtxSfXlVyIzhoPgVYo0cOnN1cITfAA==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.11.tgz",
+ "integrity": "sha512-cptVopko/tNKEXyBP174yBjHQBEwg6CqaKN2S0M3J+5LEB8u31bLL75ioOPd+5vubqBrA0liyTdcHeZ8UTRbmg==",
"license": "SEE LICENSE IN LICENSE.md",
"bin": {
"copilot": "npm-loader.js"
},
"optionalDependencies": {
- "@github/copilot-darwin-arm64": "1.0.11-1",
- "@github/copilot-darwin-x64": "1.0.11-1",
- "@github/copilot-linux-arm64": "1.0.11-1",
- "@github/copilot-linux-x64": "1.0.11-1",
- "@github/copilot-win32-arm64": "1.0.11-1",
- "@github/copilot-win32-x64": "1.0.11-1"
+ "@github/copilot-darwin-arm64": "1.0.11",
+ "@github/copilot-darwin-x64": "1.0.11",
+ "@github/copilot-linux-arm64": "1.0.11",
+ "@github/copilot-linux-x64": "1.0.11",
+ "@github/copilot-win32-arm64": "1.0.11",
+ "@github/copilot-win32-x64": "1.0.11"
}
},
"node_modules/@github/copilot-darwin-arm64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.11-1.tgz",
- "integrity": "sha512-VVL6qgV0MqWfi0Lh5xNuydgqq+QEWty8kXVq9gTHhu9RtVIxMjqF9Ay5IkiKTZf6lijTdMOdlRW6ds90dHQKtQ==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.11.tgz",
+ "integrity": "sha512-wdKimjtbsVeXqMqQSnGpGBPFEYHljxXNuWeH8EIJTNRgFpAsimcivsFgql3Twq4YOp0AxfsH36icG4IEen30mA==",
"cpu": [
"arm64"
],
@@ -695,9 +695,9 @@
}
},
"node_modules/@github/copilot-darwin-x64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.11-1.tgz",
- "integrity": "sha512-nHatPin4ZRUmNnSyZ0Vir32M/yWF5fg0IYCT3HOxJCvDxAe60P86FBMWIW5oH4BFWqLB37Vs/XUc5WK08miaLw==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.11.tgz",
+ "integrity": "sha512-VeuPv8rzBVGBB8uDwMEhcHBpldoKaq26yZ5YQm+G9Ka5QIF+1DMah8ZNRMVsTeNKkb1ji9G8vcuCsaPbnG3fKg==",
"cpu": [
"x64"
],
@@ -711,9 +711,9 @@
}
},
"node_modules/@github/copilot-linux-arm64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.11-1.tgz",
- "integrity": "sha512-Ybdb+gzJMKi8+poa+3XQGKPubgh6/LPJFkzhOumKdi/Jf1yOB3QmDXVltjuKbgaav4RZS+Gq8OvfdH4DL987SQ==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.11.tgz",
+ "integrity": "sha512-/d8p6RlFYKj1Va2hekFIcYNMHWagcEkaxgcllUNXSyQLnmEtXUkaWtz62VKGWE+n/UMkEwCB6vI2xEwPTlUNBQ==",
"cpu": [
"arm64"
],
@@ -727,9 +727,9 @@
}
},
"node_modules/@github/copilot-linux-x64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.11-1.tgz",
- "integrity": "sha512-dXwxh9FkheEeeKV8mSW1JGmjjAb7ntE7zoc6GXJJaS1L91QcrfkZag6gbG3fdc2X9hwNZMUCRbVX2meqQidrIg==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.11.tgz",
+ "integrity": "sha512-UujTRO3xkPFC1CybchBbCnaTEAG6JrH0etIst07JvfekMWgvRxbiCHQPpDPSzBCPiBcGu0gba0/IT+vUCORuIw==",
"cpu": [
"x64"
],
@@ -743,9 +743,9 @@
}
},
"node_modules/@github/copilot-win32-arm64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.11-1.tgz",
- "integrity": "sha512-YEcACVYSfn2mc+xR+OBSX8XM5HvXMuFIF3NixfswEFzqJBMhHAj9ECtsdAkgG2QEFL8vLkOdpcVwbXqvdu4jxA==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.11.tgz",
+ "integrity": "sha512-EOW8HUM+EmnHEZEa+iUMl4pP1+2eZUk2XCbynYiMehwX9sidc4BxEHp2RuxADSzFPTieQEWzgjQmHWrtet8pQg==",
"cpu": [
"arm64"
],
@@ -759,9 +759,9 @@
}
},
"node_modules/@github/copilot-win32-x64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.11-1.tgz",
- "integrity": "sha512-5YsCGeIDC62z7oQbWRjioBOX71JODYeYNif1PrJu2mUavCMuxHdt5/ZasLfX92HZpv+3zIrWTVnNUAaBVPKYlQ==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.11.tgz",
+ "integrity": "sha512-fKGkSNamzs3h9AbmswNvPYJBORCb2Y8CbusijU3C7fT3ohvqnHJwKo5iHhJXLOKZNOpFZgq9YKha410u9sIs6Q==",
"cpu": [
"x64"
],
diff --git a/nodejs/package.json b/nodejs/package.json
index 20525385d..4ccda703d 100644
--- a/nodejs/package.json
+++ b/nodejs/package.json
@@ -56,7 +56,7 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
- "@github/copilot": "^1.0.11-1",
+ "@github/copilot": "^1.0.11",
"vscode-jsonrpc": "^8.2.1",
"zod": "^4.3.6"
},
diff --git a/nodejs/samples/package-lock.json b/nodejs/samples/package-lock.json
index a05be5360..cd2ce2305 100644
--- a/nodejs/samples/package-lock.json
+++ b/nodejs/samples/package-lock.json
@@ -18,7 +18,7 @@
"version": "0.1.8",
"license": "MIT",
"dependencies": {
- "@github/copilot": "^1.0.10",
+ "@github/copilot": "^1.0.11",
"vscode-jsonrpc": "^8.2.1",
"zod": "^4.3.6"
},
diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts
index 3453f0191..91dc023e9 100644
--- a/nodejs/src/generated/session-events.ts
+++ b/nodejs/src/generated/session-events.ts
@@ -2124,6 +2124,10 @@ export type SessionEvent =
* Version of the plugin this skill originated from, when applicable
*/
pluginVersion?: string;
+ /**
+ * Description of the skill from its SKILL.md frontmatter
+ */
+ description?: string;
};
}
| {
@@ -2200,6 +2204,22 @@ export type SessionEvent =
* Human-readable display name of the sub-agent
*/
agentDisplayName: string;
+ /**
+ * Model used by the sub-agent
+ */
+ model?: string;
+ /**
+ * Total number of tool calls made by the sub-agent
+ */
+ totalToolCalls?: number;
+ /**
+ * Total tokens (input + output) consumed by the sub-agent
+ */
+ totalTokens?: number;
+ /**
+ * Wall-clock duration of the sub-agent execution in milliseconds
+ */
+ durationMs?: number;
};
}
| {
@@ -2240,6 +2260,22 @@ export type SessionEvent =
* Error message describing why the sub-agent failed
*/
error: string;
+ /**
+ * Model used by the sub-agent (if any model calls succeeded before failure)
+ */
+ model?: string;
+ /**
+ * Total number of tool calls made before the sub-agent failed
+ */
+ totalToolCalls?: number;
+ /**
+ * Total tokens (input + output) consumed before the sub-agent failed
+ */
+ totalTokens?: number;
+ /**
+ * Wall-clock duration of the sub-agent execution in milliseconds
+ */
+ durationMs?: number;
};
}
| {
@@ -3400,6 +3436,69 @@ export type SessionEvent =
}[];
};
}
+ | {
+ /**
+ * Unique event identifier (UUID v4), generated when the event is emitted
+ */
+ id: string;
+ /**
+ * ISO 8601 timestamp when the event was created
+ */
+ timestamp: string;
+ /**
+ * ID of the chronologically preceding event in the session, forming a linked chain. Null for the first event.
+ */
+ parentId: string | null;
+ ephemeral: true;
+ type: "session.custom_agents_updated";
+ data: {
+ /**
+ * Array of loaded custom agent metadata
+ */
+ agents: {
+ /**
+ * Unique identifier for the agent
+ */
+ id: string;
+ /**
+ * Internal name of the agent
+ */
+ name: string;
+ /**
+ * Human-readable display name
+ */
+ displayName: string;
+ /**
+ * Description of what the agent does
+ */
+ description: string;
+ /**
+ * Source location: user, project, inherited, remote, or plugin
+ */
+ source: string;
+ /**
+ * List of tool names available to this agent
+ */
+ tools: string[];
+ /**
+ * Whether the agent can be selected by the user
+ */
+ userInvocable: boolean;
+ /**
+ * Model override for this agent, if set
+ */
+ model?: string;
+ }[];
+ /**
+ * Non-fatal warnings from agent loading
+ */
+ warnings: string[];
+ /**
+ * Fatal errors from agent loading
+ */
+ errors: string[];
+ };
+ }
| {
/**
* Unique event identifier (UUID v4), generated when the event is emitted
diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py
index 9701a4d9f..9143c9b0b 100644
--- a/python/copilot/generated/session_events.py
+++ b/python/copilot/generated/session_events.py
@@ -5,8 +5,7 @@
from enum import Enum
from dataclasses import dataclass
-from typing import Any, TypeVar, cast
-from collections.abc import Callable
+from typing import Any, TypeVar, Callable, cast
from datetime import datetime
from uuid import UUID
import dateutil.parser
@@ -16,23 +15,18 @@
EnumT = TypeVar("EnumT", bound=Enum)
-def from_float(x: Any) -> float:
- assert isinstance(x, (float, int)) and not isinstance(x, bool)
- return float(x)
-
-
-def to_float(x: Any) -> float:
- assert isinstance(x, (int, float))
+def from_str(x: Any) -> str:
+ assert isinstance(x, str)
return x
-def to_class(c: type[T], x: Any) -> dict:
- assert isinstance(x, c)
- return cast(Any, x).to_dict()
+def from_list(f: Callable[[Any], T], x: Any) -> list[T]:
+ assert isinstance(x, list)
+ return [f(y) for y in x]
-def from_str(x: Any) -> str:
- assert isinstance(x, str)
+def from_bool(x: Any) -> bool:
+ assert isinstance(x, bool)
return x
@@ -50,14 +44,24 @@ def from_union(fs, x):
assert False
-def to_enum(c: type[EnumT], x: Any) -> EnumT:
+def from_float(x: Any) -> float:
+ assert isinstance(x, (float, int)) and not isinstance(x, bool)
+ return float(x)
+
+
+def to_float(x: Any) -> float:
+ assert isinstance(x, (int, float))
+ return x
+
+
+def to_class(c: type[T], x: Any) -> dict:
assert isinstance(x, c)
- return x.value
+ return cast(Any, x).to_dict()
-def from_list(f: Callable[[Any], T], x: Any) -> list[T]:
- assert isinstance(x, list)
- return [f(y) for y in x]
+def to_enum(c: type[EnumT], x: Any) -> EnumT:
+ assert isinstance(x, c)
+ return x.value
def from_dict(f: Callable[[Any], T], x: Any) -> dict[str, T]:
@@ -65,11 +69,6 @@ def from_dict(f: Callable[[Any], T], x: Any) -> dict[str, T]:
return { k: f(v) for (k, v) in x.items() }
-def from_bool(x: Any) -> bool:
- assert isinstance(x, bool)
- return x
-
-
def from_datetime(x: Any) -> datetime:
return dateutil.parser.parse(x)
@@ -88,6 +87,59 @@ class AgentMode(Enum):
SHELL = "shell"
+@dataclass
+class DataAgent:
+ description: str
+ """Description of what the agent does"""
+
+ display_name: str
+ """Human-readable display name"""
+
+ id: str
+ """Unique identifier for the agent"""
+
+ name: str
+ """Internal name of the agent"""
+
+ source: str
+ """Source location: user, project, inherited, remote, or plugin"""
+
+ tools: list[str]
+ """List of tool names available to this agent"""
+
+ user_invocable: bool
+ """Whether the agent can be selected by the user"""
+
+ model: str | None = None
+ """Model override for this agent, if set"""
+
+ @staticmethod
+ def from_dict(obj: Any) -> 'DataAgent':
+ assert isinstance(obj, dict)
+ description = from_str(obj.get("description"))
+ display_name = from_str(obj.get("displayName"))
+ id = from_str(obj.get("id"))
+ name = from_str(obj.get("name"))
+ source = from_str(obj.get("source"))
+ tools = from_list(from_str, obj.get("tools"))
+ user_invocable = from_bool(obj.get("userInvocable"))
+ model = from_union([from_str, from_none], obj.get("model"))
+ return DataAgent(description, display_name, id, name, source, tools, user_invocable, model)
+
+ def to_dict(self) -> dict:
+ result: dict = {}
+ result["description"] = from_str(self.description)
+ result["displayName"] = from_str(self.display_name)
+ result["id"] = from_str(self.id)
+ result["name"] = from_str(self.name)
+ result["source"] = from_str(self.source)
+ result["tools"] = from_list(from_str, self.tools)
+ result["userInvocable"] = from_bool(self.user_invocable)
+ if self.model is not None:
+ result["model"] = from_union([from_str, from_none], self.model)
+ return result
+
+
@dataclass
class LineRange:
"""Optional line range to scope the attachment to a specific section of the file"""
@@ -312,7 +364,7 @@ def to_dict(self) -> dict:
@dataclass
-class Agent:
+class BackgroundTasksAgent:
"""A background agent task"""
agent_id: str
@@ -325,12 +377,12 @@ class Agent:
"""Human-readable description of the agent task"""
@staticmethod
- def from_dict(obj: Any) -> 'Agent':
+ def from_dict(obj: Any) -> 'BackgroundTasksAgent':
assert isinstance(obj, dict)
agent_id = from_str(obj.get("agentId"))
agent_type = from_str(obj.get("agentType"))
description = from_union([from_str, from_none], obj.get("description"))
- return Agent(agent_id, agent_type, description)
+ return BackgroundTasksAgent(agent_id, agent_type, description)
def to_dict(self) -> dict:
result: dict = {}
@@ -370,7 +422,7 @@ def to_dict(self) -> dict:
class BackgroundTasks:
"""Background tasks still running when the agent became idle"""
- agents: list[Agent]
+ agents: list[BackgroundTasksAgent]
"""Currently running background agents"""
shells: list[Shell]
@@ -379,13 +431,13 @@ class BackgroundTasks:
@staticmethod
def from_dict(obj: Any) -> 'BackgroundTasks':
assert isinstance(obj, dict)
- agents = from_list(Agent.from_dict, obj.get("agents"))
+ agents = from_list(BackgroundTasksAgent.from_dict, obj.get("agents"))
shells = from_list(Shell.from_dict, obj.get("shells"))
return BackgroundTasks(agents, shells)
def to_dict(self) -> dict:
result: dict = {}
- result["agents"] = from_list(lambda x: to_class(Agent, x), self.agents)
+ result["agents"] = from_list(lambda x: to_class(BackgroundTasksAgent, x), self.agents)
result["shells"] = from_list(lambda x: to_class(Shell, x), self.shells)
return result
@@ -2283,6 +2335,10 @@ class Data:
"""Model identifier used for this API call
Model identifier that generated this tool call
+
+ Model used by the sub-agent
+
+ Model used by the sub-agent (if any model calls succeeded before failure)
"""
quota_snapshots: dict[str, QuotaSnapshot] | None = None
"""Per-quota resource usage snapshots, keyed by quota identifier"""
@@ -2349,6 +2405,9 @@ class Data:
allowed_tools: list[str] | None = None
"""Tool names that should be auto-approved when this skill is active"""
+ description: str | None = None
+ """Description of the skill from its SKILL.md frontmatter"""
+
name: str | None = None
"""Name of the invoked skill
@@ -2373,6 +2432,19 @@ class Data:
Internal name of the selected custom agent
"""
+ duration_ms: float | None = None
+ """Wall-clock duration of the sub-agent execution in milliseconds"""
+
+ total_tokens: float | None = None
+ """Total tokens (input + output) consumed by the sub-agent
+
+ Total tokens (input + output) consumed before the sub-agent failed
+ """
+ total_tool_calls: float | None = None
+ """Total number of tool calls made by the sub-agent
+
+ Total number of tool calls made before the sub-agent failed
+ """
tools: list[str] | None = None
"""List of tool names available to this agent, or null for all tools"""
@@ -2466,6 +2538,15 @@ class Data:
skills: list[Skill] | None = None
"""Array of resolved skill metadata"""
+ agents: list[DataAgent] | None = None
+ """Array of loaded custom agent metadata"""
+
+ errors: list[str] | None = None
+ """Fatal errors from agent loading"""
+
+ warnings: list[str] | None = None
+ """Non-fatal warnings from agent loading"""
+
servers: list[Server] | None = None
"""Array of MCP server status summaries"""
@@ -2595,12 +2676,16 @@ def from_dict(obj: Any) -> 'Data':
result = from_union([Result.from_dict, from_none], obj.get("result"))
tool_telemetry = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("toolTelemetry"))
allowed_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("allowedTools"))
+ description = from_union([from_str, from_none], obj.get("description"))
name = from_union([from_str, from_none], obj.get("name"))
plugin_name = from_union([from_str, from_none], obj.get("pluginName"))
plugin_version = from_union([from_str, from_none], obj.get("pluginVersion"))
agent_description = from_union([from_str, from_none], obj.get("agentDescription"))
agent_display_name = from_union([from_str, from_none], obj.get("agentDisplayName"))
agent_name = from_union([from_str, from_none], obj.get("agentName"))
+ duration_ms = from_union([from_float, from_none], obj.get("durationMs"))
+ total_tokens = from_union([from_float, from_none], obj.get("totalTokens"))
+ total_tool_calls = from_union([from_float, from_none], obj.get("totalToolCalls"))
tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools"))
hook_invocation_id = from_union([from_str, from_none], obj.get("hookInvocationId"))
hook_type = from_union([from_str, from_none], obj.get("hookType"))
@@ -2629,10 +2714,13 @@ def from_dict(obj: Any) -> 'Data':
plan_content = from_union([from_str, from_none], obj.get("planContent"))
recommended_action = from_union([from_str, from_none], obj.get("recommendedAction"))
skills = from_union([lambda x: from_list(Skill.from_dict, x), from_none], obj.get("skills"))
+ agents = from_union([lambda x: from_list(DataAgent.from_dict, x), from_none], obj.get("agents"))
+ errors = from_union([lambda x: from_list(from_str, x), from_none], obj.get("errors"))
+ warnings = from_union([lambda x: from_list(from_str, x), from_none], obj.get("warnings"))
servers = from_union([lambda x: from_list(Server.from_dict, x), from_none], obj.get("servers"))
status = from_union([ServerStatus, from_none], obj.get("status"))
extensions = from_union([lambda x: from_list(Extension.from_dict, x), from_none], obj.get("extensions"))
- return Data(already_in_use, context, copilot_version, producer, reasoning_effort, selected_model, session_id, start_time, version, event_count, resume_time, error_type, message, provider_call_id, stack, status_code, url, background_tasks, title, info_type, warning_type, new_model, previous_model, previous_reasoning_effort, new_mode, previous_mode, operation, path, handoff_time, 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, model, quota_snapshots, reason, arguments, tool_call_id, tool_name, mcp_server_name, mcp_tool_name, partial_output, progress_message, is_user_requested, result, tool_telemetry, allowed_tools, name, plugin_name, plugin_version, agent_description, agent_display_name, agent_name, tools, hook_invocation_id, hook_type, input, output, metadata, role, kind, permission_request, allow_freeform, choices, question, elicitation_source, mode, requested_schema, server_name, server_url, static_client_config, traceparent, tracestate, command, args, command_name, commands, actions, plan_content, recommended_action, skills, servers, status, extensions)
+ return Data(already_in_use, context, copilot_version, producer, reasoning_effort, selected_model, session_id, start_time, version, event_count, resume_time, error_type, message, provider_call_id, stack, status_code, url, background_tasks, title, info_type, warning_type, new_model, previous_model, previous_reasoning_effort, new_mode, previous_mode, operation, path, handoff_time, 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, model, quota_snapshots, reason, arguments, tool_call_id, tool_name, mcp_server_name, mcp_tool_name, partial_output, progress_message, is_user_requested, result, tool_telemetry, allowed_tools, 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, server_name, server_url, static_client_config, traceparent, tracestate, command, args, command_name, commands, actions, plan_content, recommended_action, skills, agents, errors, warnings, servers, status, extensions)
def to_dict(self) -> dict:
result: dict = {}
@@ -2870,6 +2958,8 @@ def to_dict(self) -> dict:
result["toolTelemetry"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.tool_telemetry)
if self.allowed_tools is not None:
result["allowedTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.allowed_tools)
+ if self.description is not None:
+ result["description"] = from_union([from_str, from_none], self.description)
if self.name is not None:
result["name"] = from_union([from_str, from_none], self.name)
if self.plugin_name is not None:
@@ -2882,6 +2972,12 @@ def to_dict(self) -> dict:
result["agentDisplayName"] = from_union([from_str, from_none], self.agent_display_name)
if self.agent_name is not None:
result["agentName"] = from_union([from_str, from_none], self.agent_name)
+ if self.duration_ms is not None:
+ result["durationMs"] = from_union([to_float, from_none], self.duration_ms)
+ if self.total_tokens is not None:
+ result["totalTokens"] = from_union([to_float, from_none], self.total_tokens)
+ if self.total_tool_calls is not None:
+ result["totalToolCalls"] = from_union([to_float, from_none], self.total_tool_calls)
if self.tools is not None:
result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools)
if self.hook_invocation_id is not None:
@@ -2938,6 +3034,12 @@ def to_dict(self) -> dict:
result["recommendedAction"] = from_union([from_str, from_none], self.recommended_action)
if self.skills is not None:
result["skills"] = from_union([lambda x: from_list(lambda x: to_class(Skill, x), x), from_none], self.skills)
+ if self.agents is not None:
+ result["agents"] = from_union([lambda x: from_list(lambda x: to_class(DataAgent, x), x), from_none], self.agents)
+ if self.errors is not None:
+ result["errors"] = from_union([lambda x: from_list(from_str, x), from_none], self.errors)
+ if self.warnings is not None:
+ result["warnings"] = from_union([lambda x: from_list(from_str, x), from_none], self.warnings)
if self.servers is not None:
result["servers"] = from_union([lambda x: from_list(lambda x: to_class(Server, x), x), from_none], self.servers)
if self.status is not None:
@@ -2979,6 +3081,7 @@ class SessionEventType(Enum):
SESSION_COMPACTION_COMPLETE = "session.compaction_complete"
SESSION_COMPACTION_START = "session.compaction_start"
SESSION_CONTEXT_CHANGED = "session.context_changed"
+ SESSION_CUSTOM_AGENTS_UPDATED = "session.custom_agents_updated"
SESSION_ERROR = "session.error"
SESSION_EXTENSIONS_LOADED = "session.extensions_loaded"
SESSION_HANDOFF = "session.handoff"
diff --git a/test/harness/package-lock.json b/test/harness/package-lock.json
index 66616150f..5ab4ae513 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.11-1",
+ "@github/copilot": "^1.0.11",
"@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.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.11-1.tgz",
- "integrity": "sha512-W34C5TLJxE3SvB/TTt//LBNUbxNZV0tuobWUjBG7TnKQ4HHuJSzvQDE9dtxSfXlVyIzhoPgVYo0cOnN1cITfAA==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.11.tgz",
+ "integrity": "sha512-cptVopko/tNKEXyBP174yBjHQBEwg6CqaKN2S0M3J+5LEB8u31bLL75ioOPd+5vubqBrA0liyTdcHeZ8UTRbmg==",
"dev": true,
"license": "SEE LICENSE IN LICENSE.md",
"bin": {
"copilot": "npm-loader.js"
},
"optionalDependencies": {
- "@github/copilot-darwin-arm64": "1.0.11-1",
- "@github/copilot-darwin-x64": "1.0.11-1",
- "@github/copilot-linux-arm64": "1.0.11-1",
- "@github/copilot-linux-x64": "1.0.11-1",
- "@github/copilot-win32-arm64": "1.0.11-1",
- "@github/copilot-win32-x64": "1.0.11-1"
+ "@github/copilot-darwin-arm64": "1.0.11",
+ "@github/copilot-darwin-x64": "1.0.11",
+ "@github/copilot-linux-arm64": "1.0.11",
+ "@github/copilot-linux-x64": "1.0.11",
+ "@github/copilot-win32-arm64": "1.0.11",
+ "@github/copilot-win32-x64": "1.0.11"
}
},
"node_modules/@github/copilot-darwin-arm64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.11-1.tgz",
- "integrity": "sha512-VVL6qgV0MqWfi0Lh5xNuydgqq+QEWty8kXVq9gTHhu9RtVIxMjqF9Ay5IkiKTZf6lijTdMOdlRW6ds90dHQKtQ==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.11.tgz",
+ "integrity": "sha512-wdKimjtbsVeXqMqQSnGpGBPFEYHljxXNuWeH8EIJTNRgFpAsimcivsFgql3Twq4YOp0AxfsH36icG4IEen30mA==",
"cpu": [
"arm64"
],
@@ -497,9 +497,9 @@
}
},
"node_modules/@github/copilot-darwin-x64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.11-1.tgz",
- "integrity": "sha512-nHatPin4ZRUmNnSyZ0Vir32M/yWF5fg0IYCT3HOxJCvDxAe60P86FBMWIW5oH4BFWqLB37Vs/XUc5WK08miaLw==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.11.tgz",
+ "integrity": "sha512-VeuPv8rzBVGBB8uDwMEhcHBpldoKaq26yZ5YQm+G9Ka5QIF+1DMah8ZNRMVsTeNKkb1ji9G8vcuCsaPbnG3fKg==",
"cpu": [
"x64"
],
@@ -514,9 +514,9 @@
}
},
"node_modules/@github/copilot-linux-arm64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.11-1.tgz",
- "integrity": "sha512-Ybdb+gzJMKi8+poa+3XQGKPubgh6/LPJFkzhOumKdi/Jf1yOB3QmDXVltjuKbgaav4RZS+Gq8OvfdH4DL987SQ==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.11.tgz",
+ "integrity": "sha512-/d8p6RlFYKj1Va2hekFIcYNMHWagcEkaxgcllUNXSyQLnmEtXUkaWtz62VKGWE+n/UMkEwCB6vI2xEwPTlUNBQ==",
"cpu": [
"arm64"
],
@@ -531,9 +531,9 @@
}
},
"node_modules/@github/copilot-linux-x64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.11-1.tgz",
- "integrity": "sha512-dXwxh9FkheEeeKV8mSW1JGmjjAb7ntE7zoc6GXJJaS1L91QcrfkZag6gbG3fdc2X9hwNZMUCRbVX2meqQidrIg==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.11.tgz",
+ "integrity": "sha512-UujTRO3xkPFC1CybchBbCnaTEAG6JrH0etIst07JvfekMWgvRxbiCHQPpDPSzBCPiBcGu0gba0/IT+vUCORuIw==",
"cpu": [
"x64"
],
@@ -548,9 +548,9 @@
}
},
"node_modules/@github/copilot-win32-arm64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.11-1.tgz",
- "integrity": "sha512-YEcACVYSfn2mc+xR+OBSX8XM5HvXMuFIF3NixfswEFzqJBMhHAj9ECtsdAkgG2QEFL8vLkOdpcVwbXqvdu4jxA==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.11.tgz",
+ "integrity": "sha512-EOW8HUM+EmnHEZEa+iUMl4pP1+2eZUk2XCbynYiMehwX9sidc4BxEHp2RuxADSzFPTieQEWzgjQmHWrtet8pQg==",
"cpu": [
"arm64"
],
@@ -565,9 +565,9 @@
}
},
"node_modules/@github/copilot-win32-x64": {
- "version": "1.0.11-1",
- "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.11-1.tgz",
- "integrity": "sha512-5YsCGeIDC62z7oQbWRjioBOX71JODYeYNif1PrJu2mUavCMuxHdt5/ZasLfX92HZpv+3zIrWTVnNUAaBVPKYlQ==",
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.11.tgz",
+ "integrity": "sha512-fKGkSNamzs3h9AbmswNvPYJBORCb2Y8CbusijU3C7fT3ohvqnHJwKo5iHhJXLOKZNOpFZgq9YKha410u9sIs6Q==",
"cpu": [
"x64"
],
diff --git a/test/harness/package.json b/test/harness/package.json
index 99dcb464a..9fe936ea7 100644
--- a/test/harness/package.json
+++ b/test/harness/package.json
@@ -11,7 +11,7 @@
"test": "vitest run"
},
"devDependencies": {
- "@github/copilot": "^1.0.11-1",
+ "@github/copilot": "^1.0.11",
"@modelcontextprotocol/sdk": "^1.26.0",
"@types/node": "^25.3.3",
"openai": "^6.17.0",