wulf-pulse/lib/services/llm/pricing.ts
lorentz 8f8b5ab7be feat: AI ticket analyzer (phases 1-6)
Multi-stage LLM pipeline that produces structured analyses of Autotask
tickets from local Postgres. Migration 069 + Zod schemas, Stage 0
preprocessor, IT Glue redaction + search, Anthropic SDK wrapper, Stages
1/3/4 (Haiku/Sonnet/Opus), pipeline + cost circuit breaker, job worker
(opt-in autostart), 6 API routes, 3 frontend pages, share-row
persistence (email send deferred to phase 7). 128 vitest tests, tsc
clean. Build journal in docs/wulf-pulse-ticket-analyzer-build-notes.md.

Sync: adds syncTicketNotes() + ticket_notes to ordered/date-filtered
entities so the analyzer's local mirror stays current via scheduler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 10:59:40 -04:00

52 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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
* Last verified: 2026-04-15
*/
import { HAIKU, SONNET, OPUS, 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) */
cacheRead: number;
/** USD per 1M tokens written to 5-minute prompt cache (~1.25× input) */
cacheWrite5m: number;
}
export const PRICING: Record<ModelId, ModelRate> = {
[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 },
};
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;
}