load chat transcripts as a tail window and lazy-load older on scroll-up
extremely long transcripts made bottom-anchoring the virtualized list unreliable (thousands of unmeasured variable-height items = a huge estimate the scroll never lands on). now GET /chat/sessions/:id takes limit+before and returns a windowed slice plus total+offset. the chat opens on the last 20 messages, anchors to the bottom instantly, and scrolling near the top pages in the next older window, prepending it and pinning the previously-top message so the view stays put. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -46,7 +46,12 @@ chatRouter.get('/sessions', async (ctx) => {
|
||||
return ctx.json({ sessions });
|
||||
});
|
||||
|
||||
// GET /chat/sessions/:id[?cwd=] — one conversation's transcript. Routes by harness (ses_ = OpenCode).
|
||||
// GET /chat/sessions/:id[?cwd=][&limit=&before=] — one conversation's transcript. Routes by harness
|
||||
// (ses_ = OpenCode). Transcripts get extremely long, so the client opens at the tail and pages upward:
|
||||
// `limit` caps how many messages come back and `before` (absolute index into the full transcript,
|
||||
// exclusive) selects the window's upper bound. Absent params return the whole transcript (legacy). The
|
||||
// response carries `total` (full length) and `offset` (absolute index of messages[0]) so the client knows
|
||||
// where the window sits and whether older messages remain above it.
|
||||
chatRouter.get('/sessions/:id', async (ctx) => {
|
||||
const email = ctx.get('user').email;
|
||||
const id = ctx.req.param('id');
|
||||
@@ -57,7 +62,17 @@ chatRouter.get('/sessions/:id', async (ctx) => {
|
||||
? await loadOpenCodeSession(id)
|
||||
: (loadClaudeSession(email, cwd, id) ?? loadClaudeSessionById(email, id));
|
||||
if (!detail) return ctx.text('Not found', 404);
|
||||
return ctx.json(detail);
|
||||
|
||||
const total = detail.messages.length;
|
||||
const limitRaw = ctx.req.query('limit');
|
||||
const beforeRaw = ctx.req.query('before');
|
||||
const limit = limitRaw != null ? Math.max(0, parseInt(limitRaw, 10) || 0) : null;
|
||||
const end = beforeRaw != null ? Math.min(total, Math.max(0, parseInt(beforeRaw, 10) || 0)) : total;
|
||||
const start = limit != null ? Math.max(0, end - limit) : 0;
|
||||
const windowed = limit != null || beforeRaw != null;
|
||||
const messages = windowed ? detail.messages.slice(start, end) : detail.messages;
|
||||
|
||||
return ctx.json({ ...detail, messages, total, offset: windowed ? start : 0 });
|
||||
});
|
||||
|
||||
// DELETE /chat/sessions/:id[?cwd=] — remove a conversation from the owning harness's store.
|
||||
|
||||
Reference in New Issue
Block a user