@kontextmind/kxm
Version:
KXM local-first multi-agent orchestration and operator dashboard
959 lines (884 loc) • 39.4 kB
text/typescript
import { createHash } from "node:crypto";
import { calculateModelCost, type PriceCatalog } from "./price-calc.ts";
import type { RouteSwitchRecord } from "./route-switch.ts";
/**
* Model/harness routing telemetry (v0.5, issue #40).
*
* Optimization targets complete verified agent configurations, not model
* names alone. Every run/stage can carry a metadata-only routing record:
* the behaviorally relevant configuration tuple is content-addressed so two
* runs are comparable without ever reading raw private context bodies.
*
* The behavioral hash covers: model route, role prompt/config hash, skill
* versions/hashes, tool policy/version, retrieval/context policy, workflow
* config hash, and verifier config. Everything else (tokens, cost, retries,
* outcomes) is outcome telemetry, deliberately outside the hash.
*/
export const ROUTING_RECORD_SCHEMA = "kxm.routing-record.v1" as const;
export const ROUTING_RECORD_V2_SCHEMA = "kxm.routing-record.v2" as const;
export const BEHAVIORAL_HASH_VERSION = 1;
export type RoutingCostBasis = "metered" | "unmetered" | "unknown";
export type RoutingVerifierOutcome = "passed" | "warning" | "failed";
export type RoutingFinalOutcome = "accepted" | "blocked" | "failed" | "pending";
export interface RoutingRecordV2 {
schema: typeof ROUTING_RECORD_V2_SCHEMA;
recordedAt: string;
project: string;
runId: string;
stepId: string;
assignmentId: string;
attemptId: string;
harness: string;
provider: string;
requestedModel: string;
effectiveModel: string;
thinking?: string | undefined;
agentRole?: string | undefined;
behavioralSha256: string;
contextTokens?: number | null | undefined;
tokensIn?: number | null | undefined;
tokensOut?: number | null | undefined;
cacheReadTokens?: number | null | undefined;
cacheWriteTokens?: number | null | undefined;
latencyMs: number;
costBasis: RoutingCostBasis;
costUsd?: number | null | undefined;
priceRef?: string | null | undefined;
verifierOutcome?: RoutingVerifierOutcome | undefined;
finalOutcome?: RoutingFinalOutcome | string | undefined;
retries: number;
transitions?: number | undefined;
humanInterventions?: number | undefined;
providerMetadata?: Record<string, string | number | boolean> | undefined;
}
export interface SkillVersionRef {
id: string;
contentSha256: string;
}
export interface BehavioralConfigInput {
/** Requested model route (e.g. "pi/kimi-k3"), normalized. */
requestedModel?: string | undefined;
/** Effective model after fallback/rotation, normalized. */
effectiveModel?: string | undefined;
/** Reasoning effort identifier (e.g. "high"). */
reasoningEffort?: string | undefined;
/** Agent role (repro, planner, ...). */
agentRole?: string | undefined;
/** Role prompt/config content hash. */
rolePromptSha256?: string | undefined;
/** Selected skills with pinned content hashes. */
skills?: SkillVersionRef[] | undefined;
/** Context/retrieval policy version. */
contextPolicyVersion?: string | undefined;
/** Tool policy/schema version. */
toolPolicyVersion?: string | undefined;
/** Workflow definition hash. */
workflowDefinitionSha256?: string | undefined;
/** Verifier configuration hash. */
verifierConfigSha256?: string | undefined;
}
export interface RoutingRecord {
schema: typeof ROUTING_RECORD_SCHEMA;
behavioralHashVersion: typeof BEHAVIORAL_HASH_VERSION;
behavioralSha256: string;
workflowRunId?: string;
stageId?: string;
attempt?: number;
requestedModel?: string;
effectiveModel?: string;
reasoningEffort?: string;
agentRole?: string;
rolePromptSha256?: string;
skills: SkillVersionRef[];
contextPolicyVersion?: string;
contextItemIds: string[];
toolPolicyVersion?: string;
workflowDefinitionSha256?: string;
verifierConfigSha256?: string;
retries: number;
transitions: number;
tokensIn?: number;
tokensOut?: number;
cacheReadTokens?: number;
costUsd?: number;
humanInterventions: number;
verifierOutcome?: RoutingVerifierOutcome;
finalOutcome?: RoutingFinalOutcome;
/** Additive, normalized provider-specific metadata. Never raw bodies. */
providerMetadata?: Record<string, string | number | boolean>;
}
export const MAX_CONTEXT_ITEM_IDS = 256;
export const MAX_SKILL_REFS = 32;
export const MAX_PROVIDER_METADATA_FIELDS = 32;
function normalizeModel(value: string | undefined): string | undefined {
if (value === undefined) return undefined;
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
return normalized === "" ? undefined : normalized;
}
/** Content-addressed hash over the behaviorally relevant tuple. Stable for
* identical configurations; different for any behavioral difference. */
export function behavioralConfigHash(input: BehavioralConfigInput): string {
const canonical = {
version: BEHAVIORAL_HASH_VERSION,
requestedModel: normalizeModel(input.requestedModel) ?? null,
effectiveModel: normalizeModel(input.effectiveModel) ?? null,
reasoningEffort: input.reasoningEffort?.trim() ?? null,
agentRole: input.agentRole ? input.agentRole.trim().toLowerCase().replace(/\s+/g, "-") : null,
rolePromptSha256: input.rolePromptSha256?.trim() ?? null,
skills: (input.skills ?? [])
.map((skill) => ({ id: skill.id.trim(), sha: skill.contentSha256.trim() }))
.sort((left, right) => left.id.localeCompare(right.id) || left.sha.localeCompare(right.sha)),
contextPolicyVersion: input.contextPolicyVersion?.trim() ?? null,
toolPolicyVersion: input.toolPolicyVersion?.trim() ?? null,
workflowDefinitionSha256: input.workflowDefinitionSha256?.trim() ?? null,
verifierConfigSha256: input.verifierConfigSha256?.trim() ?? null,
};
return createHash("sha256").update(JSON.stringify(canonical), "utf8").digest("hex");
}
function boundedInt(value: unknown, field: string): number | undefined {
if (value === undefined || value === null) return undefined;
if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > 1_000_000) {
throw new Error(`${field} must be an integer between 0 and 1000000`);
}
return value as number;
}
function boundedString(value: unknown, field: string, max: number): string | undefined {
if (value === undefined || value === null) return undefined;
if (typeof value !== "string" || value.length > max) {
throw new Error(`${field} must be a string of at most ${max} characters`);
}
return value;
}
/** Parse and validate a routing record from untrusted input. Metadata only:
* fail closed on unbounded fields, invalid identifiers, or negative costs. */
export function parseRoutingRecord(value: { schema: typeof ROUTING_RECORD_V2_SCHEMA } & Record<string, unknown>): RoutingRecordV2;
export function parseRoutingRecord(value: { schema: typeof ROUTING_RECORD_SCHEMA } & Record<string, unknown>): RoutingRecord;
export function parseRoutingRecord(value: unknown): RoutingRecord | RoutingRecordV2;
export function parseRoutingRecord(value: unknown): RoutingRecord | RoutingRecordV2 {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error("routing record must be an object");
}
const input = value as Record<string, unknown>;
if (input.schema === ROUTING_RECORD_V2_SCHEMA) {
return parseRoutingRecordV2(value);
}
if (input.schema !== ROUTING_RECORD_SCHEMA) {
throw new Error(`routing record schema must be ${ROUTING_RECORD_SCHEMA} or ${ROUTING_RECORD_V2_SCHEMA}`);
}
const skills = input.skills === undefined || input.skills === null
? []
: (() => {
if (!Array.isArray(input.skills) || input.skills.length > MAX_SKILL_REFS) {
throw new Error(`routing skills must be an array of at most ${MAX_SKILL_REFS} refs`);
}
return input.skills.map((skill) => {
const ref = skill as Partial<SkillVersionRef>;
if (typeof ref?.id !== "string" || !ref.id.trim() || ref.id.length > 200
|| typeof ref?.contentSha256 !== "string" || !/^[a-f0-9]{64}$/.test(ref.contentSha256)) {
throw new Error("routing skill refs must carry an id and a sha256 content hash");
}
return { id: ref.id.trim(), contentSha256: ref.contentSha256 };
});
})();
const contextItemIds = input.contextItemIds === undefined || input.contextItemIds === null
? []
: (() => {
if (!Array.isArray(input.contextItemIds) || input.contextItemIds.length > MAX_CONTEXT_ITEM_IDS) {
throw new Error(`routing contextItemIds must be an array of at most ${MAX_CONTEXT_ITEM_IDS} ids`);
}
return input.contextItemIds.map((id) => {
if (typeof id !== "string" || !id.trim() || id.length > 200) {
throw new Error("routing contextItemIds must be bounded non-empty strings");
}
return id.trim();
});
})();
const providerMetadata = input.providerMetadata === undefined || input.providerMetadata === null
? undefined
: (() => {
if (!input.providerMetadata || typeof input.providerMetadata !== "object" || Array.isArray(input.providerMetadata)) {
throw new Error("routing providerMetadata must be an object");
}
const entries = Object.entries(input.providerMetadata as Record<string, unknown>);
if (entries.length > MAX_PROVIDER_METADATA_FIELDS) {
throw new Error(`routing providerMetadata may carry at most ${MAX_PROVIDER_METADATA_FIELDS} fields`);
}
const normalized: Record<string, string | number | boolean> = {};
for (const [key, field] of entries) {
if (typeof key !== "string" || key.length > 64 || /prompt|body|content|message/i.test(key)
|| (typeof field !== "string" && typeof field !== "number" && typeof field !== "boolean")) {
throw new Error("routing providerMetadata values must be bounded strings, numbers, or booleans; raw bodies are rejected");
}
normalized[key] = typeof field === "string" ? field.slice(0, 200) : field;
}
return normalized;
})();
const verifierOutcome = input.verifierOutcome === undefined || input.verifierOutcome === null
? undefined
: (() => {
if (input.verifierOutcome !== "passed" && input.verifierOutcome !== "warning" && input.verifierOutcome !== "failed") {
throw new Error("routing verifierOutcome must be passed, warning, or failed");
}
return input.verifierOutcome;
})();
const finalOutcome = input.finalOutcome === undefined || input.finalOutcome === null
? undefined
: (() => {
if (input.finalOutcome !== "accepted" && input.finalOutcome !== "blocked" && input.finalOutcome !== "failed" && input.finalOutcome !== "pending") {
throw new Error("routing finalOutcome must be accepted, blocked, failed, or pending");
}
return input.finalOutcome;
})();
const costUsd = input.costUsd === undefined || input.costUsd === null
? undefined
: (() => {
if (typeof input.costUsd !== "number" || !Number.isFinite(input.costUsd) || input.costUsd < 0 || input.costUsd > 1_000_000) {
throw new Error("routing costUsd must be a non-negative finite number");
}
return input.costUsd;
})();
const behavioralSha256 = boundedString(input.behavioralSha256, "behavioralSha256", 64) ?? "";
if (!/^[a-f0-9]{64}$/.test(behavioralSha256)) {
throw new Error("routing behavioralSha256 must be a sha256 hex digest");
}
const record: RoutingRecord = {
schema: ROUTING_RECORD_SCHEMA,
behavioralHashVersion: BEHAVIORAL_HASH_VERSION,
behavioralSha256,
skills,
contextItemIds,
retries: boundedInt(input.retries, "retries") ?? 0,
transitions: boundedInt(input.transitions, "transitions") ?? 0,
humanInterventions: boundedInt(input.humanInterventions, "humanInterventions") ?? 0,
};
const strings: Array<[keyof RoutingRecord, string | undefined]> = [
["workflowRunId", boundedString(input.workflowRunId, "workflowRunId", 128)],
["stageId", boundedString(input.stageId, "stageId", 128)],
["requestedModel", normalizeModel(boundedString(input.requestedModel, "requestedModel", 200))],
["effectiveModel", normalizeModel(boundedString(input.effectiveModel, "effectiveModel", 200))],
["reasoningEffort", boundedString(input.reasoningEffort, "reasoningEffort", 64)],
["agentRole", boundedString(input.agentRole, "agentRole", 64)],
["rolePromptSha256", boundedString(input.rolePromptSha256, "rolePromptSha256", 64)],
["contextPolicyVersion", boundedString(input.contextPolicyVersion, "contextPolicyVersion", 64)],
["toolPolicyVersion", boundedString(input.toolPolicyVersion, "toolPolicyVersion", 64)],
["workflowDefinitionSha256", boundedString(input.workflowDefinitionSha256, "workflowDefinitionSha256", 64)],
["verifierConfigSha256", boundedString(input.verifierConfigSha256, "verifierConfigSha256", 64)],
];
for (const [key, value] of strings) {
if (value !== undefined) (record as unknown as Record<string, unknown>)[key] = value;
}
for (const [key, value] of [["attempt", boundedInt(input.attempt, "attempt")], ["tokensIn", boundedInt(input.tokensIn, "tokensIn")], ["tokensOut", boundedInt(input.tokensOut, "tokensOut")], ["cacheReadTokens", boundedInt(input.cacheReadTokens, "cacheReadTokens")]] as const) {
if (value !== undefined) (record as unknown as Record<string, unknown>)[key] = value;
}
if (costUsd !== undefined) record.costUsd = costUsd;
if (verifierOutcome !== undefined) record.verifierOutcome = verifierOutcome;
if (finalOutcome !== undefined) record.finalOutcome = finalOutcome;
if (providerMetadata !== undefined) record.providerMetadata = providerMetadata;
return record;
}
export function parseRoutingRecordV2(value: unknown): RoutingRecordV2 {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error("routing record v2 must be an object");
}
const input = value as Record<string, unknown>;
if (input.schema !== ROUTING_RECORD_V2_SCHEMA) {
throw new Error(`routing record v2 schema must be ${ROUTING_RECORD_V2_SCHEMA}`);
}
const costBasis = input.costBasis;
if (costBasis !== "metered" && costBasis !== "unmetered" && costBasis !== "unknown") {
throw new Error("routing record v2 costBasis must be metered, unmetered, or unknown");
}
let costUsd: number | null | undefined = undefined;
if (costBasis === "metered") {
if (typeof input.costUsd !== "number" || !Number.isFinite(input.costUsd) || input.costUsd < 0 || input.costUsd > 1_000_000) {
throw new Error("routing record v2 costUsd must be a non-negative finite number when costBasis is metered");
}
costUsd = input.costUsd;
} else if (input.costUsd !== undefined && input.costUsd !== null) {
if (typeof input.costUsd !== "number" || !Number.isFinite(input.costUsd) || input.costUsd < 0) {
throw new Error("routing record v2 costUsd must be a non-negative finite number when present");
}
costUsd = input.costUsd;
} else {
costUsd = null;
}
const rawHash = boundedString(input.behavioralSha256, "behavioralSha256", 72) ?? "";
if (!/^(?:sha256:)?[a-f0-9]{64}$/.test(rawHash)) {
throw new Error("routing record v2 behavioralSha256 must be a sha256 hex digest");
}
const behavioralSha256 = rawHash.startsWith("sha256:") ? rawHash : `sha256:${rawHash}`;
const latencyMs = input.latencyMs;
if (typeof latencyMs !== "number" || !Number.isFinite(latencyMs) || latencyMs < 0) {
throw new Error("routing record v2 latencyMs must be a non-negative number");
}
const providerMetadata = input.providerMetadata === undefined || input.providerMetadata === null
? undefined
: (() => {
if (!input.providerMetadata || typeof input.providerMetadata !== "object" || Array.isArray(input.providerMetadata)) {
throw new Error("routing providerMetadata must be an object");
}
const entries = Object.entries(input.providerMetadata as Record<string, unknown>);
if (entries.length > MAX_PROVIDER_METADATA_FIELDS) {
throw new Error(`routing providerMetadata may carry at most ${MAX_PROVIDER_METADATA_FIELDS} fields`);
}
const normalized: Record<string, string | number | boolean> = {};
for (const [key, field] of entries) {
if (typeof key !== "string" || key.length > 64 || /prompt|body|content|message/i.test(key)
|| (typeof field !== "string" && typeof field !== "number" && typeof field !== "boolean")) {
throw new Error("routing providerMetadata values must be bounded strings, numbers, or booleans; raw bodies are rejected");
}
normalized[key] = typeof field === "string" ? field.slice(0, 200) : field;
}
return normalized;
})();
const record: RoutingRecordV2 = {
schema: ROUTING_RECORD_V2_SCHEMA,
recordedAt: boundedString(input.recordedAt, "recordedAt", 64) ?? new Date().toISOString(),
project: boundedString(input.project, "project", 128) ?? "",
runId: boundedString(input.runId, "runId", 128) ?? "",
stepId: boundedString(input.stepId, "stepId", 128) ?? "",
assignmentId: boundedString(input.assignmentId, "assignmentId", 128) ?? "",
attemptId: boundedString(input.attemptId, "attemptId", 128) ?? "",
harness: boundedString(input.harness, "harness", 64) ?? "",
provider: boundedString(input.provider, "provider", 64) ?? "",
requestedModel: normalizeModel(boundedString(input.requestedModel, "requestedModel", 200)) ?? "",
effectiveModel: normalizeModel(boundedString(input.effectiveModel, "effectiveModel", 200)) ?? "",
behavioralSha256,
latencyMs,
costBasis,
costUsd,
retries: boundedInt(input.retries, "retries") ?? 0,
};
if (input.thinking !== undefined && input.thinking !== null) {
record.thinking = boundedString(input.thinking, "thinking", 64);
}
const rawRole = input.agentRole ?? (input as Record<string, unknown>).role;
if (rawRole !== undefined && rawRole !== null) {
record.agentRole = boundedString(rawRole, "agentRole", 64);
}
if (input.contextTokens !== undefined) {
record.contextTokens = boundedInt(input.contextTokens, "contextTokens") ?? null;
}
if (input.tokensIn !== undefined) {
record.tokensIn = boundedInt(input.tokensIn, "tokensIn") ?? null;
}
if (input.tokensOut !== undefined) {
record.tokensOut = boundedInt(input.tokensOut, "tokensOut") ?? null;
}
if (input.cacheReadTokens !== undefined) {
record.cacheReadTokens = boundedInt(input.cacheReadTokens, "cacheReadTokens") ?? null;
}
if (input.cacheWriteTokens !== undefined) {
record.cacheWriteTokens = boundedInt(input.cacheWriteTokens, "cacheWriteTokens") ?? null;
}
if (input.priceRef !== undefined && input.priceRef !== null) {
record.priceRef = boundedString(input.priceRef, "priceRef", 128);
}
if (input.verifierOutcome !== undefined && input.verifierOutcome !== null) {
if (input.verifierOutcome !== "passed" && input.verifierOutcome !== "warning" && input.verifierOutcome !== "failed") {
throw new Error("routing verifierOutcome must be passed, warning, or failed");
}
record.verifierOutcome = input.verifierOutcome;
}
if (input.finalOutcome !== undefined && input.finalOutcome !== null) {
record.finalOutcome = typeof input.finalOutcome === "string" ? input.finalOutcome.slice(0, 64) : undefined;
}
if (input.transitions !== undefined) {
record.transitions = boundedInt(input.transitions, "transitions");
}
if (input.humanInterventions !== undefined) {
record.humanInterventions = boundedInt(input.humanInterventions, "humanInterventions");
}
if (providerMetadata !== undefined) {
record.providerMetadata = providerMetadata;
}
return record;
}
export interface RoutingComparison {
behavioralSha256: string;
runs: number;
verifiedCompletions: number;
blocked: number;
failed: number;
reworkRate: number;
totalCostUsd: number | null;
missingCostRuns: number;
totalTokensIn: number;
totalTokensOut: number;
totalHumanInterventions: number;
}
/** Aggregate comparable outcome metrics for one behavioral configuration.
* Purely metadata-driven: no raw prompt or reply bodies are read. */
export function compareRoutingRecords(records: RoutingRecord[]): RoutingComparison {
if (records.length === 0) {
throw new Error("compareRoutingRecords requires at least one record");
}
const behavioralSha256 = records[0]!.behavioralSha256;
for (const record of records) {
if (record.behavioralSha256 !== behavioralSha256) {
throw new Error("compareRoutingRecords requires records with identical behavioral hashes");
}
}
const settled = records.filter((record) => record.finalOutcome !== undefined && record.finalOutcome !== "pending");
const accepted = settled.filter((record) => record.finalOutcome === "accepted").length;
const blocked = settled.filter((record) => record.finalOutcome === "blocked").length;
const failed = settled.filter((record) => record.finalOutcome === "failed").length;
const reworked = records.filter((record) => record.retries > 0 || record.transitions > 0).length;
const missingCostRuns = records.filter((record) => typeof record.costUsd !== "number" || !Number.isFinite(record.costUsd)).length;
const summedCost = records.reduce((sum, record) => sum + (typeof record.costUsd === "number" && Number.isFinite(record.costUsd) ? record.costUsd : 0), 0);
return {
behavioralSha256,
runs: records.length,
verifiedCompletions: accepted,
blocked,
failed,
reworkRate: records.length === 0 ? 0 : Math.round((reworked / records.length) * 100) / 100,
totalCostUsd: missingCostRuns > 0 ? null : Math.round(summedCost * 10_000) / 10_000,
missingCostRuns,
totalTokensIn: records.reduce((sum, record) => sum + (record.tokensIn ?? 0), 0),
totalTokensOut: records.reduce((sum, record) => sum + (record.tokensOut ?? 0), 0),
totalHumanInterventions: records.reduce((sum, record) => sum + record.humanInterventions, 0),
};
}
/** Group routing records by behavioral configuration for champion/challenger
* comparisons. */
export function groupByBehavior(records: RoutingRecord[]): Map<string, RoutingRecord[]> {
const groups = new Map<string, RoutingRecord[]>();
for (const record of records) {
const bucket = groups.get(record.behavioralSha256) ?? [];
bucket.push(record);
groups.set(record.behavioralSha256, bucket);
}
return groups;
}
export const ROUTING_REPORT_SCHEMA = "kxm.routing-report.v1" as const;
export function isQuotaExhausted(record: RoutingRecord | RoutingRecordV2): boolean {
if ("providerMetadata" in record && record.providerMetadata) {
const meta = record.providerMetadata;
if (meta.failureClass === "quota" || meta.errorCode === "provider_quota" || meta.stopReason === "quota_exhausted" || meta.quotaExhausted === true || meta.quota_exhausted === true) {
return true;
}
for (const [key, val] of Object.entries(meta)) {
if (/quota/i.test(key) && val === true) return true;
if (typeof val === "string" && /\b(quota reached|quota exceeded|rate limit(?:ed)?|too many requests|resource exhausted|http 429|quota_exhausted)\b/i.test(val)) {
return true;
}
}
}
if (record.finalOutcome === "quota" || record.finalOutcome === "quota_exhausted") return true;
return false;
}
function computePercentile(sorted: number[], p: number): number {
if (sorted.length === 0) return 0;
if (sorted.length === 1) return sorted[0]!;
const pos = p * (sorted.length - 1);
const base = Math.floor(pos);
const rest = pos - base;
if (sorted[base + 1] !== undefined) {
return Math.round(sorted[base]! + rest * (sorted[base + 1]! - sorted[base]!));
}
return sorted[base]!;
}
export interface RoutingReportRow {
harness: string;
model: string;
thinking: string;
role: string;
attempts: number;
verifyPassRate: number;
reworkRate: number;
latencyP50Ms: number;
latencyP95Ms: number;
medianContextTokens: number | null;
meteredCostUsd: number;
costPerAcceptedUsd: number | null;
unmeteredAttempts: number;
unknownCostAttempts: number;
quotaExhaustedAttempts: number;
flagged: boolean;
equivalentListCostUsd?: number | null | undefined;
}
export interface RoutingReport {
schema: typeof ROUTING_REPORT_SCHEMA;
generatedAt: string;
totalAttempts: number;
rows: RoutingReportRow[];
/** Present when the caller supplied at least one route switch. */
routeSwitches?: RouteSwitchRecord[] | undefined;
}
export interface GenerateRoutingReportOptions {
catalog?: PriceCatalog | undefined;
includeEquivalentListCost?: boolean | undefined;
halfLifeDays?: number | undefined;
now?: () => string;
routeSwitches?: readonly RouteSwitchRecord[] | undefined;
}
/**
* Calculates exponential decay weight for historical telemetry (Decision Q14).
* Weight w = 2^(-delta_t / halfLifeDays).
*/
export function computeDecayedWeight(
recordedAt: string | number,
halfLifeDays: number = 14,
now: number = Date.now(),
): number {
const ts = typeof recordedAt === "number" ? recordedAt : Date.parse(recordedAt);
if (!Number.isFinite(ts)) return 1.0;
const deltaMs = Math.max(0, now - ts);
const halfLifeMs = halfLifeDays * 24 * 60 * 60 * 1000;
return Math.pow(2, -deltaMs / halfLifeMs);
}
export interface RouteCircuitStatus {
status: "healthy" | "demoted" | "quarantined";
consecutiveFailures: number;
penaltyMultiplier: number;
reason?: string | undefined;
}
/**
* Evaluates route health against the circuit breaker policy (Decision Q13).
* Detects failure streaks in the observation window and applies soft demotion or quarantine.
*/
export function evaluateCircuitBreaker(
records: Array<RoutingRecord | RoutingRecordV2>,
route: { harness: string; model: string },
config?: {
mode?: "soft_demotion" | "quarantine" | undefined;
failureThreshold?: number | undefined;
windowSeconds?: number | undefined;
penaltyMultiplier?: number | undefined;
},
now: number = Date.now(),
): RouteCircuitStatus {
const mode = config?.mode ?? "soft_demotion";
const failureThreshold = config?.failureThreshold ?? 3;
const windowSeconds = config?.windowSeconds ?? 3600;
const penaltyMultiplier = config?.penaltyMultiplier ?? 5.0;
const windowMs = windowSeconds * 1000;
const matching = records.filter((r) => {
const isV2 = r.schema === ROUTING_RECORD_V2_SCHEMA;
const harness = isV2 ? (r as RoutingRecordV2).harness : (r.providerMetadata?.harness as string | undefined);
const model = isV2
? ((r as RoutingRecordV2).effectiveModel || (r as RoutingRecordV2).requestedModel)
: (r.effectiveModel || r.requestedModel);
if (harness !== route.harness || model !== route.model) return false;
const recAt = (r as any).recordedAt;
const ts = typeof recAt === "string" ? Date.parse(recAt) : 0;
return ts >= (now - windowMs);
});
matching.sort((a, b) => {
const ta = typeof (a as any).recordedAt === "string" ? Date.parse((a as any).recordedAt) : 0;
const tb = typeof (b as any).recordedAt === "string" ? Date.parse((b as any).recordedAt) : 0;
return tb - ta;
});
let consecutiveFailures = 0;
for (const r of matching) {
const passed = r.verifierOutcome === "passed" || r.finalOutcome === "accepted" || r.finalOutcome === "completed";
if (passed && (r.retries ?? 0) === 0) {
break;
}
consecutiveFailures++;
}
if (consecutiveFailures >= failureThreshold) {
if (mode === "quarantine") {
return {
status: "quarantined",
consecutiveFailures,
penaltyMultiplier,
reason: `Route quarantined after ${consecutiveFailures} consecutive failures within ${windowSeconds}s`,
};
}
return {
status: "demoted",
consecutiveFailures,
penaltyMultiplier,
reason: `Route demoted with ${penaltyMultiplier}x penalty after ${consecutiveFailures} consecutive failures`,
};
}
return {
status: "healthy",
consecutiveFailures,
penaltyMultiplier: 1.0,
};
}
export function generateRoutingReport(
records: Array<RoutingRecord | RoutingRecordV2>,
options: GenerateRoutingReportOptions = {},
): RoutingReport {
const generatedAt = options.now ? options.now() : new Date().toISOString();
const routeSwitches = options.routeSwitches?.filter((item) => item.from && item.to) ?? [];
if (records.length === 0) {
return {
schema: ROUTING_REPORT_SCHEMA,
generatedAt,
totalAttempts: 0,
rows: [],
...(routeSwitches.length > 0 ? { routeSwitches: [...routeSwitches] } : {}),
};
}
// Group by (harness, model, thinking, role)
const groups = new Map<string, Array<RoutingRecord | RoutingRecordV2>>();
for (const record of records) {
const isV2 = record.schema === ROUTING_RECORD_V2_SCHEMA;
const harness = (isV2 ? (record as RoutingRecordV2).harness : (record.providerMetadata?.harness as string | undefined)) || "unknown";
const model = (isV2 ? ((record as RoutingRecordV2).effectiveModel || (record as RoutingRecordV2).requestedModel) : (record.effectiveModel || record.requestedModel)) || "unknown";
const thinking = (isV2 ? (record as RoutingRecordV2).thinking : record.reasoningEffort) || "none";
const role = (record as any).role || record.agentRole || "unknown";
const key = `${harness}\0${model}\0${thinking}\0${role}`;
let bucket = groups.get(key);
if (!bucket) {
bucket = [];
groups.set(key, bucket);
}
bucket.push(record);
}
const rows: RoutingReportRow[] = [];
for (const [key, groupRecords] of groups.entries()) {
const [harness, model, thinking, role] = key.split("\0") as [string, string, string, string];
const attempts = groupRecords.length;
let verifyPassedCount = 0;
let reworkCount = 0;
let acceptedCount = 0;
let meteredCostTotal = 0;
let unmeteredAttempts = 0;
let unknownCostAttempts = 0;
let quotaExhaustedAttempts = 0;
const latencies: number[] = [];
const contextVals: number[] = [];
for (const r of groupRecords) {
const isV2 = r.schema === ROUTING_RECORD_V2_SCHEMA;
const v2 = isV2 ? (r as RoutingRecordV2) : undefined;
// Verification pass
if (r.verifierOutcome === "passed" || (!r.verifierOutcome && r.finalOutcome === "accepted")) {
verifyPassedCount++;
}
// Rework: back-edge re-entries only
if ((r.transitions ?? 0) > 0) {
reworkCount++;
}
// Accepted attempts
if (r.finalOutcome === "accepted" || r.verifierOutcome === "passed") {
acceptedCount++;
}
// Cost basis
const costBasis = v2 ? v2.costBasis : (typeof r.costUsd === "number" ? "metered" : "unknown");
if (costBasis === "metered") {
if (typeof r.costUsd === "number" && Number.isFinite(r.costUsd)) {
meteredCostTotal += r.costUsd;
}
} else if (costBasis === "unmetered") {
unmeteredAttempts++;
} else {
unknownCostAttempts++;
}
// Quota exhausted
if (isQuotaExhausted(r)) {
quotaExhaustedAttempts++;
}
// Latencies
const lat = v2 ? v2.latencyMs : (typeof r.providerMetadata?.latencyMs === "number" ? (r.providerMetadata.latencyMs as number) : undefined);
if (typeof lat === "number" && Number.isFinite(lat) && lat >= 0) {
latencies.push(lat);
}
// Context tokens
const ctx = v2 ? (v2.contextTokens ?? v2.tokensIn) : (r.tokensIn);
if (typeof ctx === "number" && Number.isFinite(ctx) && ctx >= 0) {
contextVals.push(ctx);
}
}
const verifyPassRate = attempts > 0 ? Math.round((verifyPassedCount / attempts) * 1000) / 1000 : 0;
const reworkRate = attempts > 0 ? Math.round((reworkCount / attempts) * 1000) / 1000 : 0;
latencies.sort((a, b) => a - b);
const latencyP50Ms = computePercentile(latencies, 0.50);
const latencyP95Ms = computePercentile(latencies, 0.95);
contextVals.sort((a, b) => a - b);
let medianContextTokens: number | null = null;
if (contextVals.length > 0) {
const mid = Math.floor(contextVals.length / 2);
medianContextTokens = contextVals.length % 2 !== 0
? contextVals[mid]!
: Math.round((contextVals[mid - 1]! + contextVals[mid]!) / 2);
}
const meteredCostUsd = Math.round(meteredCostTotal * 10_000) / 10_000;
const costPerAcceptedUsd = acceptedCount > 0
? (unknownCostAttempts > 0
? null
: (meteredCostUsd > 0 || unmeteredAttempts > 0
? Math.round((meteredCostUsd / acceptedCount) * 10_000) / 10_000
: 0))
: null;
const flagged = unknownCostAttempts > 0;
let equivalentListCostUsd: number | null | undefined = undefined;
if (options.includeEquivalentListCost && options.catalog) {
let equivTotal = 0;
let calculatedAll = true;
for (const r of groupRecords) {
const isV2 = r.schema === ROUTING_RECORD_V2_SCHEMA;
const v2 = isV2 ? (r as RoutingRecordV2) : undefined;
const costBasis = v2 ? v2.costBasis : (typeof r.costUsd === "number" ? "metered" : "unknown");
if (costBasis === "metered" && typeof r.costUsd === "number") {
equivTotal += r.costUsd;
} else {
const calc = calculateModelCost(options.catalog, {
model,
...(v2?.provider ? { provider: v2.provider } : {}),
tokensIn: r.tokensIn ?? null,
tokensOut: r.tokensOut ?? null,
cacheReadTokens: r.cacheReadTokens ?? null,
cacheWriteTokens: v2?.cacheWriteTokens ?? null,
contextTokens: v2?.contextTokens ?? null,
});
if (calc) {
equivTotal += calc.costUsd;
} else {
calculatedAll = false;
}
}
}
equivalentListCostUsd = calculatedAll ? Math.round(equivTotal * 10_000) / 10_000 : null;
}
rows.push({
harness,
model,
thinking,
role,
attempts,
verifyPassRate,
reworkRate,
latencyP50Ms,
latencyP95Ms,
medianContextTokens,
meteredCostUsd,
costPerAcceptedUsd,
unmeteredAttempts,
unknownCostAttempts,
quotaExhaustedAttempts,
flagged,
...(options.includeEquivalentListCost ? { equivalentListCostUsd } : {}),
});
}
// Sort quality then cost; unknown is never ranked cheapest
rows.sort((a, b) => {
// 1. Quality: higher verifyPassRate is better
if (a.verifyPassRate !== b.verifyPassRate) {
return b.verifyPassRate - a.verifyPassRate;
}
// Lower reworkRate is better
if (a.reworkRate !== b.reworkRate) {
return a.reworkRate - b.reworkRate;
}
// 2. Cost: unknown is never ranked cheapest. Any unknown-cost attempt leaves the
// route's cost unknown (unmetered or metered attempts beside it do not price it).
const aCostUnknown = a.unknownCostAttempts > 0;
const bCostUnknown = b.unknownCostAttempts > 0;
if (aCostUnknown && !bCostUnknown) return 1;
if (!aCostUnknown && bCostUnknown) return -1;
if (a.costPerAcceptedUsd !== null && b.costPerAcceptedUsd !== null) {
if (a.costPerAcceptedUsd !== b.costPerAcceptedUsd) {
return a.costPerAcceptedUsd - b.costPerAcceptedUsd;
}
} else if (a.costPerAcceptedUsd !== null) {
return -1;
} else if (b.costPerAcceptedUsd !== null) {
return 1;
}
if (a.meteredCostUsd !== b.meteredCostUsd) {
return a.meteredCostUsd - b.meteredCostUsd;
}
// 3. Tiebreakers
if (a.attempts !== b.attempts) {
return b.attempts - a.attempts;
}
const cmpH = a.harness.localeCompare(b.harness);
if (cmpH !== 0) return cmpH;
const cmpM = a.model.localeCompare(b.model);
if (cmpM !== 0) return cmpM;
return a.role.localeCompare(b.role);
});
return {
schema: ROUTING_REPORT_SCHEMA,
generatedAt,
totalAttempts: records.length,
rows,
...(routeSwitches.length > 0 ? { routeSwitches: [...routeSwitches] } : {}),
};
}
export function formatRoutingReport(
report: RoutingReport,
options: { equivalentListCost?: boolean } = {},
): string {
if (report.rows.length === 0 && (!report.routeSwitches || report.routeSwitches.length === 0)) {
return "no routing records to report";
}
if (report.rows.length === 0) {
const lines = ["no routing records to report", "", `Route switches (${report.routeSwitches!.length})`];
for (const item of report.routeSwitches!) {
const effort = item.effort ? ` effort ${item.effort}` : "";
lines.push(` ${item.from} -> ${item.to} (${item.reason}${effort}) step ${item.stepId}`);
}
return lines.join("\n");
}
const showListCost = Boolean(options.equivalentListCost);
const headers = [
"Harness".padEnd(10),
"Model".padEnd(24),
"Effort".padEnd(8),
"Role".padEnd(14),
"Att".padStart(4),
"Pass%".padStart(7),
"Rwk%".padStart(6),
"p50(ms)".padStart(8),
"p95(ms)".padStart(8),
"CtxTok".padStart(8),
"Metered($)".padStart(11),
"$/Acc".padStart(9),
"Unm".padStart(4),
"Unk".padStart(5),
"Quota".padStart(6),
...(showListCost ? ["ListEquiv($)".padStart(13)] : []),
].join(" ");
const lines: string[] = [
`Routing Telemetry Report (${report.totalAttempts} attempt(s) across ${report.rows.length} route(s), quality-first ranking)`,
headers,
];
for (const row of report.rows) {
const passPct = `${(row.verifyPassRate * 100).toFixed(1)}%`;
const rwkPct = `${(row.reworkRate * 100).toFixed(1)}%`;
const p50 = `${row.latencyP50Ms}`;
const p95 = `${row.latencyP95Ms}`;
const ctx = row.medianContextTokens !== null ? `${row.medianContextTokens}` : "-";
const metered = `$${row.meteredCostUsd.toFixed(4)}`;
const perAcc = row.costPerAcceptedUsd !== null ? `$${row.costPerAcceptedUsd.toFixed(4)}` : "-";
const unkText = `${row.unknownCostAttempts}${row.flagged ? "*" : ""}`;
const cells = [
row.harness.padEnd(10),
(row.model.length > 24 ? `${row.model.slice(0, 21)}...` : row.model).padEnd(24),
row.thinking.padEnd(8),
(row.role.length > 14 ? `${row.role.slice(0, 11)}...` : row.role).padEnd(14),
String(row.attempts).padStart(4),
passPct.padStart(7),
rwkPct.padStart(6),
p50.padStart(8),
p95.padStart(8),
ctx.padStart(8),
metered.padStart(11),
perAcc.padStart(9),
String(row.unmeteredAttempts).padStart(4),
unkText.padStart(5),
String(row.quotaExhaustedAttempts).padStart(6),
...(showListCost ? [(row.equivalentListCostUsd !== undefined && row.equivalentListCostUsd !== null ? `$${row.equivalentListCostUsd.toFixed(4)}` : "-").padStart(13)] : []),
];
lines.push(cells.join(" "));
}
if (report.rows.some((r) => r.flagged)) {
lines.push("* = unknown-cost attempts present (never ranked cheapest)");
}
if (report.routeSwitches && report.routeSwitches.length > 0) {
lines.push("");
lines.push(`Route switches (${report.routeSwitches.length})`);
for (const item of report.routeSwitches) {
const effort = item.effort ? ` effort ${item.effort}` : "";
lines.push(` ${item.from} -> ${item.to} (${item.reason}${effort}) step ${item.stepId}`);
}
}
return lines.join("\n");
}