mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-10-21 05:23:19 +00:00
* fix(codex): keep token_count events in sessions that never write total_token_usage * fix(codex): preserve distinct requests when cumulative usage is missing * fix(codex): narrow missing-cumulative fix - byte-identical re-emissions still collapse (#257) Real-data answer to the review's question: Codex does re-emit byte-identical token_count events. Scanned 53 public rollout sessions (codeset-ai/ codeset-release-evals, 1313 token_count events): 603 (46%) are byte-identical repeats of their predecessor (identical total AND last usage), 0 cumulative monotonicity violations, 54 events carry no total_token_usage at all. The missing-cumulative path now collapses a record whose info payload is byte-identical to the previous event's (#257 semantics restored); only records with differing payloads count as distinct requests. prevInfoIdentity is persisted in the resume state. The #1088 invariant note is restored at the dedupKey in adapted form; docs/providers/codex.md documents the three-layer dedup and the accepted fork-cutoff trade-off. * fix(codex): revert cache/parse version bumps, correct null-info docs per review Re-verified on a fresh spread sample of codeset-release-evals (21 sessions, 404 events): exactly one info:null rate-limit ping per session, zero events with info present but total_token_usage absent — matching the reviewer's 137k-event corpus. The missing-cumulative branch is a no-op on real data: - CODEX_CACHE_VERSION stays 15 (no cold reparse for identical numbers; v16 never shipped in a release) - drop the -missing-cumulative-v1 parse suffix - Quirks: null-info pings take the estimate path, not the dedup path; the earlier 54-of-1313 figure conflated them with partial-info events - dedup layer 3 now documents the forkedFromId/#1383 sub-agent caveat --------- Co-authored-by: Roy tong <tongxiarui@elliwooddeMacBook-Air.local>
58 lines
3.2 KiB
TypeScript
58 lines
3.2 KiB
TypeScript
import { it, expect, vi } from 'vitest'
|
|
import { mkdtemp, writeFile, rm } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { createCodexProvider } from '../src/providers/codex.js'
|
|
|
|
vi.mock('../src/codex-cache.js', async (original) => ({
|
|
...await original<typeof import('../src/codex-cache.js')>(),
|
|
readCachedCodexResults: async () => null,
|
|
readCodexResume: async () => null,
|
|
writeCachedCodexResults: async () => {},
|
|
}))
|
|
|
|
// Real-data basis (codeset-ai/codeset-release-evals, 53 sessions / 1313
|
|
// token_count events): 603 events are byte-identical repeats of their
|
|
// predecessor -- Codex re-emits token_count snapshots unchanged within a
|
|
// response -- while 54 events carry no total_token_usage at all. Both
|
|
// behaviors must be handled: identical repeats collapse (#257), distinct
|
|
// payloads without cumulative stay distinct.
|
|
for (const total of [undefined, null, {}]) {
|
|
it(`collapses byte-identical re-emitted records with cumulative ${JSON.stringify(total)}`, async () => {
|
|
const dir = await mkdtemp(join(tmpdir(), 'codeburn-missing-total-'))
|
|
try {
|
|
const path = join(dir, 'rollout-reemit.jsonl')
|
|
const identical = { last_token_usage: { input_tokens: 100, output_tokens: 20 }, total_token_usage: total }
|
|
const lines = [
|
|
{ type: 'session_meta', timestamp: '2026-09-01T10:00:00Z', payload: { session_id: 's', model: 'gpt-5.3-codex' } },
|
|
...[1, 2, 3].map(n => ({ type: 'event_msg', timestamp: `2026-09-01T10:00:0${n}Z`, payload: { type: 'token_count', info: identical } })),
|
|
]
|
|
await writeFile(path, lines.map(line => JSON.stringify(line)).join('\n') + '\n')
|
|
const parser = createCodexProvider(dir).createSessionParser({ path, project: 'test', provider: 'codex' }, new Set())
|
|
const calls = []
|
|
for await (const call of parser.parse()) calls.push(call)
|
|
expect(calls).toHaveLength(1)
|
|
expect(calls[0].outputTokens).toBe(20)
|
|
} finally { await rm(dir, { recursive: true, force: true }) }
|
|
})
|
|
|
|
it(`preserves distinct records with differing payloads when cumulative is ${JSON.stringify(total)}`, async () => {
|
|
const dir = await mkdtemp(join(tmpdir(), 'codeburn-missing-total-'))
|
|
try {
|
|
const path = join(dir, 'rollout-distinct.jsonl')
|
|
const lines = [
|
|
{ type: 'session_meta', timestamp: '2026-09-01T10:00:00Z', payload: { session_id: 's', model: 'gpt-5.3-codex' } },
|
|
...[0, 1, 2].map(n => ({ type: 'event_msg', timestamp: `2026-09-01T10:00:0${n + 1}Z`, payload: {
|
|
type: 'token_count', info: { last_token_usage: { input_tokens: 100 + n, output_tokens: 20 + n }, total_token_usage: total },
|
|
} })),
|
|
]
|
|
await writeFile(path, lines.map(line => JSON.stringify(line)).join('\n') + '\n')
|
|
const parser = createCodexProvider(dir).createSessionParser({ path, project: 'test', provider: 'codex' }, new Set())
|
|
const calls = []
|
|
for await (const call of parser.parse()) calls.push(call)
|
|
expect(calls).toHaveLength(3)
|
|
expect(calls.reduce((sum, call) => sum + call.outputTokens, 0)).toBe(63)
|
|
expect(new Set(calls.map(call => call.deduplicationKey)).size).toBe(3)
|
|
} finally { await rm(dir, { recursive: true, force: true }) }
|
|
})
|
|
}
|