import type { ActorTokenUsage } from "./actor-contract.js"; export declare const PRICING_SCHEMA = "humanish.pricing.v1"; export declare const ACTOR_ESTIMATED_COST_SCHEMA = "humanish.actor-estimated-cost.v1"; export interface ModelRate { /** USD per input token (the per-1M equivalent is noted in the comment beside each entry). */ inputUsdPerToken: number; /** USD per output token. */ outputUsdPerToken: number; /** USD per input token served from the provider's prompt cache, when the provider bills those at * a reduced rate. Optional: absent means we do not model a discount and every input token is * billed at `inputUsdPerToken` — the previous behavior, kept as the fallback so a rate sheet * without this field prices exactly as it did before (#391). */ cachedInputUsdPerToken?: number; /** USD per input token newly WRITTEN to the provider's prompt cache, when the provider bills * writes (OpenAI: GPT-5.6+ bills `cache_write_tokens` at 1.25x the uncached input rate, as the * TOTAL rate for those tokens — not an extra charge on top). Absent = writes are free (every * pre-5.6 model) and any reported write tokens price at the plain input rate. */ cacheWriteUsdPerToken?: number; /** Long-context tier, when the provider re-prices the WHOLE request past an input-size * threshold (OpenAI GPT-5.6: >272K input tokens => 2x input-side, 1.5x output, full request). * Priced exactly only when the usage carries per-request `turns` records; totals alone cannot * say which requests crossed, so without turns the estimate stays on the short-context rate * (the historical behavior, and the under-estimate direction is called out in #334's fix). */ longContext?: { thresholdInputTokens: number; inputMultiplier: number; outputMultiplier: number; }; /** "YYYY-MM-DD" the entry was last checked against `source`. */ asOf: string; /** Public pricing page the number came from (a comment/URL, never a secret). */ source: string; /** true = a stand-in NOT copied from a live sheet; the estimate carries this flag so a * placeholder rate is never mistaken for a confirmed one. */ placeholder?: boolean; } export interface DesktopRate { usdPerMinute: number; asOf: string; source: string; placeholder?: boolean; } /** Resource quantities reported by the owned E2B allocation, not its template label. */ export interface DesktopResources { cpuCount: number; /** E2B's `memoryMB` field is in MiB; normalize the unit before pricing GiB. */ memoryMiB: number; } export interface DesktopResourceRate { usdPerCpuSecond: number; usdPerGiBSecond: number; asOf: string; source: string; } /** * The token-derived cost ESTIMATE for one actor lane. `estimatedCostUsd: null` = DECLARED ABSENT * (unknown rate or no token usage) — never coerced to 0. A non-null figure ALWAYS carries its * pricing provenance (`ratesAsOf` + `source`) so the mechanism (a rate-table multiply) matches * the claim (an estimate, not a charge). Defined here so the rate table and the field that * consumes it live together; `ActorTrace` imports it type-only. */ export interface ActorEstimatedCost { schema: typeof ACTOR_ESTIMATED_COST_SCHEMA; /** null = declared absent (no rate for the model / no token usage). */ estimatedCostUsd: number | null; reason?: "no_rate_for_model" | "no_token_usage"; /** Pricing provenance date; null iff estimatedCostUsd is null. */ ratesAsOf: string | null; /** The pricing-page URL/comment that produced the rate. */ source?: string; /** The model id the estimate was keyed on. */ modelId?: string; /** true when the rate is a stand-in, not a live sheet. */ placeholder?: boolean; breakdown?: { inputUsd: number; outputUsd: number; inputTokens: number; outputTokens: number; /** Of `inputTokens`, how many were billed at the reduced cached rate. Present only when the * provider reported cache hits AND the rate sheet models a cached rate. */ cachedInputTokens?: number; /** Of `inputTokens`, how many were billed at the cache-WRITE rate (OpenAI 5.6+). */ cacheWriteInputTokens?: number; /** How many requests crossed the long-context threshold and were re-tiered. Present only * when per-request `turns` records made exact tiering possible. */ longContextTurns?: number; }; } /** The desktop-minute cost ESTIMATE (host-side create->teardown span * a per-minute rate). Same * null-discipline as ActorEstimatedCost: `estimatedCostUsd: null` = not measured (no duration). */ export interface DesktopCostEstimate { estimatedCostUsd: number | null; reason?: "no_duration" | "no_desktop_resources" | "no_rate_for_desktop"; ratesAsOf: string | null; source?: string; /** The billed minutes the estimate was keyed on; null when no duration was measured. */ minutes: number | null; placeholder?: boolean; resources?: DesktopResources; usdPerSecond?: number; } export declare const MODEL_RATES: Record; export declare const DESKTOP_RESOURCE_RATE: DesktopResourceRate; export declare const DESKTOP_RATE: DesktopRate; export declare function isDesktopResources(value: unknown): value is DesktopResources; /** Price one observed allocation. Missing quantities/rates stay unknown, never a stock guess. */ export declare function estimateAllocatedDesktopCost(minutes: number | undefined, resources: DesktopResources | undefined, rate?: DesktopResourceRate): DesktopCostEstimate; /** Round a USD figure to 6 decimals so a float-accumulated total never carries spurious * precision. This mirrors the SPIRIT of the terminal ledger's private roundUsd (6dp) without * importing it — pricing stays a standalone pure module. */ export declare function round6(n: number): number; /** * Estimate one actor lane's model-token cost from its trace tokenUsage + model id. Deterministic; * the rate table is injectable (tests pass a fake sheet). Returns a DECLARED-ABSENT estimate * (estimatedCostUsd: null + a reason) for a missing rate or missing usage — never a guessed cost. */ export declare function estimateActorCost(tokenUsage: ActorTokenUsage | undefined, modelId: string | undefined, rates?: Record): ActorEstimatedCost; /** * Estimate the E2B desktop-minute cost from a host-side create->teardown span (minutes). The rate * is injectable. Returns a DECLARED-ABSENT estimate (null + "no_duration") when no duration was * measured (no sandbox / unmeasurable span) — never a guessed 0. */ export declare function estimateDesktopCost(minutes: number | undefined, rate?: DesktopRate): DesktopCostEstimate;