diff --git a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs
index 73079cc0..c2f7fa83 100644
--- a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs
+++ b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs
@@ -2011,6 +2011,14 @@ public sealed record SessionChatSummary
/// chat is not archived.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public bool? Archived { get; init; }
+
+ /// Aggregate summary of file changes associated with this chat.
+ ///
+ /// Servers may populate this so session lists can show per-chat change
+ /// counts without subscribing to the session or chat channel. Updates travel
+ /// with the rest of the catalog in `root/sessionSummaryChanged`.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public ChangesSummary? Changes { get; init; }
}
/// Aggregate counts describing the file changes associated with a session or
diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go
index fb84f563..5516b942 100644
--- a/clients/go/ahptypes/state.generated.go
+++ b/clients/go/ahptypes/state.generated.go
@@ -1219,6 +1219,12 @@ type SessionChatSummary struct {
// lists without subscribing to the session channel. Absence means the
// chat is not archived.
Archived *bool `json:"archived,omitempty"`
+ // Aggregate summary of file changes associated with this chat.
+ //
+ // Servers may populate this so session lists can show per-chat change
+ // counts without subscribing to the session or chat channel. Updates travel
+ // with the rest of the catalog in `root/sessionSummaryChanged`.
+ Changes *ChangesSummary `json:"changes,omitempty"`
}
// Aggregate counts describing the file changes associated with a session or
diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt
index 8fb7f0a4..55ee9ffd 100644
--- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt
+++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt
@@ -2179,7 +2179,15 @@ data class SessionChatSummary(
* lists without subscribing to the session channel. Absence means the
* chat is not archived.
*/
- val archived: Boolean? = null
+ val archived: Boolean? = null,
+ /**
+ * Aggregate summary of file changes associated with this chat.
+ *
+ * Servers may populate this so session lists can show per-chat change
+ * counts without subscribing to the session or chat channel. Updates travel
+ * with the rest of the catalog in `root/sessionSummaryChanged`.
+ */
+ val changes: ChangesSummary? = null
)
@Serializable
diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs
index 99547d09..6175e861 100644
--- a/clients/rust/crates/ahp-types/src/state.rs
+++ b/clients/rust/crates/ahp-types/src/state.rs
@@ -2470,6 +2470,13 @@ pub struct SessionChatSummary {
/// chat is not archived.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub archived: Option,
+ /// Aggregate summary of file changes associated with this chat.
+ ///
+ /// Servers may populate this so session lists can show per-chat change
+ /// counts without subscribing to the session or chat channel. Updates travel
+ /// with the rest of the catalog in `root/sessionSummaryChanged`.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub changes: Option,
}
/// Aggregate counts describing the file changes associated with a session or
diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift
index 6293a123..3a23761d 100644
--- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift
+++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift
@@ -2297,19 +2297,27 @@ public struct SessionChatSummary: Codable, Sendable {
/// lists without subscribing to the session channel. Absence means the
/// chat is not archived.
public var archived: Bool?
+ /// Aggregate summary of file changes associated with this chat.
+ ///
+ /// Servers may populate this so session lists can show per-chat change
+ /// counts without subscribing to the session or chat channel. Updates travel
+ /// with the rest of the catalog in `root/sessionSummaryChanged`.
+ public var changes: ChangesSummary?
public init(
resource: String,
title: String,
origin: ChatOrigin? = nil,
interactivity: ChatInteractivity? = nil,
- archived: Bool? = nil
+ archived: Bool? = nil,
+ changes: ChangesSummary? = nil
) {
self.resource = resource
self.title = title
self.origin = origin
self.interactivity = interactivity
self.archived = archived
+ self.changes = changes
}
}
diff --git a/docs/.changes/20261001-session-chat-summary-changes.json b/docs/.changes/20261001-session-chat-summary-changes.json
new file mode 100644
index 00000000..ba2e78d3
--- /dev/null
+++ b/docs/.changes/20261001-session-chat-summary-changes.json
@@ -0,0 +1,4 @@
+{
+ "type": "added",
+ "message": "`SessionChatSummary.changes` exposes per-chat change counts in the lightweight chat catalog without requiring a session subscription."
+}
diff --git a/schema/actions.schema.json b/schema/actions.schema.json
index 61ca03d6..d964ec9e 100644
--- a/schema/actions.schema.json
+++ b/schema/actions.schema.json
@@ -3698,6 +3698,10 @@
"archived": {
"type": "boolean",
"description": "Whether this chat has been archived independently of its owning session\n(see `chat/isArchivedChanged`).\n\nGeneric clients use this to group or filter archived chats in session\nlists without subscribing to the session channel. Absence means the\nchat is not archived."
+ },
+ "changes": {
+ "$ref": "#/$defs/ChangesSummary",
+ "description": "Aggregate summary of file changes associated with this chat.\n\nServers may populate this so session lists can show per-chat change\ncounts without subscribing to the session or chat channel. Updates travel\nwith the rest of the catalog in `root/sessionSummaryChanged`."
}
},
"required": [
diff --git a/schema/commands.schema.json b/schema/commands.schema.json
index 177cf399..62a11f8f 100644
--- a/schema/commands.schema.json
+++ b/schema/commands.schema.json
@@ -2964,6 +2964,10 @@
"archived": {
"type": "boolean",
"description": "Whether this chat has been archived independently of its owning session\n(see `chat/isArchivedChanged`).\n\nGeneric clients use this to group or filter archived chats in session\nlists without subscribing to the session channel. Absence means the\nchat is not archived."
+ },
+ "changes": {
+ "$ref": "#/$defs/ChangesSummary",
+ "description": "Aggregate summary of file changes associated with this chat.\n\nServers may populate this so session lists can show per-chat change\ncounts without subscribing to the session or chat channel. Updates travel\nwith the rest of the catalog in `root/sessionSummaryChanged`."
}
},
"required": [
diff --git a/schema/errors.schema.json b/schema/errors.schema.json
index 981b450f..9886f386 100644
--- a/schema/errors.schema.json
+++ b/schema/errors.schema.json
@@ -1236,6 +1236,10 @@
"archived": {
"type": "boolean",
"description": "Whether this chat has been archived independently of its owning session\n(see `chat/isArchivedChanged`).\n\nGeneric clients use this to group or filter archived chats in session\nlists without subscribing to the session channel. Absence means the\nchat is not archived."
+ },
+ "changes": {
+ "$ref": "#/$defs/ChangesSummary",
+ "description": "Aggregate summary of file changes associated with this chat.\n\nServers may populate this so session lists can show per-chat change\ncounts without subscribing to the session or chat channel. Updates travel\nwith the rest of the catalog in `root/sessionSummaryChanged`."
}
},
"required": [
diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json
index c7b6a199..608d4840 100644
--- a/schema/notifications.schema.json
+++ b/schema/notifications.schema.json
@@ -1414,6 +1414,10 @@
"archived": {
"type": "boolean",
"description": "Whether this chat has been archived independently of its owning session\n(see `chat/isArchivedChanged`).\n\nGeneric clients use this to group or filter archived chats in session\nlists without subscribing to the session channel. Absence means the\nchat is not archived."
+ },
+ "changes": {
+ "$ref": "#/$defs/ChangesSummary",
+ "description": "Aggregate summary of file changes associated with this chat.\n\nServers may populate this so session lists can show per-chat change\ncounts without subscribing to the session or chat channel. Updates travel\nwith the rest of the catalog in `root/sessionSummaryChanged`."
}
},
"required": [
diff --git a/schema/state.schema.json b/schema/state.schema.json
index 74b608dc..b3a94a4d 100644
--- a/schema/state.schema.json
+++ b/schema/state.schema.json
@@ -1147,6 +1147,10 @@
"archived": {
"type": "boolean",
"description": "Whether this chat has been archived independently of its owning session\n(see `chat/isArchivedChanged`).\n\nGeneric clients use this to group or filter archived chats in session\nlists without subscribing to the session channel. Absence means the\nchat is not archived."
+ },
+ "changes": {
+ "$ref": "#/$defs/ChangesSummary",
+ "description": "Aggregate summary of file changes associated with this chat.\n\nServers may populate this so session lists can show per-chat change\ncounts without subscribing to the session or chat channel. Updates travel\nwith the rest of the catalog in `root/sessionSummaryChanged`."
}
},
"required": [
diff --git a/types/channels-session/state.ts b/types/channels-session/state.ts
index d85c824c..cb3946dd 100644
--- a/types/channels-session/state.ts
+++ b/types/channels-session/state.ts
@@ -552,6 +552,14 @@ export interface SessionChatSummary {
* chat is not archived.
*/
archived?: boolean;
+ /**
+ * Aggregate summary of file changes associated with this chat.
+ *
+ * Servers may populate this so session lists can show per-chat change
+ * counts without subscribing to the session or chat channel. Updates travel
+ * with the rest of the catalog in `root/sessionSummaryChanged`.
+ */
+ changes?: ChangesSummary;
}
/**
diff --git a/types/test-cases/round-trips/051-session-chat-summary-changes-round-trip.json b/types/test-cases/round-trips/051-session-chat-summary-changes-round-trip.json
new file mode 100644
index 00000000..c7b81124
--- /dev/null
+++ b/types/test-cases/round-trips/051-session-chat-summary-changes-round-trip.json
@@ -0,0 +1,66 @@
+{
+ "name": "session-chat-summary-changes-round-trip",
+ "group": "A",
+ "description": "SessionSummary chat catalog entries preserve optional per-chat change counts so list clients can render them without subscribing to the session or chat channel.",
+ "type": "SessionSummary",
+ "input": {
+ "resource": "ahp-session:/s1",
+ "provider": "demo",
+ "title": "Agent team",
+ "status": 1,
+ "createdAt": "2024-01-01T00:00:00.001Z",
+ "modifiedAt": "2024-01-01T00:00:00.002Z",
+ "changes": {
+ "additions": 15,
+ "deletions": 4,
+ "files": 3
+ },
+ "chats": [
+ {
+ "resource": "ahp-chat:/lead",
+ "title": "Lead"
+ },
+ {
+ "resource": "ahp-chat:/worker",
+ "title": "Worker",
+ "changes": {
+ "additions": 12,
+ "deletions": 3,
+ "files": 2
+ }
+ }
+ ],
+ "defaultChat": "ahp-chat:/lead"
+ },
+ "acceptableOutputs": [
+ {
+ "resource": "ahp-session:/s1",
+ "provider": "demo",
+ "title": "Agent team",
+ "status": 1,
+ "createdAt": "2024-01-01T00:00:00.001Z",
+ "modifiedAt": "2024-01-01T00:00:00.002Z",
+ "changes": {
+ "additions": 15,
+ "deletions": 4,
+ "files": 3
+ },
+ "chats": [
+ {
+ "resource": "ahp-chat:/lead",
+ "title": "Lead"
+ },
+ {
+ "resource": "ahp-chat:/worker",
+ "title": "Worker",
+ "changes": {
+ "additions": 12,
+ "deletions": 3,
+ "files": 2
+ }
+ }
+ ],
+ "defaultChat": "ahp-chat:/lead"
+ }
+ ]
+}