Capture Codex worker token usage

Record per-turn app-server token notifications so Live architecture benchmarks can compare context and cache costs.\n\nAI-assisted: OpenAI Codex.
This commit is contained in:
Paul Bakaus
2026-07-12 20:47:01 -07:00
parent 27bbf90ede
commit edde928736
2 changed files with 16 additions and 0 deletions
@@ -384,6 +384,7 @@ export class CodexAppServerClient {
let turnId = null;
let started = null;
let completed = null;
let tokenUsage = null;
const agentMessages = [];
const agentMessageCallbacks = [];
let firstAgentMessageAt = null;
@@ -407,6 +408,9 @@ export class CodexAppServerClient {
}
if (notificationTurnId !== turnId) return;
if (notification.method === 'turn/started') started = notification;
if (notification.method === 'thread/tokenUsage/updated') {
tokenUsage = notification.params?.tokenUsage || tokenUsage;
}
if (notification.method === 'item/completed'
&& notification.params?.item?.type === 'agentMessage'
&& typeof notification.params.item.text === 'string') {
@@ -456,6 +460,7 @@ export class CodexAppServerClient {
startResponse: result,
started,
completed,
tokenUsage,
status: completed?.params?.turn?.status || result.turn?.status || null,
agentMessages,
message: agentMessages.at(-1) || null,
@@ -294,6 +294,16 @@ describe('dedicated Codex worker threads', () => {
method: 'item/completed',
params: { ...common, item: { type: 'agentMessage', text: 'final answer' } },
});
process.send({
method: 'thread/tokenUsage/updated',
params: {
...common,
tokenUsage: {
last: { inputTokens: 100, cachedInputTokens: 60, outputTokens: 20, reasoningOutputTokens: 4, totalTokens: 124 },
total: { inputTokens: 100, cachedInputTokens: 60, outputTokens: 20, reasoningOutputTokens: 4, totalTokens: 124 },
},
},
});
process.send({
method: 'turn/completed',
params: { threadId: 'worker', turn: { id: 'turn-1', status: 'completed' } },
@@ -321,6 +331,7 @@ describe('dedicated Codex worker threads', () => {
assert.deepEqual(deliveredMessages, ['first fragment', 'final answer']);
assert.equal(result.message, 'final answer');
assert.equal(result.firstAgentMessageMs >= 0, true);
assert.equal(result.tokenUsage.last.inputTokens, 100);
assert.equal(result.started.method, 'turn/started');
assert.equal(result.durationMs > 0, true);
await client.close();