import { createHash } from "node:crypto"; import { ULTRAPI_VERSION } from "../config/defaults.js"; import { estimateCredits } from "../models/price-catalog.js"; import type { PriceCatalog, UltraConfig } from "../types.js"; /** Identity, provenance, and redaction helpers the controller stamps onto what it records. */ export function providerFailureStatus(error: string): number | undefined { if (/(rate.?limit|too many requests|\b429\b|overloaded)/i.test(error)) return 429; if (/(?:\b5\d\d\b|internal server|service unavailable|bad gateway|gateway timeout)/i.test(error)) return 500; return undefined; } export function redactLedgerValue(value: T, redactions: readonly string[]): T { if (typeof value === "string") return redactions.reduce((text, raw) => raw ? text.replaceAll(raw, "") : text, value) as T; if (Array.isArray(value)) return value.map((entry) => redactLedgerValue(entry, redactions)) as T; if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, redactLedgerValue(entry, redactions)])) as T; return value; } export function configFingerprint(config: UltraConfig): string { const { changeReason: _changeReason, createdAt: _createdAt, ...stable } = config as UltraConfig & { changeReason?: unknown; createdAt?: unknown }; return createHash("sha256").update(JSON.stringify(stable)).digest("hex"); } export function requestProvenance(config: UltraConfig, availableModels: readonly string[], priceCatalog: PriceCatalog) { return { configHash: configFingerprint(config), modelCatalogHash: createHash("sha256").update(JSON.stringify(availableModels)).digest("hex"), priceCatalogVersion: priceCatalog.version, piVersion: config.compatibility.piVersion, piAgentsVersion: config.compatibility.piAgentsVersion, ultraPiVersion: ULTRAPI_VERSION, }; } export function expectedModelSavings(catalog: PriceCatalog, expensiveModel: string, cheapModel: string): number { if (!catalog.models[expensiveModel] || !catalog.models[cheapModel]) return 0; const expensive = estimateCredits(catalog, expensiveModel, 8_000, 0, 800); const cheap = estimateCredits(catalog, cheapModel, 8_000, 0, 800); return expensive > 0 ? Math.max(0, (expensive - cheap) / expensive) : 0; } export function sameJsonValue(left: unknown, right: unknown): boolean { if (left === right) return true; if (!left || !right || typeof left !== "object" || typeof right !== "object") return false; if (Array.isArray(left) || Array.isArray(right)) { return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => sameJsonValue(value, right[index])); } const leftRecord = left as Record; const rightRecord = right as Record; const leftKeys = Object.keys(leftRecord); const rightKeys = Object.keys(rightRecord); return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(rightRecord, key) && sameJsonValue(leftRecord[key], rightRecord[key])); }