feat: add chat summary tab in the right sidebar and per-chat cost endpoint (#26649)

Stacked on #26657 (the persisted whole-chat summary backend). Base
branch is `chat-summary-62j9`; review/merge that first.

Adds a reusable `ChatSummary` component.

The summary text is the persisted whole-chat summary (`chat.summary`)
introduced by #26657. It is generated asynchronously and may be `null`
until the first summary is produced, in which case the popover renders a
muted empty state. Live updates arrive via that PR's
`chat_summary_change` watch event, which is already merged into the chat
caches.

Cost is served by a new per-chat endpoint, `GET
/api/experimental/chats/{chat}/cost`, which rolls up assistant-message
cost across a chat's root and child (subagent) chats and is authorized
like the other `{chat}` routes (read on the chat, 404 otherwise).

Visual and interaction coverage lives in `ChatSummary.stories.tsx` and
`ChatSummaryPopover.stories.tsx` (including populated-summary,
empty-state, and cost-loading cases).

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jaayden Halko
2026-07-27 10:05:05 +01:00
committed by GitHub
co-authored by Cursor
parent 88c7304e0b
commit 6f2011af88
38 changed files with 1744 additions and 87 deletions
+54
View File
@@ -580,6 +580,42 @@ const docTemplate = `{
]
}
},
"/api/experimental/chats/{chat}/cost": {
"get": {
"description": "Experimental: this endpoint is subject to change.",
"produces": [
"application/json"
],
"tags": [
"Chats"
],
"summary": "Get chat cost",
"operationId": "get-chat-cost",
"parameters": [
{
"type": "string",
"format": "uuid",
"description": "Chat ID",
"name": "chat",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/codersdk.ChatCost"
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/experimental/chats/{chat}/diff": {
"get": {
"description": "Experimental: this endpoint is subject to change.",
@@ -17271,6 +17307,24 @@ const docTemplate = `{
}
}
},
"codersdk.ChatCost": {
"type": "object",
"properties": {
"chat_id": {
"type": "string",
"format": "uuid"
},
"priced_message_count": {
"type": "integer"
},
"total_cost_micros": {
"type": "integer"
},
"unpriced_messages_having_usage_count": {
"type": "integer"
}
}
},
"codersdk.ChatDiffContents": {
"type": "object",
"properties": {