Before submitting
Area
apps/server
Steps to reproduce
- Start a long-running T3 Code thread using the Codex app-server provider.
- Have the parent agent spawn two or more native Codex subagents.
- Open the Agents panel or inspect the subagent CTA while the children are working.
- Compare each child's reported
thread/tokenUsage/updated total with its cumulative token total at the start of the child task.
Expected behavior
Each subagent should contribute only the tokens generated by that child after it was spawned.
Summing multiple children should therefore show the combined new work performed by those children, without counting the inherited parent conversation once per child.
Actual behavior
Codex child threads begin with the parent conversation's cumulative token history. T3 treats each child's raw tokenUsage.total.totalTokens value as usage generated by that child and then sums those values in the Agents UI.
In one live reproduction with two children:
| Child |
Starting inherited total |
Later raw total |
Actual new usage |
| A |
5,800,940,557 |
5,803,101,943 |
2,161,386 |
| B |
5,801,183,295 |
5,803,507,447 |
2,324,152 |
T3 summed the raw totals:
5,803,101,943 + 5,803,507,447 = 11,606,609,390
The CTA displayed:
Σ 11606.6M
The actual combined work performed by the children was:
2,161,386 + 2,324,152 = 4,485,538
The display should therefore have been approximately Σ 4.5M.
Likely cause
Current main maps the child notification's cumulative total.totalTokens directly into RuntimeTaskUsage:
|
case "collabAgent/tokenUsage": { |
|
// Cumulative per child thread: always the `total` breakdown, never |
|
// `last` (which shrinks on follow-ups). Client folds max-merge. |
|
const tokenUsage = |
|
typeof payload.tokenUsage === "object" && payload.tokenUsage !== null |
|
? (payload.tokenUsage as Record<string, unknown>) |
|
: undefined; |
|
const total = |
|
typeof tokenUsage?.total === "object" && tokenUsage.total !== null |
|
? (tokenUsage.total as Record<string, unknown>) |
|
: undefined; |
|
const count = (value: unknown): number | undefined => |
|
typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined; |
|
// Same validation as every other field: RuntimeTaskUsage.totalTokens |
|
// is NonNegativeInt, so NaN/Infinity/negative wire values must miss. |
|
const totalTokens = count(total?.totalTokens); |
|
if (totalTokens === undefined) { |
|
return []; |
|
} |
|
const typedUsage: RuntimeTaskUsage = { |
|
totalTokens, |
The CTA then sums every agent's stored total:
|
// Same rule as the panel footer: providers may aggregate member usage into |
|
// the coordinator, so count the coordinator only when no members exist. |
|
const totalTokens = agents.reduce( |
|
(sum, agent) => sum + (agent.usage?.totalTokens ?? 0), |
|
spawn.workflowId && agents.length === 0 ? (workflowGroup?.workflow.usage?.totalTokens ?? 0) : 0, |
|
); |
This assumes a Codex child's cumulative total starts at zero. In practice, the child inherits the parent's existing conversation history.
The formatter also has no billions branch, so a genuinely billion-scale input is rendered as thousands of millions:
|
export function formatSubagentTokenCount(totalTokens: number): string { |
|
if (totalTokens < 1000) { |
|
return `${totalTokens}`; |
|
} |
|
if (totalTokens < 1_000_000) { |
|
const value = totalTokens / 1000; |
|
return `${value >= 100 ? Math.round(value) : value.toFixed(1)}k`; |
|
} |
|
return `${(totalTokens / 1_000_000).toFixed(1)}M`; |
Suggested direction
Normalize each Codex child's cumulative counters against its inherited starting baseline before storing or summing its usage.
The implementation should preserve monotonic accounting across child follow-ups and resumed activations. Simply switching every display to tokenUsage.last may not be sufficient because that value can shrink between follow-ups.
Suggested regression coverage:
- A newly spawned child whose cumulative counter begins at a large non-zero value.
- Two children with different inherited baselines.
- A resumed child that must not reset or double-count prior child work.
- Matching totals between the Agents panel and the spawn CTA.
- A real total above one billion formatting with a
B suffix rather than thousands of M.
Related work
These are related but do not fix this path:
Impact
Minor bug or occasional failure
The agents themselves continue working, but the Agents panel's usage reporting becomes unusable and can overstate a small amount of child work by several orders of magnitude.
Version or commit
t3@0.0.33-nightly.20260808.1035
Installed app commit: a20923ce4633
Also reproduced by inspection against current main at ba9c9ae81dce4e554b4dd52abfd28d0c01b5c651.
Environment
Linux x86_64
Codex app-server provider
Native Codex multi-agent/subagent notifications
Workaround
Ignore the Agents total and manually subtract each child's starting cumulative counter from its latest counter.
Before submitting
Area
apps/server
Steps to reproduce
thread/tokenUsage/updatedtotal with its cumulative token total at the start of the child task.Expected behavior
Each subagent should contribute only the tokens generated by that child after it was spawned.
Summing multiple children should therefore show the combined new work performed by those children, without counting the inherited parent conversation once per child.
Actual behavior
Codex child threads begin with the parent conversation's cumulative token history. T3 treats each child's raw
tokenUsage.total.totalTokensvalue as usage generated by that child and then sums those values in the Agents UI.In one live reproduction with two children:
T3 summed the raw totals:
5,803,101,943 + 5,803,507,447 = 11,606,609,390The CTA displayed:
Σ 11606.6MThe actual combined work performed by the children was:
2,161,386 + 2,324,152 = 4,485,538The display should therefore have been approximately
Σ 4.5M.Likely cause
Current
mainmaps the child notification's cumulativetotal.totalTokensdirectly intoRuntimeTaskUsage:t3code/apps/server/src/provider/Layers/CodexAdapter.ts
Lines 669 to 689 in ba9c9ae
The CTA then sums every agent's stored total:
t3code/apps/web/src/components/chat/MessagesTimeline.tsx
Lines 2163 to 2168 in ba9c9ae
This assumes a Codex child's cumulative total starts at zero. In practice, the child inherits the parent's existing conversation history.
The formatter also has no billions branch, so a genuinely billion-scale input is rendered as thousands of millions:
t3code/packages/client-runtime/src/state/subagentRuntime.ts
Lines 931 to 939 in ba9c9ae
Suggested direction
Normalize each Codex child's cumulative counters against its inherited starting baseline before storing or summing its usage.
The implementation should preserve monotonic accounting across child follow-ups and resumed activations. Simply switching every display to
tokenUsage.lastmay not be sufficient because that value can shrink between follow-ups.Suggested regression coverage:
Bsuffix rather than thousands ofM.Related work
These are related but do not fix this path:
Impact
Minor bug or occasional failure
The agents themselves continue working, but the Agents panel's usage reporting becomes unusable and can overstate a small amount of child work by several orders of magnitude.
Version or commit
t3@0.0.33-nightly.20260808.1035Installed app commit:
a20923ce4633Also reproduced by inspection against current
mainatba9c9ae81dce4e554b4dd52abfd28d0c01b5c651.Environment
Linux x86_64
Codex app-server provider
Native Codex multi-agent/subagent notifications
Workaround
Ignore the Agents total and manually subtract each child's starting cumulative counter from its latest counter.