mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-15 11:22:15 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
64 lines
2.6 KiB
TypeScript
64 lines
2.6 KiB
TypeScript
/**
|
|
* Probe-origin tracking via AsyncLocalStorage.
|
|
*
|
|
* Convention: ANY probe flow (model test-all, future batch tests,
|
|
* credential-health if it ever routes through the chat path) MUST execute
|
|
* inside runAsProbe() so deactivation guards can refuse probe-origin
|
|
* failures (invariant #9817: only a real request-path failure deactivates
|
|
* a connection). Pinned by tests/unit/probe-testall-isolation.test.ts.
|
|
*
|
|
* NOTE: when a probe dispatches through a scheduler with a queue
|
|
* (Bottleneck via withRateLimit), runAsProbe must wrap the scheduled fn
|
|
* itself — a queued job otherwise executes outside this context
|
|
* (pinned by the queued-scheduler test below).
|
|
*
|
|
* EXCEPTIONS (deliberate, documented in the PR): tokenHealthCheck refresh
|
|
* failures keep deactivating (re-auth semantics — a dead refresh token is
|
|
* a real death, not a probe artifact), and circuit-breaker HALF_OPEN
|
|
* probes are real generations by design. Those flows stay outside
|
|
* runAsProbe.
|
|
*/
|
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
|
const probeContext = new AsyncLocalStorage<{ probe: true }>();
|
|
|
|
export function runAsProbe<T>(fn: () => Promise<T>): Promise<T> {
|
|
return probeContext.run({ probe: true }, fn);
|
|
}
|
|
|
|
export function isProbeContext(): boolean {
|
|
return probeContext.getStore() !== undefined;
|
|
}
|
|
|
|
/**
|
|
* Central probe-isolation decision used by every deactivation site.
|
|
*
|
|
* True when the current execution is probe-origin AND the opt-in setting
|
|
* `probeCanDisable` is OFF (default): the probe failure is recorded but
|
|
* must never remove the connection from the pool (cooldowns, terminal
|
|
* status, per-model lockouts, auto-disable, circuit breaker). Operators
|
|
* who use test-all as a maintenance tool set `probeCanDisable: true` to
|
|
* restore the historical behavior where a probe counts as a real
|
|
* generation.
|
|
*/
|
|
export async function shouldIsolateProbeFailures(): Promise<boolean> {
|
|
if (!isProbeContext()) return false;
|
|
// Feature-flag kill-switch (env/DB override; fail-safe false like the
|
|
// AUTH_LOG_INCLUDE_ACCOUNT_ID usage): PROBE_CAN_DISABLE restores the
|
|
// historical behavior where a probe counts as a real generation.
|
|
try {
|
|
const { isFeatureFlagEnabled } = await import("@/shared/utils/featureFlags");
|
|
if (isFeatureFlagEnabled("PROBE_CAN_DISABLE")) return false;
|
|
} catch {
|
|
// Fail-safe: on lookup failure the isolation stays ON.
|
|
}
|
|
try {
|
|
const { getCachedSettings } = await import("@/lib/db/readCache");
|
|
const settings = await getCachedSettings();
|
|
return !settings.probeCanDisable;
|
|
} catch {
|
|
// Fail-safe: on settings-lookup failure the isolation stays ON.
|
|
return true;
|
|
}
|
|
}
|