Usage
Read thread, run, and model-step token usage from client state.
PAI records provider-reported model usage at model-step scope and aggregates it for runs and threads. Usage is not a deduplicated count of unique transcript content: every model call reports the context it actually consumed.
Previous turns' reasoning is excluded from later model calls, not deducted from recorded usage: generating it still consumed output tokens. Each new call reports its own usage for the filtered prompt. Run and thread totals remain analytics totals, not the size of the live context window; see context compaction for that estimate.
Thread Usage
const state = await thread.refresh();
console.log(state.usage.totalTokens);
console.log(state.usage.inputTokenDetails.cacheReadTokens);An absent value means the provider did not report it. Treat it as zero only for a deliberate display fallback.
import { hasUsage } from "@pai/client";
if (hasUsage(state.usage)) renderUsage(state.usage);Run Usage
Runs are normalized in state.runs:
for await (const state of thread.watch()) {
const activeRun = state.activeRunId
? state.runs.find((run) => run.runId === state.activeRunId)
: undefined;
renderCurrentRunUsage(activeRun?.usage);
}For one exact run, its handle exposes the same durable record:
const run = await thread.send("Research this customer and draft a reply");
await run.waitUntilIdle();
const runState = await run.getState();
console.log(runState?.usage.totalTokens);Model-Step Usage
PAI stores one model-produced assistant message per model step. The usage for that call is in PAI message metadata:
const state = await thread.refresh();
for (const message of state.messages) {
if (message.role !== "assistant") continue;
const usage = message.metadata.pai.usage;
if (usage) console.log(message.id, usage.totalTokens);
}This explains which tool loop or continuation made a run expensive. Run and thread totals remain the convenient rollups.
Cache And Output Details
const input = state.usage.inputTokenDetails;
const output = state.usage.outputTokenDetails;
input.noCacheTokens;
input.cacheReadTokens;
input.cacheWriteTokens;
output.textTokens;
output.reasoningTokens;Provider pricing is application-owned. PAI exposes normalized token counts but does not persist provider-native usage payloads or maintain a price table.