Repository navigation
feat(cli): expose pageable agent usage HTTP API - #15205
Conversation
Add GET /kilocode/agent-usage/summary and GET /kilocode/agent-usage/runs so IDE clients can render one project-scoped agent usage history from the core aggregation instead of recomputing cost and duration. Runs page with an opaque cursor over (startedAt, id), applied as a keyset predicate in the aggregation SQL so pages stay stable while new runs arrive. Malformed cursors are rejected with a declared 400, and limit is bounded by the query schema. Summary ignores paging and always returns one rollup per agent. Regenerates the SDK with typed agentUsage.summary and agentUsage.runs clients.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge The prior suggestion is resolved: Files Reviewed (2 files)
Previous Review Summary (commit 3d118a2)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 3d118a2)Status: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)SUGGESTION
Files Reviewed (11 files)
Notes: the keyset predicate Reviewed by deepseek-v4.1-flash · Input: 39.9K · Output: 3.2K · Cached: 230.3K Review guidance: REVIEW.md from base branch |
Encode only (startedAt, id) so the opaque next token stays minimal even when callers pass a full run, and assert the token shape in the cursor test.
|
Tracked for the opencode v2 rewrite in #15253 ( |
Issue
No public issue. This is the HTTP/SDK layer over the aggregation already merged from #15185.
Context
The core now computes per-agent usage (runs, direct
step-finishcost, per-message active time, tokens, outcomes) from existingsession/message/partrows, but only the server process can reach it. IDE clients have no way to show "how much time and money did this agent spend, and on which sessions" without re-implementing the semantics client-side, which would let JetBrains and VS Code drift apart.This exposes that aggregation over the Kilo HTTP API so every client renders the same numbers, and regenerates the SDK so they can call it.
Implementation
Two new endpoints in a new Kilo-owned
agent-usagegroup, using the same instance-context, workspace-routing, and authorization middleware as the other Kilo groups:GET /kilocode/agent-usage/summary— one rollup per agent (agent,runs,sessions,cost,activeMs,tokens,errors,lastRunAt). Paging is deliberately ignored here.GET /kilocode/agent-usage/runs—{ items, next? }, newest first.Paging is keyset, not offset, so pages stay correct while runs are being written. The cursor is an opaque base64url token encoding the last item's
(startedAt, id), and it becomes a predicate in the aggregation SQL (startedAt < :s OR (startedAt = :s AND id < :i)) rather than a slice of a fully materialized list — a page costs onelimit + 1query, not a whole-project scan. The extra row only decides whethernextis returned; there is nonexton the last page.idis the run's first assistant message id, so two runs that start in the same millisecond still page individually.Errors follow the existing declared-error convention: a malformed or non-decodable cursor is a
400 InvalidRequestErrorwithfield: "cursor"(not a silent reset), andlimitis bounded by the query schema (1–100, default 50), so out-of-range values are rejected before the query runs. An unknown agent filter is an empty page with nonext, not an error.Nothing is recomputed in the HTTP layer: cost, active time, and outcome come straight from the aggregation, so propagated subagent cost is still never double-counted and idle time is still excluded. There is no new table, migration, config-schema, or
modechange; removing the endpoints restores prior behavior exactly.Screenshots / Video
N/A - no visual changes.
How to Test
Manual/local verification
Agent-run:
bun test ./test/kilocode/agent-usage ./test/kilocode/server/httpapi-agent-usage.test.tsfrompackages/opencode/— 14 passed, 0 failed (51 assertions). Covers keyset paging, same-timestamp tiebreaking, cursor round-trip/rejection, per-agent summary rollups, a full paging sweep that inserts a new run between pages and asserts every pre-insert run appears exactly once, unknown-agent empty page, malformed cursor400, andlimitbounds400.bun run typecheckfrompackages/opencode/— passed.bun run script/httpapi-exercise.ts --mode coverage --fail-on-missing --fail-on-skip— 336 pass, 0 fail, 0 missing (includes both new routes).bun run script/httpapi-exercise.ts --mode auth --fail-on-missing --fail-on-skip— 336 pass, 0 fail; both routes return401without credentials.bun run script/httpapi-exercise.ts --mode effect --fail-on-missing --fail-on-skip --shards 4— all shards passed; both routes execute against the real handler.bun run script/check-opencode-annotations.ts --worktree— passed.bun run lint— 0 errors; no new warnings in the added files../script/generate.ts— regeneratedpackages/sdk/openapi.jsonandsrc/v2/genwithagentUsage.summary/agentUsage.runs.Reviewer test steps
packages/opencode/, runbun run dev serveagainst a project with some agent history.curl 'http://127.0.0.1:<port>/kilocode/agent-usage/summary?directory=<project>'and confirm one row per agent.curl 'http://127.0.0.1:<port>/kilocode/agent-usage/runs?directory=<project>&limit=1', then page with the returnednext; confirm runs appear newest-first with no repeats.curl '.../kilocode/agent-usage/runs?cursor=not-a-cursor'and confirm a400.Blocked checks and substitute verification
No blocked checks.
Checklist
No changeset: additive internal API with no user-facing behavior change.
Get in Touch