- RMM Overshell (migration 077): admin page, dispatch UI, executor/worker, target resolver, script registry (AD/DHCP/DNS/event-log/services/software/network/loglift) - LogLift evidence pipeline (migration 078): upload webhook, B2 storage client, receiver/matcher, EventLogCollector PowerShell script - IT Glue audit + write-back (migrations 075, 076): asset-audit runner, ticket xrefs, applications/configurations browse pages + apply/revert/audit endpoints - Link-aware analyzer bundles (migration 073) + provider toggle (migration 074): link-discovery service, OpenRouter LLM provider, related-tickets/itglue-suggestion panels, analyze-bundle endpoint - Endpoint data model + device-link reconciliation (migrations 079, 080): conflicts admin page, reconciler service, resolve endpoints - Dashboard overhaul: integration-health service + alerts, overview/health endpoints - Permissions: add itglue + rmm scopes; middleware: public /api/rmm/loglift route Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
71 lines
2.7 KiB
TypeScript
71 lines
2.7 KiB
TypeScript
/**
|
||
* Per-model token pricing for cost estimation in analyzer_analyses.estimated_cost_usd.
|
||
*
|
||
* Rates are USD per 1,000,000 tokens.
|
||
*
|
||
* VERIFY QUARTERLY against:
|
||
* - https://docs.claude.com/en/docs/about-claude/pricing
|
||
* - https://openrouter.ai/api/v1/models (deepseek/* entries)
|
||
*
|
||
* Last verified: 2026-05-02 (V4 Pro/Flash + R1-0528 added from OpenRouter live list)
|
||
*/
|
||
|
||
import {
|
||
HAIKU,
|
||
SONNET,
|
||
OPUS,
|
||
DEEPSEEK_V4_FLASH,
|
||
DEEPSEEK_V4_PRO,
|
||
DEEPSEEK_R1,
|
||
type ModelId,
|
||
} from './models';
|
||
|
||
interface ModelRate {
|
||
/** USD per 1M input tokens */
|
||
input: number;
|
||
/** USD per 1M output tokens */
|
||
output: number;
|
||
/** USD per 1M tokens read from prompt cache (~0.1× input on Anthropic; not applicable on OpenRouter — set equal to input). */
|
||
cacheRead: number;
|
||
/** USD per 1M tokens written to 5-minute prompt cache (~1.25× input on Anthropic; not applicable on OpenRouter — set equal to input). */
|
||
cacheWrite5m: number;
|
||
}
|
||
|
||
export const PRICING: Record<ModelId, ModelRate> = {
|
||
// Anthropic
|
||
[HAIKU]: { input: 1.0, output: 5.0, cacheRead: 0.1, cacheWrite5m: 1.25 },
|
||
[SONNET]: { input: 3.0, output: 15.0, cacheRead: 0.3, cacheWrite5m: 3.75 },
|
||
[OPUS]: { input: 5.0, output: 25.0, cacheRead: 0.5, cacheWrite5m: 6.25 },
|
||
|
||
// OpenRouter / DeepSeek (no prompt-cache discount surfaced via the OpenAI-
|
||
// compatible API; we treat cacheRead/cacheWrite as the input rate so the
|
||
// estimator stays additive even if those usage fields ever come back filled).
|
||
[DEEPSEEK_V4_FLASH]: { input: 0.14, output: 0.28, cacheRead: 0.14, cacheWrite5m: 0.14 },
|
||
[DEEPSEEK_V4_PRO]: { input: 0.435, output: 0.87, cacheRead: 0.435, cacheWrite5m: 0.435 },
|
||
[DEEPSEEK_R1]: { input: 0.50, output: 2.15, cacheRead: 0.50, cacheWrite5m: 0.50 },
|
||
};
|
||
|
||
export interface TokenUsage {
|
||
input_tokens: number;
|
||
output_tokens: number;
|
||
cache_creation_input_tokens?: number;
|
||
cache_read_input_tokens?: number;
|
||
}
|
||
|
||
/**
|
||
* USD cost of a single LLM call given its token usage. Caches are billed
|
||
* separately from raw input tokens — cache_read at ~0.1×, cache_write at ~1.25×.
|
||
*/
|
||
export function estimateCostUsd(model: ModelId, usage: TokenUsage): number {
|
||
const rate = PRICING[model];
|
||
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
||
const cacheWrite = usage.cache_creation_input_tokens ?? 0;
|
||
const uncachedInput = usage.input_tokens; // SDK reports this as the uncached remainder
|
||
const cost =
|
||
(uncachedInput / 1_000_000) * rate.input +
|
||
(usage.output_tokens / 1_000_000) * rate.output +
|
||
(cacheRead / 1_000_000) * rate.cacheRead +
|
||
(cacheWrite / 1_000_000) * rate.cacheWrite5m;
|
||
// Round to 4 decimals (matches analyzer_analyses.estimated_cost_usd numeric(10,4)).
|
||
return Math.round(cost * 10_000) / 10_000;
|
||
}
|