Pi spend via pi-acp usage patch

Task 9943 · Done · Coder · created · updated

Original request (verbatim): "Close the gap between Claude, Codex, Antigravity and Pi. More universal code, less provider specific" Settled inputs: PRD (Task 9932) and Architecture (Task 9933) of this epic. Approach (architecture §1): lifecycle events run in Jaah-owned code in front of every session (ACP: `jaah-acp-host`, `apps/jaahd/acp/host.py`; terminal: node daemon + vendor CLI events); tool events run in-band through ONE neutral dispatcher `tools/hook_bridge_core.py::dispatch`. Adapters contribute only declarations (event names, tool-name map, placement literals, error text patterns, question prefix), never a copy of the logic. Requirement R1 (verbatim): "Each of these mechanisms has exactly ONE provider-neutral implementation home that every provider uses; an adapter contributes only vendor literals and capability declarations, never its own copy of the logic: (a) hook/guard rendering & chaining, (b) hook-context injection into the model, (c) charter placement as system/built-in instructions, (d) session-start rule list (guard brief), (e) read-once guard reset signal, (f) prompt-submit and session-end lifecycle events, (g) StopFailure / API-error self-heal, (h) project-memory hooks, (i) token/cost (spend) reading, (j) usage-window (quota) reading, (k) the operator question / structured interview channel." R5 (verbatim): "Availability: every closed capability is ON by default on the dev control plane (`dev.jaah.ai`) — no new switch that ships OFF; if a switch is unavoidable it defaults ON and is wired in the real deployment." Closing-test naming contract (architecture §4): every degradation key this child closes gets a test named `test_closes_<key with - as _>` (e.g. `test_closes_no_hook_context`); C9 refuses to remove a key without it. Do NOT remove catalogue degradation keys in this child — the close-out child removes them; this child delivers the behaviour and the closing test. ## Scope (this child) Architecture child C5 — closes Pi `no-spend-reading` (PRD "Spend & quota"; mechanism (i), home `apps/jaahd/acp/events.py::Normaliser` (`_turn_usage`, `_cost_usd`)). - S5: add fork patch `packages/acp-forks/pi-acp/0003-usage-cost.patch` extending `toUsageUpdate` to carry ACP `cost: {amount: stats.cost, currency: "USD"}` (read cumulatively by `acp/events.py:57-59`; source `get_session_stats`, `pi-acp/dist/index.js:261`). The prompt result carries `_meta["quota"]` token counts in the shape the `_QUOTA_USAGE` readers already parse for Claude and Codex. - Document the patch in `packages/acp-forks/pi-acp/README.md` and pin it in `packaging/platform-pins.toml` `patches` (follow 0001/0002's pattern). - Pi row: `usage_meta=_QUOTA_USAGE`, `Usage(tokens=True, cost=True)`. No Pi-specific parsing in the host (declarations only). - Pi `no-quota-reading` is I1-escaped and stays; do not touch it. PRD AC9 (verbatim): "after a completed run on Antigravity and Pi, the task/session shows token counts and cost; Accounts page shows a usage window for Pi and DeepSeek accounts (or the item is feasibility-escaped with cited evidence)." (Antigravity spend and Pi/DeepSeek quota are escaped; live Pi check runs in the close-out child.) Credentials & reach: - C1–C7 unit and replay tests, AC1–AC4 | nothing beyond the worktree (`./dc check full`) | verified (worktree) - AC6/AC9/AC10 Pi | dev account `t7281-pi-key` (Pi API key; row present, currently Disabled, and its enable toggle is a live button on the Accounts page, so C9's verifier enables it as a console action); the Anthropic key behind it: roster `me/jaah/system/anthropic_api_key`, `credential_get` ok | verified (probe: Accounts page row read in browser, toggle present) Out of scope (PRD, verbatim — do NOT touch): - MUST NOT retire, rewrite or change the runtime selection of the legacy terminal runtime; Claude `oauth` stays `legacy_only` (ADR in `docs/adrs/README.md`, ACP Claude entry). - MUST NOT remove or reword any "stay published" degradation (list above), including Pi `no-subagents` and `acp-runtime-only`. - MUST NOT build Pi subagents or a Jaah-side subagent lane. - MUST NOT add Jaah-side workarounds for vendor-intrinsic DeepSeek/Codex gaps (PDF conversion, model remap changes, throttling avoidance). - MUST NOT do live-verification work for Antigravity `not-yet-observed`, nor touch `home-is-account-dir` or `microvm-signed-in-legacy-runtime`. - MUST NOT change `tools/provider_branches.toml` patterns/allowlist scope beyond what removing branches requires (gate tightening was not selected), and set no line-count target. - MUST NOT add a new provider or retire one; no change to login/sign-in flows, model-tier resolution, or the plan gate (`non_claude_engines`). Stay-published keys (must stay byte-identical): DeepSeek `document-blocks-unsupported`, `images-flash-only`, `prompt-cache-controls-ignored`, `beta-features-ignored`, `web-search-extra-calls`, `claude-model-names-remapped`, `model-quality-differs`; Codex `device-code-login-workspace-gated`, `subscription-concurrency-throttling`; Pi `no-subagents`, `acp-runtime-only`. I1-escaped (stay, unchanged): Antigravity `no-spend-reading`; Pi and DeepSeek `no-quota-reading`. Done means: - Patch applies cleanly to the pinned pi-acp and the packaging build/pin check passes — cite output. - An ACP replay fixture under `apps/jaahd/tests/acp_replay/` proves tokens AND a non-zero cost reach the session record for a Pi run — `test_closes_no_spend_reading` exists and passes. - Pi row declares `Usage(tokens=True, cost=True)` and `usage_meta=_QUOTA_USAGE`; Claude/Codex usage tests unchanged and green. - Quick gate green.

Outcome

Pi spend: pi-acp patch 0003 (cumulative cost + per-turn _meta.quota tokens), Pi row declares tokens/cost; test_closes_no_spend_reading on a recorded fixture passes; quick gate green; PR #6883 queued. Filed draft #9952 (CP double-counts ACP reported cost). Memory: used mem-23370; proposed 0. No UI surface affected.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Runner ended (done)