Files
OmniRoute/open-sse/services/admission/runtime.ts
Brandon Bennett 6615a5445b feat: combo-lane awareness + activation UX + MCP visibility (Wave 2 of #9654) (#10039)
* feat(admission): per-target lane-aware probes for combo/fusion fan-out (#9654 Wave 2)

Combo and fusion fan out N targets without ever consulting the adaptive-admission
layer: the parent request holds one lease, but each fan-out target is dispatched
unconditionally. With virtual lanes enabled (OMNIROUTE_CHAT_VIRTUAL_LANES=1), a
connection whose lane queue is full now SKIPS additional fan-out targets instead
of piling more queued work onto an already-congested session.

Adds PerTargetAdmissionHook (admission/types.ts) + createPerTargetAdmissionHook
factory (chatAdmission.ts): strictly non-blocking (maxWaitMs 0 - skip, never
queue), a no-op when virtual lanes are off, keyed to the parent tenantKey, and
release-on-admit so the probe is a capacity gate, not a hold.

Threaded through every parallel fan-out path:
- priority/weighted executeTarget + round-robin skip chains (combo.ts)
- fusion panel before fan-out (fusion.ts), judge fallback prefers survivors
- chaos parallel panel (autoCombo/chaosEngine.ts)
- tryFusionDispatch / tryRuntimeUnitDispatch / buildBaseOptions (dispatchPrelude.ts)
- chat.ts primary + safety-net redirect call sites

Snapshot exposes virtualLanes so the no-op gate is cheap and honest.

Tests: tests/unit/combo-lane-awareness-9654.test.ts (10 tests) - factory
semantics, priority/RR skip, fusion panel drop + all-skipped 503, no-hook
backward-compat baseline.

* feat(flags): activation UX - env-wins adaptive virtual-lanes flag + env docs (#9654 Wave 2)

U7: make adaptive virtual admission lanes discoverable + activatable.
- New OMNIROUTE_CHAT_VIRTUAL_LANES feature flag (boolean/runtime/requiresRestart) in featureFlagDefinitions + en.json i18n key.
- lib/admissionVirtualLanes.ts: env-wins resolver (env > DB > default) + boot warm folding a DB-sourced override into the process-global runtime env via reloadAdaptiveAdmissionRuntime(options.env) - no process.env mutation, no open-sse changes. Env still wins; DB toggle gates at next boot.
- GET /api/settings/feature-flags special-cases the flag to report the gate true source (ccDiscoveryAliases precedent); flagPayload helper dedupes the payload shape.
- Wire the warm into instrumentation-node registerNodejs (non-fatal, DB-ready).
- Document the master switch in .env.example + ENVIRONMENT.md with the system-1/system-2 distinction; zero new env-doc-sync drift.
- 11 new tests (resolver precedence + warm); 60/60 across feature-flag suites; typecheck core clean; ESLint + doc gates green.

* feat(mcp): surface adaptive admission lane data in omniroute_get_health (#9654 Wave 2)

U8: make adaptive virtual-lane admission visible to agents via the MCP health tool. handleGetHealth now surfaces a curated adaptiveAdmission block from the health payload (which already carried the runtime snapshot but was dropping it): virtualLanes/pressure/utilization/laneCount/laneQueuedCount/laneQueuedCost, laneTenants capped at top-10 by queued cost, admitted/rejected/wouldReject counts, shutdown. Block omitted entirely when the health endpoint reports none.

isLaneFlagOn mirrors the runtime 1|true convention so a string serialization can never invert a boolean lane report. getHealthOutput schema extended with the matching optional shape; tool description updated.

4 new dispatch tests (full block, top-10 cap/order, omission, defensive coercion of string flags + malformed lane entries) - 22/22 in essentialTools.test.ts. README: Adaptive Admission Lane Data table + Skills & Tool Navigability audit (29/43 schema entries covered, 14 undocumented, tool_search keyword runtime discovery, full catalog in docs/frameworks/MCP-SERVER.md).

No new lint errors (4 pre-existing in server.ts), typecheck core clean, doc counts + fabricated-docs gates green.

* docs: add changelog entry for #9654 Wave 2 (#10039)

* fix(codeql): suppress js/insufficient-password-hash false positive in lane-key fingerprinting (#10039)

resolveSessionId sha256-hashes bearer/x-api-key/x-goog-api-key to derive a deterministic, non-reversible per-key lane-bucket ID for virtual admission lanes (#9654). This is not password storage or verification, so the rule is a false positive; suppress it inline (same house style as src/lib/sync/tokens.ts) to clear the codeqlAlerts ratchet (2 > baseline 1) that blocks #10039 and every PR against release/v3.8.50.

* docs(mcp): complete MCP server README tool reference (#10039)

The MCP server README covered only 29 of the 43 schema entries, listing the
remaining tools solely as a gap note with omniroute_tool_search as the runtime
fallback. Add tool-reference tables for the agent-skills trio, oneproxy trio,
web_fetch/web_search, tool_search, create_combo, set_routing_strategy,
pick_fastest_model, sync_pricing, and db_health_check so the README covers the
full schemas catalog, and fold the coverage note into the tool_search discovery
paragraph.

* fix(chat): drop unused correlationId from safety-net combo redirect (#10039)

handleComboChat's HandleComboChatOptions has no correlationId member and
the combo pipeline never consumes it; the property was copied from the
handleSingleModelChat options shape by accident and introduced a new
TS2353 under the open-sse workspace typecheck gate.

* fix(i18n): translate featureFlagChatVirtualLanesEnabledDescription into 42 locales (#10039)

en.json gained the flag description in this PR but the locale catalogs
were never mirrored, failing the pt-BR key-parity (#6695) and vi
completeness gates. Adds a real translation to every locale, keeping the
zh-CN/zh-TW glossary canonical terms (提供者/儀表板) and no ICU drift.

* chore(quality): ratchet open-sse-typecheck baseline down (#10039)

The Wave 2 admission refactor removed 66 baselined open-sse type errors;
re-freeze the baseline so the gate pins the new, tighter state.

* docs: resync provider reference to 341 and CLI tools to 34

The release branch gained an 11th no-auth provider (freeaiapikey registry
resync, #10233) and a 26th CLI Code tool without regenerating the
auto-generated docs, leaving every PR against release/v3.8.50 failing the
Docs Gates strict validator (code 341 vs doc 340, CLI 34 vs "33 tools").

Regenerate docs/reference/PROVIDER_REFERENCE.md and sync the provider/tool
counts across README.md, AGENTS.md, llm.txt plus 42 i18n mirrors,
package.json description, and the four diagram SVGs.

* fix(tests): align count expectations with live catalogs (pre-existing release drift)

Release/v3.8.50 currently fails five gates on its own tree; this PR inherits
them. Fix the stale expectations to match live code:

- feature-flags-settings: 48 -> 49 flags (Wave 2 adds OMNIROUTE_CHAT_VIRTUAL_LANES)
- cli-tools-schema / cli-catalog-counts: 33 -> 34 tools (zcode added; 26 code = 21 visible + 5 none)
- optional-transformers-dependency: onnxruntime-node ~1.24.3 -> ~1.27.0 (bump #10382)
- stryker.conf.json: register chatcore-header-drop-warn-dedupe-10315 test
- check-public-creds: freeze zcodeProtocol clientId false positive (client identifier, not a credential)

* fix(tests): follow release's onnxruntime-node revert to ~1.24.3

release/v3.8.50's #10543 pinned onnxruntime-node back to ~1.24.3 after
#10403's ~1.27.0 bump caused npm to nest a second native copy under
@huggingface/transformers and broke the Docker SONAME contract. This
PR's own drift-alignment commit (57b9c033) predates that revert and
still expected ~1.27.0; the 3-way merge did not flag it as a textual
conflict since only one side touched this exact line, but the merged
tree became internally inconsistent (package.json ~1.24.3 vs test
expecting ~1.27.0). Align the test with the now-canonical release
value.

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

* fix(quality): dedupe stryker.conf.json chatcore-header-drop-warn-dedupe entry

The 3-way merge applied both sides' insertion of the same test-file entry
at different positions, producing a duplicate with broken indentation.
Adopted release's clean version of the file.

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

---------

Co-authored-by: Brandon Bennett <brandonbennett@macbookair.myfiosgateway.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: Brandon Bennett <branben@users.noreply.github.com>
2026-08-18 11:31:46 -03:00

627 lines
19 KiB
TypeScript

/**
* Process-local adaptive admission runtime facade around the pure controller.
* No HTTP route wiring — suitable for later shared handleChat integration.
*/
import { AdaptiveAdmissionController } from "./controller.ts";
import { validateConfig } from "./config.ts";
import { extractAdmissionCostFeatures } from "./requestFeatures.ts";
import {
type AdaptiveAdmissionConfig,
type AdmissionAcquireResult,
type AdmissionClock,
type AdmissionLease,
type AdmissionMode,
type AdmissionPressure,
type AdmissionRejectCode,
type AdmissionReleaseOutcome,
type AdmissionSnapshot,
type ShadowDecision,
} from "./types.ts";
import { buildErrorBody } from "../../utils/error.ts";
import { CORS_HEADERS } from "../../utils/cors.ts";
import {
checkResourcePressureGuard,
getResourcePressureObservation,
type ResourcePressureGuardResult,
type ResourcePressureObservation,
} from "../../utils/resourcePressure.ts";
import type { PressureReason, PressureSeverity } from "../../utils/resourcePressurePolicy.ts";
export { extractAdmissionCostFeatures } from "./requestFeatures.ts";
export const DEFAULT_ADAPTIVE_ADMISSION_CONFIG: Readonly<AdaptiveAdmissionConfig> = Object.freeze({
mode: "shadow",
minLimit: 8,
initialLimit: 64,
maxLimit: 1000,
maxQueueCount: 128,
maxQueueCost: 2000,
defaultMaxWaitMs: 5_000,
windowMs: 1_000,
virtualLanes: false,
});
const RUNTIME_STORE_KEY = Symbol.for("omniroute.adaptiveAdmission.runtime");
type RuntimeStore = {
runtime: AdaptiveAdmissionRuntime | null;
};
type GlobalWithRuntimeStore = typeof globalThis & {
[RUNTIME_STORE_KEY]?: RuntimeStore;
};
function getRuntimeStore(): RuntimeStore {
const globalWithStore = globalThis as GlobalWithRuntimeStore;
let store = globalWithStore[RUNTIME_STORE_KEY];
if (!store) {
store = { runtime: null };
globalWithStore[RUNTIME_STORE_KEY] = store;
}
return store;
}
const ENV_KEYS = {
mode: "ADAPTIVE_ADMISSION_MODE",
minLimit: "ADAPTIVE_ADMISSION_MIN_LIMIT",
initialLimit: "ADAPTIVE_ADMISSION_INITIAL_LIMIT",
maxLimit: "ADAPTIVE_ADMISSION_MAX_LIMIT",
maxQueueCount: "ADAPTIVE_ADMISSION_MAX_QUEUE_COUNT",
maxQueueCost: "ADAPTIVE_ADMISSION_MAX_QUEUE_COST",
defaultMaxWaitMs: "ADAPTIVE_ADMISSION_MAX_WAIT_MS",
windowMs: "ADAPTIVE_ADMISSION_WINDOW_MS",
} as const;
function parsePositiveSafeInt(name: string, raw: string): number {
if (!/^[0-9]+$/.test(raw)) {
throw new RangeError(`${name} must be a positive safe integer`);
}
const value = Number(raw);
if (!Number.isSafeInteger(value) || value <= 0) {
throw new RangeError(`${name} must be a positive safe integer`);
}
return value;
}
/** Strict env → config resolver. Throws clear config errors for direct callers. */
export function resolveAdaptiveAdmissionConfigFromEnv(
env: NodeJS.ProcessEnv | Record<string, string | undefined> = process.env
): AdaptiveAdmissionConfig {
const cfg: AdaptiveAdmissionConfig = { ...DEFAULT_ADAPTIVE_ADMISSION_CONFIG };
const modeRaw = env[ENV_KEYS.mode];
if (modeRaw !== undefined && modeRaw !== "") {
if (modeRaw !== "off" && modeRaw !== "shadow" && modeRaw !== "enforce") {
throw new RangeError(`${ENV_KEYS.mode} must be off|shadow|enforce`);
}
cfg.mode = modeRaw;
}
// Numeric env keys only — typed assignment without index-signature cast (TS2352).
type EnvIntField = Exclude<keyof typeof ENV_KEYS, "mode">;
const intFields = [
"minLimit",
"initialLimit",
"maxLimit",
"maxQueueCount",
"maxQueueCost",
"defaultMaxWaitMs",
"windowMs",
] as const satisfies ReadonlyArray<EnvIntField>;
for (const field of intFields) {
const envName = ENV_KEYS[field];
const raw = env[envName];
if (raw === undefined || raw === "") continue;
cfg[field] = parsePositiveSafeInt(envName, raw);
}
// Shared pure validation — accept exact documented maxima, reject core-invalid configs.
validateConfig(cfg);
// Per-tenant virtual admission lanes (#9654) — opt-in via OMNIROUTE_CHAT_VIRTUAL_LANES.
const vlRaw = env.OMNIROUTE_CHAT_VIRTUAL_LANES;
cfg.virtualLanes = vlRaw === "1" || vlRaw === "true";
return cfg;
}
export type AdaptiveAdmissionAcquireInput = {
/** Opaque fairness key; never exposed in snapshots or client errors. */
tenantKey: string;
/** Already-parsed request body — must not be re-read or stringified for cost. */
body: unknown;
signal?: AbortSignal;
maxWaitMs?: number;
/** Authoritative streaming class; wins body stream inference when set. */
streaming?: boolean;
};
export type AdaptiveAdmissionAdmitted = {
status: "admitted";
mode: AdmissionMode;
lease: AdmissionLease;
admittedAtMs: number;
shadowDecision?: ShadowDecision;
};
export type AdaptiveAdmissionRejected = {
status: "rejected";
code: string;
response: Response;
};
export type AdaptiveAdmissionAcquireResult = AdaptiveAdmissionAdmitted | AdaptiveAdmissionRejected;
export type AdaptiveAdmissionPublicSnapshot = AdmissionSnapshot & {
resourceSeverity: PressureSeverity;
resourceReason: PressureReason;
resourceObservedAtMs: number;
pressureGuardRejectCount: number;
};
export type AdaptiveAdmissionLifecycleOptions = {
admittedAtMs: number;
signal?: AbortSignal;
nowMs?: () => number;
};
export type AdaptiveAdmissionRuntimeOptions = {
config?: AdaptiveAdmissionConfig;
env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
clock?: Partial<AdmissionClock>;
checkResourcePressure?: () => ResourcePressureGuardResult | null;
getResourcePressureObservation?: () => ResourcePressureObservation;
/** Test seam: observe pressure values fed into the controller after dedupe. */
onPressureObserved?: (pressure: AdmissionPressure) => void;
warn?: (message: string) => void;
nowMs?: () => number;
};
/** Non-success release outcomes callers must choose explicitly for handler failures. */
export type AdaptiveAdmissionFailureOutcome = Exclude<AdmissionReleaseOutcome, "success">;
export type AdaptiveAdmissionRuntime = {
acquire(input: AdaptiveAdmissionAcquireInput): Promise<AdaptiveAdmissionAcquireResult>;
snapshot(): AdaptiveAdmissionPublicSnapshot;
dispose(): void;
/**
* Release an admitted lease after a handler failure before any HTTP response exists.
* Callers must supply the concrete non-success outcome — never defaults to local_reject.
*/
releaseHandlerFailure(
lease: AdmissionLease,
outcome: AdaptiveAdmissionFailureOutcome,
options?: { admittedAtMs?: number; nowMs?: () => number }
): void;
attachResponseLifecycle(
response: Response,
lease: AdmissionLease,
options: AdaptiveAdmissionLifecycleOptions
): Response;
};
type RejectHttpMapping = {
status: number;
code: string;
message: string;
retryAfter?: string;
};
const REJECT_MAP: Record<AdmissionRejectCode, RejectHttpMapping> = {
ADMISSION_ABORTED: {
status: 499,
code: "admission_aborted",
message: "Request aborted",
},
ADMISSION_OVERSIZED: {
status: 503,
code: "admission_oversized",
message: "Request too large for current capacity",
},
ADMISSION_QUEUE_FULL: {
status: 503,
code: "admission_queue_full",
message: "Service temporarily unavailable",
retryAfter: "1",
},
ADMISSION_DEADLINE: {
status: 503,
code: "admission_deadline",
message: "Service temporarily unavailable",
retryAfter: "1",
},
ADMISSION_SHUTDOWN: {
status: 503,
code: "admission_shutdown",
message: "Service temporarily unavailable",
},
ADMISSION_UNAVAILABLE: {
status: 503,
code: "admission_unavailable",
message: "Service temporarily unavailable",
retryAfter: "1",
},
ADMISSION_LANE_EVICTED: {
status: 503,
code: "admission_lane_evicted",
message: "Connection lane evicted",
retryAfter: "1",
},
};
function isAdmissionRejectError(
err: unknown
): err is { code: AdmissionRejectCode; name: string; message: string } {
return (
!!err &&
typeof err === "object" &&
(err as { name?: string }).name === "AdmissionRejectError" &&
typeof (err as { code?: unknown }).code === "string"
);
}
function buildAdmissionRejectResponse(code: AdmissionRejectCode): AdaptiveAdmissionRejected {
const mapping = REJECT_MAP[code] ?? REJECT_MAP.ADMISSION_UNAVAILABLE;
const headers: Record<string, string> = {
"Content-Type": "application/json",
...CORS_HEADERS,
};
if (mapping.retryAfter) headers["Retry-After"] = mapping.retryAfter;
const body = buildErrorBody(mapping.status, mapping.message, undefined, {
type: mapping.status === 499 ? "client_disconnected" : "server_error",
code: mapping.code,
});
return {
status: "rejected",
code: mapping.code,
response: new Response(JSON.stringify(body), {
status: mapping.status,
headers,
}),
};
}
function observationIdentity(state: ResourcePressureObservation["state"]): string {
return `${state.observedAtMs}|${state.severity}|${state.reason}`;
}
function toAdmissionPressure(severity: PressureSeverity): AdmissionPressure {
if (severity === "critical") return "critical";
if (severity === "high") return "high";
return "normal";
}
function isSseResponse(response: Response): boolean {
const contentType = response.headers.get("content-type") ?? "";
return contentType.toLowerCase().includes("text/event-stream");
}
function releaseOnce(
lease: AdmissionLease,
outcome: AdmissionReleaseOutcome,
admittedAtMs: number | undefined,
nowMs: () => number
): void {
if (lease.released) return;
const latencyMs = admittedAtMs === undefined ? undefined : Math.max(0, nowMs() - admittedAtMs);
lease.release(outcome, latencyMs === undefined ? undefined : { latencyMs });
}
/**
* Map HTTP status (+ optional request signal) to admission release outcome.
* Cancellation always wins over status classification.
*/
function classifyHttpOutcome(status: number, signal?: AbortSignal): AdmissionReleaseOutcome {
if (signal?.aborted || status === 499) return "cancelled";
if (status === 408 || status === 504) return "timeout";
if (status >= 500) return "upstream_error";
if (status >= 400) return "local_reject";
// 2xx / 3xx (and rare 1xx) complete successfully from admission's perspective.
return "success";
}
class AdaptiveAdmissionRuntimeImpl implements AdaptiveAdmissionRuntime {
private readonly controller: AdaptiveAdmissionController;
private readonly checkResourcePressure: () => ResourcePressureGuardResult | null;
private readonly getResourcePressureObservation: () => ResourcePressureObservation;
private readonly onPressureObserved?: (pressure: AdmissionPressure) => void;
private readonly nowMs: () => number;
private lastObservationKey: string | null = null;
private lastResource: {
severity: PressureSeverity;
reason: PressureReason;
observedAtMs: number;
} = { severity: "normal", reason: "none", observedAtMs: 0 };
private pressureGuardRejectCount = 0;
private disposed = false;
constructor(options: AdaptiveAdmissionRuntimeOptions, config: AdaptiveAdmissionConfig) {
this.controller = new AdaptiveAdmissionController(config, options.clock);
this.checkResourcePressure = options.checkResourcePressure ?? checkResourcePressureGuard;
this.getResourcePressureObservation =
options.getResourcePressureObservation ?? getResourcePressureObservation;
this.onPressureObserved = options.onPressureObserved;
this.nowMs = options.nowMs ?? options.clock?.now ?? (() => Date.now());
}
async acquire(input: AdaptiveAdmissionAcquireInput): Promise<AdaptiveAdmissionAcquireResult> {
if (this.disposed) {
return buildAdmissionRejectResponse("ADMISSION_SHUTDOWN");
}
// Independent safety fuse first — never acquire provider work on critical guard.
// Still feed pressure observations so the controller learns from critical samples.
let guard: ResourcePressureGuardResult | null = null;
try {
guard = this.checkResourcePressure();
} catch {
// Fail open on sampling/check failures.
}
this.feedFreshPressureObservation();
if (guard) {
this.pressureGuardRejectCount += 1;
return {
status: "rejected",
code: "resource_pressure",
response: guard.response,
};
}
const features = extractAdmissionCostFeatures(
input.body,
input.streaming === undefined ? undefined : { streaming: input.streaming }
);
let result: AdmissionAcquireResult;
try {
result = await this.controller.acquire({
tenantKey: input.tenantKey,
features,
signal: input.signal,
maxWaitMs: input.maxWaitMs,
});
} catch (err) {
if (isAdmissionRejectError(err)) {
return buildAdmissionRejectResponse(err.code);
}
return buildAdmissionRejectResponse("ADMISSION_UNAVAILABLE");
}
if (result.status === "rejected") {
return buildAdmissionRejectResponse(result.code);
}
if (result.status === "queued") {
try {
const admitted = await result.promise;
return {
status: "admitted",
mode: this.controller.snapshot().mode,
lease: admitted.lease,
admittedAtMs: this.nowMs(),
shadowDecision: admitted.shadowDecision,
};
} catch (err) {
if (isAdmissionRejectError(err)) {
return buildAdmissionRejectResponse(err.code);
}
return buildAdmissionRejectResponse("ADMISSION_UNAVAILABLE");
}
}
return {
status: "admitted",
mode: this.controller.snapshot().mode,
lease: result.lease,
admittedAtMs: this.nowMs(),
shadowDecision: result.shadowDecision,
};
}
snapshot(): AdaptiveAdmissionPublicSnapshot {
const core = this.controller.snapshot();
return {
...core,
resourceSeverity: this.lastResource.severity,
resourceReason: this.lastResource.reason,
resourceObservedAtMs: this.lastResource.observedAtMs,
pressureGuardRejectCount: this.pressureGuardRejectCount,
};
}
dispose(): void {
if (this.disposed) return;
this.disposed = true;
this.controller.shutdown();
}
releaseHandlerFailure(
lease: AdmissionLease,
outcome: AdaptiveAdmissionFailureOutcome,
options?: { admittedAtMs?: number; nowMs?: () => number }
): void {
releaseOnce(lease, outcome, options?.admittedAtMs, options?.nowMs ?? this.nowMs);
}
attachResponseLifecycle(
response: Response,
lease: AdmissionLease,
options: AdaptiveAdmissionLifecycleOptions
): Response {
const nowMs = options.nowMs ?? this.nowMs;
const admittedAtMs = options.admittedAtMs;
if (!response.body || !isSseResponse(response)) {
releaseOnce(lease, classifyHttpOutcome(response.status, options.signal), admittedAtMs, nowMs);
return response;
}
const upstream = response.body;
const reader = upstream.getReader();
let settled = false;
let readerCancelled = false;
const settle = (outcome: AdmissionReleaseOutcome): void => {
if (settled) return;
settled = true;
releaseOnce(lease, outcome, admittedAtMs, nowMs);
};
const cancelReader = (reason?: unknown): void => {
if (readerCancelled) return;
readerCancelled = true;
void reader.cancel(reason).catch(() => {
/* ignore cancel races */
});
};
const onAbort = (): void => {
cancelReader(options.signal?.reason);
settle("cancelled");
};
if (options.signal) {
if (options.signal.aborted) {
onAbort();
} else {
options.signal.addEventListener("abort", onAbort, { once: true });
}
}
const detachAbort = (): void => {
options.signal?.removeEventListener("abort", onAbort);
};
const stream = new ReadableStream<Uint8Array>({
async pull(controller) {
if (settled) {
controller.close();
return;
}
try {
const { done, value } = await reader.read();
if (done) {
detachAbort();
settle(classifyHttpOutcome(response.status, options.signal));
controller.close();
return;
}
controller.enqueue(value);
} catch (err) {
detachAbort();
settle(options.signal?.aborted ? "cancelled" : "upstream_error");
controller.error(err);
}
},
cancel(reason) {
detachAbort();
cancelReader(reason);
settle("cancelled");
},
});
return new Response(stream, {
status: response.status,
statusText: response.statusText,
headers: response.headers,
});
}
private feedFreshPressureObservation(): void {
try {
const observation = this.getResourcePressureObservation();
const state = observation.state;
this.lastResource = {
severity: state.severity,
reason: state.reason,
observedAtMs: state.observedAtMs,
};
const key = observationIdentity(state);
if (state.observedAtMs <= 0) return;
if (key === this.lastObservationKey) return;
this.lastObservationKey = key;
const pressure = toAdmissionPressure(state.severity);
this.controller.observePressure(pressure);
this.onPressureObserved?.(pressure);
} catch {
// Fail open.
}
}
}
function createRuntimeFromResolvedConfig(
options: AdaptiveAdmissionRuntimeOptions,
config: AdaptiveAdmissionConfig
): AdaptiveAdmissionRuntime {
return new AdaptiveAdmissionRuntimeImpl(options, config);
}
/**
* Create an injected adaptive-admission runtime for tests or process use.
* Invalid explicit `config` still throws (direct callers want fail-fast).
*/
export function createAdaptiveAdmissionRuntime(
options: AdaptiveAdmissionRuntimeOptions = {}
): AdaptiveAdmissionRuntime {
const config =
options.config ??
(options.env
? resolveAdaptiveAdmissionConfigFromEnv(options.env)
: { ...DEFAULT_ADAPTIVE_ADMISSION_CONFIG });
return createRuntimeFromResolvedConfig(options, config);
}
function warnInvalidDefaultConfig(warn: ((message: string) => void) | undefined): void {
const message =
"[adaptiveAdmission] invalid environment configuration; using default shadow admission settings";
if (warn) {
warn(message);
return;
}
console.warn(message);
}
function createDefaultProcessRuntime(
options: AdaptiveAdmissionRuntimeOptions = {}
): AdaptiveAdmissionRuntime {
const warn = options.warn;
try {
const config =
options.config ?? resolveAdaptiveAdmissionConfigFromEnv(options.env ?? process.env);
return createRuntimeFromResolvedConfig(options, config);
} catch {
warnInvalidDefaultConfig(warn);
return createRuntimeFromResolvedConfig(options, {
...DEFAULT_ADAPTIVE_ADMISSION_CONFIG,
});
}
}
/** Call-time process-global runtime (HMR-safe via globalThis symbol store). */
export function getAdaptiveAdmissionRuntime(): AdaptiveAdmissionRuntime {
const store = getRuntimeStore();
if (!store.runtime) {
store.runtime = createDefaultProcessRuntime();
}
return store.runtime;
}
/** Dispose previous controller and replace the process-global runtime. */
export function reloadAdaptiveAdmissionRuntime(
options: AdaptiveAdmissionRuntimeOptions = {}
): AdaptiveAdmissionRuntime {
const store = getRuntimeStore();
store.runtime?.dispose();
store.runtime = createDefaultProcessRuntime(options);
return store.runtime;
}
/** Test isolation: dispose and clear the process-global runtime slot. */
export function resetAdaptiveAdmissionRuntimeForTests(): void {
const store = getRuntimeStore();
store.runtime?.dispose();
store.runtime = null;
}