@sema-agent/core
Version:
Stateless, task-oriented AI agent core
69 lines (68 loc) • 4.58 kB
TypeScript
/**
* 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;