UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

72 lines • 4.49 kB
import type { MessageUsage } from '../types.js'; /** * The WRITE side of the model pricing table the loop's cost fold prices token usage against. Cost is * `null` (not `0`) for an unpriced model, so an app seeds its models' per-1M rates once (and * re-`upsert`s when a provider changes prices). An adapter implements this — `LucidPricingStore` * (production, over the `agent_model_pricing` table) and `InMemoryPricingStore` (testing) ship. Wire * it in `config/agent.ts` via `pricingStore: pricingStores.lucid()`; use {@link seedModelPrices} for a * one-shot batch. Mirrors the reference `AgentPricingStore` contract exactly. */ /** A per-1M-token price for one model. Cache rates fall back to the input rate when omitted. */ export interface ModelPriceInput { modelId: string; inputPricePer1m: number; outputPricePer1m: number; /** Per-1M price for cache-write (prompt-cache) input tokens. Omit → priced at the input rate. */ cacheWritePricePer1m?: number; /** Per-1M price for cache-read (prompt-cache) input tokens. Omit → priced at the input rate. */ cacheReadPricePer1m?: number; } /** A current price row as read back, with the ISO timestamp it took effect. */ export interface CurrentModelPrice extends ModelPriceInput { effectiveFrom: string; } export interface AgentPricingStore { /** * Set the current price for a model. Atomic supersede: the model's prior `is_current` row (if any) * is retired and this one is inserted as current, effective now — so the cost fold always joins to * exactly one live price per model, with no window where two rows race for `is_current`. */ upsertModelPrice(input: ModelPriceInput): Promise<void>; /** The current price row per model (`is_current`), fetched ONCE per run for the loop's cost fold. */ listCurrentPrices(): Promise<CurrentModelPrice[]>; } /** Seed (or refresh) a batch of model prices — one `upsertModelPrice` per row, in order. */ export declare function seedModelPrices(store: AgentPricingStore, prices: ModelPriceInput[]): Promise<void>; /** * Token-ledger estimate for one turn against a pricing row: the uncached input at the input rate, * cache-write/cache-read tokens at their own rates (falling back to the input rate when unpriced), * plus output at the output rate. Reasoning tokens are a subset of output and are billed at the * output rate, so they don't change the estimate. Cache token counts are subsets of `inputTokens`, * so the uncached remainder is the difference. Pure — the SQL and in-memory adapters share it, so * every surface reports identical numbers. */ export declare function estimateCost(usage: MessageUsage, price: CurrentModelPrice): number; /** * The forms of a model id we will accept a price under, most specific first. * * Exists because the ledger and the price table are filled by two different parties. The ledger gets * what the PROVIDER reports (`finalStep.response.modelId`), and OpenAI answers a request for * `gpt-4o-mini` with the dated snapshot `gpt-4o-mini-2024-07-18`. The price table gets what an * OPERATOR typed — and every example in these docs, and every published rate card, uses the alias. * Matched by raw equality, those two never meet: the fold misses and the dashboard prints `$0.00` * next to a real token count. * * Only DATE-shaped suffixes are stripped, and only from the end. That is the conservative line: a * date suffix is unambiguously a snapshot of the same model, whereas a trailing `-002` or `-v2` * could be a genuinely different model with a different price. Mispricing silently is worse than * not pricing — so anything we are not sure about stays unpriced and stays visible. * * The exact id is always tried FIRST, so an operator who deliberately prices one snapshot * differently from its alias keeps that. */ export declare function modelPriceCandidates(modelId: string): string[]; /** * The price to use for `modelId`, or `undefined` when the model is genuinely unpriced. * * `undefined` is the honest answer for "we don't know", and callers must keep it distinguishable * from zero: a run that cost nothing and a run nobody priced are different facts, and collapsing * them is what made a whole dashboard read `$0.00` while tokens were being burned. */ export declare function resolveModelPrice(pricing: ReadonlyMap<string, CurrentModelPrice>, modelId: string): CurrentModelPrice | undefined; //# sourceMappingURL=pricing-store.d.ts.map