mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 10:59:32 +01:00
perf(story-mode): 304 for an unchanged page, and a longer read for a turn bigger than the tail
GET /story now sends a weak ETag (server start, transcript size and mtime, turn) with Cache-Control: no-cache, and answers 304 before building anything when the transcript has not changed, so a live view's polls cost a stat. A turn can be bigger than the 8 MB tail on its own (tool results carry whole files, ~60 KB per result line on large local transcripts), which cut its first panels. When the window holds no prompt, the reader re-reads a 24 MB, then a 64 MB tail. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
d20208bda6
commit
7c21973c54
3 files changed
+93
-20
No files matched your search
@@ -116,6 +116,43 @@ describe('GET /api/sessions/:id/story', () => {
|
||||
expect(res.statusCode).toBe(404);
|
||||
});
|
||||
|
||||
it('answers 304 to a matching If-None-Match until the transcript changes', async () => {
|
||||
writeFileSync(transcript, jsonl(demoTurn()));
|
||||
const { app } = await setup();
|
||||
const first = await app.inject({ method: 'GET', url: URL });
|
||||
const etag = first.headers.etag as string;
|
||||
expect(etag).toMatch(/^W\/"story-/);
|
||||
expect(first.headers['cache-control']).toBe('no-cache');
|
||||
const again = await app.inject({ method: 'GET', url: URL, headers: { 'if-none-match': etag } });
|
||||
expect(again.statusCode).toBe(304);
|
||||
expect(again.body).toBe('');
|
||||
appendFileSync(transcript, jsonl([prompt('next job')]));
|
||||
const changed = await app.inject({ method: 'GET', url: URL, headers: { 'if-none-match': etag } });
|
||||
expect(changed.statusCode).toBe(200);
|
||||
expect(changed.headers.etag).not.toBe(etag);
|
||||
// Another turn of the same file is another page, so another tag.
|
||||
const other = await app.inject({
|
||||
method: 'GET',
|
||||
url: `${URL}?turn=x`,
|
||||
headers: { 'if-none-match': changed.headers.etag as string },
|
||||
});
|
||||
expect(other.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it('reads further back when a long turn does not fit the first tail', async () => {
|
||||
// A prompt, then ~10 MB of tool results (Read results carry whole files), then the turn's end.
|
||||
const big = 'x'.repeat(100_000);
|
||||
const lines: unknown[] = [prompt('a turn longer than eight megabytes')];
|
||||
for (let i = 0; i < 100; i++) lines.push(...bash(`b${i}`, `cat big${i}.txt`, `Show file ${i}`, big));
|
||||
lines.push(end(60_000));
|
||||
writeFileSync(transcript, jsonl(lines));
|
||||
const { app } = await setup();
|
||||
const page = (await app.inject({ method: 'GET', url: URL })).json().data.page;
|
||||
expect(page).toMatchObject({ prompt: 'a turn longer than eight megabytes', partial: false, complete: true });
|
||||
expect(page.toolCalls).toBe(100);
|
||||
expect(page.panels[0].kind).toBe('mission');
|
||||
});
|
||||
|
||||
it('a live turn grows as the transcript grows', async () => {
|
||||
writeFileSync(transcript, jsonl([prompt('go'), ...read('r1', '/w/a.ts')]));
|
||||
const { app } = await setup();
|
||||
|
||||
Reference in new issue
Block a user