Observability contracts: usage accounting, plan blocks, price table (Phase 0)

The 2026-09 observability wave's type-level foundation, landed before the
streams so nothing renders against guessed shapes:

- contracts/chat.ts: CallUsage + TurnUsage (per-model-call token accounting,
  one entry per teacher/wake turn keyed by messageId) and ChatRecord.turns —
  a DELIBERATELY parallel append-only usage log, not per-message metadata:
  the client re-POSTs its message list every turn and its copies never
  carry server-stamped fields, so anything inside messages gets clobbered
  by the next persist (the wave-3 merge-rule lesson).
- contracts/chat.ts: PlanBlockData — the persisted data-plan-block part
  (full DAG on plan_init, one-level neighborhood on plan updates, snapshot
  semantics so history renders what was true then).
- contracts/jobs.ts: JobUsage + JobRecord.usage — a sub-agent run's
  accumulated accounting, written by the runner.
- core/ports.ts + store/chats.ts: ChatStore.appendTurnUsage — idempotent
  per messageId (abort replays / wake retries append once); listChats no
  longer leaks turns into the list payload.
- core/prices.ts: PRICES + CONTEXT_LIMITS (generated from OpenRouter's
  published pricing via scripts/sync-pricing.ts) + pure folds: callCost,
  turnCost, sessionCost, contextWindow, jobCost. Unknown model or absent
  fields render as absent, never zero.
- server/observability.ts: barrel-approved surface for the transport layer
  (fixes the import-law violation in the graph status route that slipped
  through the wave-3 merge verification).

Capture wiring (agent onStepFinish -> persist seam, plan-block emission)
lands next as master seam work; the streams start against these shapes.
This commit is contained in:
amosblomqvist
2026-09-11 02:43:35 +03:00
parent afccb83fdb
commit 83a00800e9
12 changed files with 492 additions and 7 deletions
+21
View File
@@ -27,6 +27,27 @@ export interface JobRecord {
/** The sub-agent's result (steer-artifact payload). */
result?: unknown;
error?: string;
/** Money channel (observability, 2026-09): accumulated token usage of
* the sub-agent's run, written by the runner as steps complete. Cost is
* inferred at read time (core/prices.ts). Absent on pre-2026-09 jobs and
* until the runner's capture lands — renderers show "—", never zero. */
usage?: JobUsage;
}
/** A sub-agent run's accumulated usage — the same accounting shape as a
* chat turn (contracts/chat.ts CallUsage), flattened to one running total
* plus a step count. */
export interface JobUsage {
/** The OpenRouter model id that ran the sub-agent. */
model: string;
/** Running totals summed over the run's model calls so far. */
inputTokens: number;
outputTokens: number;
cacheReadTokens: number;
cacheWriteTokens: number;
reasoningTokens: number;
/** How many model calls the run has made (each bills separately). */
steps: number;
}
/**