Skip to content

perf(sessions): clip task in the query, not after SELECT * (v0.292.4) - #535

Merged
vikasprogrammer merged 1 commit into
mainfrom
feat/sessions-substr
Aug 3, 2026
Merged

perf(sessions): clip task in the query, not after SELECT * (v0.292.4)#535
vikasprogrammer merged 1 commit into
mainfrom
feat/sessions-substr

Conversation

@vikasprogrammer

Copy link
Copy Markdown
Owner

Problem

GET /api/sessions has shipped task clipped to LIST_CLIP (240) since #525 — but the server still SELECT *'d every session's full prompt out of SQLite first, only for server.ts to clip it. On instawp that's up to 53 KB per row, 2.1 MB materialised per poll, every 1.5 s, per tab. #530/#532 killed the bytes on the wire and the client render; this cuts the server-side materialisation that #533 left as the remaining SELECT * cost.

Change

listSessions/listArchivedSessions take an optional taskClip. The list endpoint passes LIST_CLIP; the SELECT then projects substr(task,1,241) AS task via a schema-derived column list (PRAGMA table_info, cached), so SQLite stops materialising the overflow text. Internal callers that read the whole prompt (sessionsForAgent → the session-detail "other runs" meta + search; the Cockpit workspace context) pass no clip and keep the full SELECT *.

clipText in the handler is untouched — it now runs as the ellipsis-preserving finisher on the ≤241-char string, so the wire output is byte-identical to before.

Measured (live instawp snapshot, 950 rows)

before after
task bytes materialised 2.10 MB 201 KB
raw query 5.23 ms 3.53 ms (−33%)
full listSessions(owner) 13.3 ms 11.1 ms (−17%)
max task len fetched 53,581 243

Plus ~1.9 MB less string allocation per 1.5 s tick.

Verification

  • Byte-equivalence of task output vs the old SELECT *+clipText path across all 950 rows (746 of them >240 chars, all retain the ellipsis); substr honoured (0 rows >241); column set unchanged.
  • End-to-end bench of the real TerminalManager.listSessions (dist code) on the snapshot.
  • Typecheck + npm run test:governance (18/18) green.

Still open

Pagination — /api/sessions is still unbounded (~950 rows). That's the structural fix; this is the last easy win on the current shape.

🤖 Generated with Claude Code

GET /api/sessions has always shipped `task` clipped to 240 chars, but the server
still SELECT *'d every session's FULL prompt out of SQLite — up to 53 KB/row on
instawp, 2.1 MB materialised per 1.5s poll — only for server.ts to throw it away.
listSessions/listArchivedSessions now take an optional taskClip; the list endpoint
passes LIST_CLIP and the SELECT projects substr(task,1,241) AS task (schema-derived
column list), so SQLite stops materialising the overflow text.

Measured on a live instawp snapshot (950 rows): task bytes 2.10 MB → 201 KB, raw
query 5.23 → 3.53 ms (-33%), full listSessions(owner) 13.3 → 11.1 ms (-17%) per poll,
plus ~1.9 MB less string allocation each tick. Output is byte-identical — clipText
still runs as the ellipsis-preserving finisher on the ≤241-char string (verified
across all 950 rows, 746 of them >240). Internal callers that read the whole prompt
(sessionsForAgent, Cockpit context) pass no clip and keep the full SELECT *.

Follow-on to #530/#532/#533; pagination (the structural fix) still open.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vikasprogrammer vikasprogrammer changed the title perf(sessions): clip task in the query, not after SELECT * (v0.292.3) perf(sessions): clip task in the query, not after SELECT * (v0.292.4) Aug 3, 2026
@vikasprogrammer
vikasprogrammer merged commit 8532851 into main Aug 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant