UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

96 lines (95 loc) 4.63 kB
/** * Token-usage accumulator for `$eve.*` observability tags and session limits. * Lives on `session.state` so the totals survive workflow step boundaries the * way the rest of the harness state does. * * The harness runs each turn as a sequence of `"use step"` invocations * (one per tool-loop iteration). Each step knows its own * `result.usage`, but the dashboard cares about totals **per turn**. * The workflow runtime's attribute store is "last write wins" per key, * so the simplest cumulative pattern is: read the previous total from * `session.state`, add the new step's usage, write the running total * back. The most recent emit then carries the final per-turn total. * * `turnId` keys the turn totals so a fresh turn starts at zero without relying * on a separate "reset" code path. Session totals stay in the same state record * and keep accumulating until the durable session ends. * * `TokenUsageTotals` carries `costUsd`/`sawCost` alongside the token counts * for the `$eve.*` dashboard tags and session limits — fields the * cross-cutting {@link TokenUsage} contract (subagent results, callback * bodies, usage spans) does not carry. {@link toUsage} projects a total down * to that shared shape at the one site (the driver's `done` action) where a * session total crosses into it. */ import type { HarnessSession, SessionStateMap } from "#harness/types.js"; import type { TokenUsage } from "#shared/token-usage.js"; export interface TokenUsageTotals { readonly cacheReadTokens: number; readonly cacheWriteTokens: number; readonly costUsd: number; readonly inputTokens: number; readonly outputTokens: number; readonly sawCost: boolean; } export type TokenUsageDelta = Partial<TokenUsageTotals>; /** * Rolling token usage for the durable session and the in-flight turn. * * `turnId` is the in-flight turn's stable id; when the harness step * runs in a different turn, the flat turn totals reset. The nested * `session` totals do not reset. */ export interface TurnUsageState extends TokenUsageTotals { readonly session: TokenUsageTotals; readonly turnId: string; } /** Reads the stored per-turn token state, or `undefined` when absent. */ export declare function getTurnUsageState(state: SessionStateMap | undefined): TurnUsageState | undefined; export type SessionTokenLimitViolation = { readonly kind: "input"; readonly limit: number; readonly usedTokens: number; } | { readonly kind: "output"; readonly limit: number; readonly usedTokens: number; }; export declare function getSessionTokenUsage(session: Pick<HarnessSession, "state">): TokenUsageTotals; /** Projects a {@link TokenUsageTotals} down to the cross-cutting {@link TokenUsage} shape. */ export declare function toUsage(totals: TokenUsageTotals): TokenUsage; /** * Resets the session token budget windows to the current usage totals. * * Called when the user grants a continuation after a session token limit was * reached. The configured limits keep their values and act as the size of the * next budget window, measured from the moment of the grant. Both windows * reset together so a session near two limits gets one prompt, not two * back-to-back. */ export declare function extendSessionTokenBudget(session: HarnessSession): HarnessSession; export declare function getSessionTokenLimitViolation(session: Pick<HarnessSession, "limits" | "state">): SessionTokenLimitViolation | null; /** Writes per-turn token state onto a new copy of the session. */ export declare function setTurnUsageState(session: HarnessSession, next: TurnUsageState): HarnessSession; /** * Folds one step's `usage` into the running per-turn totals. When * `turnId` differs from the stored state (e.g. a new turn just * started), the previous totals are discarded — fresh turns start at * zero without an explicit reset path. */ export declare function accumulateTurnUsage(input: { readonly previous: TurnUsageState | undefined; readonly turnId: string; readonly usage: TokenUsageDelta | undefined; }): TurnUsageState; /** * Folds a delegated child session's reported totals into the parent's * session totals without touching the in-flight turn totals. Turn tags * attribute only the parent's own model calls (child spend is attributed by * the caller-side `invoke_agent` span); session totals feed the session * token limits and the remaining-quota budget granted to later delegations. */ export declare function accumulateSessionUsage(input: { readonly previous: TurnUsageState | undefined; readonly usage: TokenUsageDelta; }): TurnUsageState;