Skip to content

Usage dashboard never counts Pi sessions, although Pi is a shipped provider on main #14866

Description

@astarktc

What happened

Pi is a shipped provider on main since the Orchestrator V2 merge (#2829). The Usage page still never counts it. Every Pi session's tokens and cost are missing from the totals, the per-provider rows and the model breakdown. On a machine where Pi is the main provider, the dashboard shows only the other providers' spend, and nothing on the page says Pi was left out.

Diagnosis

The Usage pipeline is keyed by a closed provider list, and Pi is the only shipped CLI provider that is not on it:

  • packages/contracts/src/usage.ts: UsageProviderKind = claude, codex, grok, cursor, opencode, antigravity. There is no pi.
  • apps/server/src/orchestration-v2/Adapters/PiAdapterV2.ts ships PI_PROVIDER = ProviderDriverKind.make("pi"). Every other *AdapterV2 provider with on-disk transcripts has a usage reader. (acpRegistry is generic.)
  • apps/server/src/usage/UsageService.ts resolves transcript dirs per provider instance (driver === "codex", "claudeAgent", …). It has no Pi branch.
  • apps/web/src/components/usage/usageProviders.ts and apps/mobile/src/features/usage/usageProviders.ts have no Pi presentation entry.

The data is already on disk, in the same shape the existing readers consume. Pi writes one JSONL file per session under ~/.pi/agent/sessions/<cwd-slug>/*.jsonl (PI_CODING_AGENT_DIR-aware). The file starts with a session header line, followed by message entries. Each assistant message carries provider, model and a usage block (input, output, cacheRead, cacheWrite, cost.total). That maps 1:1 onto UsageRecord. This was verified on Pi 1.0.0, session format version: 3.

Steps to reproduce

  1. Run T3 Code built from main, with the Pi provider enabled and logged in.
  2. Run a few turns in a Pi thread.
  3. Open Usage.
  4. There is no Pi row, and the totals and model breakdown exclude every Pi turn. The Pi session files under ~/.pi/agent/sessions/ contain the per-message usage blocks that should have been counted.

Version

main @ cc1e634 (V2 merged as de34391); the same on 0.0.46-preview.20261002.2598

Environment

macOS 26.6.2, Node 26.10.0, pi 1.0.0

Evidence

# main: the usage contract's provider list
$ git show main:packages/contracts/src/usage.ts | sed -n '/UsageProviderKind = /,/]);/p'
export const UsageProviderKind = Schema.Literals([
  "claude",
  "codex",
  "grok",
  "cursor",
  "opencode",
  "antigravity",
]);

# main: Pi is a shipped provider
$ git grep -n 'PI_PROVIDER =' main -- apps/server/src
apps/server/src/orchestration-v2/Adapters/PiAdapterV2.ts:97:export const PI_PROVIDER = ProviderDriverKind.make("pi");

# a Pi 1.0.0 session transcript line (assistant message, trimmed to the usage-relevant fields)
{"type":"message", "message":{"role":"assistant","provider":"anthropic","model":"claude-opus-5-5",
 "usage":{"input":4,"output":260,"cacheRead":0,"cacheWrite":80557,"totalTokens":80821,"cost":{"total":0.649672}}}}

Related issues

Ideas discussion #12288 (2026-09-17) proposed this against the V2 branch before it merged, and got no replies. This issue reports the gap on main, now that Pi is a released provider. No existing issue covers it.

Fix applied or workaround

We have run a fix in our own build every day since 2026-08-19. It has been carried through 18 rebases of the V2 branch and now sits on main, as one commit on a clean branch:

It adds "pi" to UsageProviderKind, which is additive on the wire with no migration. It also adds a Pi transcript reader with an entry in the streaming USAGE_FIELDS selector, so oversized lines keep their usage. A driver === "pi" branch inside UsageService's per-instance transcript-dir loop resolves the Pi home through the merged instance environment. Web and mobile each get a presentation entry. It includes reader, aggregation and scan-cache tests.

The fix makes 13 files change, 463 insertions, no new dependencies. On that branch, server tsc is clean and the usage suites pass: 136/136 server, 64/64 web. Resumed Pi sessions that repeat a shared prefix in a second file are counted once, because the reader emits the same dedupeKey shape that UsageAggregator already dedupes on.

With the fix, the Usage page shows the Pi row and the Pi-served models:

Usage page with a Pi row

Happy to open it as a focused PR if you want it.

Filed by

Pi (claude-opus-5-5) on behalf of @astarktc

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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