UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

69 lines (68 loc) • 4.58 kB
/** * The run's usage account for the model calls made BESIDE the main loop — the compaction summarizer, the permission * classifier, a mod's `$.model.complete`: the lanes, what a reply tells the account, the one door a lane books through, and the * ONE function behind it. The lane table says which `Stats` line keeps a lane's cost besides `costMicroUsd` (every lane folds * into the total — it is the budget coordinate and the reported figure); it is total over the lanes by its fence, so a fourth * lane is a row here, not a second accounting function. */ import type { AssistantMessageDiagnostic, Model, Usage } from "../../internal/llm.js"; import { type ModelPricing } from "../pricing.js"; import type { AssertAllKeysHandled } from "../ask-origin.js"; import type { RunnerDeps, TaskSpec } from "../types.js"; import type { Stats } from "./assemble-result.js"; /** Whose model call it is: the compaction summarizer, the permission classifier, a mod's `$.model.complete`. */ export type SideCallLane = "compaction" | "classifier" | "mod"; /** The `Stats` line a lane's cost is also kept in: compaction is its own partition line; the classifier and the mods share the side-call line. */ export declare const SIDE_CALL_LANE_TOTAL: { readonly compaction: "compactionMicroUsd"; readonly classifier: "sideCallMicroUsd"; readonly mod: "sideCallMicroUsd"; }; export type LaneTotalCoversEverySideCallLane = AssertAllKeysHandled<Exclude<SideCallLane, keyof typeof SIDE_CALL_LANE_TOTAL>>; /** A side call's reply as the account reads it: the provider's usage (absent ⇒ none reported), the marks of what is unknown, * and the diagnostics that say a degrading brain served it from its fallback (the model that ANSWERED is the one priced). */ export interface SideCallReply { readonly usage?: Usage; readonly usageMissing?: true; readonly stopReason?: string; readonly diagnostics?: AssistantMessageDiagnostic[]; } /** The leg's one door onto the run's usage account: every side call's reply is booked through it, once. */ export type SideCallBook = (lane: SideCallLane, model: Model, reply: SideCallReply | undefined) => void; /** The leg's seats a side call is priced and traced on — everything the call needs that `stats` does not carry. */ export interface SideCallAccount { /** The run's telemetry: a call on an unpriced model taints `unpricedSpend`; the trace row goes to its tracer. */ telemetry: { unpricedSpend: boolean; readonly tracer: TaskSpec["tracer"]; readonly taskId: string; }; /** The deployment's price table, read at the call (a swapped deps seat reaches legs already running). */ pricing: () => RunnerDeps["pricing"]; /** The telemetry lane's price-table door, consulted for every table a side call adopts. */ noteUnevaluablePriceTable: (p: ModelPricing) => void; /** The deployment's model catalog: where the fallback model of a degraded reply is looked up. */ catalog: RunnerDeps["models"]; } /** What one side call tells the account beyond its usage: the model it asked, the marks of what is unknown, and — when a * degrading brain served the reply from another model — that model's id. */ export interface SideCallCall { model: Model; account: SideCallAccount; usageMissing?: true; stopReason?: string; servedBy?: string; } /** * THE one place a model call made beside the main loop reaches the run's account: the compaction summarizer, the * permission classifier and a mod's `$.model.complete` all land here, each with its lane. The call is accounted exactly * like a main-loop call (re-priced in core from the deployment's table and the model's cache family, integer * micro-USD, never the brain's own `usage.cost`), so the reported total, the budget gate at the next turn end and the * trace agree about what the run spent. Latency and first-token time are not modeled (there are no per-delta hooks here). * * `usage` absent — the reply reported none — marks the leg's stats `usageMissing` (the totals are then a lower bound: * unknown is not free). A reply the brain itself marked `usageMissing` does the same for its zero-filled usage. */ export declare function recordSideCallUsage(stats: Stats, usage: Usage | undefined, lane: SideCallLane, call: SideCallCall): void; /** The leg's door: `recordSideCallUsage` bound to the leg's `stats` and account, reading what the reply itself says (its marks, and who served it). */ export declare function sideCallBookOf(stats: Stats, account: SideCallAccount): SideCallBook;