floe-guard 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/livekit.cjs.map +1 -1
- package/dist/adapters/livekit.d.cts +1 -1
- package/dist/adapters/livekit.d.ts +1 -1
- package/dist/adapters/livekit.js +1 -1
- package/dist/adapters/retell.cjs.map +1 -1
- package/dist/adapters/retell.d.cts +1 -1
- package/dist/adapters/retell.d.ts +1 -1
- package/dist/adapters/retell.js +1 -1
- package/dist/adapters/vapi.cjs.map +1 -1
- package/dist/adapters/vapi.d.cts +2 -2
- package/dist/adapters/vapi.d.ts +2 -2
- package/dist/adapters/vapi.js +1 -1
- package/dist/{chunk-Y4YGC4KV.js → chunk-5Q5VQC6J.js} +8 -1
- package/dist/chunk-5Q5VQC6J.js.map +1 -0
- package/dist/{guard-B0viBXC1.d.cts → guard-BXtXoark.d.cts} +68 -1
- package/dist/{guard-B0viBXC1.d.ts → guard-BXtXoark.d.ts} +68 -1
- package/dist/index.cjs +252 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -3
- package/dist/index.d.ts +51 -3
- package/dist/index.js +246 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-Y4YGC4KV.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/livekit.ts","../../src/errors.ts","../../src/gates.ts","../../src/cost_map.json","../../src/voice-pricing.ts"],"sourcesContent":["/**\n * LiveKit Agents adapter (optional peer: `npm i @livekit/agents`).\n *\n * Like the Python `LiveKitBudgetGuard`, a LiveKit `AgentSession` (STT -> LLM ->\n * TTS) has no single call site to wrap: turns fire for the life of a call. The\n * two enforcement points are the agent's LLM turn hook (before the LLM call, so a\n * turn is admitted or blocked before its TTS/audio spend piles on) and the\n * session's usage/metrics event (real usage, after). {@link LiveKitBudgetGuard}\n * holds the reservation state across both.\n *\n * import { BudgetGuard } from \"floe-guard\";\n * import { LiveKitBudgetGuard } from \"floe-guard/adapters/livekit\";\n *\n * const guard = new BudgetGuard(1.0, {\n * priceOverrides: {\n * \"gemini-2.0-flash\": { inputCostPerToken: 0.30e-6, outputCostPerToken: 2.5e-6 },\n * },\n * });\n * const budget = new LiveKitBudgetGuard(guard, { model: \"gemini-2.0-flash\" });\n *\n * const session = new AgentSession({ ... });\n * budget.attach(session, agent); // wire reserve / settle / release\n * await session.start({ agent, room });\n *\n * ## Why agents-js, not a blind port of the Python adapter\n *\n * The Node SDK (`@livekit/agents`) differs from Python and was verified against\n * the installed types (v1.6.x):\n *\n * - **LLM turn hook.** Python wraps `agent.llm_node`, an async generator. The JS\n * analog is `Agent.llmNode(chatCtx, toolCtx, modelSettings):\n * Promise<ReadableStream<ChatChunk | string | FlushSentinel> | null>` — it\n * returns a web `ReadableStream`, not a generator. We reserve BEFORE calling the\n * original, then wrap the returned stream so a consumer cancel (interrupt)\n * releases the hold — the JS twin of Python's generator `except BaseException`.\n *\n * - **Settlement event.** Session-level `metrics_collected` is *deprecated in\n * Python* (→ `session_usage_updated` + `ChatMessage.metrics`). In **agents-js**\n * it is **not** deprecated: `AgentSession` (a `TypedEmitter<AgentSessionCallbacks>`)\n * still emits `metrics_collected` with a `MetricsCollectedEvent { metrics:\n * AgentMetrics }`, and `AgentMetrics` is a discriminated union keyed by `type`\n * (`'llm_metrics' | 'stt_metrics' | 'tts_metrics' | ...`) — not the `isinstance`\n * classes Python uses. We settle on that live event.\n *\n * LiveKit's `LLMMetrics` does not name the served model in a way we rely on, so\n * cost is settled against the `model` passed here (as in Python). STT/TTS spend —\n * often a voice agent's larger bill — is metered whenever you name the vendor:\n * pass `sttModel` / `ttsModel` and the rate comes from the bundled voice cost map,\n * or pass a per-unit override (`sttUsdPerSecond` / `ttsUsdPer1kChars`) which wins\n * over the map. Telephony (per-minute) is metered via {@link meterTelephony},\n * since LiveKit emits no telephony metric. A leg with neither a vendor nor an\n * override is left un-metered (the token-only contract); a vendor the voice map\n * cannot price fails closed ({@link UnpriceableVoiceError}).\n *\n * Scope is strictly **pre-turn / pre-call admission plus per-turn settlement**.\n * There is no mid-call intervention: an admitted turn runs to completion; nothing\n * here cuts a turn off partway.\n */\n\nimport { BudgetExceeded } from \"../errors.js\";\nimport { preCall } from \"../gates.js\";\nimport type { BudgetGuard, ReservationHandle } from \"../guard.js\";\nimport { priceVoiceLeg } from \"../voice-pricing.js\";\n\n/**\n * The `LLMMetrics` fields we settle against (agents-js discriminated-union member\n * `type: 'llm_metrics'`). Typed structurally so the adapter carries no hard\n * dependency on `@livekit/agents` — the same idiom the Vercel-AI middleware uses\n * for `ai`. The test file pins these shapes against the real exported types.\n */\ninterface LlmMetricsLike {\n readonly type: \"llm_metrics\";\n readonly promptTokens: number;\n readonly completionTokens: number;\n}\n\n/** `STTMetrics` fields we meter against (`type: 'stt_metrics'`). Duration is ms. */\ninterface SttMetricsLike {\n readonly type: \"stt_metrics\";\n /** Duration of the pushed audio in **milliseconds** (LiveKit's `audioDurationMs`). */\n readonly audioDurationMs: number;\n}\n\n/** `TTSMetrics` fields we meter against (`type: 'tts_metrics'`). */\ninterface TtsMetricsLike {\n readonly type: \"tts_metrics\";\n readonly charactersCount: number;\n}\n\n/** Any member of LiveKit's `AgentMetrics` union — we branch on `type`. */\ntype AgentMetricsLike =\n | LlmMetricsLike\n | SttMetricsLike\n | TtsMetricsLike\n | { readonly type: string };\n\n/** The `MetricsCollectedEvent` payload (`{ metrics: AgentMetrics }`). */\ninterface MetricsCollectedEventLike {\n readonly metrics: AgentMetricsLike;\n}\n\n/**\n * The slice of `AgentSession` we wire onto — its typed event emitter. Structural,\n * so a stubbed session in a test (or the real `AgentSession`) both satisfy it.\n */\nexport interface LiveKitSessionLike {\n on(event: \"metrics_collected\", listener: (ev: MetricsCollectedEventLike) => void): unknown;\n on(event: \"close\", listener: (ev: unknown) => void): unknown;\n}\n\n/** A web `ReadableStream` (Node 18+ global), as returned by `Agent.llmNode`. */\ntype LlmNodeStream = ReadableStream<unknown>;\n\n/**\n * The slice of `Agent` we wrap — its `llmNode` turn hook. The real signature is\n * `llmNode(chatCtx, toolCtx, modelSettings): Promise<ReadableStream<...> | null>`;\n * we forward the arguments unchanged, so an upstream signature change can't break\n * the wrapper.\n */\nexport interface LiveKitAgentLike {\n llmNode: (...args: unknown[]) => Promise<LlmNodeStream | null>;\n}\n\n/** Callback invoked when a turn is blocked, so the bot can speak a wrap-up line. */\nexport type OnBudgetExceeded = (error: BudgetExceeded) => Promise<void> | void;\n\nexport interface LiveKitBudgetGuardOptions {\n /**\n * Model id to settle LLM cost against (LiveKit's `LLMMetrics` carries no model\n * name we rely on). Must be priceable via the bundled cost map or the guard's\n * `priceOverrides`.\n */\n model: string;\n /**\n * Invoked with the {@link BudgetExceeded} when a turn is blocked, so a bot can\n * speak a graceful \"wrapping up\" line before the turn ends silently (the LLM\n * hook returns no stream). If omitted, the {@link BudgetExceeded} propagates out\n * of `llmNode`.\n */\n onBudgetExceeded?: OnBudgetExceeded;\n /** Voice-map vendor key for the STT leg (e.g. `\"deepgram-nova-3\"`). */\n sttModel?: string;\n /** Voice-map vendor key for the TTS leg (e.g. `\"elevenlabs-flash-v2.5\"`). */\n ttsModel?: string;\n /** Voice-map vendor key for the telephony leg (e.g. `\"twilio-us-inbound-local\"`). */\n telephony?: string;\n /** Per-second STT override — wins over `sttModel`. Omit both to leave STT un-metered. */\n sttUsdPerSecond?: number;\n /** Per-1k-chars TTS override — wins over `ttsModel`. Omit both to leave TTS un-metered. */\n ttsUsdPer1kChars?: number;\n /** Per-minute telephony override — wins over `telephony`. */\n telephonyUsdPerMinute?: number;\n}\n\n/**\n * One `llmNode` invocation awaiting (or already past) its `LLMMetrics` event.\n *\n * `open` means the USD amount is still held on the {@link BudgetGuard}. Early\n * release (next turn, interrupt, close) clears the guard hold but leaves the slot\n * in the FIFO queue so a delayed metrics event settles against this turn's slot\n * (with `amount` 0) instead of stealing a later turn's hold.\n */\ninterface TurnSlot {\n amount: ReservationHandle;\n open: boolean;\n}\n\n/**\n * Enforce a {@link BudgetGuard} ceiling on a LiveKit `AgentSession`, one turn at\n * a time: reserve before the LLM turn, settle on real usage, release on interrupt.\n */\nexport class LiveKitBudgetGuard {\n private readonly guard: BudgetGuard;\n private readonly model: string;\n private readonly onBudgetExceeded?: OnBudgetExceeded;\n private readonly sttModel?: string;\n private readonly ttsModel?: string;\n private readonly telephony?: string;\n private readonly sttUsdPerSecond?: number;\n private readonly ttsUsdPer1kChars?: number;\n private readonly telephonyUsdPerMinute?: number;\n\n private pending = false;\n private attached = false;\n private active: TurnSlot | null = null;\n /** FIFO of turns that may still emit `LLMMetrics` (including early-released). */\n private readonly slots: TurnSlot[] = [];\n /**\n * Cap on the FIFO. A realtime / text-only turn returns no stream and emits\n * `realtime_metrics` (not `llm_metrics`), so its slot never settles and would\n * linger; on a long call the queue would grow without bound. Past this many\n * slots we drop the oldest (releasing an open hold), bounding memory and the\n * settlement drift a stale slot introduces.\n */\n private static readonly MAX_SLOTS = 64;\n\n constructor(guard: BudgetGuard, options: LiveKitBudgetGuardOptions) {\n this.guard = guard;\n this.model = options.model;\n this.onBudgetExceeded = options.onBudgetExceeded;\n this.sttModel = options.sttModel;\n this.ttsModel = options.ttsModel;\n this.telephony = options.telephony;\n this.sttUsdPerSecond = options.sttUsdPerSecond;\n this.ttsUsdPer1kChars = options.ttsUsdPer1kChars;\n this.telephonyUsdPerMinute = options.telephonyUsdPerMinute;\n // Bound once so the emitter calls them with the right `this`.\n this.onMetrics = this.onMetrics.bind(this);\n this.onClose = this.onClose.bind(this);\n // Fail fast: a misconfigured voice vendor throws UnpriceableVoiceError at\n // construction, not mid-call. quantity 0 resolves the rate (priced at $0)\n // without metering; an unconfigured leg is a no-op (null).\n priceVoiceLeg(\"stt\", 0, { model: this.sttModel, override: this.sttUsdPerSecond });\n priceVoiceLeg(\"tts\", 0, { model: this.ttsModel, override: this.ttsUsdPer1kChars });\n priceVoiceLeg(\"telephony\", 0, { model: this.telephony, override: this.telephonyUsdPerMinute });\n }\n\n /**\n * Wire reserve (`agent.llmNode`), settle/meter (`metrics_collected`) and release\n * (`close`) onto a session + agent pair. Reserving before the LLM turn is what\n * blocks a turn before its TTS/audio spend piles on.\n */\n attach(session: LiveKitSessionLike, agent: LiveKitAgentLike): void {\n // One guard binds one session/agent pair. A second attach() would wrap the\n // wrapper and register duplicate listeners — each turn would then reserve and\n // settle twice, double-counting spend. Reject the repeat (a reconnect / retried\n // setup should create a fresh LiveKitBudgetGuard).\n if (this.attached) {\n throw new Error(\n \"LiveKitBudgetGuard.attach() called twice — a guard instance binds one \" +\n \"session/agent pair. Create a new LiveKitBudgetGuard to re-attach.\",\n );\n }\n this.attached = true;\n // Bind so the original keeps its `this` when we call it from the wrapper.\n const origLlmNode = agent.llmNode.bind(agent);\n\n const guardedLlmNode = async (...args: unknown[]): Promise<LlmNodeStream | null> => {\n // A previous turn that never settled still holds its reservation — release\n // the guard hold before opening this one, but keep a queue slot so delayed\n // metrics cannot steal this turn's hold.\n if (this.pending) this.earlyReleaseActive();\n\n let handle: ReservationHandle;\n try {\n handle = this.guard.reserve(); // throws BudgetExceeded before the turn runs\n } catch (err) {\n this.clearActive();\n if (err instanceof BudgetExceeded && this.onBudgetExceeded !== undefined) {\n // Let the bot speak a wrap-up line; the turn ends with no stream.\n await this.onBudgetExceeded(err);\n return null;\n }\n throw err;\n }\n\n const slot: TurnSlot = { amount: handle, open: true };\n this.slots.push(slot);\n this.active = slot;\n this.pending = true;\n this.trimSlots(slot);\n\n let stream: LlmNodeStream | null;\n try {\n stream = await origLlmNode(...args);\n } catch (err) {\n // Release only if this invocation still owns the open hold — a later turn\n // may already have early-released ours and reserved its own.\n if (this.active === slot) this.earlyReleaseActive();\n throw err;\n }\n\n // No stream to wrap (realtime / text-only turn): leave the slot open for the\n // metrics event to settle against.\n if (stream === null) return null;\n return this.guardStream(stream, slot);\n };\n\n agent.llmNode = guardedLlmNode;\n session.on(\"metrics_collected\", this.onMetrics);\n session.on(\"close\", this.onClose);\n }\n\n /**\n * Pre-call admission decision (`true` = admit, `false` = reject), delegating to\n * {@link preCall} on the wrapped guard's remaining budget. A coarse,\n * non-binding preflight — the binding hard-stop is the per-turn reserve wired by\n * {@link attach}. Pass `estimatedCallUsd` (e.g. `$/min × expected minutes`) to\n * reject earlier, when the remaining budget can't cover the call.\n */\n admitCall(options: { estimatedCallUsd?: number } = {}): boolean {\n return preCall(this.guard, options);\n }\n\n /**\n * Accrue telephony spend for `minutes` of call time (per-minute).\n *\n * LiveKit emits no telephony metric, so the transport/caller drives this — call\n * it as the call accrues minutes, or once with the final duration. This is\n * per-minute accrual, not live line-cutting: the guard meters the leg, it does\n * not cut the phone line mid-call. Priced from the voice map when `telephony` is\n * set, or the `telephonyUsdPerMinute` override; returns `null` (no-op) when the\n * leg is unconfigured, and fails closed on a vendor the voice map cannot price.\n * Returns the USD accrued, if any.\n */\n meterTelephony(minutes: number): number | null {\n const cost = priceVoiceLeg(\"telephony\", minutes, {\n model: this.telephony,\n override: this.telephonyUsdPerMinute,\n });\n if (cost !== null) this.guard.recordTool(\"livekit-telephony\", cost);\n return cost;\n }\n\n /**\n * Wrap the `llmNode` stream so a consumer cancel (interrupt) releases this turn's\n * hold — the JS twin of Python's generator `except BaseException`. Chunks pass\n * through untouched; a clean end leaves the hold for the metrics event to settle.\n */\n private guardStream(stream: LlmNodeStream, slot: TurnSlot): LlmNodeStream {\n const release = (): void => {\n // Release only if this turn still owns the open hold — a metrics event may\n // already have settled it, or a later turn early-released it.\n if (this.active === slot) this.earlyReleaseActive();\n };\n return stream.pipeThrough(\n new TransformStream<unknown, unknown>({\n transform(chunk, controller) {\n controller.enqueue(chunk); // passthrough; we only need the lifecycle hooks\n },\n // Clean completion: do NOT release — leave the hold for the metrics event\n // to settle against (mirrors Python's generator finishing normally).\n flush() {},\n // Interrupt / downstream cancel: free the held budget. `Transformer.cancel`\n // is honored on Node >=20.14; Node 18 does NOT invoke it — there the hold is\n // released at the next turn's early-release or on session close instead\n // (delayed, never leaked). TS's Transformer lib type lags and omits cancel —\n // cast to keep the type check (as the Vercel-AI middleware does).\n cancel() {\n release();\n },\n } as Transformer<unknown, unknown>),\n );\n }\n\n private onMetrics(ev: MetricsCollectedEventLike): void {\n const m = ev.metrics;\n if (m.type === \"llm_metrics\") {\n const metrics = m as LlmMetricsLike;\n // Pop the oldest turn slot. Early-released turns contribute 0 so a delayed\n // metrics event meters usage without consuming a later hold. An empty queue\n // (reserve hook bypassed) settles as a plain record().\n let reserved: ReservationHandle = 0;\n const slot = this.slots.shift();\n if (slot !== undefined) {\n if (slot.open) {\n reserved = slot.amount;\n slot.open = false;\n }\n if (this.active === slot) this.clearActive();\n }\n this.guard.settle(this.model, metrics.promptTokens, metrics.completionTokens, { reserved });\n } else if (m.type === \"stt_metrics\") {\n // audioDurationMs is milliseconds; the STT leg is priced per second.\n const seconds = (m as SttMetricsLike).audioDurationMs / 1000;\n const cost = priceVoiceLeg(\"stt\", seconds, {\n model: this.sttModel,\n override: this.sttUsdPerSecond,\n });\n if (cost !== null) this.guard.recordTool(\"livekit-stt\", cost);\n } else if (m.type === \"tts_metrics\") {\n const cost = priceVoiceLeg(\"tts\", (m as TtsMetricsLike).charactersCount, {\n model: this.ttsModel,\n override: this.ttsUsdPer1kChars,\n });\n if (cost !== null) this.guard.recordTool(\"livekit-tts\", cost);\n }\n // Other metric kinds (VAD, EOU, realtime, ...) carry no billable leg here.\n }\n\n private onClose(): void {\n // Session torn down with a turn still reserved — release it. Drop any leftover\n // slots so a post-close metrics event cannot touch a stale hold.\n if (this.pending) this.earlyReleaseActive();\n this.slots.length = 0;\n }\n\n private clearActive(): void {\n this.active = null;\n this.pending = false;\n }\n\n /** Drop the open guard hold; leave a zeroed queue slot for delayed metrics. */\n private earlyReleaseActive(): void {\n const slot = this.active;\n if (slot === null || !slot.open) {\n this.clearActive();\n return;\n }\n this.guard.release(slot.amount);\n slot.open = false;\n slot.amount = 0;\n this.clearActive();\n }\n\n /**\n * Bound the FIFO: drop oldest slots past {@link MAX_SLOTS}, releasing an open\n * hold as it goes. Never drops the just-reserved active slot. Prevents a long\n * call from accumulating slots for turns that never emit `llm_metrics`.\n */\n private trimSlots(active: TurnSlot): void {\n while (this.slots.length > LiveKitBudgetGuard.MAX_SLOTS && this.slots[0] !== active) {\n const stale = this.slots.shift();\n if (stale !== undefined && stale.open) this.guard.release(stale.amount);\n }\n }\n}\n","/**\n * Exceptions for floe-guard.\n *\n * Everything derives from {@link FloeGuardError} (the package-root base) so callers\n * can catch the whole family with a single `catch (e) { if (e instanceof FloeGuardError) ... }`.\n *\n * Mirrors `src/floe_guard/errors.py` in the Python package — message formats are\n * kept byte-for-byte identical so both adapters read the same.\n */\n\n/** Base class for every error raised by floe-guard. */\nexport class FloeGuardError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FloeGuardError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown before an LLM call that would cross the configured spend ceiling.\n *\n * The guard throws this *instead of* letting the next call run, so a runaway loop\n * stops here rather than burning more money.\n */\nexport class BudgetExceeded extends FloeGuardError {\n readonly spentUsd: number;\n readonly limitUsd: number;\n\n constructor(spentUsd: number, limitUsd: number, message?: string) {\n // Subclasses (the token twin) pass their own message through so they don't\n // have to reassign `this.message` after super().\n super(\n message ??\n `BUDGET EXCEEDED — call blocked (spent $${spentUsd.toFixed(6)} of $${limitUsd.toFixed(6)} ceiling)`,\n );\n this.name = \"BudgetExceeded\";\n this.spentUsd = spentUsd;\n this.limitUsd = limitUsd;\n }\n}\n\n/**\n * Thrown before a call that would cross a token ceiling (aggregate or step).\n *\n * The token twin of {@link BudgetExceeded} — it extends it so the same retry\n * logic that treats a USD block as terminal (`!(error instanceof\n * BudgetExceeded)`) treats a token block as terminal too, with no extra wiring.\n * `spentUsd` / `limitUsd` are inherited but not meaningful here; the token\n * fields are the payload.\n *\n * `scope` is `\"aggregate\"` (the guard-wide `tokenLimit`) or `\"step\"` (the\n * innermost active {@link BudgetGuard.step} cap).\n */\nexport class TokenBudgetExceeded extends BudgetExceeded {\n readonly spentTokens: number;\n readonly limitTokens: number;\n readonly scope: \"aggregate\" | \"step\";\n\n constructor(spentTokens: number, limitTokens: number, scope: \"aggregate\" | \"step\") {\n // Pass the token-shaped message through super (BudgetExceeded's default is\n // dollar-shaped); 0/0 for the inherited spentUsd/limitUsd — a token block\n // spent no tracked USD.\n super(\n 0,\n 0,\n `TOKEN BUDGET EXCEEDED — call blocked (${scope}: ${spentTokens} of ` +\n `${limitTokens} token ceiling)`,\n );\n this.name = \"TokenBudgetExceeded\";\n this.spentTokens = spentTokens;\n this.limitTokens = limitTokens;\n this.scope = scope;\n }\n}\n\n/**\n * Thrown when a model cannot be priced and the guard is fail-closed.\n *\n * We refuse rather than silently accrue $0 — \"we cannot cap what we cannot price\".\n * Pass a manual price (`priceOverrides` or `record(..., { price })`) to make the\n * model enforceable.\n */\nexport class UnpriceableModelError extends FloeGuardError {\n readonly model: string;\n\n constructor(model: string) {\n super(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price was given. The guard cannot enforce a budget on spend ` +\n `it cannot measure. Pass a price override to enable enforcement.`,\n );\n this.name = \"UnpriceableModelError\";\n this.model = model;\n }\n}\n\n/**\n * Thrown when a voice leg (STT/TTS/telephony) cannot be priced and the guard is\n * fail-closed.\n *\n * The voice twin of {@link UnpriceableModelError}: we refuse rather than silently\n * accrue $0 — \"we cannot cap what we cannot price\". It fires when an adapter is\n * asked to meter a leg for a vendor that is absent from the bundled voice cost map\n * (or whose entry has the wrong unit/mode for the leg) and no per-unit override was\n * given. Pass a per-unit rate (`stt_usd_per_second` / `tts_usd_per_1k_chars` /\n * `telephony_usd_per_minute`) to make the leg enforceable.\n *\n * Mirrors `UnpriceableVoiceError` in `src/floe_guard/errors.py`.\n */\nexport class UnpriceableVoiceError extends FloeGuardError {\n readonly vendor: string | null;\n readonly mode: string;\n\n constructor(vendor: string | null, mode: string) {\n // Match Python's `{vendor!r}`: a string is quoted, None renders as `None`.\n const shown = vendor === null ? \"None\" : `'${vendor}'`;\n super(\n `Cannot price ${mode} vendor ${shown}: not in the bundled voice cost ` +\n `map (or its entry has the wrong unit for a ${mode} leg) and no per-unit ` +\n `override was given. The guard cannot enforce a budget on spend it ` +\n `cannot measure. Pass a per-unit rate to enable enforcement.`,\n );\n this.name = \"UnpriceableVoiceError\";\n this.vendor = vendor;\n this.mode = mode;\n }\n}\n\n/**\n * Thrown before a call whose projected duration would blow the SLA.\n *\n * The latency twin of {@link BudgetExceeded}: `LatencyBudget.check()` throws this\n * *instead of* letting the next tool/model call start, so the chain sheds work or\n * falls back to a faster path rather than violating the end-user SLA. Cooperative —\n * killing an already-running stalled call is the framework's job (AbortSignal),\n * not the guard's.\n *\n * Mirrors `DeadlineExceeded` in `src/floe_guard/errors.py` — message format is\n * kept byte-for-byte identical so both adapters read the same.\n */\n/** Shared millisecond rounding for cross-language message parity: `toFixed(0)`\n * rounds half-up while Python's `:.0f` rounds half-to-even, so tie values\n * would break the byte-for-byte contract. Both packages use floor(x + 0.5)\n * (see `_round_half_up` in `src/floe_guard/errors.py`). */\nfunction roundHalfUp(ms: number): number {\n return Math.floor(ms + 0.5);\n}\n\nexport class DeadlineExceeded extends FloeGuardError {\n readonly elapsedMs: number;\n readonly slaMs: number;\n\n constructor(elapsedMs: number, slaMs: number) {\n super(\n `DEADLINE EXCEEDED — call blocked (elapsed ${roundHalfUp(elapsedMs)}ms of ${roundHalfUp(slaMs)}ms SLA)`,\n );\n this.name = \"DeadlineExceeded\";\n this.elapsedMs = elapsedMs;\n this.slaMs = slaMs;\n }\n}\n","/**\n * Pre-call admission gates for voice orchestrators.\n *\n * These decide **at the call boundary** whether to *admit* or *reject* an incoming\n * call, from the guard's remaining budget. They return the exact JSON shape each\n * provider's inbound webhook expects, so a free/local user can reject a call on\n * budget exhaustion with the **same contract** the hosted gateway serves — the paid\n * upgrade is a URL swap, not a rewrite.\n *\n * Scope — strictly pre-call. A gate answers one question: *given the budget left,\n * do we let this call start?* It does **not** intervene mid-call. Once a call is\n * admitted it runs to completion; nothing here cuts a call off partway.\n *\n * Budget, not balance: admission reads the guard's local *remaining budget*, a\n * ceiling signal — not an account balance. US-only telephony, v1.\n *\n * A faithful port of `src/floe_guard/gates.py`.\n */\n\nimport type { BudgetGuard } from \"./guard.js\";\n\n/**\n * True when there isn't budget left to admit one more call.\n *\n * A **non-binding preflight read**: it checks the guard's `remainingUsd` but does\n * *not* reserve anything, so under concurrent inbound calls it can admit more than\n * the budget strictly covers (two calls may see the same headroom and both pass).\n * It is coarse admission control — the binding, atomic hard-stop is the in-call\n * guard (`check` / `reserve` while the call runs). This mirrors the hosted pre-dial\n * gate, which is likewise check-only.\n *\n * With the default `estimatedCallUsd = 0` a call is rejected only once the budget\n * is fully spent (`remainingUsd` at or below zero). Pass an estimate (e.g.\n * `$/min × expected minutes`) to reject earlier, when the remaining budget can't\n * cover it; an estimate that *exactly* equals the remaining budget still admits\n * (inclusive ceiling, matching `BudgetGuard.reserve`). Budget signal, not a balance.\n *\n * @throws RangeError when `estimatedCallUsd` is negative or non-finite — a bad\n * estimate must not silently admit an exhausted guard (NaN/negative comparisons\n * are always false, the same trap `BudgetGuard` rejects for `limitUsd`).\n */\nexport function budgetExhausted(\n guard: BudgetGuard,\n options: { estimatedCallUsd?: number } = {},\n): boolean {\n // Default ONLY undefined — a `null` estimate is malformed input and must reach\n // validation (below) rather than being silently coerced to 0 (which would admit\n // the call with no intended headroom). Mirrors Python raising on a None estimate.\n const estimatedCallUsd = options.estimatedCallUsd === undefined ? 0 : options.estimatedCallUsd;\n if (!Number.isFinite(estimatedCallUsd) || estimatedCallUsd < 0) {\n throw new RangeError(\n `estimatedCallUsd must be a finite, non-negative number, got ${estimatedCallUsd}`,\n );\n }\n const remainingUsd = guard.remainingUsd;\n return remainingUsd <= 0 || remainingUsd < estimatedCallUsd;\n}\n\n/**\n * Generic pre-call admission decision: `true` = admit, `false` = reject.\n *\n * The provider-agnostic gate for Pipecat, custom telephony, or any inbound hook\n * without a first-class helper below. Wire the `false` case into your provider's\n * reject path.\n *\n * TODO(bland): Bland's *Send Call* metadata field name is an OPEN VERIFICATION\n * ITEM (pending confirmation) — this package does not invent it. Use `preCall` to\n * get the admit/reject decision and map `false` onto Bland's Pathway Webhook node\n * once the field name is confirmed.\n */\nexport function preCall(guard: BudgetGuard, options: { estimatedCallUsd?: number } = {}): boolean {\n return !budgetExhausted(guard, options);\n}\n\n/**\n * Response for Retell's inbound-call webhook — reject or admit the call.\n *\n * On budget exhaustion returns `{ call_inbound: { reject: true } }`; otherwise\n * `{ call_inbound: {...} }` carrying any `admit` overrides you pass\n * (`dynamic_variables`, `metadata`, `override_agent_id`, …).\n *\n * Retell contract (verified against docs.retellai.com/features/inbound-call-webhook):\n * **only the boolean `true` rejects** — any other value is ignored. The webhook\n * fires for inbound **phone and SMS** calls (not dial-to-sip); its behaviour for\n * web calls is not documented, so treat this as phone/SMS-only. 10s timeout, up to\n * 3 retries.\n */\nexport function retell(\n guard: BudgetGuard,\n options: { estimatedCallUsd?: number; admit?: Record<string, unknown> } = {},\n): { call_inbound: Record<string, unknown> } {\n if (budgetExhausted(guard, { estimatedCallUsd: options.estimatedCallUsd })) {\n return { call_inbound: { reject: true } };\n }\n // The gate's budget decision — not the caller's overrides — controls admission.\n // Strip `reject` from admit overrides so an errant `admit: { reject: true }` on\n // an available-budget call can't flip the response into Retell's reject shape.\n const safeAdmit = { ...(options.admit ?? {}) };\n delete safeAdmit.reject;\n return { call_inbound: safeAdmit };\n}\n\n/**\n * Response for Vapi's `assistant-request` webhook — reject or admit the call.\n *\n * On budget exhaustion returns `{ error: errorMessage }` (Vapi speaks it, then ends\n * the call). Otherwise admits with `{ assistantId }` if given (`assistantId` takes\n * precedence), else `{ assistant }`.\n *\n * Vapi has **no** `reject: true` boolean — rejection *is* returning an error, and\n * admission *is* returning an assistant. Respond within **~7.5 s** or the call may\n * fail (verified against docs.vapi.ai/server-url/spam-call-rejection).\n *\n * @throws RangeError when admitted (budget available) but neither `assistant` nor\n * `assistantId` was provided — there'd be nothing to hand Vapi.\n */\nexport function vapi(\n guard: BudgetGuard,\n options: {\n assistant?: Record<string, unknown>;\n assistantId?: string;\n errorMessage?: string;\n estimatedCallUsd?: number;\n } = {},\n): Record<string, unknown> {\n const {\n assistant,\n assistantId,\n errorMessage = \"Sorry, this agent is out of budget right now.\",\n estimatedCallUsd,\n } = options;\n if (budgetExhausted(guard, { estimatedCallUsd })) {\n return { error: errorMessage };\n }\n if (assistantId !== undefined && assistantId !== null) {\n return { assistantId };\n }\n if (assistant !== undefined && assistant !== null) {\n return { assistant };\n }\n throw new RangeError(\n \"vapi() admitted the call but has nothing to return: pass assistant or \" +\n \"assistantId for the admit path.\",\n );\n}\n","{\n \"chatgpt-4o-latest\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-haiku-20240307\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-opus-20240229\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-opus-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-sonnet-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-fable-5\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5-20251001\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1-20250805\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5-20251101\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6-20260205\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7-20260416\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-8\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-6\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-5\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0613\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 8e-7,\n \"output_cost_per_token\": 0.0000032,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 8e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash-001\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash-lite\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash-lite-001\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-computer-use-preview-10-2025\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-lite\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-lite-preview-06-17\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-lite-preview-09-2025\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-native-audio-latest\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-native-audio-preview-09-2025\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-native-audio-preview-12-2025\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-preview-09-2025\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-pro\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-pro-preview-tts\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3-flash-preview\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.000003,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3-pro-preview\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-flash-lite\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-flash-live-preview\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-pro-preview\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.5-flash\": {\n \"input_cost_per_token\": 0.0000015,\n \"output_cost_per_token\": 0.000009,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.5-flash-lite\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.6-flash\": {\n \"input_cost_per_token\": 0.0000015,\n \"output_cost_per_token\": 0.0000075,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-embedding-001\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"embedding\"\n },\n \"gemini-embedding-2\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"embedding\"\n },\n \"gemini-embedding-2-preview\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"embedding\"\n },\n \"gemini-exp-1206\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-flash-latest\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-flash-lite-latest\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-gemma-2-27b-it\": {\n \"input_cost_per_token\": 3.5e-7,\n \"output_cost_per_token\": 0.00000105,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-gemma-2-9b-it\": {\n \"input_cost_per_token\": 3.5e-7,\n \"output_cost_per_token\": 0.00000105,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-omni-flash-preview\": {\n \"input_cost_per_token\": 0.0000015,\n \"output_cost_per_token\": 0.000009,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-pro-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-robotics-er-1.5-preview\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-robotics-er-1.6-preview\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-robotics-er-2-preview\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-16k\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000004,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0125-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0314\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-1106-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-05-13\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-2025-08-07\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api-2025-10-14\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-2025-11-13\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-2025-12-11\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.3-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-2026-03-05\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini-2026-03-17\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano-2026-03-17\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5-2026-04-23\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-luna\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-sol\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-terra\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-1.5\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-2025-08-28\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"llama-3.1-8b-instant\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 8e-8,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"llama-3.3-70b-versatile\": {\n \"input_cost_per_token\": 5.9e-7,\n \"output_cost_per_token\": 7.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"meta-llama/llama-4-scout-17b-16e-instruct\": {\n \"input_cost_per_token\": 1.1e-7,\n \"output_cost_per_token\": 3.4e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"o1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o1-2024-12-17\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-2025-04-16\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini-2025-01-31\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-120b\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-safeguard-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"qwen/qwen3-32b\": {\n \"input_cost_per_token\": 2.9e-7,\n \"output_cost_per_token\": 5.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"text-embedding-3-large\": {\n \"input_cost_per_token\": 1.3e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-3-small\": {\n \"input_cost_per_token\": 2e-8,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002-v2\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"__voice__\": {\n \"deepgram-nova-3\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0001283333,\n \"provider\": \"deepgram\"\n },\n \"deepgram-nova-3-multilingual\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0001533333,\n \"provider\": \"deepgram\"\n },\n \"deepgram-nova-3-base\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0002416667,\n \"provider\": \"deepgram\"\n },\n \"assemblyai-universal-streaming\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0000416667,\n \"provider\": \"assemblyai\"\n },\n \"elevenlabs-multilingual-v2\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.1,\n \"provider\": \"elevenlabs\"\n },\n \"elevenlabs-flash-v2.5\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.05,\n \"provider\": \"elevenlabs\"\n },\n \"elevenlabs-turbo-v2.5\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.05,\n \"provider\": \"elevenlabs\"\n },\n \"cartesia-sonic\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.03,\n \"provider\": \"cartesia\"\n },\n \"cartesia-line\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.06,\n \"provider\": \"cartesia\"\n },\n \"rime-mist-v2\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.03,\n \"provider\": \"rime\"\n },\n \"twilio-us-inbound-local\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.0085,\n \"provider\": \"twilio\"\n },\n \"twilio-us-outbound-local\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.014,\n \"provider\": \"twilio\"\n },\n \"twilio-us-sip-inbound\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.004,\n \"provider\": \"twilio\"\n }\n }\n}\n","/**\n * Offline pricing for voice legs (STT / TTS / telephony) from the vendored map.\n *\n * The voice twin of `pricing.ts`. The token cost map is per-token; a voice\n * pipeline's bill is per-second (STT), per-1k-chars (TTS), and per-minute\n * (telephony) instead, so the voice rates live under the reserved `\"__voice__\"`\n * key of `cost_map.json` with their own schema:\n *\n * \"deepgram-nova-3\": {\n * \"mode\": \"stt\", // discriminator: \"stt\" | \"tts\" | \"telephony\"\n * \"unit\": \"usd_per_second\", // explicit unit — a mismatch fails closed\n * \"rate\": 0.0001283333, // USD in that unit\n * \"provider\": \"deepgram\"\n * }\n *\n * Same fail-closed contract as token pricing: a vendor absent from the map (or an\n * entry whose `unit`/`mode` does not match the leg it is asked to price) is\n * unpriceable — {@link lookupVoiceRate} returns `null` and the adapter throws\n * {@link UnpriceableVoiceError} rather than silently metering the leg at $0. Pass a\n * per-unit override to enforce a leg the map cannot price.\n *\n * No network. The rates are a **drift-prone snapshot** of each vendor's public\n * list price — refresh them (`scripts/update-cost-map.mjs`) like the token map, or\n * estimates drift as vendors change prices. Telephony is **US-only in v1**.\n *\n * This is a faithful port of `src/floe_guard/voice_pricing.py`.\n */\n\nimport costMapJson from \"./cost_map.json\";\nimport { UnpriceableVoiceError } from \"./errors.js\";\n\nexport type VoiceMode = \"stt\" | \"tts\" | \"telephony\";\n\ninterface VoiceMapEntry {\n mode?: unknown;\n unit?: unknown;\n rate?: unknown;\n provider?: unknown;\n}\n\n/** The vendored voice rates — the reserved `\"__voice__\"` section of the cost map. */\nconst VOICE_MAP = ((costMapJson as Record<string, unknown>)[\"__voice__\"] ?? {}) as Record<\n string,\n VoiceMapEntry\n>;\n\n/**\n * The one unit each leg is billed in. An entry whose `unit` disagrees with its\n * leg is a schema mismatch and fails closed — a Deepgram $/min figure stored\n * without the ÷60 conversion would over-bill 60x if it were silently accepted.\n */\nexport const unitForMode: Record<VoiceMode, string> = {\n stt: \"usd_per_second\",\n tts: \"usd_per_1k_chars\",\n telephony: \"usd_per_minute\",\n};\n\n/** A resolved per-unit voice rate plus where it came from. */\nexport interface VoiceRate {\n mode: string;\n unit: string;\n rate: number;\n source: \"override\" | \"cost_map\";\n}\n\nfunction finiteNonNegative(value: unknown): value is number {\n // typeof excludes booleans (Python's _finite_non_negative excludes bool too).\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\n/**\n * Resolve a voice vendor to its per-unit rate, or `null` if unpriceable.\n *\n * The pure resolver (the voice twin of {@link resolvePrice}): it never throws.\n * Fail-closed on every mismatch — a missing vendor, an entry whose `mode` is not\n * `mode`, an entry whose `unit` is not the canonical unit for `mode`, or a\n * non-finite/negative rate — so a schema slip can never surface as a silent,\n * valid-looking price.\n */\nexport function lookupVoiceRate(model: string | null | undefined, mode: VoiceMode): number | null {\n if (model === null || model === undefined) return null;\n const entry = Object.prototype.hasOwnProperty.call(VOICE_MAP, model)\n ? VOICE_MAP[model]\n : undefined;\n if (!entry) return null;\n if (entry.mode !== mode) return null;\n if (entry.unit !== unitForMode[mode]) return null;\n const rate = entry.rate;\n if (!finiteNonNegative(rate)) return null;\n return rate;\n}\n\n/**\n * Resolve a leg's per-unit rate, fail-closed. An `override` wins over the map.\n *\n * Throws {@link UnpriceableVoiceError} when neither an override nor the bundled\n * map can price the leg — the guard refuses to meter spend it cannot measure.\n */\nexport function resolveVoiceRate(\n model: string | null | undefined,\n mode: VoiceMode,\n override?: number | null,\n): VoiceRate {\n if (override !== undefined && override !== null) {\n if (!finiteNonNegative(override)) {\n throw new RangeError(\n `voice ${mode} override must be a finite, non-negative number, got ${override}`,\n );\n }\n return { mode, unit: unitForMode[mode], rate: override, source: \"override\" };\n }\n const rate = lookupVoiceRate(model, mode);\n if (rate === null) throw new UnpriceableVoiceError(model ?? null, mode);\n return { mode, unit: unitForMode[mode], rate, source: \"cost_map\" };\n}\n\n/**\n * USD for one leg. `quantity` is seconds (stt), characters (tts), or minutes\n * (telephony); negative quantities clamp to zero.\n */\nexport function voiceLegCost(mode: VoiceMode, quantity: number, rate: number): number {\n // Reject non-finite quantities: Math.max(0, NaN) is NaN, so a NaN/Infinity\n // quantity would return a non-finite USD amount that then poisons the guard's\n // running total (NaN disables every ceiling comparison). Negatives still clamp.\n if (!Number.isFinite(quantity)) {\n throw new RangeError(`voice ${mode} quantity must be a finite number, got ${quantity}`);\n }\n const q = Math.max(0, quantity);\n if (mode === \"stt\") return q * rate; // seconds * $/second\n if (mode === \"tts\") return (q / 1000) * rate; // chars / 1000 * $/1k-chars\n if (mode === \"telephony\") return q * rate; // minutes * $/minute\n throw new RangeError(`unknown voice mode ${mode}`);\n}\n\n/**\n * USD for one voice leg, or `null` when the leg is unconfigured (skip it).\n *\n * The single entry point the adapters use. A leg with neither a vendor (`model`)\n * nor an `override` is unconfigured — return `null` so the token-only contract is\n * preserved and nothing is metered. A leg that *is* configured but cannot be\n * priced throws {@link UnpriceableVoiceError} (via {@link resolveVoiceRate}) rather\n * than accruing a silent $0.\n */\nexport function priceVoiceLeg(\n mode: VoiceMode,\n quantity: number,\n options: { model?: string | null; override?: number | null } = {},\n): number | null {\n const model = options.model ?? null;\n const override = options.override ?? null;\n if (model === null && override === null) return null;\n const resolved = resolveVoiceRate(model, mode, override);\n return voiceLegCost(mode, quantity, resolved.rate);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/livekit.ts","../../src/errors.ts","../../src/gates.ts","../../src/cost_map.json","../../src/voice-pricing.ts"],"sourcesContent":["/**\n * LiveKit Agents adapter (optional peer: `npm i @livekit/agents`).\n *\n * Like the Python `LiveKitBudgetGuard`, a LiveKit `AgentSession` (STT -> LLM ->\n * TTS) has no single call site to wrap: turns fire for the life of a call. The\n * two enforcement points are the agent's LLM turn hook (before the LLM call, so a\n * turn is admitted or blocked before its TTS/audio spend piles on) and the\n * session's usage/metrics event (real usage, after). {@link LiveKitBudgetGuard}\n * holds the reservation state across both.\n *\n * import { BudgetGuard } from \"floe-guard\";\n * import { LiveKitBudgetGuard } from \"floe-guard/adapters/livekit\";\n *\n * const guard = new BudgetGuard(1.0, {\n * priceOverrides: {\n * \"gemini-2.0-flash\": { inputCostPerToken: 0.30e-6, outputCostPerToken: 2.5e-6 },\n * },\n * });\n * const budget = new LiveKitBudgetGuard(guard, { model: \"gemini-2.0-flash\" });\n *\n * const session = new AgentSession({ ... });\n * budget.attach(session, agent); // wire reserve / settle / release\n * await session.start({ agent, room });\n *\n * ## Why agents-js, not a blind port of the Python adapter\n *\n * The Node SDK (`@livekit/agents`) differs from Python and was verified against\n * the installed types (v1.6.x):\n *\n * - **LLM turn hook.** Python wraps `agent.llm_node`, an async generator. The JS\n * analog is `Agent.llmNode(chatCtx, toolCtx, modelSettings):\n * Promise<ReadableStream<ChatChunk | string | FlushSentinel> | null>` — it\n * returns a web `ReadableStream`, not a generator. We reserve BEFORE calling the\n * original, then wrap the returned stream so a consumer cancel (interrupt)\n * releases the hold — the JS twin of Python's generator `except BaseException`.\n *\n * - **Settlement event.** Session-level `metrics_collected` is *deprecated in\n * Python* (→ `session_usage_updated` + `ChatMessage.metrics`). In **agents-js**\n * it is **not** deprecated: `AgentSession` (a `TypedEmitter<AgentSessionCallbacks>`)\n * still emits `metrics_collected` with a `MetricsCollectedEvent { metrics:\n * AgentMetrics }`, and `AgentMetrics` is a discriminated union keyed by `type`\n * (`'llm_metrics' | 'stt_metrics' | 'tts_metrics' | ...`) — not the `isinstance`\n * classes Python uses. We settle on that live event.\n *\n * LiveKit's `LLMMetrics` does not name the served model in a way we rely on, so\n * cost is settled against the `model` passed here (as in Python). STT/TTS spend —\n * often a voice agent's larger bill — is metered whenever you name the vendor:\n * pass `sttModel` / `ttsModel` and the rate comes from the bundled voice cost map,\n * or pass a per-unit override (`sttUsdPerSecond` / `ttsUsdPer1kChars`) which wins\n * over the map. Telephony (per-minute) is metered via {@link meterTelephony},\n * since LiveKit emits no telephony metric. A leg with neither a vendor nor an\n * override is left un-metered (the token-only contract); a vendor the voice map\n * cannot price fails closed ({@link UnpriceableVoiceError}).\n *\n * Scope is strictly **pre-turn / pre-call admission plus per-turn settlement**.\n * There is no mid-call intervention: an admitted turn runs to completion; nothing\n * here cuts a turn off partway.\n */\n\nimport { BudgetExceeded } from \"../errors.js\";\nimport { preCall } from \"../gates.js\";\nimport type { BudgetGuard, ReservationHandle } from \"../guard.js\";\nimport { priceVoiceLeg } from \"../voice-pricing.js\";\n\n/**\n * The `LLMMetrics` fields we settle against (agents-js discriminated-union member\n * `type: 'llm_metrics'`). Typed structurally so the adapter carries no hard\n * dependency on `@livekit/agents` — the same idiom the Vercel-AI middleware uses\n * for `ai`. The test file pins these shapes against the real exported types.\n */\ninterface LlmMetricsLike {\n readonly type: \"llm_metrics\";\n readonly promptTokens: number;\n readonly completionTokens: number;\n}\n\n/** `STTMetrics` fields we meter against (`type: 'stt_metrics'`). Duration is ms. */\ninterface SttMetricsLike {\n readonly type: \"stt_metrics\";\n /** Duration of the pushed audio in **milliseconds** (LiveKit's `audioDurationMs`). */\n readonly audioDurationMs: number;\n}\n\n/** `TTSMetrics` fields we meter against (`type: 'tts_metrics'`). */\ninterface TtsMetricsLike {\n readonly type: \"tts_metrics\";\n readonly charactersCount: number;\n}\n\n/** Any member of LiveKit's `AgentMetrics` union — we branch on `type`. */\ntype AgentMetricsLike =\n | LlmMetricsLike\n | SttMetricsLike\n | TtsMetricsLike\n | { readonly type: string };\n\n/** The `MetricsCollectedEvent` payload (`{ metrics: AgentMetrics }`). */\ninterface MetricsCollectedEventLike {\n readonly metrics: AgentMetricsLike;\n}\n\n/**\n * The slice of `AgentSession` we wire onto — its typed event emitter. Structural,\n * so a stubbed session in a test (or the real `AgentSession`) both satisfy it.\n */\nexport interface LiveKitSessionLike {\n on(event: \"metrics_collected\", listener: (ev: MetricsCollectedEventLike) => void): unknown;\n on(event: \"close\", listener: (ev: unknown) => void): unknown;\n}\n\n/** A web `ReadableStream` (Node 18+ global), as returned by `Agent.llmNode`. */\ntype LlmNodeStream = ReadableStream<unknown>;\n\n/**\n * The slice of `Agent` we wrap — its `llmNode` turn hook. The real signature is\n * `llmNode(chatCtx, toolCtx, modelSettings): Promise<ReadableStream<...> | null>`;\n * we forward the arguments unchanged, so an upstream signature change can't break\n * the wrapper.\n */\nexport interface LiveKitAgentLike {\n llmNode: (...args: unknown[]) => Promise<LlmNodeStream | null>;\n}\n\n/** Callback invoked when a turn is blocked, so the bot can speak a wrap-up line. */\nexport type OnBudgetExceeded = (error: BudgetExceeded) => Promise<void> | void;\n\nexport interface LiveKitBudgetGuardOptions {\n /**\n * Model id to settle LLM cost against (LiveKit's `LLMMetrics` carries no model\n * name we rely on). Must be priceable via the bundled cost map or the guard's\n * `priceOverrides`.\n */\n model: string;\n /**\n * Invoked with the {@link BudgetExceeded} when a turn is blocked, so a bot can\n * speak a graceful \"wrapping up\" line before the turn ends silently (the LLM\n * hook returns no stream). If omitted, the {@link BudgetExceeded} propagates out\n * of `llmNode`.\n */\n onBudgetExceeded?: OnBudgetExceeded;\n /** Voice-map vendor key for the STT leg (e.g. `\"deepgram-nova-3\"`). */\n sttModel?: string;\n /** Voice-map vendor key for the TTS leg (e.g. `\"elevenlabs-flash-v2.5\"`). */\n ttsModel?: string;\n /** Voice-map vendor key for the telephony leg (e.g. `\"twilio-us-inbound-local\"`). */\n telephony?: string;\n /** Per-second STT override — wins over `sttModel`. Omit both to leave STT un-metered. */\n sttUsdPerSecond?: number;\n /** Per-1k-chars TTS override — wins over `ttsModel`. Omit both to leave TTS un-metered. */\n ttsUsdPer1kChars?: number;\n /** Per-minute telephony override — wins over `telephony`. */\n telephonyUsdPerMinute?: number;\n}\n\n/**\n * One `llmNode` invocation awaiting (or already past) its `LLMMetrics` event.\n *\n * `open` means the USD amount is still held on the {@link BudgetGuard}. Early\n * release (next turn, interrupt, close) clears the guard hold but leaves the slot\n * in the FIFO queue so a delayed metrics event settles against this turn's slot\n * (with `amount` 0) instead of stealing a later turn's hold.\n */\ninterface TurnSlot {\n amount: ReservationHandle;\n open: boolean;\n}\n\n/**\n * Enforce a {@link BudgetGuard} ceiling on a LiveKit `AgentSession`, one turn at\n * a time: reserve before the LLM turn, settle on real usage, release on interrupt.\n */\nexport class LiveKitBudgetGuard {\n private readonly guard: BudgetGuard;\n private readonly model: string;\n private readonly onBudgetExceeded?: OnBudgetExceeded;\n private readonly sttModel?: string;\n private readonly ttsModel?: string;\n private readonly telephony?: string;\n private readonly sttUsdPerSecond?: number;\n private readonly ttsUsdPer1kChars?: number;\n private readonly telephonyUsdPerMinute?: number;\n\n private pending = false;\n private attached = false;\n private active: TurnSlot | null = null;\n /** FIFO of turns that may still emit `LLMMetrics` (including early-released). */\n private readonly slots: TurnSlot[] = [];\n /**\n * Cap on the FIFO. A realtime / text-only turn returns no stream and emits\n * `realtime_metrics` (not `llm_metrics`), so its slot never settles and would\n * linger; on a long call the queue would grow without bound. Past this many\n * slots we drop the oldest (releasing an open hold), bounding memory and the\n * settlement drift a stale slot introduces.\n */\n private static readonly MAX_SLOTS = 64;\n\n constructor(guard: BudgetGuard, options: LiveKitBudgetGuardOptions) {\n this.guard = guard;\n this.model = options.model;\n this.onBudgetExceeded = options.onBudgetExceeded;\n this.sttModel = options.sttModel;\n this.ttsModel = options.ttsModel;\n this.telephony = options.telephony;\n this.sttUsdPerSecond = options.sttUsdPerSecond;\n this.ttsUsdPer1kChars = options.ttsUsdPer1kChars;\n this.telephonyUsdPerMinute = options.telephonyUsdPerMinute;\n // Bound once so the emitter calls them with the right `this`.\n this.onMetrics = this.onMetrics.bind(this);\n this.onClose = this.onClose.bind(this);\n // Fail fast: a misconfigured voice vendor throws UnpriceableVoiceError at\n // construction, not mid-call. quantity 0 resolves the rate (priced at $0)\n // without metering; an unconfigured leg is a no-op (null).\n priceVoiceLeg(\"stt\", 0, { model: this.sttModel, override: this.sttUsdPerSecond });\n priceVoiceLeg(\"tts\", 0, { model: this.ttsModel, override: this.ttsUsdPer1kChars });\n priceVoiceLeg(\"telephony\", 0, { model: this.telephony, override: this.telephonyUsdPerMinute });\n }\n\n /**\n * Wire reserve (`agent.llmNode`), settle/meter (`metrics_collected`) and release\n * (`close`) onto a session + agent pair. Reserving before the LLM turn is what\n * blocks a turn before its TTS/audio spend piles on.\n */\n attach(session: LiveKitSessionLike, agent: LiveKitAgentLike): void {\n // One guard binds one session/agent pair. A second attach() would wrap the\n // wrapper and register duplicate listeners — each turn would then reserve and\n // settle twice, double-counting spend. Reject the repeat (a reconnect / retried\n // setup should create a fresh LiveKitBudgetGuard).\n if (this.attached) {\n throw new Error(\n \"LiveKitBudgetGuard.attach() called twice — a guard instance binds one \" +\n \"session/agent pair. Create a new LiveKitBudgetGuard to re-attach.\",\n );\n }\n this.attached = true;\n // Bind so the original keeps its `this` when we call it from the wrapper.\n const origLlmNode = agent.llmNode.bind(agent);\n\n const guardedLlmNode = async (...args: unknown[]): Promise<LlmNodeStream | null> => {\n // A previous turn that never settled still holds its reservation — release\n // the guard hold before opening this one, but keep a queue slot so delayed\n // metrics cannot steal this turn's hold.\n if (this.pending) this.earlyReleaseActive();\n\n let handle: ReservationHandle;\n try {\n handle = this.guard.reserve(); // throws BudgetExceeded before the turn runs\n } catch (err) {\n this.clearActive();\n if (err instanceof BudgetExceeded && this.onBudgetExceeded !== undefined) {\n // Let the bot speak a wrap-up line; the turn ends with no stream.\n await this.onBudgetExceeded(err);\n return null;\n }\n throw err;\n }\n\n const slot: TurnSlot = { amount: handle, open: true };\n this.slots.push(slot);\n this.active = slot;\n this.pending = true;\n this.trimSlots(slot);\n\n let stream: LlmNodeStream | null;\n try {\n stream = await origLlmNode(...args);\n } catch (err) {\n // Release only if this invocation still owns the open hold — a later turn\n // may already have early-released ours and reserved its own.\n if (this.active === slot) this.earlyReleaseActive();\n throw err;\n }\n\n // No stream to wrap (realtime / text-only turn): leave the slot open for the\n // metrics event to settle against.\n if (stream === null) return null;\n return this.guardStream(stream, slot);\n };\n\n agent.llmNode = guardedLlmNode;\n session.on(\"metrics_collected\", this.onMetrics);\n session.on(\"close\", this.onClose);\n }\n\n /**\n * Pre-call admission decision (`true` = admit, `false` = reject), delegating to\n * {@link preCall} on the wrapped guard's remaining budget. A coarse,\n * non-binding preflight — the binding hard-stop is the per-turn reserve wired by\n * {@link attach}. Pass `estimatedCallUsd` (e.g. `$/min × expected minutes`) to\n * reject earlier, when the remaining budget can't cover the call.\n */\n admitCall(options: { estimatedCallUsd?: number } = {}): boolean {\n return preCall(this.guard, options);\n }\n\n /**\n * Accrue telephony spend for `minutes` of call time (per-minute).\n *\n * LiveKit emits no telephony metric, so the transport/caller drives this — call\n * it as the call accrues minutes, or once with the final duration. This is\n * per-minute accrual, not live line-cutting: the guard meters the leg, it does\n * not cut the phone line mid-call. Priced from the voice map when `telephony` is\n * set, or the `telephonyUsdPerMinute` override; returns `null` (no-op) when the\n * leg is unconfigured, and fails closed on a vendor the voice map cannot price.\n * Returns the USD accrued, if any.\n */\n meterTelephony(minutes: number): number | null {\n const cost = priceVoiceLeg(\"telephony\", minutes, {\n model: this.telephony,\n override: this.telephonyUsdPerMinute,\n });\n if (cost !== null) this.guard.recordTool(\"livekit-telephony\", cost);\n return cost;\n }\n\n /**\n * Wrap the `llmNode` stream so a consumer cancel (interrupt) releases this turn's\n * hold — the JS twin of Python's generator `except BaseException`. Chunks pass\n * through untouched; a clean end leaves the hold for the metrics event to settle.\n */\n private guardStream(stream: LlmNodeStream, slot: TurnSlot): LlmNodeStream {\n const release = (): void => {\n // Release only if this turn still owns the open hold — a metrics event may\n // already have settled it, or a later turn early-released it.\n if (this.active === slot) this.earlyReleaseActive();\n };\n return stream.pipeThrough(\n new TransformStream<unknown, unknown>({\n transform(chunk, controller) {\n controller.enqueue(chunk); // passthrough; we only need the lifecycle hooks\n },\n // Clean completion: do NOT release — leave the hold for the metrics event\n // to settle against (mirrors Python's generator finishing normally).\n flush() {},\n // Interrupt / downstream cancel: free the held budget. `Transformer.cancel`\n // is honored on Node >=20.14; Node 18 does NOT invoke it — there the hold is\n // released at the next turn's early-release or on session close instead\n // (delayed, never leaked). TS's Transformer lib type lags and omits cancel —\n // cast to keep the type check (as the Vercel-AI middleware does).\n cancel() {\n release();\n },\n } as Transformer<unknown, unknown>),\n );\n }\n\n private onMetrics(ev: MetricsCollectedEventLike): void {\n const m = ev.metrics;\n if (m.type === \"llm_metrics\") {\n const metrics = m as LlmMetricsLike;\n // Pop the oldest turn slot. Early-released turns contribute 0 so a delayed\n // metrics event meters usage without consuming a later hold. An empty queue\n // (reserve hook bypassed) settles as a plain record().\n let reserved: ReservationHandle = 0;\n const slot = this.slots.shift();\n if (slot !== undefined) {\n if (slot.open) {\n reserved = slot.amount;\n slot.open = false;\n }\n if (this.active === slot) this.clearActive();\n }\n this.guard.settle(this.model, metrics.promptTokens, metrics.completionTokens, { reserved });\n } else if (m.type === \"stt_metrics\") {\n // audioDurationMs is milliseconds; the STT leg is priced per second.\n const seconds = (m as SttMetricsLike).audioDurationMs / 1000;\n const cost = priceVoiceLeg(\"stt\", seconds, {\n model: this.sttModel,\n override: this.sttUsdPerSecond,\n });\n if (cost !== null) this.guard.recordTool(\"livekit-stt\", cost);\n } else if (m.type === \"tts_metrics\") {\n const cost = priceVoiceLeg(\"tts\", (m as TtsMetricsLike).charactersCount, {\n model: this.ttsModel,\n override: this.ttsUsdPer1kChars,\n });\n if (cost !== null) this.guard.recordTool(\"livekit-tts\", cost);\n }\n // Other metric kinds (VAD, EOU, realtime, ...) carry no billable leg here.\n }\n\n private onClose(): void {\n // Session torn down with a turn still reserved — release it. Drop any leftover\n // slots so a post-close metrics event cannot touch a stale hold.\n if (this.pending) this.earlyReleaseActive();\n this.slots.length = 0;\n }\n\n private clearActive(): void {\n this.active = null;\n this.pending = false;\n }\n\n /** Drop the open guard hold; leave a zeroed queue slot for delayed metrics. */\n private earlyReleaseActive(): void {\n const slot = this.active;\n if (slot === null || !slot.open) {\n this.clearActive();\n return;\n }\n this.guard.release(slot.amount);\n slot.open = false;\n slot.amount = 0;\n this.clearActive();\n }\n\n /**\n * Bound the FIFO: drop oldest slots past {@link MAX_SLOTS}, releasing an open\n * hold as it goes. Never drops the just-reserved active slot. Prevents a long\n * call from accumulating slots for turns that never emit `llm_metrics`.\n */\n private trimSlots(active: TurnSlot): void {\n while (this.slots.length > LiveKitBudgetGuard.MAX_SLOTS && this.slots[0] !== active) {\n const stale = this.slots.shift();\n if (stale !== undefined && stale.open) this.guard.release(stale.amount);\n }\n }\n}\n","/**\n * Exceptions for floe-guard.\n *\n * Everything derives from {@link FloeGuardError} (the package-root base) so callers\n * can catch the whole family with a single `catch (e) { if (e instanceof FloeGuardError) ... }`.\n *\n * Mirrors `src/floe_guard/errors.py` in the Python package — message formats are\n * kept byte-for-byte identical so both adapters read the same.\n */\n\n/** Base class for every error raised by floe-guard. */\nexport class FloeGuardError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FloeGuardError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown before an LLM call that would cross the configured spend ceiling.\n *\n * The guard throws this *instead of* letting the next call run, so a runaway loop\n * stops here rather than burning more money.\n */\nexport class BudgetExceeded extends FloeGuardError {\n readonly spentUsd: number;\n readonly limitUsd: number;\n\n constructor(spentUsd: number, limitUsd: number, message?: string) {\n // Subclasses (the token twin) pass their own message through so they don't\n // have to reassign `this.message` after super().\n super(\n message ??\n `BUDGET EXCEEDED — call blocked (spent $${spentUsd.toFixed(6)} of $${limitUsd.toFixed(6)} ceiling)`,\n );\n this.name = \"BudgetExceeded\";\n this.spentUsd = spentUsd;\n this.limitUsd = limitUsd;\n }\n}\n\n/**\n * Thrown before a call that would cross a token ceiling (aggregate or step).\n *\n * The token twin of {@link BudgetExceeded} — it extends it so the same retry\n * logic that treats a USD block as terminal (`!(error instanceof\n * BudgetExceeded)`) treats a token block as terminal too, with no extra wiring.\n * `spentUsd` / `limitUsd` are inherited but not meaningful here; the token\n * fields are the payload.\n *\n * `scope` is `\"aggregate\"` (the guard-wide `tokenLimit`) or `\"step\"` (the\n * innermost active {@link BudgetGuard.step} cap).\n */\nexport class TokenBudgetExceeded extends BudgetExceeded {\n readonly spentTokens: number;\n readonly limitTokens: number;\n readonly scope: \"aggregate\" | \"step\";\n\n constructor(spentTokens: number, limitTokens: number, scope: \"aggregate\" | \"step\") {\n // Pass the token-shaped message through super (BudgetExceeded's default is\n // dollar-shaped); 0/0 for the inherited spentUsd/limitUsd — a token block\n // spent no tracked USD.\n super(\n 0,\n 0,\n `TOKEN BUDGET EXCEEDED — call blocked (${scope}: ${spentTokens} of ` +\n `${limitTokens} token ceiling)`,\n );\n this.name = \"TokenBudgetExceeded\";\n this.spentTokens = spentTokens;\n this.limitTokens = limitTokens;\n this.scope = scope;\n }\n}\n\n/**\n * Thrown when a model cannot be priced and the guard is fail-closed.\n *\n * We refuse rather than silently accrue $0 — \"we cannot cap what we cannot price\".\n * Pass a manual price (`priceOverrides` or `record(..., { price })`) to make the\n * model enforceable.\n */\nexport class UnpriceableModelError extends FloeGuardError {\n readonly model: string;\n\n constructor(model: string) {\n super(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price was given. The guard cannot enforce a budget on spend ` +\n `it cannot measure. Pass a price override to enable enforcement.`,\n );\n this.name = \"UnpriceableModelError\";\n this.model = model;\n }\n}\n\n/**\n * Thrown when a voice leg (STT/TTS/telephony) cannot be priced and the guard is\n * fail-closed.\n *\n * The voice twin of {@link UnpriceableModelError}: we refuse rather than silently\n * accrue $0 — \"we cannot cap what we cannot price\". It fires when an adapter is\n * asked to meter a leg for a vendor that is absent from the bundled voice cost map\n * (or whose entry has the wrong unit/mode for the leg) and no per-unit override was\n * given. Pass a per-unit rate (`stt_usd_per_second` / `tts_usd_per_1k_chars` /\n * `telephony_usd_per_minute`) to make the leg enforceable.\n *\n * Mirrors `UnpriceableVoiceError` in `src/floe_guard/errors.py`.\n */\nexport class UnpriceableVoiceError extends FloeGuardError {\n readonly vendor: string | null;\n readonly mode: string;\n\n constructor(vendor: string | null, mode: string) {\n // Match Python's `{vendor!r}`: a string is quoted, None renders as `None`.\n const shown = vendor === null ? \"None\" : `'${vendor}'`;\n super(\n `Cannot price ${mode} vendor ${shown}: not in the bundled voice cost ` +\n `map (or its entry has the wrong unit for a ${mode} leg) and no per-unit ` +\n `override was given. The guard cannot enforce a budget on spend it ` +\n `cannot measure. Pass a per-unit rate to enable enforcement.`,\n );\n this.name = \"UnpriceableVoiceError\";\n this.vendor = vendor;\n this.mode = mode;\n }\n}\n\n/**\n * Thrown when an **opt-in** ledger sync to Reconcile Mode fails.\n *\n * Covers a missing API key, a non-https/malformed base URL, a non-2xx response\n * (401 bad/missing key, 403 agent closed/suspended), a network/timeout failure, or\n * a malformed response. Sync is off by default and only runs when the caller\n * explicitly opts in ({@link BudgetGuard.enableSync} + {@link BudgetGuard.sync}) —\n * this error never fires for a guard that hasn't opted in, because such a guard\n * never sends.\n *\n * Mirrors `LedgerSyncError` in `src/floe_guard/errors.py`.\n */\nexport class LedgerSyncError extends FloeGuardError {\n constructor(message: string) {\n super(message);\n this.name = \"LedgerSyncError\";\n }\n}\n\n/**\n * Thrown before a call whose projected duration would blow the SLA.\n *\n * The latency twin of {@link BudgetExceeded}: `LatencyBudget.check()` throws this\n * *instead of* letting the next tool/model call start, so the chain sheds work or\n * falls back to a faster path rather than violating the end-user SLA. Cooperative —\n * killing an already-running stalled call is the framework's job (AbortSignal),\n * not the guard's.\n *\n * Mirrors `DeadlineExceeded` in `src/floe_guard/errors.py` — message format is\n * kept byte-for-byte identical so both adapters read the same.\n */\n/** Shared millisecond rounding for cross-language message parity: `toFixed(0)`\n * rounds half-up while Python's `:.0f` rounds half-to-even, so tie values\n * would break the byte-for-byte contract. Both packages use floor(x + 0.5)\n * (see `_round_half_up` in `src/floe_guard/errors.py`). */\nfunction roundHalfUp(ms: number): number {\n return Math.floor(ms + 0.5);\n}\n\nexport class DeadlineExceeded extends FloeGuardError {\n readonly elapsedMs: number;\n readonly slaMs: number;\n\n constructor(elapsedMs: number, slaMs: number) {\n super(\n `DEADLINE EXCEEDED — call blocked (elapsed ${roundHalfUp(elapsedMs)}ms of ${roundHalfUp(slaMs)}ms SLA)`,\n );\n this.name = \"DeadlineExceeded\";\n this.elapsedMs = elapsedMs;\n this.slaMs = slaMs;\n }\n}\n","/**\n * Pre-call admission gates for voice orchestrators.\n *\n * These decide **at the call boundary** whether to *admit* or *reject* an incoming\n * call, from the guard's remaining budget. They return the exact JSON shape each\n * provider's inbound webhook expects, so a free/local user can reject a call on\n * budget exhaustion with the **same contract** the hosted gateway serves — the paid\n * upgrade is a URL swap, not a rewrite.\n *\n * Scope — strictly pre-call. A gate answers one question: *given the budget left,\n * do we let this call start?* It does **not** intervene mid-call. Once a call is\n * admitted it runs to completion; nothing here cuts a call off partway.\n *\n * Budget, not balance: admission reads the guard's local *remaining budget*, a\n * ceiling signal — not an account balance. US-only telephony, v1.\n *\n * A faithful port of `src/floe_guard/gates.py`.\n */\n\nimport type { BudgetGuard } from \"./guard.js\";\n\n/**\n * True when there isn't budget left to admit one more call.\n *\n * A **non-binding preflight read**: it checks the guard's `remainingUsd` but does\n * *not* reserve anything, so under concurrent inbound calls it can admit more than\n * the budget strictly covers (two calls may see the same headroom and both pass).\n * It is coarse admission control — the binding, atomic hard-stop is the in-call\n * guard (`check` / `reserve` while the call runs). This mirrors the hosted pre-dial\n * gate, which is likewise check-only.\n *\n * With the default `estimatedCallUsd = 0` a call is rejected only once the budget\n * is fully spent (`remainingUsd` at or below zero). Pass an estimate (e.g.\n * `$/min × expected minutes`) to reject earlier, when the remaining budget can't\n * cover it; an estimate that *exactly* equals the remaining budget still admits\n * (inclusive ceiling, matching `BudgetGuard.reserve`). Budget signal, not a balance.\n *\n * @throws RangeError when `estimatedCallUsd` is negative or non-finite — a bad\n * estimate must not silently admit an exhausted guard (NaN/negative comparisons\n * are always false, the same trap `BudgetGuard` rejects for `limitUsd`).\n */\nexport function budgetExhausted(\n guard: BudgetGuard,\n options: { estimatedCallUsd?: number } = {},\n): boolean {\n // Default ONLY undefined — a `null` estimate is malformed input and must reach\n // validation (below) rather than being silently coerced to 0 (which would admit\n // the call with no intended headroom). Mirrors Python raising on a None estimate.\n const estimatedCallUsd = options.estimatedCallUsd === undefined ? 0 : options.estimatedCallUsd;\n if (!Number.isFinite(estimatedCallUsd) || estimatedCallUsd < 0) {\n throw new RangeError(\n `estimatedCallUsd must be a finite, non-negative number, got ${estimatedCallUsd}`,\n );\n }\n const remainingUsd = guard.remainingUsd;\n return remainingUsd <= 0 || remainingUsd < estimatedCallUsd;\n}\n\n/**\n * Generic pre-call admission decision: `true` = admit, `false` = reject.\n *\n * The provider-agnostic gate for Pipecat, custom telephony, or any inbound hook\n * without a first-class helper below. Wire the `false` case into your provider's\n * reject path.\n *\n * TODO(bland): Bland's *Send Call* metadata field name is an OPEN VERIFICATION\n * ITEM (pending confirmation) — this package does not invent it. Use `preCall` to\n * get the admit/reject decision and map `false` onto Bland's Pathway Webhook node\n * once the field name is confirmed.\n */\nexport function preCall(guard: BudgetGuard, options: { estimatedCallUsd?: number } = {}): boolean {\n return !budgetExhausted(guard, options);\n}\n\n/**\n * Response for Retell's inbound-call webhook — reject or admit the call.\n *\n * On budget exhaustion returns `{ call_inbound: { reject: true } }`; otherwise\n * `{ call_inbound: {...} }` carrying any `admit` overrides you pass\n * (`dynamic_variables`, `metadata`, `override_agent_id`, …).\n *\n * Retell contract (verified against docs.retellai.com/features/inbound-call-webhook):\n * **only the boolean `true` rejects** — any other value is ignored. The webhook\n * fires for inbound **phone and SMS** calls (not dial-to-sip); its behaviour for\n * web calls is not documented, so treat this as phone/SMS-only. 10s timeout, up to\n * 3 retries.\n */\nexport function retell(\n guard: BudgetGuard,\n options: { estimatedCallUsd?: number; admit?: Record<string, unknown> } = {},\n): { call_inbound: Record<string, unknown> } {\n if (budgetExhausted(guard, { estimatedCallUsd: options.estimatedCallUsd })) {\n return { call_inbound: { reject: true } };\n }\n // The gate's budget decision — not the caller's overrides — controls admission.\n // Strip `reject` from admit overrides so an errant `admit: { reject: true }` on\n // an available-budget call can't flip the response into Retell's reject shape.\n const safeAdmit = { ...(options.admit ?? {}) };\n delete safeAdmit.reject;\n return { call_inbound: safeAdmit };\n}\n\n/**\n * Response for Vapi's `assistant-request` webhook — reject or admit the call.\n *\n * On budget exhaustion returns `{ error: errorMessage }` (Vapi speaks it, then ends\n * the call). Otherwise admits with `{ assistantId }` if given (`assistantId` takes\n * precedence), else `{ assistant }`.\n *\n * Vapi has **no** `reject: true` boolean — rejection *is* returning an error, and\n * admission *is* returning an assistant. Respond within **~7.5 s** or the call may\n * fail (verified against docs.vapi.ai/server-url/spam-call-rejection).\n *\n * @throws RangeError when admitted (budget available) but neither `assistant` nor\n * `assistantId` was provided — there'd be nothing to hand Vapi.\n */\nexport function vapi(\n guard: BudgetGuard,\n options: {\n assistant?: Record<string, unknown>;\n assistantId?: string;\n errorMessage?: string;\n estimatedCallUsd?: number;\n } = {},\n): Record<string, unknown> {\n const {\n assistant,\n assistantId,\n errorMessage = \"Sorry, this agent is out of budget right now.\",\n estimatedCallUsd,\n } = options;\n if (budgetExhausted(guard, { estimatedCallUsd })) {\n return { error: errorMessage };\n }\n if (assistantId !== undefined && assistantId !== null) {\n return { assistantId };\n }\n if (assistant !== undefined && assistant !== null) {\n return { assistant };\n }\n throw new RangeError(\n \"vapi() admitted the call but has nothing to return: pass assistant or \" +\n \"assistantId for the admit path.\",\n );\n}\n","{\n \"chatgpt-4o-latest\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-haiku-20240307\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-opus-20240229\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-opus-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-sonnet-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-fable-5\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5-20251001\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1-20250805\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5-20251101\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6-20260205\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7-20260416\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-8\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-6\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-5\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0613\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 8e-7,\n \"output_cost_per_token\": 0.0000032,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 8e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash-001\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash-lite\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.0-flash-lite-001\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-computer-use-preview-10-2025\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-lite\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-lite-preview-06-17\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-lite-preview-09-2025\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-native-audio-latest\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-native-audio-preview-09-2025\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-native-audio-preview-12-2025\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-flash-preview-09-2025\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-pro\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-2.5-pro-preview-tts\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3-flash-preview\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.000003,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3-pro-preview\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-flash-lite\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-flash-live-preview\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-pro-preview\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.5-flash\": {\n \"input_cost_per_token\": 0.0000015,\n \"output_cost_per_token\": 0.000009,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.5-flash-lite\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-3.6-flash\": {\n \"input_cost_per_token\": 0.0000015,\n \"output_cost_per_token\": 0.0000075,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-embedding-001\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"embedding\"\n },\n \"gemini-embedding-2\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"embedding\"\n },\n \"gemini-embedding-2-preview\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"embedding\"\n },\n \"gemini-exp-1206\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-flash-latest\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-flash-lite-latest\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-gemma-2-27b-it\": {\n \"input_cost_per_token\": 3.5e-7,\n \"output_cost_per_token\": 0.00000105,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-gemma-2-9b-it\": {\n \"input_cost_per_token\": 3.5e-7,\n \"output_cost_per_token\": 0.00000105,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-omni-flash-preview\": {\n \"input_cost_per_token\": 0.0000015,\n \"output_cost_per_token\": 0.000009,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-pro-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-robotics-er-1.5-preview\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000025,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-robotics-er-1.6-preview\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gemini-robotics-er-2-preview\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"gemini\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-16k\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000004,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0125-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0314\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-1106-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-05-13\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-2025-08-07\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api-2025-10-14\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-2025-11-13\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-2025-12-11\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.3-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-2026-03-05\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini-2026-03-17\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano-2026-03-17\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5-2026-04-23\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-luna\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-sol\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-terra\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-1.5\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-2025-08-28\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"llama-3.1-8b-instant\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 8e-8,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"llama-3.3-70b-versatile\": {\n \"input_cost_per_token\": 5.9e-7,\n \"output_cost_per_token\": 7.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"meta-llama/llama-4-scout-17b-16e-instruct\": {\n \"input_cost_per_token\": 1.1e-7,\n \"output_cost_per_token\": 3.4e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"o1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o1-2024-12-17\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-2025-04-16\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini-2025-01-31\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-120b\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-safeguard-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"qwen/qwen3-32b\": {\n \"input_cost_per_token\": 2.9e-7,\n \"output_cost_per_token\": 5.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"text-embedding-3-large\": {\n \"input_cost_per_token\": 1.3e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-3-small\": {\n \"input_cost_per_token\": 2e-8,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002-v2\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"__voice__\": {\n \"deepgram-nova-3\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0001283333,\n \"provider\": \"deepgram\"\n },\n \"deepgram-nova-3-multilingual\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0001533333,\n \"provider\": \"deepgram\"\n },\n \"deepgram-nova-3-base\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0002416667,\n \"provider\": \"deepgram\"\n },\n \"assemblyai-universal-streaming\": {\n \"mode\": \"stt\",\n \"unit\": \"usd_per_second\",\n \"rate\": 0.0000416667,\n \"provider\": \"assemblyai\"\n },\n \"elevenlabs-multilingual-v2\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.1,\n \"provider\": \"elevenlabs\"\n },\n \"elevenlabs-flash-v2.5\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.05,\n \"provider\": \"elevenlabs\"\n },\n \"elevenlabs-turbo-v2.5\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.05,\n \"provider\": \"elevenlabs\"\n },\n \"cartesia-sonic\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.03,\n \"provider\": \"cartesia\"\n },\n \"cartesia-line\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.06,\n \"provider\": \"cartesia\"\n },\n \"rime-mist-v2\": {\n \"mode\": \"tts\",\n \"unit\": \"usd_per_1k_chars\",\n \"rate\": 0.03,\n \"provider\": \"rime\"\n },\n \"twilio-us-inbound-local\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.0085,\n \"provider\": \"twilio\"\n },\n \"twilio-us-outbound-local\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.014,\n \"provider\": \"twilio\"\n },\n \"twilio-us-sip-inbound\": {\n \"mode\": \"telephony\",\n \"unit\": \"usd_per_minute\",\n \"rate\": 0.004,\n \"provider\": \"twilio\"\n }\n }\n}\n","/**\n * Offline pricing for voice legs (STT / TTS / telephony) from the vendored map.\n *\n * The voice twin of `pricing.ts`. The token cost map is per-token; a voice\n * pipeline's bill is per-second (STT), per-1k-chars (TTS), and per-minute\n * (telephony) instead, so the voice rates live under the reserved `\"__voice__\"`\n * key of `cost_map.json` with their own schema:\n *\n * \"deepgram-nova-3\": {\n * \"mode\": \"stt\", // discriminator: \"stt\" | \"tts\" | \"telephony\"\n * \"unit\": \"usd_per_second\", // explicit unit — a mismatch fails closed\n * \"rate\": 0.0001283333, // USD in that unit\n * \"provider\": \"deepgram\"\n * }\n *\n * Same fail-closed contract as token pricing: a vendor absent from the map (or an\n * entry whose `unit`/`mode` does not match the leg it is asked to price) is\n * unpriceable — {@link lookupVoiceRate} returns `null` and the adapter throws\n * {@link UnpriceableVoiceError} rather than silently metering the leg at $0. Pass a\n * per-unit override to enforce a leg the map cannot price.\n *\n * No network. The rates are a **drift-prone snapshot** of each vendor's public\n * list price — refresh them (`scripts/update-cost-map.mjs`) like the token map, or\n * estimates drift as vendors change prices. Telephony is **US-only in v1**.\n *\n * This is a faithful port of `src/floe_guard/voice_pricing.py`.\n */\n\nimport costMapJson from \"./cost_map.json\";\nimport { UnpriceableVoiceError } from \"./errors.js\";\n\nexport type VoiceMode = \"stt\" | \"tts\" | \"telephony\";\n\ninterface VoiceMapEntry {\n mode?: unknown;\n unit?: unknown;\n rate?: unknown;\n provider?: unknown;\n}\n\n/** The vendored voice rates — the reserved `\"__voice__\"` section of the cost map. */\nconst VOICE_MAP = ((costMapJson as Record<string, unknown>)[\"__voice__\"] ?? {}) as Record<\n string,\n VoiceMapEntry\n>;\n\n/**\n * The one unit each leg is billed in. An entry whose `unit` disagrees with its\n * leg is a schema mismatch and fails closed — a Deepgram $/min figure stored\n * without the ÷60 conversion would over-bill 60x if it were silently accepted.\n */\nexport const unitForMode: Record<VoiceMode, string> = {\n stt: \"usd_per_second\",\n tts: \"usd_per_1k_chars\",\n telephony: \"usd_per_minute\",\n};\n\n/** A resolved per-unit voice rate plus where it came from. */\nexport interface VoiceRate {\n mode: string;\n unit: string;\n rate: number;\n source: \"override\" | \"cost_map\";\n}\n\nfunction finiteNonNegative(value: unknown): value is number {\n // typeof excludes booleans (Python's _finite_non_negative excludes bool too).\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\n/**\n * Resolve a voice vendor to its per-unit rate, or `null` if unpriceable.\n *\n * The pure resolver (the voice twin of {@link resolvePrice}): it never throws.\n * Fail-closed on every mismatch — a missing vendor, an entry whose `mode` is not\n * `mode`, an entry whose `unit` is not the canonical unit for `mode`, or a\n * non-finite/negative rate — so a schema slip can never surface as a silent,\n * valid-looking price.\n */\nexport function lookupVoiceRate(model: string | null | undefined, mode: VoiceMode): number | null {\n if (model === null || model === undefined) return null;\n const entry = Object.prototype.hasOwnProperty.call(VOICE_MAP, model)\n ? VOICE_MAP[model]\n : undefined;\n if (!entry) return null;\n if (entry.mode !== mode) return null;\n if (entry.unit !== unitForMode[mode]) return null;\n const rate = entry.rate;\n if (!finiteNonNegative(rate)) return null;\n return rate;\n}\n\n/**\n * Resolve a leg's per-unit rate, fail-closed. An `override` wins over the map.\n *\n * Throws {@link UnpriceableVoiceError} when neither an override nor the bundled\n * map can price the leg — the guard refuses to meter spend it cannot measure.\n */\nexport function resolveVoiceRate(\n model: string | null | undefined,\n mode: VoiceMode,\n override?: number | null,\n): VoiceRate {\n if (override !== undefined && override !== null) {\n if (!finiteNonNegative(override)) {\n throw new RangeError(\n `voice ${mode} override must be a finite, non-negative number, got ${override}`,\n );\n }\n return { mode, unit: unitForMode[mode], rate: override, source: \"override\" };\n }\n const rate = lookupVoiceRate(model, mode);\n if (rate === null) throw new UnpriceableVoiceError(model ?? null, mode);\n return { mode, unit: unitForMode[mode], rate, source: \"cost_map\" };\n}\n\n/**\n * USD for one leg. `quantity` is seconds (stt), characters (tts), or minutes\n * (telephony); negative quantities clamp to zero.\n */\nexport function voiceLegCost(mode: VoiceMode, quantity: number, rate: number): number {\n // Reject non-finite quantities: Math.max(0, NaN) is NaN, so a NaN/Infinity\n // quantity would return a non-finite USD amount that then poisons the guard's\n // running total (NaN disables every ceiling comparison). Negatives still clamp.\n if (!Number.isFinite(quantity)) {\n throw new RangeError(`voice ${mode} quantity must be a finite number, got ${quantity}`);\n }\n const q = Math.max(0, quantity);\n if (mode === \"stt\") return q * rate; // seconds * $/second\n if (mode === \"tts\") return (q / 1000) * rate; // chars / 1000 * $/1k-chars\n if (mode === \"telephony\") return q * rate; // minutes * $/minute\n throw new RangeError(`unknown voice mode ${mode}`);\n}\n\n/**\n * USD for one voice leg, or `null` when the leg is unconfigured (skip it).\n *\n * The single entry point the adapters use. A leg with neither a vendor (`model`)\n * nor an `override` is unconfigured — return `null` so the token-only contract is\n * preserved and nothing is metered. A leg that *is* configured but cannot be\n * priced throws {@link UnpriceableVoiceError} (via {@link resolveVoiceRate}) rather\n * than accruing a silent $0.\n */\nexport function priceVoiceLeg(\n mode: VoiceMode,\n quantity: number,\n options: { model?: string | null; override?: number | null } = {},\n): number | null {\n const model = options.model ?? null;\n const override = options.override ?? null;\n if (model === null && override === null) return null;\n const resolved = resolveVoiceRate(model, mode, override);\n return voiceLegCost(mode, quantity, resolved.rate);\n}\n"],"mappings":"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","names":[]}
|