Skip to content

[Bug]: Codex Agents panel counts inherited parent history in each child token total #5793

Description

@rabesss

Before submitting

  • I searched existing issues and open PRs and did not find a duplicate or pending fix.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Start a long-running T3 Code thread using the Codex app-server provider.
  2. Have the parent agent spawn two or more native Codex subagents.
  3. Open the Agents panel or inspect the subagent CTA while the children are working.
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions