Files
OmniRoute/src/lib/omnirouteStatus.ts
desamours-hub d93b24e761 feat(api): add provider quota telemetry, adaptive routing, and status inventory (#10148)
* feat(api): add provider quota telemetry, adaptive routing, and status inventory

Adds a read-only OmniRoute status/inventory surface plus supporting
resilience and usage-tracking infrastructure:

- src/lib/quota/providerQuotaTelemetry.ts, providerCapabilities.ts:
  provider quota state and capability signals, sourced from configured
  metadata rather than invented values; unknown stays unknown.
- src/lib/resilience/adaptiveCircuit.ts, failureClassification.ts:
  circuit state with lazy recovery and explicit failure classification.
- src/lib/usage/usageLedger.ts, budgetGuard.ts, modelPricingRegistry.ts:
  internal usage tracking and budget allow/warn/deny decisions, kept
  separate from upstream-reported quota (never conflated).
- src/lib/routing/adaptiveRouting.ts: excludes exhausted-quota and
  open-circuit candidates from routing, penalizes approaching-limit.
- src/lib/omnirouteStatus.ts + src/app/api/omniroute/status,
  route/preview: read-only status endpoint; never issues a live
  upstream model request (asserted via liveRequestExecuted: false).
- src/lib/db/quotaPools.ts: adds ensurePool() for idempotent pool
  management by automation/CLI callers, following the existing
  group-demo default-group convention.
- scripts/omniroute-verify.mjs (+ omniroute:verify script): local
  verification against the running gateway.

9 new unit tests, all passing. typecheck:core clean relative to base
(release/v3.8.50) -- the 2 pre-existing gateways.ts errors are tracked
separately in #9985 and untouched by this change.

* test(cli): align cli-machine-token assertions with HMAC-SHA256 64-char format

The quota-telemetry feature hardens cliToken to HMAC-SHA256(machineId, SALT)
(64-char hex, pristine machine id). Update the regression test to the new
format and mirror the production derivation in the different-machine-id check.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
Co-authored-by: desamours-hub <desamours-hub@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-08-18 11:31:53 -03:00

88 lines
3.2 KiB
TypeScript

import { getDbInstance, pingDb } from "@/lib/db/core";
import { listPools } from "@/lib/db/quotaPools";
interface ProviderStatusRow {
id: string;
provider: string;
is_active: number | boolean | null;
test_status: string | null;
last_error: string | null;
}
function readProviderStatusRows(): ProviderStatusRow[] {
const db = getDbInstance();
return db
.prepare<ProviderStatusRow>(
"SELECT id, provider, is_active, test_status, last_error FROM provider_connections"
)
.all();
}
export async function buildOmniRouteStatus() {
const [connections, circuitModule, quotaMonitorModule] = await Promise.all([
Promise.resolve(readProviderStatusRows()),
import("@/shared/utils/circuitBreaker").catch(() => null),
import("../../open-sse/services/quotaMonitor").catch(() => null),
]);
const pools = listPools().items;
const circuitStatuses = circuitModule?.getAllCircuitBreakerStatuses() ?? null;
const quotaSummary = quotaMonitorModule?.getQuotaMonitorSummary() ?? null;
const active = connections.filter(
(connection) => connection.is_active !== 0 && connection.is_active !== false
);
const disabled = connections.filter(
(connection) => connection.is_active === 0 || connection.is_active === false
);
const healthy = active.filter((connection) => connection.test_status === "active");
return {
gateway: pingDb() ? "healthy" : "degraded",
catalog: { available: true },
providers: {
configured: connections.length,
active: active.length,
healthy: healthy.length,
disabled: disabled.length,
connections: connections.map((connection) => ({
id: connection.id,
provider: connection.provider,
active: connection.is_active !== 0 && connection.is_active !== false,
health:
connection.is_active === 0 || connection.is_active === false
? "disabled"
: connection.test_status === "active"
? "healthy"
: "unknown",
failureState: connection.last_error ? "recent_error" : "none",
})),
},
pools: {
count: pools.length,
allocations: pools.reduce((count, pool) => count + pool.allocations.length, 0),
items: pools.map((pool) => ({
id: pool.id,
name: pool.name,
connectionIds: pool.connectionIds,
allocationCount: pool.allocations.length,
})),
},
quotaMonitoring: {
authoritative: quotaSummary?.active ?? 0,
headerBased: 0,
configured: 0,
unsupported: quotaSummary ? Math.max(0, active.length - quotaSummary.active) : null,
status: quotaSummary?.active ? "partial" : "unknown",
},
circuits: circuitStatuses
? {
open: circuitStatuses.filter((c) => c.state === "OPEN").length,
halfOpen: circuitStatuses.filter((c) => c.state === "HALF_OPEN").length,
closed: circuitStatuses.filter((c) => c.state === "CLOSED").length,
source: "persisted circuit breaker registry",
}
: { status: "unknown", source: "resilience subsystem unavailable" },
usage: { source: "usage_history and call_logs", liveRequestsExecuted: false },
budgets: { source: "internal governance limits", upstreamQuotaClaims: false },
};
}