@albinocrabs/o-switcher 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/LICENSE +199 -21
- package/README.md +88 -288
- package/dist/{chunk-BTDKGS7P.js → chunk-IKNWSNAS.js} +120 -307
- package/dist/chunk-VABBGKSR.cjs +1663 -0
- package/dist/index.cjs +583 -1927
- package/dist/index.js +348 -224
- package/dist/plugin.cjs +35 -1031
- package/dist/plugin.js +16 -34
- package/package.json +47 -11
- package/CONTRIBUTING.md +0 -72
- package/dist/chunk-BTDKGS7P.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/plugin.cjs.map +0 -1
- package/dist/plugin.js.map +0 -1
- package/docs/api-reference.md +0 -286
- package/docs/architecture.md +0 -511
- package/docs/examples.md +0 -190
- package/docs/getting-started.md +0 -316
- package/scripts/collect-errors.ts +0 -159
- package/scripts/corpus.jsonl +0 -5
package/dist/index.cjs
CHANGED
|
@@ -1,428 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
ADMISSION_RESULTS: () => ADMISSION_RESULTS,
|
|
34
|
-
BackoffConfigSchema: () => BackoffConfigSchema,
|
|
35
|
-
ConfigValidationError: () => ConfigValidationError,
|
|
36
|
-
DEFAULT_ALPHA: () => DEFAULT_ALPHA,
|
|
37
|
-
DEFAULT_BACKOFF_BASE_MS: () => DEFAULT_BACKOFF_BASE_MS,
|
|
38
|
-
DEFAULT_BACKOFF_JITTER: () => DEFAULT_BACKOFF_JITTER,
|
|
39
|
-
DEFAULT_BACKOFF_MAX_MS: () => DEFAULT_BACKOFF_MAX_MS,
|
|
40
|
-
DEFAULT_BACKOFF_MULTIPLIER: () => DEFAULT_BACKOFF_MULTIPLIER,
|
|
41
|
-
DEFAULT_BACKOFF_PARAMS: () => DEFAULT_BACKOFF_PARAMS,
|
|
42
|
-
DEFAULT_FAILOVER_BUDGET: () => DEFAULT_FAILOVER_BUDGET,
|
|
43
|
-
DEFAULT_RETRY: () => DEFAULT_RETRY,
|
|
44
|
-
DEFAULT_RETRY_BUDGET: () => DEFAULT_RETRY_BUDGET,
|
|
45
|
-
DEFAULT_TIMEOUT_MS: () => DEFAULT_TIMEOUT_MS,
|
|
46
|
-
DualBreaker: () => DualBreaker,
|
|
47
|
-
EXCLUSION_REASONS: () => EXCLUSION_REASONS,
|
|
48
|
-
ErrorClassSchema: () => ErrorClassSchema,
|
|
49
|
-
HEURISTIC_PATTERNS: () => HEURISTIC_PATTERNS,
|
|
50
|
-
INITIAL_HEALTH_SCORE: () => INITIAL_HEALTH_SCORE,
|
|
51
|
-
PROVIDER_PATTERNS: () => PROVIDER_PATTERNS,
|
|
52
|
-
REDACT_PATHS: () => REDACT_PATHS,
|
|
53
|
-
SwitcherConfigSchema: () => SwitcherConfigSchema,
|
|
54
|
-
TARGET_STATES: () => TARGET_STATES,
|
|
55
|
-
TEMPORAL_QUOTA_PATTERN: () => TEMPORAL_QUOTA_PATTERN,
|
|
56
|
-
TargetConfigSchema: () => TargetConfigSchema,
|
|
57
|
-
TargetRegistry: () => TargetRegistry,
|
|
58
|
-
addProfile: () => addProfile,
|
|
59
|
-
applyConfigDiff: () => applyConfigDiff,
|
|
60
|
-
checkHardRejects: () => checkHardRejects,
|
|
61
|
-
classify: () => classify,
|
|
62
|
-
computeBackoffMs: () => computeBackoffMs,
|
|
63
|
-
computeConfigDiff: () => computeConfigDiff,
|
|
64
|
-
computeCooldownMs: () => computeCooldownMs,
|
|
65
|
-
computeScore: () => computeScore,
|
|
66
|
-
createAdmissionController: () => createAdmissionController,
|
|
67
|
-
createAuditCollector: () => createAuditCollector,
|
|
68
|
-
createAuditLogger: () => createAuditLogger,
|
|
69
|
-
createAuthWatcher: () => createAuthWatcher,
|
|
70
|
-
createCircuitBreaker: () => createCircuitBreaker,
|
|
71
|
-
createConcurrencyTracker: () => createConcurrencyTracker,
|
|
72
|
-
createCooldownManager: () => createCooldownManager,
|
|
73
|
-
createExecutionOrchestrator: () => createExecutionOrchestrator,
|
|
74
|
-
createFailoverOrchestrator: () => createFailoverOrchestrator,
|
|
75
|
-
createLogSubscriber: () => createLogSubscriber,
|
|
76
|
-
createModeAdapter: () => createModeAdapter,
|
|
77
|
-
createOperatorTools: () => createOperatorTools,
|
|
78
|
-
createProfileTools: () => createProfileTools,
|
|
79
|
-
createRegistry: () => createRegistry,
|
|
80
|
-
createRequestLogger: () => createRequestLogger,
|
|
81
|
-
createRequestTraceBuffer: () => createRequestTraceBuffer,
|
|
82
|
-
createRetryPolicy: () => createRetryPolicy,
|
|
83
|
-
createRoutingEventBus: () => createRoutingEventBus,
|
|
84
|
-
createStreamBuffer: () => createStreamBuffer,
|
|
85
|
-
createStreamStitcher: () => createStreamStitcher,
|
|
86
|
-
detectDeploymentMode: () => detectDeploymentMode,
|
|
87
|
-
determineContinuationMode: () => determineContinuationMode,
|
|
88
|
-
directSignalFromResponse: () => directSignalFromResponse,
|
|
89
|
-
disableTarget: () => disableTarget,
|
|
90
|
-
discoverTargets: () => discoverTargets,
|
|
91
|
-
discoverTargetsFromProfiles: () => discoverTargetsFromProfiles,
|
|
92
|
-
drainTarget: () => drainTarget,
|
|
93
|
-
extractRetryAfterMs: () => extractRetryAfterMs,
|
|
94
|
-
generateCorrelationId: () => generateCorrelationId,
|
|
95
|
-
getExclusionReason: () => getExclusionReason,
|
|
96
|
-
getModeCapabilities: () => getModeCapabilities,
|
|
97
|
-
getSignalFidelity: () => getSignalFidelity,
|
|
98
|
-
getTargetStateTransition: () => getTargetStateTransition,
|
|
99
|
-
heuristicSignalFromEvent: () => heuristicSignalFromEvent,
|
|
100
|
-
inspectRequest: () => inspectRequest,
|
|
101
|
-
isRetryable: () => isRetryable,
|
|
102
|
-
listProfiles: () => listProfiles,
|
|
103
|
-
listTargets: () => listTargets,
|
|
104
|
-
loadProfiles: () => loadProfiles,
|
|
105
|
-
nextProfileId: () => nextProfileId,
|
|
106
|
-
normalizeLatency: () => normalizeLatency,
|
|
107
|
-
pauseTarget: () => pauseTarget,
|
|
108
|
-
reloadConfig: () => reloadConfig,
|
|
109
|
-
removeProfile: () => removeProfile,
|
|
110
|
-
resumeTarget: () => resumeTarget,
|
|
111
|
-
saveProfiles: () => saveProfiles,
|
|
112
|
-
selectTarget: () => selectTarget,
|
|
113
|
-
updateHealthScore: () => updateHealthScore,
|
|
114
|
-
updateLatencyEma: () => updateLatencyEma,
|
|
115
|
-
validateBearerToken: () => validateBearerToken,
|
|
116
|
-
validateConfig: () => validateConfig
|
|
117
|
-
});
|
|
118
|
-
module.exports = __toCommonJS(index_exports);
|
|
119
|
-
|
|
120
|
-
// src/config/schema.ts
|
|
121
|
-
var import_zod = require("zod");
|
|
122
|
-
|
|
123
|
-
// src/config/defaults.ts
|
|
124
|
-
var DEFAULT_RETRY_BUDGET = 3;
|
|
125
|
-
var DEFAULT_FAILOVER_BUDGET = 2;
|
|
126
|
-
var DEFAULT_BACKOFF_BASE_MS = 1e3;
|
|
127
|
-
var DEFAULT_BACKOFF_MULTIPLIER = 2;
|
|
128
|
-
var DEFAULT_BACKOFF_MAX_MS = 3e4;
|
|
129
|
-
var DEFAULT_BACKOFF_JITTER = "full";
|
|
130
|
-
var DEFAULT_ROUTING_WEIGHT_HEALTH = 1;
|
|
131
|
-
var DEFAULT_ROUTING_WEIGHT_LATENCY = 0.5;
|
|
132
|
-
var DEFAULT_ROUTING_WEIGHT_FAILURE = 0.8;
|
|
133
|
-
var DEFAULT_ROUTING_WEIGHT_PRIORITY = 0.3;
|
|
134
|
-
var DEFAULT_MAX_EXPECTED_LATENCY_MS = 3e4;
|
|
135
|
-
var DEFAULT_QUEUE_LIMIT = 100;
|
|
136
|
-
var DEFAULT_GLOBAL_CONCURRENCY_LIMIT = 10;
|
|
137
|
-
var DEFAULT_BACKPRESSURE_THRESHOLD = 50;
|
|
138
|
-
var DEFAULT_CB_FAILURE_THRESHOLD = 5;
|
|
139
|
-
var DEFAULT_CB_FAILURE_RATE_THRESHOLD = 0.5;
|
|
140
|
-
var DEFAULT_CB_SLIDING_WINDOW_SIZE = 10;
|
|
141
|
-
var DEFAULT_CB_HALF_OPEN_AFTER_MS = 3e4;
|
|
142
|
-
var DEFAULT_CB_HALF_OPEN_MAX_PROBES = 1;
|
|
143
|
-
var DEFAULT_CB_SUCCESS_THRESHOLD = 2;
|
|
144
|
-
var DEFAULT_RETRY = 3;
|
|
145
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
146
|
-
|
|
147
|
-
// src/config/schema.ts
|
|
148
|
-
var BackoffConfigSchema = import_zod.z.object({
|
|
149
|
-
base_ms: import_zod.z.number().positive().default(DEFAULT_BACKOFF_BASE_MS),
|
|
150
|
-
multiplier: import_zod.z.number().positive().default(DEFAULT_BACKOFF_MULTIPLIER),
|
|
151
|
-
max_ms: import_zod.z.number().positive().default(DEFAULT_BACKOFF_MAX_MS),
|
|
152
|
-
jitter: import_zod.z.enum(["full", "equal", "none"]).default(DEFAULT_BACKOFF_JITTER)
|
|
153
|
-
});
|
|
154
|
-
var RoutingWeightsSchema = import_zod.z.object({
|
|
155
|
-
health: import_zod.z.number().default(DEFAULT_ROUTING_WEIGHT_HEALTH),
|
|
156
|
-
latency: import_zod.z.number().default(DEFAULT_ROUTING_WEIGHT_LATENCY),
|
|
157
|
-
failure: import_zod.z.number().default(DEFAULT_ROUTING_WEIGHT_FAILURE),
|
|
158
|
-
priority: import_zod.z.number().default(DEFAULT_ROUTING_WEIGHT_PRIORITY)
|
|
159
|
-
});
|
|
160
|
-
var CircuitBreakerConfigSchema = import_zod.z.object({
|
|
161
|
-
failure_threshold: import_zod.z.number().int().positive().default(DEFAULT_CB_FAILURE_THRESHOLD),
|
|
162
|
-
failure_rate_threshold: import_zod.z.number().gt(0).lt(1).default(DEFAULT_CB_FAILURE_RATE_THRESHOLD),
|
|
163
|
-
sliding_window_size: import_zod.z.number().int().positive().default(DEFAULT_CB_SLIDING_WINDOW_SIZE),
|
|
164
|
-
half_open_after_ms: import_zod.z.number().positive().default(DEFAULT_CB_HALF_OPEN_AFTER_MS),
|
|
165
|
-
half_open_max_probes: import_zod.z.number().int().positive().default(DEFAULT_CB_HALF_OPEN_MAX_PROBES),
|
|
166
|
-
success_threshold: import_zod.z.number().int().positive().default(DEFAULT_CB_SUCCESS_THRESHOLD)
|
|
167
|
-
});
|
|
168
|
-
var TargetConfigSchema = import_zod.z.object({
|
|
169
|
-
target_id: import_zod.z.string().min(1),
|
|
170
|
-
provider_id: import_zod.z.string().min(1),
|
|
171
|
-
profile: import_zod.z.string().optional(),
|
|
172
|
-
endpoint_id: import_zod.z.string().optional(),
|
|
173
|
-
capabilities: import_zod.z.array(import_zod.z.string()).default([]),
|
|
174
|
-
enabled: import_zod.z.boolean().default(true),
|
|
175
|
-
operator_priority: import_zod.z.number().int().default(0),
|
|
176
|
-
policy_tags: import_zod.z.array(import_zod.z.string()).default([]),
|
|
177
|
-
retry_budget: import_zod.z.number().int().positive().optional(),
|
|
178
|
-
failover_budget: import_zod.z.number().int().positive().optional(),
|
|
179
|
-
backoff: BackoffConfigSchema.optional(),
|
|
180
|
-
concurrency_limit: import_zod.z.number().int().positive().optional(),
|
|
181
|
-
circuit_breaker: CircuitBreakerConfigSchema.optional()
|
|
182
|
-
});
|
|
183
|
-
var SwitcherConfigSchema = import_zod.z.object({
|
|
184
|
-
targets: import_zod.z.array(TargetConfigSchema).min(1).optional(),
|
|
185
|
-
retry: import_zod.z.number().int().positive().optional(),
|
|
186
|
-
timeout: import_zod.z.number().positive().optional(),
|
|
187
|
-
retry_budget: import_zod.z.number().int().positive().default(DEFAULT_RETRY_BUDGET),
|
|
188
|
-
failover_budget: import_zod.z.number().int().positive().default(DEFAULT_FAILOVER_BUDGET),
|
|
189
|
-
backoff: BackoffConfigSchema.default({
|
|
190
|
-
base_ms: DEFAULT_BACKOFF_BASE_MS,
|
|
191
|
-
multiplier: DEFAULT_BACKOFF_MULTIPLIER,
|
|
192
|
-
max_ms: DEFAULT_BACKOFF_MAX_MS,
|
|
193
|
-
jitter: DEFAULT_BACKOFF_JITTER
|
|
194
|
-
}),
|
|
195
|
-
deployment_mode_hint: import_zod.z.enum(["plugin-only", "server-companion", "sdk-control", "auto"]).default("auto"),
|
|
196
|
-
routing_weights: RoutingWeightsSchema.default({
|
|
197
|
-
health: DEFAULT_ROUTING_WEIGHT_HEALTH,
|
|
198
|
-
latency: DEFAULT_ROUTING_WEIGHT_LATENCY,
|
|
199
|
-
failure: DEFAULT_ROUTING_WEIGHT_FAILURE,
|
|
200
|
-
priority: DEFAULT_ROUTING_WEIGHT_PRIORITY
|
|
201
|
-
}),
|
|
202
|
-
queue_limit: import_zod.z.number().int().positive().default(DEFAULT_QUEUE_LIMIT),
|
|
203
|
-
concurrency_limit: import_zod.z.number().int().positive().default(DEFAULT_GLOBAL_CONCURRENCY_LIMIT),
|
|
204
|
-
backpressure_threshold: import_zod.z.number().int().nonnegative().default(DEFAULT_BACKPRESSURE_THRESHOLD),
|
|
205
|
-
circuit_breaker: CircuitBreakerConfigSchema.default({
|
|
206
|
-
failure_threshold: DEFAULT_CB_FAILURE_THRESHOLD,
|
|
207
|
-
failure_rate_threshold: DEFAULT_CB_FAILURE_RATE_THRESHOLD,
|
|
208
|
-
sliding_window_size: DEFAULT_CB_SLIDING_WINDOW_SIZE,
|
|
209
|
-
half_open_after_ms: DEFAULT_CB_HALF_OPEN_AFTER_MS,
|
|
210
|
-
half_open_max_probes: DEFAULT_CB_HALF_OPEN_MAX_PROBES,
|
|
211
|
-
success_threshold: DEFAULT_CB_SUCCESS_THRESHOLD
|
|
212
|
-
}),
|
|
213
|
-
max_expected_latency_ms: import_zod.z.number().positive().default(DEFAULT_MAX_EXPECTED_LATENCY_MS)
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
// src/config/loader.ts
|
|
217
|
-
var ConfigValidationError = class extends Error {
|
|
218
|
-
diagnostics;
|
|
219
|
-
constructor(diagnostics) {
|
|
220
|
-
const summary = diagnostics.map((d) => ` ${d.path}: ${d.message}`).join("\n");
|
|
221
|
-
super(`Invalid O-Switcher configuration:
|
|
222
|
-
${summary}`);
|
|
223
|
-
this.name = "ConfigValidationError";
|
|
224
|
-
this.diagnostics = diagnostics;
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
var validateConfig = (raw) => {
|
|
228
|
-
const result = SwitcherConfigSchema.safeParse(raw);
|
|
229
|
-
if (result.success) {
|
|
230
|
-
const data = { ...result.data };
|
|
231
|
-
if (data.retry !== void 0 && data.retry_budget === DEFAULT_RETRY_BUDGET) {
|
|
232
|
-
data.retry_budget = data.retry;
|
|
233
|
-
}
|
|
234
|
-
if (data.timeout !== void 0 && data.max_expected_latency_ms === DEFAULT_MAX_EXPECTED_LATENCY_MS) {
|
|
235
|
-
data.max_expected_latency_ms = data.timeout;
|
|
236
|
-
}
|
|
237
|
-
if (data.targets !== void 0) {
|
|
238
|
-
const seen = /* @__PURE__ */ new Set();
|
|
239
|
-
const duplicateDiagnostics = [];
|
|
240
|
-
for (const target of data.targets) {
|
|
241
|
-
const key = `${target.provider_id}::${target.profile ?? "__default__"}`;
|
|
242
|
-
if (seen.has(key)) {
|
|
243
|
-
duplicateDiagnostics.push({
|
|
244
|
-
path: "targets",
|
|
245
|
-
message: `Duplicate provider_id + profile combination: ${key}`,
|
|
246
|
-
received: key
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
seen.add(key);
|
|
250
|
-
}
|
|
251
|
-
if (duplicateDiagnostics.length > 0) {
|
|
252
|
-
throw new ConfigValidationError(duplicateDiagnostics);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return Object.freeze(data);
|
|
256
|
-
}
|
|
257
|
-
const diagnostics = result.error.issues.map(
|
|
258
|
-
(issue) => ({
|
|
259
|
-
path: issue.path.join("."),
|
|
260
|
-
message: issue.message,
|
|
261
|
-
received: "expected" in issue ? issue.expected : void 0
|
|
262
|
-
})
|
|
263
|
-
);
|
|
264
|
-
throw new ConfigValidationError(diagnostics);
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
// src/config/discovery.ts
|
|
268
|
-
var discoverTargets = (providerConfig) => {
|
|
269
|
-
const targets = [];
|
|
270
|
-
for (const [key, value] of Object.entries(providerConfig)) {
|
|
271
|
-
if (!value) continue;
|
|
272
|
-
const raw = {
|
|
273
|
-
target_id: key,
|
|
274
|
-
provider_id: value.id ?? key,
|
|
275
|
-
capabilities: ["chat"],
|
|
276
|
-
enabled: true,
|
|
277
|
-
operator_priority: 0,
|
|
278
|
-
policy_tags: []
|
|
279
|
-
};
|
|
280
|
-
const parsed = TargetConfigSchema.parse(raw);
|
|
281
|
-
targets.push(parsed);
|
|
282
|
-
}
|
|
283
|
-
return targets;
|
|
284
|
-
};
|
|
285
|
-
var discoverTargetsFromProfiles = (store) => {
|
|
286
|
-
const targets = [];
|
|
287
|
-
for (const entry of Object.values(store)) {
|
|
288
|
-
if (!entry) continue;
|
|
289
|
-
const raw = {
|
|
290
|
-
target_id: entry.id,
|
|
291
|
-
provider_id: entry.provider,
|
|
292
|
-
profile: entry.id,
|
|
293
|
-
capabilities: ["chat"],
|
|
294
|
-
enabled: true,
|
|
295
|
-
operator_priority: 0,
|
|
296
|
-
policy_tags: []
|
|
297
|
-
};
|
|
298
|
-
const parsed = TargetConfigSchema.parse(raw);
|
|
299
|
-
targets.push(parsed);
|
|
300
|
-
}
|
|
301
|
-
return targets;
|
|
302
|
-
};
|
|
1
|
+
'use strict';
|
|
303
2
|
|
|
304
|
-
|
|
305
|
-
var
|
|
306
|
-
var
|
|
307
|
-
var updateHealthScore = (currentScore, observation, alpha = DEFAULT_ALPHA) => alpha * observation + (1 - alpha) * currentScore;
|
|
308
|
-
var updateLatencyEma = (currentEma, observedMs, alpha = DEFAULT_ALPHA) => alpha * observedMs + (1 - alpha) * currentEma;
|
|
309
|
-
|
|
310
|
-
// src/registry/registry.ts
|
|
311
|
-
var TargetRegistry = class {
|
|
312
|
-
targets;
|
|
313
|
-
constructor(config) {
|
|
314
|
-
this.targets = new Map(
|
|
315
|
-
(config.targets ?? []).map((t) => [
|
|
316
|
-
t.target_id,
|
|
317
|
-
{
|
|
318
|
-
target_id: t.target_id,
|
|
319
|
-
provider_id: t.provider_id,
|
|
320
|
-
profile: t.profile,
|
|
321
|
-
endpoint_id: t.endpoint_id,
|
|
322
|
-
capabilities: [...t.capabilities],
|
|
323
|
-
enabled: t.enabled,
|
|
324
|
-
state: "Active",
|
|
325
|
-
health_score: INITIAL_HEALTH_SCORE,
|
|
326
|
-
cooldown_until: null,
|
|
327
|
-
latency_ema_ms: 0,
|
|
328
|
-
failure_score: 0,
|
|
329
|
-
operator_priority: t.operator_priority,
|
|
330
|
-
policy_tags: [...t.policy_tags]
|
|
331
|
-
}
|
|
332
|
-
])
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
/** Returns the target entry for the given id, or undefined if not found. */
|
|
336
|
-
getTarget(id) {
|
|
337
|
-
return this.targets.get(id);
|
|
338
|
-
}
|
|
339
|
-
/** Returns a readonly array of all target entries. */
|
|
340
|
-
getAllTargets() {
|
|
341
|
-
return [...this.targets.values()];
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Updates the state of a target.
|
|
345
|
-
* @returns true if the target was found and updated, false otherwise.
|
|
346
|
-
*/
|
|
347
|
-
updateState(id, newState) {
|
|
348
|
-
const target = this.targets.get(id);
|
|
349
|
-
if (!target) {
|
|
350
|
-
return false;
|
|
351
|
-
}
|
|
352
|
-
this.targets.set(id, { ...target, state: newState });
|
|
353
|
-
return true;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Records a success (1) or failure (0) observation for a target.
|
|
357
|
-
* Updates health_score via EMA.
|
|
358
|
-
*/
|
|
359
|
-
recordObservation(id, observation) {
|
|
360
|
-
const target = this.targets.get(id);
|
|
361
|
-
if (!target) {
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
const newHealthScore = updateHealthScore(
|
|
365
|
-
target.health_score,
|
|
366
|
-
observation
|
|
367
|
-
);
|
|
368
|
-
this.targets.set(id, { ...target, health_score: newHealthScore });
|
|
369
|
-
}
|
|
370
|
-
/** Sets the cooldown_until timestamp for a target. */
|
|
371
|
-
setCooldown(id, untilMs) {
|
|
372
|
-
const target = this.targets.get(id);
|
|
373
|
-
if (!target) {
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
this.targets.set(id, { ...target, cooldown_until: untilMs });
|
|
377
|
-
}
|
|
378
|
-
/** Updates the latency EMA for a target. */
|
|
379
|
-
updateLatency(id, ms) {
|
|
380
|
-
const target = this.targets.get(id);
|
|
381
|
-
if (!target) {
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
const newLatency = updateLatencyEma(target.latency_ema_ms, ms);
|
|
385
|
-
this.targets.set(id, { ...target, latency_ema_ms: newLatency });
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Adds a new target entry to the registry.
|
|
389
|
-
* @returns true if added, false if target_id already exists.
|
|
390
|
-
*/
|
|
391
|
-
addTarget(entry) {
|
|
392
|
-
if (this.targets.has(entry.target_id)) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
this.targets.set(entry.target_id, entry);
|
|
396
|
-
return true;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Removes a target entry from the registry.
|
|
400
|
-
* @returns true if found and removed, false if not found.
|
|
401
|
-
*/
|
|
402
|
-
removeTarget(id) {
|
|
403
|
-
return this.targets.delete(id);
|
|
404
|
-
}
|
|
405
|
-
/** Returns a deep-frozen snapshot of all targets. */
|
|
406
|
-
getSnapshot() {
|
|
407
|
-
const snapshot = {
|
|
408
|
-
targets: [...this.targets.values()].map((t) => ({ ...t }))
|
|
409
|
-
};
|
|
410
|
-
return Object.freeze(snapshot);
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
var createRegistry = (config) => new TargetRegistry(config);
|
|
414
|
-
|
|
415
|
-
// src/registry/types.ts
|
|
416
|
-
var TARGET_STATES = [
|
|
417
|
-
"Active",
|
|
418
|
-
"CoolingDown",
|
|
419
|
-
"ReauthRequired",
|
|
420
|
-
"PolicyBlocked",
|
|
421
|
-
"CircuitOpen",
|
|
422
|
-
"CircuitHalfOpen",
|
|
423
|
-
"Draining",
|
|
424
|
-
"Disabled"
|
|
425
|
-
];
|
|
3
|
+
var chunkVABBGKSR_cjs = require('./chunk-VABBGKSR.cjs');
|
|
4
|
+
var crypto = require('crypto');
|
|
5
|
+
var tool = require('@opencode-ai/plugin/tool');
|
|
426
6
|
|
|
427
7
|
// src/mode/detection.ts
|
|
428
8
|
var detectDeploymentMode = (hint) => {
|
|
@@ -456,176 +36,248 @@ var getModeCapabilities = (mode) => {
|
|
|
456
36
|
};
|
|
457
37
|
};
|
|
458
38
|
|
|
459
|
-
// src/audit/logger.ts
|
|
460
|
-
var import_pino = __toESM(require("pino"), 1);
|
|
461
|
-
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
462
|
-
var REDACT_PATHS = [
|
|
463
|
-
"api_key",
|
|
464
|
-
"token",
|
|
465
|
-
"secret",
|
|
466
|
-
"password",
|
|
467
|
-
"authorization",
|
|
468
|
-
"credential",
|
|
469
|
-
"credentials",
|
|
470
|
-
"*.api_key",
|
|
471
|
-
"*.token",
|
|
472
|
-
"*.secret",
|
|
473
|
-
"*.password",
|
|
474
|
-
"*.authorization",
|
|
475
|
-
"*.credential",
|
|
476
|
-
"*.credentials"
|
|
477
|
-
];
|
|
478
|
-
var createAuditLogger = (options) => {
|
|
479
|
-
const opts = {
|
|
480
|
-
level: options?.level ?? "info",
|
|
481
|
-
redact: {
|
|
482
|
-
paths: [...REDACT_PATHS],
|
|
483
|
-
censor: "[Redacted]"
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
if (options?.destination) {
|
|
487
|
-
return (0, import_pino.default)(opts, options.destination);
|
|
488
|
-
}
|
|
489
|
-
return (0, import_pino.default)(opts);
|
|
490
|
-
};
|
|
491
|
-
var createRequestLogger = (baseLogger, requestId) => baseLogger.child({ request_id: requestId });
|
|
492
|
-
var generateCorrelationId = () => import_node_crypto.default.randomUUID();
|
|
493
|
-
|
|
494
|
-
// src/errors/taxonomy.ts
|
|
495
|
-
var import_zod2 = require("zod");
|
|
496
|
-
var RateLimitedSchema = import_zod2.z.object({
|
|
497
|
-
class: import_zod2.z.literal("RateLimited"),
|
|
498
|
-
retryable: import_zod2.z.literal(true),
|
|
499
|
-
retry_after_ms: import_zod2.z.number().optional(),
|
|
500
|
-
provider_reason: import_zod2.z.string().optional()
|
|
501
|
-
});
|
|
502
|
-
var QuotaExhaustedSchema = import_zod2.z.object({
|
|
503
|
-
class: import_zod2.z.literal("QuotaExhausted"),
|
|
504
|
-
retryable: import_zod2.z.literal(false),
|
|
505
|
-
provider_reason: import_zod2.z.string().optional()
|
|
506
|
-
});
|
|
507
|
-
var AuthFailureSchema = import_zod2.z.object({
|
|
508
|
-
class: import_zod2.z.literal("AuthFailure"),
|
|
509
|
-
retryable: import_zod2.z.literal(false),
|
|
510
|
-
recovery_attempted: import_zod2.z.boolean().default(false)
|
|
511
|
-
});
|
|
512
|
-
var PermissionFailureSchema = import_zod2.z.object({
|
|
513
|
-
class: import_zod2.z.literal("PermissionFailure"),
|
|
514
|
-
retryable: import_zod2.z.literal(false)
|
|
515
|
-
});
|
|
516
|
-
var PolicyFailureSchema = import_zod2.z.object({
|
|
517
|
-
class: import_zod2.z.literal("PolicyFailure"),
|
|
518
|
-
retryable: import_zod2.z.literal(false)
|
|
519
|
-
});
|
|
520
|
-
var RegionRestrictionSchema = import_zod2.z.object({
|
|
521
|
-
class: import_zod2.z.literal("RegionRestriction"),
|
|
522
|
-
retryable: import_zod2.z.literal(false)
|
|
523
|
-
});
|
|
524
|
-
var ModelUnavailableSchema = import_zod2.z.object({
|
|
525
|
-
class: import_zod2.z.literal("ModelUnavailable"),
|
|
526
|
-
retryable: import_zod2.z.literal(false),
|
|
527
|
-
failover_eligible: import_zod2.z.literal(true)
|
|
528
|
-
});
|
|
529
|
-
var TransientServerFailureSchema = import_zod2.z.object({
|
|
530
|
-
class: import_zod2.z.literal("TransientServerFailure"),
|
|
531
|
-
retryable: import_zod2.z.literal(true),
|
|
532
|
-
http_status: import_zod2.z.number().optional()
|
|
533
|
-
});
|
|
534
|
-
var TransportFailureSchema = import_zod2.z.object({
|
|
535
|
-
class: import_zod2.z.literal("TransportFailure"),
|
|
536
|
-
retryable: import_zod2.z.literal(true)
|
|
537
|
-
});
|
|
538
|
-
var InterruptedExecutionSchema = import_zod2.z.object({
|
|
539
|
-
class: import_zod2.z.literal("InterruptedExecution"),
|
|
540
|
-
retryable: import_zod2.z.literal(true),
|
|
541
|
-
partial_output_bytes: import_zod2.z.number().optional()
|
|
542
|
-
});
|
|
543
|
-
var ErrorClassSchema = import_zod2.z.discriminatedUnion("class", [
|
|
544
|
-
RateLimitedSchema,
|
|
545
|
-
QuotaExhaustedSchema,
|
|
546
|
-
AuthFailureSchema,
|
|
547
|
-
PermissionFailureSchema,
|
|
548
|
-
PolicyFailureSchema,
|
|
549
|
-
RegionRestrictionSchema,
|
|
550
|
-
ModelUnavailableSchema,
|
|
551
|
-
TransientServerFailureSchema,
|
|
552
|
-
TransportFailureSchema,
|
|
553
|
-
InterruptedExecutionSchema
|
|
554
|
-
]);
|
|
555
|
-
var isRetryable = (errorClass) => errorClass.retryable;
|
|
556
|
-
var getTargetStateTransition = (errorClass) => {
|
|
557
|
-
switch (errorClass.class) {
|
|
558
|
-
case "RateLimited":
|
|
559
|
-
return "CoolingDown";
|
|
560
|
-
case "QuotaExhausted":
|
|
561
|
-
return "Disabled";
|
|
562
|
-
case "AuthFailure":
|
|
563
|
-
return "ReauthRequired";
|
|
564
|
-
case "PermissionFailure":
|
|
565
|
-
return "PolicyBlocked";
|
|
566
|
-
case "PolicyFailure":
|
|
567
|
-
return "PolicyBlocked";
|
|
568
|
-
case "RegionRestriction":
|
|
569
|
-
return "Disabled";
|
|
570
|
-
case "ModelUnavailable":
|
|
571
|
-
return null;
|
|
572
|
-
case "TransientServerFailure":
|
|
573
|
-
return null;
|
|
574
|
-
case "TransportFailure":
|
|
575
|
-
return null;
|
|
576
|
-
case "InterruptedExecution":
|
|
577
|
-
return null;
|
|
578
|
-
}
|
|
579
|
-
};
|
|
580
|
-
|
|
581
39
|
// src/errors/corpus.ts
|
|
582
40
|
var PROVIDER_PATTERNS = [
|
|
583
41
|
// Anthropic
|
|
584
|
-
{
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
{
|
|
592
|
-
|
|
42
|
+
{
|
|
43
|
+
provider: "anthropic",
|
|
44
|
+
http_status: 400,
|
|
45
|
+
error_type_field: "error.type",
|
|
46
|
+
error_type_value: "invalid_request_error",
|
|
47
|
+
error_class: "PolicyFailure"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
provider: "anthropic",
|
|
51
|
+
http_status: 401,
|
|
52
|
+
error_type_field: "error.type",
|
|
53
|
+
error_type_value: "authentication_error",
|
|
54
|
+
error_class: "AuthFailure"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
provider: "anthropic",
|
|
58
|
+
http_status: 402,
|
|
59
|
+
error_type_field: "error.type",
|
|
60
|
+
error_type_value: "billing_error",
|
|
61
|
+
error_class: "QuotaExhausted"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
provider: "anthropic",
|
|
65
|
+
http_status: 403,
|
|
66
|
+
error_type_field: "error.type",
|
|
67
|
+
error_type_value: "permission_error",
|
|
68
|
+
error_class: "PermissionFailure"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
provider: "anthropic",
|
|
72
|
+
http_status: 404,
|
|
73
|
+
error_type_field: "error.type",
|
|
74
|
+
error_type_value: "not_found_error",
|
|
75
|
+
error_class: "ModelUnavailable"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
provider: "anthropic",
|
|
79
|
+
http_status: 429,
|
|
80
|
+
error_type_field: "error.type",
|
|
81
|
+
error_type_value: "rate_limit_error",
|
|
82
|
+
error_class: "RateLimited"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
provider: "anthropic",
|
|
86
|
+
http_status: 500,
|
|
87
|
+
error_type_field: "error.type",
|
|
88
|
+
error_type_value: "api_error",
|
|
89
|
+
error_class: "TransientServerFailure"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
provider: "anthropic",
|
|
93
|
+
http_status: 504,
|
|
94
|
+
error_type_field: "error.type",
|
|
95
|
+
error_type_value: "timeout_error",
|
|
96
|
+
error_class: "TransportFailure"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
provider: "anthropic",
|
|
100
|
+
http_status: 529,
|
|
101
|
+
error_type_field: "error.type",
|
|
102
|
+
error_type_value: "overloaded_error",
|
|
103
|
+
error_class: "RateLimited",
|
|
104
|
+
notes: "Server capacity exhaustion; backoff on same provider, do NOT failover"
|
|
105
|
+
},
|
|
593
106
|
// OpenAI
|
|
594
|
-
{
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
{
|
|
107
|
+
{
|
|
108
|
+
provider: "openai",
|
|
109
|
+
http_status: 400,
|
|
110
|
+
error_type_field: "error.code",
|
|
111
|
+
error_type_value: "",
|
|
112
|
+
error_class: "PolicyFailure"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
provider: "openai",
|
|
116
|
+
http_status: 401,
|
|
117
|
+
error_type_field: "error.code",
|
|
118
|
+
error_type_value: "invalid_api_key",
|
|
119
|
+
error_class: "AuthFailure"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
provider: "openai",
|
|
123
|
+
http_status: 403,
|
|
124
|
+
error_type_field: "error.code",
|
|
125
|
+
error_type_value: "unsupported_country_region_territory",
|
|
126
|
+
error_class: "RegionRestriction",
|
|
127
|
+
notes: "GeoIP block \u2014 collected 2026-04-11 from real API"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
provider: "openai",
|
|
131
|
+
http_status: 403,
|
|
132
|
+
error_type_field: "error.code",
|
|
133
|
+
error_type_value: "",
|
|
134
|
+
error_class: "PermissionFailure"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
provider: "openai",
|
|
138
|
+
http_status: 429,
|
|
139
|
+
error_type_field: "error.code",
|
|
140
|
+
error_type_value: "rate_limit_exceeded",
|
|
141
|
+
error_class: "RateLimited"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
provider: "openai",
|
|
145
|
+
http_status: 429,
|
|
146
|
+
error_type_field: "error.code",
|
|
147
|
+
error_type_value: "insufficient_quota",
|
|
148
|
+
error_class: "QuotaExhausted",
|
|
149
|
+
notes: "Billing exhausted -- NOT retryable"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
provider: "openai",
|
|
153
|
+
http_status: 500,
|
|
154
|
+
error_type_field: "error.code",
|
|
155
|
+
error_type_value: "",
|
|
156
|
+
error_class: "TransientServerFailure"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
provider: "openai",
|
|
160
|
+
http_status: 503,
|
|
161
|
+
error_type_field: "error.code",
|
|
162
|
+
error_type_value: "",
|
|
163
|
+
error_class: "TransientServerFailure"
|
|
164
|
+
},
|
|
602
165
|
// Google Vertex AI / Gemini
|
|
603
|
-
{
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
166
|
+
{
|
|
167
|
+
provider: "google",
|
|
168
|
+
http_status: 400,
|
|
169
|
+
error_type_field: "error.status",
|
|
170
|
+
error_type_value: "INVALID_ARGUMENT",
|
|
171
|
+
error_class: "PolicyFailure"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
provider: "google",
|
|
175
|
+
http_status: 403,
|
|
176
|
+
error_type_field: "error.status",
|
|
177
|
+
error_type_value: "PERMISSION_DENIED",
|
|
178
|
+
error_class: "PermissionFailure"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
provider: "google",
|
|
182
|
+
http_status: 429,
|
|
183
|
+
error_type_field: "error.status",
|
|
184
|
+
error_type_value: "RESOURCE_EXHAUSTED",
|
|
185
|
+
error_class: "RateLimited"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
provider: "google",
|
|
189
|
+
http_status: 500,
|
|
190
|
+
error_type_field: "error.status",
|
|
191
|
+
error_type_value: "INTERNAL",
|
|
192
|
+
error_class: "TransientServerFailure"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
provider: "google",
|
|
196
|
+
http_status: 503,
|
|
197
|
+
error_type_field: "error.status",
|
|
198
|
+
error_type_value: "UNAVAILABLE",
|
|
199
|
+
error_class: "TransientServerFailure"
|
|
200
|
+
},
|
|
608
201
|
// AWS Bedrock
|
|
609
|
-
{
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
202
|
+
{
|
|
203
|
+
provider: "bedrock",
|
|
204
|
+
http_status: 429,
|
|
205
|
+
error_type_field: "__type",
|
|
206
|
+
error_type_value: "ThrottlingException",
|
|
207
|
+
error_class: "RateLimited"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
provider: "bedrock",
|
|
211
|
+
http_status: 408,
|
|
212
|
+
error_type_field: "__type",
|
|
213
|
+
error_type_value: "ModelTimeoutException",
|
|
214
|
+
error_class: "TransportFailure"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
provider: "bedrock",
|
|
218
|
+
http_status: 424,
|
|
219
|
+
error_type_field: "__type",
|
|
220
|
+
error_type_value: "ModelNotReadyException",
|
|
221
|
+
error_class: "ModelUnavailable"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
provider: "bedrock",
|
|
225
|
+
http_status: 403,
|
|
226
|
+
error_type_field: "__type",
|
|
227
|
+
error_type_value: "AccessDeniedException",
|
|
228
|
+
error_class: "PermissionFailure"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
provider: "bedrock",
|
|
232
|
+
http_status: 400,
|
|
233
|
+
error_type_field: "__type",
|
|
234
|
+
error_type_value: "ValidationException",
|
|
235
|
+
error_class: "PolicyFailure"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
provider: "bedrock",
|
|
239
|
+
http_status: 500,
|
|
240
|
+
error_type_field: "__type",
|
|
241
|
+
error_type_value: "InternalServerException",
|
|
242
|
+
error_class: "TransientServerFailure"
|
|
243
|
+
}
|
|
615
244
|
];
|
|
616
245
|
var HEURISTIC_PATTERNS = [
|
|
617
246
|
// Transport errors (high confidence -- these are unambiguous)
|
|
618
|
-
{
|
|
247
|
+
{
|
|
248
|
+
pattern: /ECONNREFUSED|ECONNRESET|ETIMEDOUT/,
|
|
249
|
+
error_class: "TransportFailure",
|
|
250
|
+
confidence: "high"
|
|
251
|
+
},
|
|
619
252
|
// Quota patterns (before rate limit to avoid misclassification -- Pitfall 2/3)
|
|
620
|
-
{
|
|
621
|
-
|
|
253
|
+
{
|
|
254
|
+
pattern: /quota\s*(?:exceeded|exhausted)/i,
|
|
255
|
+
error_class: "QuotaExhausted",
|
|
256
|
+
confidence: "medium"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
pattern: /insufficient\s*quota/i,
|
|
260
|
+
error_class: "QuotaExhausted",
|
|
261
|
+
confidence: "medium",
|
|
262
|
+
provider: "openai"
|
|
263
|
+
},
|
|
622
264
|
{ pattern: /billing/i, error_class: "QuotaExhausted", confidence: "low", provider: "openai" },
|
|
623
265
|
// Rate limit patterns
|
|
624
266
|
{ pattern: /rate\s*limit/i, error_class: "RateLimited", confidence: "medium" },
|
|
625
267
|
{ pattern: /too many requests/i, error_class: "RateLimited", confidence: "medium" },
|
|
626
268
|
{ pattern: /retry\s*after/i, error_class: "RateLimited", confidence: "medium" },
|
|
627
|
-
{
|
|
628
|
-
|
|
269
|
+
{
|
|
270
|
+
pattern: /overloaded/i,
|
|
271
|
+
error_class: "RateLimited",
|
|
272
|
+
confidence: "medium",
|
|
273
|
+
provider: "anthropic"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
pattern: /resource\s*exhausted/i,
|
|
277
|
+
error_class: "RateLimited",
|
|
278
|
+
confidence: "medium",
|
|
279
|
+
provider: "google"
|
|
280
|
+
},
|
|
629
281
|
// Auth patterns
|
|
630
282
|
{ pattern: /authentication/i, error_class: "AuthFailure", confidence: "medium" },
|
|
631
283
|
{ pattern: /invalid\s*api\s*key/i, error_class: "AuthFailure", confidence: "medium" },
|
|
@@ -634,14 +286,31 @@ var HEURISTIC_PATTERNS = [
|
|
|
634
286
|
{ pattern: /permission\s*denied/i, error_class: "PermissionFailure", confidence: "medium" },
|
|
635
287
|
{ pattern: /forbidden/i, error_class: "PermissionFailure", confidence: "low" },
|
|
636
288
|
// Model availability patterns
|
|
637
|
-
{
|
|
289
|
+
{
|
|
290
|
+
pattern: /model\s*not\s*(?:available|ready|found)/i,
|
|
291
|
+
error_class: "ModelUnavailable",
|
|
292
|
+
confidence: "medium"
|
|
293
|
+
},
|
|
638
294
|
{ pattern: /not\s*found/i, error_class: "ModelUnavailable", confidence: "low" },
|
|
639
295
|
// Transport patterns (lower confidence than ECONNREFUSED)
|
|
640
296
|
{ pattern: /timeout/i, error_class: "TransportFailure", confidence: "low" },
|
|
641
297
|
// Region restriction (requires both keywords)
|
|
642
|
-
{
|
|
643
|
-
|
|
644
|
-
|
|
298
|
+
{
|
|
299
|
+
pattern: /unsupported.country.*region.*territory/i,
|
|
300
|
+
error_class: "RegionRestriction",
|
|
301
|
+
confidence: "high",
|
|
302
|
+
notes: "OpenAI GeoIP block \u2014 collected 2026-04-11"
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
pattern: /country.*region.*not supported/i,
|
|
306
|
+
error_class: "RegionRestriction",
|
|
307
|
+
confidence: "high"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
pattern: /region.*restrict|restrict.*region/i,
|
|
311
|
+
error_class: "RegionRestriction",
|
|
312
|
+
confidence: "low"
|
|
313
|
+
}
|
|
645
314
|
];
|
|
646
315
|
var TEMPORAL_QUOTA_PATTERN = /too many tokens per (?:day|month|hour|week)/i;
|
|
647
316
|
|
|
@@ -860,777 +529,6 @@ var heuristicSignalFromEvent = (eventType, message, providerId) => ({
|
|
|
860
529
|
provider_id: providerId
|
|
861
530
|
});
|
|
862
531
|
|
|
863
|
-
// src/retry/backoff.ts
|
|
864
|
-
var DEFAULT_BACKOFF_PARAMS = {
|
|
865
|
-
base_ms: 1e3,
|
|
866
|
-
multiplier: 2,
|
|
867
|
-
max_ms: 3e4,
|
|
868
|
-
jitter: "full"
|
|
869
|
-
};
|
|
870
|
-
var computeBackoffMs = (attempt, params, retryAfterMs) => {
|
|
871
|
-
const rawDelay = Math.min(
|
|
872
|
-
params.base_ms * Math.pow(params.multiplier, attempt),
|
|
873
|
-
params.max_ms
|
|
874
|
-
);
|
|
875
|
-
const jitteredDelay = params.jitter === "full" ? Math.random() * rawDelay : params.jitter === "equal" ? rawDelay / 2 + Math.random() * (rawDelay / 2) : rawDelay;
|
|
876
|
-
return Math.max(jitteredDelay, retryAfterMs ?? 0);
|
|
877
|
-
};
|
|
878
|
-
|
|
879
|
-
// src/retry/retry-policy.ts
|
|
880
|
-
var createRetryPolicy = (budget, backoffParams = DEFAULT_BACKOFF_PARAMS) => ({
|
|
881
|
-
budget,
|
|
882
|
-
backoffParams,
|
|
883
|
-
decide: (classification, attemptsSoFar) => {
|
|
884
|
-
const errorClass = classification.error_class;
|
|
885
|
-
if (!isRetryable(errorClass)) {
|
|
886
|
-
return {
|
|
887
|
-
action: "abort",
|
|
888
|
-
reason: `Non-retryable: ${errorClass.class}`,
|
|
889
|
-
target_state: getTargetStateTransition(errorClass)
|
|
890
|
-
};
|
|
891
|
-
}
|
|
892
|
-
if (attemptsSoFar >= budget) {
|
|
893
|
-
return {
|
|
894
|
-
action: "exhausted",
|
|
895
|
-
attempts_used: attemptsSoFar
|
|
896
|
-
};
|
|
897
|
-
}
|
|
898
|
-
const retryAfterMs = errorClass.class === "RateLimited" ? errorClass.retry_after_ms : void 0;
|
|
899
|
-
const delayMs = computeBackoffMs(attemptsSoFar, backoffParams, retryAfterMs);
|
|
900
|
-
return {
|
|
901
|
-
action: "retry",
|
|
902
|
-
delay_ms: delayMs,
|
|
903
|
-
attempt: attemptsSoFar + 1
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
// src/routing/types.ts
|
|
909
|
-
var EXCLUSION_REASONS = [
|
|
910
|
-
"disabled",
|
|
911
|
-
"policy_blocked",
|
|
912
|
-
"reauth_required",
|
|
913
|
-
"cooldown_active",
|
|
914
|
-
"circuit_open",
|
|
915
|
-
"capability_mismatch",
|
|
916
|
-
"draining"
|
|
917
|
-
];
|
|
918
|
-
var ADMISSION_RESULTS = [
|
|
919
|
-
"admitted",
|
|
920
|
-
"queued",
|
|
921
|
-
"degraded",
|
|
922
|
-
"rejected"
|
|
923
|
-
];
|
|
924
|
-
|
|
925
|
-
// src/routing/events.ts
|
|
926
|
-
var import_eventemitter3 = require("eventemitter3");
|
|
927
|
-
var createRoutingEventBus = () => new import_eventemitter3.EventEmitter();
|
|
928
|
-
|
|
929
|
-
// src/routing/dual-breaker.ts
|
|
930
|
-
var import_cockatiel = require("cockatiel");
|
|
931
|
-
var DualBreaker = class {
|
|
932
|
-
consecutive;
|
|
933
|
-
count;
|
|
934
|
-
constructor(consecutiveThreshold, countOpts) {
|
|
935
|
-
this.consecutive = new import_cockatiel.ConsecutiveBreaker(consecutiveThreshold);
|
|
936
|
-
this.count = new import_cockatiel.CountBreaker(countOpts);
|
|
937
|
-
}
|
|
938
|
-
/** Serializable state for both internal breakers. */
|
|
939
|
-
get state() {
|
|
940
|
-
return {
|
|
941
|
-
consecutive: this.consecutive.state,
|
|
942
|
-
count: this.count.state
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
|
-
/** Restore state for both internal breakers. */
|
|
946
|
-
set state(value) {
|
|
947
|
-
const v = value;
|
|
948
|
-
this.consecutive.state = v.consecutive;
|
|
949
|
-
this.count.state = v.count;
|
|
950
|
-
}
|
|
951
|
-
/**
|
|
952
|
-
* Record success on both breakers.
|
|
953
|
-
* ConsecutiveBreaker.success() takes no args (resets counter).
|
|
954
|
-
* CountBreaker.success() takes CircuitState.
|
|
955
|
-
*/
|
|
956
|
-
success(state) {
|
|
957
|
-
this.consecutive.success();
|
|
958
|
-
this.count.success(state);
|
|
959
|
-
}
|
|
960
|
-
/**
|
|
961
|
-
* Record failure on both breakers.
|
|
962
|
-
* Returns true if EITHER breaker trips (OR logic).
|
|
963
|
-
* ConsecutiveBreaker.failure() takes no args.
|
|
964
|
-
* CountBreaker.failure() takes CircuitState.
|
|
965
|
-
*/
|
|
966
|
-
failure(state) {
|
|
967
|
-
const consecutiveTripped = this.consecutive.failure();
|
|
968
|
-
const countTripped = this.count.failure(state);
|
|
969
|
-
return consecutiveTripped || countTripped;
|
|
970
|
-
}
|
|
971
|
-
};
|
|
972
|
-
|
|
973
|
-
// src/routing/circuit-breaker.ts
|
|
974
|
-
var import_cockatiel2 = require("cockatiel");
|
|
975
|
-
var import_eventemitter32 = require("eventemitter3");
|
|
976
|
-
var COCKATIEL_TO_TARGET = /* @__PURE__ */ new Map([
|
|
977
|
-
[import_cockatiel2.CircuitState.Closed, "Active"],
|
|
978
|
-
[import_cockatiel2.CircuitState.Open, "CircuitOpen"],
|
|
979
|
-
[import_cockatiel2.CircuitState.HalfOpen, "CircuitHalfOpen"],
|
|
980
|
-
[import_cockatiel2.CircuitState.Isolated, "Disabled"]
|
|
981
|
-
]);
|
|
982
|
-
var toTargetState = (state) => COCKATIEL_TO_TARGET.get(state) ?? "Disabled";
|
|
983
|
-
var createCircuitBreaker = (targetId, config, eventBus) => {
|
|
984
|
-
const createPolicy = () => {
|
|
985
|
-
const breaker = new DualBreaker(config.failure_threshold, {
|
|
986
|
-
threshold: config.failure_rate_threshold,
|
|
987
|
-
size: config.sliding_window_size
|
|
988
|
-
});
|
|
989
|
-
const policy = (0, import_cockatiel2.circuitBreaker)(import_cockatiel2.handleAll, {
|
|
990
|
-
halfOpenAfter: config.half_open_after_ms,
|
|
991
|
-
breaker
|
|
992
|
-
});
|
|
993
|
-
return { policy, breaker };
|
|
994
|
-
};
|
|
995
|
-
let current = createPolicy();
|
|
996
|
-
let previousState = import_cockatiel2.CircuitState.Closed;
|
|
997
|
-
let openedAtMs = 0;
|
|
998
|
-
const subscribeEvents = (policy) => {
|
|
999
|
-
policy.onStateChange((newState) => {
|
|
1000
|
-
if (newState === import_cockatiel2.CircuitState.Open) {
|
|
1001
|
-
openedAtMs = Date.now();
|
|
1002
|
-
}
|
|
1003
|
-
const from = toTargetState(previousState);
|
|
1004
|
-
const to = toTargetState(newState);
|
|
1005
|
-
previousState = newState;
|
|
1006
|
-
if (from !== to && eventBus) {
|
|
1007
|
-
eventBus.emit("circuit_state_change", {
|
|
1008
|
-
target_id: targetId,
|
|
1009
|
-
from,
|
|
1010
|
-
to,
|
|
1011
|
-
reason: `state_transition`
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
});
|
|
1015
|
-
};
|
|
1016
|
-
subscribeEvents(current.policy);
|
|
1017
|
-
const effectiveState = () => {
|
|
1018
|
-
const raw = current.policy.state;
|
|
1019
|
-
if (raw === import_cockatiel2.CircuitState.Open && openedAtMs > 0 && Date.now() - openedAtMs >= config.half_open_after_ms) {
|
|
1020
|
-
return import_cockatiel2.CircuitState.HalfOpen;
|
|
1021
|
-
}
|
|
1022
|
-
return raw;
|
|
1023
|
-
};
|
|
1024
|
-
return {
|
|
1025
|
-
state() {
|
|
1026
|
-
return toTargetState(effectiveState());
|
|
1027
|
-
},
|
|
1028
|
-
async recordSuccess() {
|
|
1029
|
-
try {
|
|
1030
|
-
await current.policy.execute(async () => void 0);
|
|
1031
|
-
} catch (err) {
|
|
1032
|
-
if (err instanceof import_cockatiel2.BrokenCircuitError || err instanceof import_cockatiel2.IsolatedCircuitError) {
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
throw err;
|
|
1036
|
-
}
|
|
1037
|
-
},
|
|
1038
|
-
async recordFailure() {
|
|
1039
|
-
try {
|
|
1040
|
-
await current.policy.execute(async () => {
|
|
1041
|
-
throw new Error("recorded-failure");
|
|
1042
|
-
});
|
|
1043
|
-
} catch {
|
|
1044
|
-
}
|
|
1045
|
-
},
|
|
1046
|
-
allowRequest() {
|
|
1047
|
-
return effectiveState() !== import_cockatiel2.CircuitState.Open;
|
|
1048
|
-
},
|
|
1049
|
-
reset() {
|
|
1050
|
-
current = createPolicy();
|
|
1051
|
-
previousState = import_cockatiel2.CircuitState.Closed;
|
|
1052
|
-
openedAtMs = 0;
|
|
1053
|
-
subscribeEvents(current.policy);
|
|
1054
|
-
}
|
|
1055
|
-
};
|
|
1056
|
-
};
|
|
1057
|
-
|
|
1058
|
-
// src/routing/concurrency-tracker.ts
|
|
1059
|
-
var createConcurrencyTracker = (defaultLimit) => {
|
|
1060
|
-
const state = /* @__PURE__ */ new Map();
|
|
1061
|
-
const getOrCreate = (target_id) => {
|
|
1062
|
-
const existing = state.get(target_id);
|
|
1063
|
-
if (existing) return existing;
|
|
1064
|
-
const entry = { active: 0, limit: defaultLimit };
|
|
1065
|
-
state.set(target_id, entry);
|
|
1066
|
-
return entry;
|
|
1067
|
-
};
|
|
1068
|
-
return {
|
|
1069
|
-
acquire(target_id) {
|
|
1070
|
-
const entry = getOrCreate(target_id);
|
|
1071
|
-
if (entry.active >= entry.limit) return false;
|
|
1072
|
-
entry.active += 1;
|
|
1073
|
-
return true;
|
|
1074
|
-
},
|
|
1075
|
-
release(target_id) {
|
|
1076
|
-
const entry = state.get(target_id);
|
|
1077
|
-
if (!entry || entry.active <= 0) return;
|
|
1078
|
-
entry.active -= 1;
|
|
1079
|
-
},
|
|
1080
|
-
headroom(target_id) {
|
|
1081
|
-
const entry = getOrCreate(target_id);
|
|
1082
|
-
return Math.max(0, entry.limit - entry.active);
|
|
1083
|
-
},
|
|
1084
|
-
active(target_id) {
|
|
1085
|
-
const entry = state.get(target_id);
|
|
1086
|
-
return entry ? entry.active : 0;
|
|
1087
|
-
},
|
|
1088
|
-
setLimit(target_id, limit) {
|
|
1089
|
-
const entry = getOrCreate(target_id);
|
|
1090
|
-
entry.limit = limit;
|
|
1091
|
-
}
|
|
1092
|
-
};
|
|
1093
|
-
};
|
|
1094
|
-
|
|
1095
|
-
// src/routing/policy-engine.ts
|
|
1096
|
-
var normalizeLatency = (latencyEmaMs, maxExpectedMs) => Math.min(latencyEmaMs / maxExpectedMs, 1);
|
|
1097
|
-
var computeScore = (target, weights, maxLatencyMs) => weights.health * target.health_score - weights.latency * normalizeLatency(target.latency_ema_ms, maxLatencyMs) - weights.failure * target.failure_score + weights.priority * target.operator_priority;
|
|
1098
|
-
var getExclusionReason = (target, circuitBreakers, requiredCapabilities, excludeTargets, nowMs) => {
|
|
1099
|
-
if (!target.enabled) {
|
|
1100
|
-
return "disabled";
|
|
1101
|
-
}
|
|
1102
|
-
if (target.state === "PolicyBlocked") {
|
|
1103
|
-
return "policy_blocked";
|
|
1104
|
-
}
|
|
1105
|
-
if (target.state === "ReauthRequired") {
|
|
1106
|
-
return "reauth_required";
|
|
1107
|
-
}
|
|
1108
|
-
if (target.state === "Draining") {
|
|
1109
|
-
return "draining";
|
|
1110
|
-
}
|
|
1111
|
-
if (target.state === "Disabled") {
|
|
1112
|
-
return "disabled";
|
|
1113
|
-
}
|
|
1114
|
-
const breaker = circuitBreakers.get(target.target_id);
|
|
1115
|
-
if (breaker !== void 0 && !breaker.allowRequest()) {
|
|
1116
|
-
return "circuit_open";
|
|
1117
|
-
}
|
|
1118
|
-
if (target.cooldown_until !== null && target.cooldown_until > nowMs) {
|
|
1119
|
-
return "cooldown_active";
|
|
1120
|
-
}
|
|
1121
|
-
if (requiredCapabilities.length > 0 && !requiredCapabilities.every((cap) => target.capabilities.includes(cap))) {
|
|
1122
|
-
return "capability_mismatch";
|
|
1123
|
-
}
|
|
1124
|
-
return null;
|
|
1125
|
-
};
|
|
1126
|
-
var selectTarget = (snapshot, circuitBreakers, requiredCapabilities, weights, maxLatencyMs, nowMs, request_id, excludeTargets, logger) => {
|
|
1127
|
-
const excluded = [];
|
|
1128
|
-
const eligible = [];
|
|
1129
|
-
for (const target of snapshot.targets) {
|
|
1130
|
-
if (excludeTargets !== void 0 && excludeTargets.has(target.target_id)) {
|
|
1131
|
-
continue;
|
|
1132
|
-
}
|
|
1133
|
-
const reason = getExclusionReason(
|
|
1134
|
-
target,
|
|
1135
|
-
circuitBreakers,
|
|
1136
|
-
requiredCapabilities,
|
|
1137
|
-
excludeTargets ?? /* @__PURE__ */ new Set(),
|
|
1138
|
-
nowMs
|
|
1139
|
-
);
|
|
1140
|
-
if (reason !== null) {
|
|
1141
|
-
excluded.push({ target_id: target.target_id, reason });
|
|
1142
|
-
} else {
|
|
1143
|
-
eligible.push(target);
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
const scored = eligible.map((target) => ({
|
|
1147
|
-
target,
|
|
1148
|
-
score: computeScore(target, weights, maxLatencyMs)
|
|
1149
|
-
}));
|
|
1150
|
-
scored.sort((a, b) => {
|
|
1151
|
-
const scoreDiff = b.score - a.score;
|
|
1152
|
-
if (scoreDiff !== 0) {
|
|
1153
|
-
return scoreDiff;
|
|
1154
|
-
}
|
|
1155
|
-
return a.target.target_id.localeCompare(b.target.target_id);
|
|
1156
|
-
});
|
|
1157
|
-
const candidates = scored.map((s) => ({
|
|
1158
|
-
target_id: s.target.target_id,
|
|
1159
|
-
score: s.score,
|
|
1160
|
-
health_score: s.target.health_score,
|
|
1161
|
-
latency_ema_ms: s.target.latency_ema_ms
|
|
1162
|
-
}));
|
|
1163
|
-
const firstCandidate = candidates.length > 0 ? candidates[0] : void 0;
|
|
1164
|
-
const selected = firstCandidate !== void 0 ? {
|
|
1165
|
-
target_id: firstCandidate.target_id,
|
|
1166
|
-
score: firstCandidate.score,
|
|
1167
|
-
rank: 0
|
|
1168
|
-
} : null;
|
|
1169
|
-
const record = {
|
|
1170
|
-
request_id,
|
|
1171
|
-
timestamp_ms: nowMs,
|
|
1172
|
-
candidates,
|
|
1173
|
-
excluded,
|
|
1174
|
-
selected
|
|
1175
|
-
};
|
|
1176
|
-
if (logger !== void 0) {
|
|
1177
|
-
const excludedSummary = {};
|
|
1178
|
-
for (const e of excluded) {
|
|
1179
|
-
excludedSummary[e.reason] = (excludedSummary[e.reason] ?? 0) + 1;
|
|
1180
|
-
}
|
|
1181
|
-
const logFields = {
|
|
1182
|
-
event: "target_selected",
|
|
1183
|
-
component: "policy-engine",
|
|
1184
|
-
request_id,
|
|
1185
|
-
selected: selected?.target_id ?? null,
|
|
1186
|
-
score: selected?.score ?? null,
|
|
1187
|
-
candidates_count: candidates.length,
|
|
1188
|
-
excluded_count: excluded.length,
|
|
1189
|
-
excluded_summary: excludedSummary
|
|
1190
|
-
};
|
|
1191
|
-
if (selected !== null) {
|
|
1192
|
-
logger.info(logFields, "Target selected");
|
|
1193
|
-
} else {
|
|
1194
|
-
logger.warn(logFields, "No eligible target");
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
return record;
|
|
1198
|
-
};
|
|
1199
|
-
|
|
1200
|
-
// src/routing/cooldown.ts
|
|
1201
|
-
var DEFAULT_COOLDOWN_BASE_MS = 5e3;
|
|
1202
|
-
var computeCooldownMs = (errorClass, consecutiveFailures, backoffParams, maxMs) => {
|
|
1203
|
-
const noJitterParams = {
|
|
1204
|
-
...backoffParams,
|
|
1205
|
-
jitter: "none"
|
|
1206
|
-
};
|
|
1207
|
-
let base;
|
|
1208
|
-
if (errorClass.class === "RateLimited" && "retry_after_ms" in errorClass && errorClass.retry_after_ms !== void 0) {
|
|
1209
|
-
base = Math.min(errorClass.retry_after_ms, maxMs);
|
|
1210
|
-
} else if (errorClass.class === "RateLimited") {
|
|
1211
|
-
base = computeBackoffMs(consecutiveFailures, noJitterParams);
|
|
1212
|
-
} else if (errorClass.class === "TransientServerFailure") {
|
|
1213
|
-
base = computeBackoffMs(consecutiveFailures, noJitterParams) / 2;
|
|
1214
|
-
} else {
|
|
1215
|
-
base = DEFAULT_COOLDOWN_BASE_MS;
|
|
1216
|
-
}
|
|
1217
|
-
base = Math.min(base, maxMs);
|
|
1218
|
-
const jitterFraction = 0.1 + Math.random() * 0.15;
|
|
1219
|
-
const jitter = jitterFraction * base;
|
|
1220
|
-
return Math.min(base + jitter, maxMs);
|
|
1221
|
-
};
|
|
1222
|
-
var createCooldownManager = (registry, eventBus) => ({
|
|
1223
|
-
setCooldown(target_id, durationMs, errorClass) {
|
|
1224
|
-
const untilMs = Date.now() + durationMs;
|
|
1225
|
-
registry.setCooldown(target_id, untilMs);
|
|
1226
|
-
registry.updateState(target_id, "CoolingDown");
|
|
1227
|
-
eventBus?.emit("cooldown_set", {
|
|
1228
|
-
target_id,
|
|
1229
|
-
until_ms: untilMs,
|
|
1230
|
-
error_class: errorClass
|
|
1231
|
-
});
|
|
1232
|
-
},
|
|
1233
|
-
checkExpired(nowMs) {
|
|
1234
|
-
const expired = [];
|
|
1235
|
-
for (const target of registry.getAllTargets()) {
|
|
1236
|
-
if (target.state === "CoolingDown" && target.cooldown_until !== null && target.cooldown_until <= nowMs) {
|
|
1237
|
-
registry.setCooldown(target.target_id, 0);
|
|
1238
|
-
registry.updateState(target.target_id, "Active");
|
|
1239
|
-
eventBus?.emit("cooldown_expired", { target_id: target.target_id });
|
|
1240
|
-
expired.push(target.target_id);
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
return expired;
|
|
1244
|
-
},
|
|
1245
|
-
isInCooldown(target_id, nowMs) {
|
|
1246
|
-
const target = registry.getTarget(target_id);
|
|
1247
|
-
if (!target) {
|
|
1248
|
-
return false;
|
|
1249
|
-
}
|
|
1250
|
-
return target.cooldown_until !== null && target.cooldown_until > nowMs;
|
|
1251
|
-
}
|
|
1252
|
-
});
|
|
1253
|
-
|
|
1254
|
-
// src/routing/admission.ts
|
|
1255
|
-
var import_p_queue = __toESM(require("p-queue"), 1);
|
|
1256
|
-
var checkHardRejects = (ctx) => {
|
|
1257
|
-
if (!ctx.hasEligibleTargets) {
|
|
1258
|
-
return { result: "rejected", reason: "no eligible targets available" };
|
|
1259
|
-
}
|
|
1260
|
-
if (ctx.operatorPaused) {
|
|
1261
|
-
return { result: "rejected", reason: "operator pause active" };
|
|
1262
|
-
}
|
|
1263
|
-
if (ctx.retryBudgetRemaining <= 0) {
|
|
1264
|
-
return { result: "rejected", reason: "retry budget exhausted" };
|
|
1265
|
-
}
|
|
1266
|
-
if (ctx.failoverBudgetRemaining <= 0) {
|
|
1267
|
-
return { result: "rejected", reason: "failover budget exhausted" };
|
|
1268
|
-
}
|
|
1269
|
-
return null;
|
|
1270
|
-
};
|
|
1271
|
-
var createAdmissionController = (config, eventBus) => {
|
|
1272
|
-
const queue = new import_p_queue.default({
|
|
1273
|
-
concurrency: config.concurrencyLimit
|
|
1274
|
-
});
|
|
1275
|
-
const emitDecision = (request_id, decision) => {
|
|
1276
|
-
eventBus?.emit("admission_decision", {
|
|
1277
|
-
request_id,
|
|
1278
|
-
result: decision.result,
|
|
1279
|
-
reason: decision.reason
|
|
1280
|
-
});
|
|
1281
|
-
};
|
|
1282
|
-
const controller = {
|
|
1283
|
-
async admit(request_id, ctx) {
|
|
1284
|
-
const hardReject = checkHardRejects(ctx);
|
|
1285
|
-
if (hardReject) {
|
|
1286
|
-
emitDecision(request_id, hardReject);
|
|
1287
|
-
return hardReject;
|
|
1288
|
-
}
|
|
1289
|
-
if (queue.size > config.backpressureThreshold) {
|
|
1290
|
-
const decision2 = {
|
|
1291
|
-
result: "degraded",
|
|
1292
|
-
reason: `backpressure: ${queue.size} queued > ${config.backpressureThreshold} threshold`
|
|
1293
|
-
};
|
|
1294
|
-
emitDecision(request_id, decision2);
|
|
1295
|
-
return decision2;
|
|
1296
|
-
}
|
|
1297
|
-
const total = queue.size + queue.pending;
|
|
1298
|
-
if (total >= config.queueLimit + config.concurrencyLimit) {
|
|
1299
|
-
const decision2 = {
|
|
1300
|
-
result: "rejected",
|
|
1301
|
-
reason: `queue full: ${total} >= ${config.queueLimit + config.concurrencyLimit}`
|
|
1302
|
-
};
|
|
1303
|
-
emitDecision(request_id, decision2);
|
|
1304
|
-
return decision2;
|
|
1305
|
-
}
|
|
1306
|
-
const decision = {
|
|
1307
|
-
result: "admitted",
|
|
1308
|
-
reason: "capacity available"
|
|
1309
|
-
};
|
|
1310
|
-
emitDecision(request_id, decision);
|
|
1311
|
-
return decision;
|
|
1312
|
-
},
|
|
1313
|
-
async execute(fn, request_id, ctx) {
|
|
1314
|
-
const decision = await controller.admit(request_id, ctx);
|
|
1315
|
-
if (decision.result === "rejected") {
|
|
1316
|
-
return { decision };
|
|
1317
|
-
}
|
|
1318
|
-
const result = await queue.add(fn);
|
|
1319
|
-
return { decision, result };
|
|
1320
|
-
},
|
|
1321
|
-
get pending() {
|
|
1322
|
-
return queue.pending;
|
|
1323
|
-
},
|
|
1324
|
-
get size() {
|
|
1325
|
-
return queue.size;
|
|
1326
|
-
}
|
|
1327
|
-
};
|
|
1328
|
-
return controller;
|
|
1329
|
-
};
|
|
1330
|
-
|
|
1331
|
-
// src/routing/log-subscriber.ts
|
|
1332
|
-
var createLogSubscriber = (eventBus, logger) => {
|
|
1333
|
-
const log = logger.child({ component: "routing" });
|
|
1334
|
-
const onCircuitStateChange = (payload) => {
|
|
1335
|
-
log.info(
|
|
1336
|
-
{
|
|
1337
|
-
event: "circuit_state_change",
|
|
1338
|
-
target_id: payload.target_id,
|
|
1339
|
-
from: payload.from,
|
|
1340
|
-
to: payload.to,
|
|
1341
|
-
reason: payload.reason
|
|
1342
|
-
},
|
|
1343
|
-
"Circuit breaker transition"
|
|
1344
|
-
);
|
|
1345
|
-
};
|
|
1346
|
-
const onCooldownSet = (payload) => {
|
|
1347
|
-
log.info(
|
|
1348
|
-
{
|
|
1349
|
-
event: "cooldown_set",
|
|
1350
|
-
target_id: payload.target_id,
|
|
1351
|
-
duration_ms: payload.until_ms - Date.now(),
|
|
1352
|
-
error_class: payload.error_class
|
|
1353
|
-
},
|
|
1354
|
-
"Cooldown set"
|
|
1355
|
-
);
|
|
1356
|
-
};
|
|
1357
|
-
const onCooldownExpired = (payload) => {
|
|
1358
|
-
log.info(
|
|
1359
|
-
{
|
|
1360
|
-
event: "cooldown_expired",
|
|
1361
|
-
target_id: payload.target_id
|
|
1362
|
-
},
|
|
1363
|
-
"Cooldown expired"
|
|
1364
|
-
);
|
|
1365
|
-
};
|
|
1366
|
-
const onAdmissionDecision = (payload) => {
|
|
1367
|
-
const fields = {
|
|
1368
|
-
event: "admission_decision",
|
|
1369
|
-
request_id: payload.request_id,
|
|
1370
|
-
result: payload.result,
|
|
1371
|
-
reason: payload.reason
|
|
1372
|
-
};
|
|
1373
|
-
if (payload.result === "admitted" || payload.result === "queued") {
|
|
1374
|
-
log.info(fields, "Admission decision");
|
|
1375
|
-
} else {
|
|
1376
|
-
log.warn(fields, "Admission decision");
|
|
1377
|
-
}
|
|
1378
|
-
};
|
|
1379
|
-
const onHealthUpdated = (payload) => {
|
|
1380
|
-
log.debug(
|
|
1381
|
-
{
|
|
1382
|
-
event: "health_updated",
|
|
1383
|
-
target_id: payload.target_id,
|
|
1384
|
-
old_score: payload.old_score,
|
|
1385
|
-
new_score: payload.new_score
|
|
1386
|
-
},
|
|
1387
|
-
"Health score updated"
|
|
1388
|
-
);
|
|
1389
|
-
};
|
|
1390
|
-
const onTargetExcluded = (payload) => {
|
|
1391
|
-
log.debug(
|
|
1392
|
-
{
|
|
1393
|
-
event: "target_excluded",
|
|
1394
|
-
target_id: payload.target_id,
|
|
1395
|
-
reason: payload.reason
|
|
1396
|
-
},
|
|
1397
|
-
"Target excluded"
|
|
1398
|
-
);
|
|
1399
|
-
};
|
|
1400
|
-
eventBus.on("circuit_state_change", onCircuitStateChange);
|
|
1401
|
-
eventBus.on("cooldown_set", onCooldownSet);
|
|
1402
|
-
eventBus.on("cooldown_expired", onCooldownExpired);
|
|
1403
|
-
eventBus.on("admission_decision", onAdmissionDecision);
|
|
1404
|
-
eventBus.on("health_updated", onHealthUpdated);
|
|
1405
|
-
eventBus.on("target_excluded", onTargetExcluded);
|
|
1406
|
-
return () => {
|
|
1407
|
-
eventBus.off("circuit_state_change", onCircuitStateChange);
|
|
1408
|
-
eventBus.off("cooldown_set", onCooldownSet);
|
|
1409
|
-
eventBus.off("cooldown_expired", onCooldownExpired);
|
|
1410
|
-
eventBus.off("admission_decision", onAdmissionDecision);
|
|
1411
|
-
eventBus.off("health_updated", onHealthUpdated);
|
|
1412
|
-
eventBus.off("target_excluded", onTargetExcluded);
|
|
1413
|
-
};
|
|
1414
|
-
};
|
|
1415
|
-
|
|
1416
|
-
// src/routing/failover.ts
|
|
1417
|
-
var createFailoverOrchestrator = (deps) => ({
|
|
1418
|
-
async execute(request_id, attemptFn, requiredCapabilities) {
|
|
1419
|
-
const log = deps.logger?.child({ component: "failover", request_id });
|
|
1420
|
-
const attempts = [];
|
|
1421
|
-
const failedTargets = /* @__PURE__ */ new Set();
|
|
1422
|
-
let totalRetries = 0;
|
|
1423
|
-
let totalFailovers = 0;
|
|
1424
|
-
let lastErrorClass;
|
|
1425
|
-
log?.info(
|
|
1426
|
-
{ event: "failover_start", retry_budget: deps.retryBudget, failover_budget: deps.failoverBudget },
|
|
1427
|
-
"Failover loop started"
|
|
1428
|
-
);
|
|
1429
|
-
for (let failoverNo = 0; failoverNo <= deps.failoverBudget; failoverNo++) {
|
|
1430
|
-
deps.cooldownManager.checkExpired(Date.now());
|
|
1431
|
-
const snapshot = deps.registry.getSnapshot();
|
|
1432
|
-
const selection = selectTarget(
|
|
1433
|
-
snapshot,
|
|
1434
|
-
deps.circuitBreakers,
|
|
1435
|
-
requiredCapabilities,
|
|
1436
|
-
deps.weights,
|
|
1437
|
-
deps.maxLatencyMs,
|
|
1438
|
-
Date.now(),
|
|
1439
|
-
request_id,
|
|
1440
|
-
failedTargets
|
|
1441
|
-
);
|
|
1442
|
-
if (!selection.selected) {
|
|
1443
|
-
log?.warn(
|
|
1444
|
-
{ event: "no_eligible_target", failover_no: failoverNo },
|
|
1445
|
-
"No eligible target available"
|
|
1446
|
-
);
|
|
1447
|
-
return {
|
|
1448
|
-
outcome: "failure",
|
|
1449
|
-
reason: "no eligible target available",
|
|
1450
|
-
attempts,
|
|
1451
|
-
total_retries: totalRetries,
|
|
1452
|
-
total_failovers: totalFailovers,
|
|
1453
|
-
last_error_class: lastErrorClass
|
|
1454
|
-
};
|
|
1455
|
-
}
|
|
1456
|
-
const targetId = selection.selected.target_id;
|
|
1457
|
-
const retryPolicy = createRetryPolicy(
|
|
1458
|
-
deps.retryBudget,
|
|
1459
|
-
deps.backoffParams
|
|
1460
|
-
);
|
|
1461
|
-
for (let retry = 0; retry <= deps.retryBudget; retry++) {
|
|
1462
|
-
const attemptNo = retry + 1;
|
|
1463
|
-
const acquired = deps.concurrency.acquire(targetId);
|
|
1464
|
-
if (!acquired) {
|
|
1465
|
-
log?.warn(
|
|
1466
|
-
{ event: "concurrency_full", target_id: targetId, failover_no: failoverNo },
|
|
1467
|
-
"No concurrency headroom \u2014 failing over"
|
|
1468
|
-
);
|
|
1469
|
-
failedTargets.add(targetId);
|
|
1470
|
-
break;
|
|
1471
|
-
}
|
|
1472
|
-
let attemptResult;
|
|
1473
|
-
try {
|
|
1474
|
-
attemptResult = await attemptFn(targetId);
|
|
1475
|
-
} finally {
|
|
1476
|
-
deps.concurrency.release(targetId);
|
|
1477
|
-
}
|
|
1478
|
-
if (attemptResult.success) {
|
|
1479
|
-
const cb2 = deps.circuitBreakers.get(targetId);
|
|
1480
|
-
if (cb2) {
|
|
1481
|
-
await cb2.recordSuccess();
|
|
1482
|
-
}
|
|
1483
|
-
deps.registry.recordObservation(targetId, 1);
|
|
1484
|
-
deps.registry.updateLatency(targetId, attemptResult.latency_ms);
|
|
1485
|
-
log?.info(
|
|
1486
|
-
{ event: "attempt_success", target_id: targetId, attempt_no: attemptNo, failover_no: failoverNo, latency_ms: attemptResult.latency_ms },
|
|
1487
|
-
"Attempt succeeded"
|
|
1488
|
-
);
|
|
1489
|
-
attempts.push({
|
|
1490
|
-
target_id: targetId,
|
|
1491
|
-
attempt_no: attemptNo,
|
|
1492
|
-
failover_no: failoverNo,
|
|
1493
|
-
outcome: "success",
|
|
1494
|
-
latency_ms: attemptResult.latency_ms,
|
|
1495
|
-
selection
|
|
1496
|
-
});
|
|
1497
|
-
return {
|
|
1498
|
-
outcome: "success",
|
|
1499
|
-
target_id: targetId,
|
|
1500
|
-
attempts,
|
|
1501
|
-
total_retries: totalRetries,
|
|
1502
|
-
total_failovers: totalFailovers,
|
|
1503
|
-
value: attemptResult.value
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
|
-
const errorClass = attemptResult.error_class;
|
|
1507
|
-
lastErrorClass = errorClass.class;
|
|
1508
|
-
const cb = deps.circuitBreakers.get(targetId);
|
|
1509
|
-
if (cb) {
|
|
1510
|
-
await cb.recordFailure();
|
|
1511
|
-
}
|
|
1512
|
-
deps.registry.recordObservation(targetId, 0);
|
|
1513
|
-
const stateTransition = getTargetStateTransition(errorClass);
|
|
1514
|
-
if (stateTransition) {
|
|
1515
|
-
deps.registry.updateState(targetId, stateTransition);
|
|
1516
|
-
}
|
|
1517
|
-
if (errorClass.class === "RateLimited") {
|
|
1518
|
-
const cooldownMs = computeCooldownMs(
|
|
1519
|
-
errorClass,
|
|
1520
|
-
retry,
|
|
1521
|
-
deps.backoffParams,
|
|
1522
|
-
deps.backoffParams.max_ms
|
|
1523
|
-
);
|
|
1524
|
-
deps.cooldownManager.setCooldown(
|
|
1525
|
-
targetId,
|
|
1526
|
-
cooldownMs,
|
|
1527
|
-
errorClass.class
|
|
1528
|
-
);
|
|
1529
|
-
}
|
|
1530
|
-
if (errorClass.class === "ModelUnavailable") {
|
|
1531
|
-
log?.info(
|
|
1532
|
-
{ event: "early_failover", target_id: targetId, error_class: errorClass.class, failover_no: failoverNo },
|
|
1533
|
-
"Early failover \u2014 ModelUnavailable"
|
|
1534
|
-
);
|
|
1535
|
-
attempts.push({
|
|
1536
|
-
target_id: targetId,
|
|
1537
|
-
attempt_no: attemptNo,
|
|
1538
|
-
failover_no: failoverNo,
|
|
1539
|
-
outcome: "failover",
|
|
1540
|
-
error_class: errorClass.class,
|
|
1541
|
-
latency_ms: attemptResult.latency_ms,
|
|
1542
|
-
selection
|
|
1543
|
-
});
|
|
1544
|
-
failedTargets.add(targetId);
|
|
1545
|
-
totalFailovers++;
|
|
1546
|
-
break;
|
|
1547
|
-
}
|
|
1548
|
-
if (!isRetryable(errorClass)) {
|
|
1549
|
-
log?.warn(
|
|
1550
|
-
{ event: "abort", target_id: targetId, error_class: errorClass.class },
|
|
1551
|
-
"Non-retryable error \u2014 aborting"
|
|
1552
|
-
);
|
|
1553
|
-
attempts.push({
|
|
1554
|
-
target_id: targetId,
|
|
1555
|
-
attempt_no: attemptNo,
|
|
1556
|
-
failover_no: failoverNo,
|
|
1557
|
-
outcome: "abort",
|
|
1558
|
-
error_class: errorClass.class,
|
|
1559
|
-
latency_ms: attemptResult.latency_ms,
|
|
1560
|
-
selection
|
|
1561
|
-
});
|
|
1562
|
-
return {
|
|
1563
|
-
outcome: "failure",
|
|
1564
|
-
reason: `non-retryable: ${errorClass.class}`,
|
|
1565
|
-
attempts,
|
|
1566
|
-
total_retries: totalRetries,
|
|
1567
|
-
total_failovers: totalFailovers,
|
|
1568
|
-
last_error_class: errorClass.class
|
|
1569
|
-
};
|
|
1570
|
-
}
|
|
1571
|
-
const decision = retryPolicy.decide(
|
|
1572
|
-
{
|
|
1573
|
-
error_class: errorClass,
|
|
1574
|
-
detection_mode: "direct",
|
|
1575
|
-
confidence: "high",
|
|
1576
|
-
raw_signal: { detection_mode: "direct" }
|
|
1577
|
-
},
|
|
1578
|
-
retry
|
|
1579
|
-
);
|
|
1580
|
-
if (decision.action === "exhausted") {
|
|
1581
|
-
log?.info(
|
|
1582
|
-
{ event: "retry_budget_exhausted", target_id: targetId, failover_no: failoverNo },
|
|
1583
|
-
"Retry budget exhausted \u2014 failing over"
|
|
1584
|
-
);
|
|
1585
|
-
attempts.push({
|
|
1586
|
-
target_id: targetId,
|
|
1587
|
-
attempt_no: attemptNo,
|
|
1588
|
-
failover_no: failoverNo,
|
|
1589
|
-
outcome: "failover",
|
|
1590
|
-
error_class: errorClass.class,
|
|
1591
|
-
latency_ms: attemptResult.latency_ms,
|
|
1592
|
-
selection
|
|
1593
|
-
});
|
|
1594
|
-
failedTargets.add(targetId);
|
|
1595
|
-
totalFailovers++;
|
|
1596
|
-
break;
|
|
1597
|
-
}
|
|
1598
|
-
attempts.push({
|
|
1599
|
-
target_id: targetId,
|
|
1600
|
-
attempt_no: attemptNo,
|
|
1601
|
-
failover_no: failoverNo,
|
|
1602
|
-
outcome: "retry",
|
|
1603
|
-
error_class: errorClass.class,
|
|
1604
|
-
latency_ms: attemptResult.latency_ms,
|
|
1605
|
-
selection
|
|
1606
|
-
});
|
|
1607
|
-
totalRetries++;
|
|
1608
|
-
if (decision.action === "retry") {
|
|
1609
|
-
log?.info(
|
|
1610
|
-
{ event: "retry", target_id: targetId, attempt_no: attemptNo, error_class: errorClass.class, delay_ms: decision.delay_ms },
|
|
1611
|
-
"Retrying after delay"
|
|
1612
|
-
);
|
|
1613
|
-
await new Promise(
|
|
1614
|
-
(resolve) => setTimeout(resolve, decision.delay_ms)
|
|
1615
|
-
);
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
log?.warn(
|
|
1620
|
-
{ event: "failover_budget_exhausted", total_retries: totalRetries, total_failovers: totalFailovers },
|
|
1621
|
-
"Failover budget exhausted"
|
|
1622
|
-
);
|
|
1623
|
-
return {
|
|
1624
|
-
outcome: "failure",
|
|
1625
|
-
reason: "failover budget exhausted",
|
|
1626
|
-
attempts,
|
|
1627
|
-
total_retries: totalRetries,
|
|
1628
|
-
total_failovers: totalFailovers,
|
|
1629
|
-
last_error_class: lastErrorClass
|
|
1630
|
-
};
|
|
1631
|
-
}
|
|
1632
|
-
});
|
|
1633
|
-
|
|
1634
532
|
// src/execution/stream-buffer.ts
|
|
1635
533
|
var createStreamBuffer = () => {
|
|
1636
534
|
const chunks = [];
|
|
@@ -1700,10 +598,7 @@ var createStreamStitcher = (_requestId) => {
|
|
|
1700
598
|
* @param provenance - Segment provenance without visible_offset (computed here).
|
|
1701
599
|
*/
|
|
1702
600
|
addSegment(buffer, provenance) {
|
|
1703
|
-
const visibleOffset = segments.reduce(
|
|
1704
|
-
(sum, entry) => sum + entry.text.length,
|
|
1705
|
-
0
|
|
1706
|
-
);
|
|
601
|
+
const visibleOffset = segments.reduce((sum, entry) => sum + entry.text.length, 0);
|
|
1707
602
|
segments.push({
|
|
1708
603
|
text: buffer.snapshot(),
|
|
1709
604
|
provenance: { ...provenance, visible_offset: visibleOffset }
|
|
@@ -1737,7 +632,7 @@ var createStreamStitcher = (_requestId) => {
|
|
|
1737
632
|
|
|
1738
633
|
// src/execution/audit-collector.ts
|
|
1739
634
|
var createAuditCollector = (logger, requestId) => {
|
|
1740
|
-
const requestLogger = createRequestLogger(logger, requestId);
|
|
635
|
+
const requestLogger = chunkVABBGKSR_cjs.createRequestLogger(logger, requestId);
|
|
1741
636
|
const attempts = [];
|
|
1742
637
|
const segments = [];
|
|
1743
638
|
return {
|
|
@@ -1767,9 +662,9 @@ var createAuditCollector = (logger, requestId) => {
|
|
|
1767
662
|
// src/execution/orchestrator.ts
|
|
1768
663
|
var createExecutionOrchestrator = (deps) => ({
|
|
1769
664
|
async execute(request) {
|
|
1770
|
-
const requestId = request.request_id || generateCorrelationId();
|
|
665
|
+
const requestId = request.request_id || chunkVABBGKSR_cjs.generateCorrelationId();
|
|
1771
666
|
const auditCollector = createAuditCollector(deps.logger, requestId);
|
|
1772
|
-
const stitcher = createStreamStitcher(
|
|
667
|
+
const stitcher = createStreamStitcher();
|
|
1773
668
|
const startMs = Date.now();
|
|
1774
669
|
const heuristicFlags = [];
|
|
1775
670
|
let outcome = "failure";
|
|
@@ -1787,9 +682,7 @@ var createExecutionOrchestrator = (deps) => ({
|
|
|
1787
682
|
for (const chunk of adapterResult.chunks) {
|
|
1788
683
|
buffer.append(chunk);
|
|
1789
684
|
}
|
|
1790
|
-
heuristicFlags.push(
|
|
1791
|
-
adapterResult.detection_mode === "heuristic"
|
|
1792
|
-
);
|
|
685
|
+
heuristicFlags.push(adapterResult.detection_mode === "heuristic");
|
|
1793
686
|
const value = { buffer, adapterResult };
|
|
1794
687
|
return {
|
|
1795
688
|
success: adapterResult.success,
|
|
@@ -1826,12 +719,8 @@ var createExecutionOrchestrator = (deps) => ({
|
|
|
1826
719
|
const stitchedOutput = stitcher.assemble();
|
|
1827
720
|
const isDegraded2 = deps.mode === "plugin-only";
|
|
1828
721
|
const isHeuristic2 = heuristicFlags.some(Boolean);
|
|
1829
|
-
const uniqueModes = [
|
|
1830
|
-
|
|
1831
|
-
];
|
|
1832
|
-
const uniqueTargets = [
|
|
1833
|
-
...new Set(stitchedOutput.segments.map((s) => s.source_target_id))
|
|
1834
|
-
];
|
|
722
|
+
const uniqueModes = [...new Set(stitchedOutput.segments.map((s) => s.continuation_mode))];
|
|
723
|
+
const uniqueTargets = [...new Set(stitchedOutput.segments.map((s) => s.source_target_id))];
|
|
1835
724
|
const provenance2 = {
|
|
1836
725
|
request_id: requestId,
|
|
1837
726
|
segments: stitchedOutput.segments,
|
|
@@ -1867,19 +756,22 @@ var createExecutionOrchestrator = (deps) => ({
|
|
|
1867
756
|
};
|
|
1868
757
|
} finally {
|
|
1869
758
|
auditCollector.flush(outcome, finalTarget);
|
|
1870
|
-
const requestLogger = createRequestLogger(deps.logger, requestId);
|
|
759
|
+
const requestLogger = chunkVABBGKSR_cjs.createRequestLogger(deps.logger, requestId);
|
|
1871
760
|
const endMs = Date.now();
|
|
1872
|
-
requestLogger.info(
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
761
|
+
requestLogger.info(
|
|
762
|
+
{
|
|
763
|
+
event: "request_summary",
|
|
764
|
+
component: "execution",
|
|
765
|
+
outcome,
|
|
766
|
+
total_attempts: summaryAttempts,
|
|
767
|
+
total_failovers: summaryFailovers,
|
|
768
|
+
total_retries: summaryRetries,
|
|
769
|
+
latency_ms: endMs - startMs,
|
|
770
|
+
targets_used: summaryTargets,
|
|
771
|
+
final_target: finalTarget ?? null
|
|
772
|
+
},
|
|
773
|
+
"Request complete"
|
|
774
|
+
);
|
|
1883
775
|
}
|
|
1884
776
|
}
|
|
1885
777
|
});
|
|
@@ -1963,188 +855,17 @@ var createSdkAdapter = (_deps) => ({
|
|
|
1963
855
|
var createModeAdapter = (mode, deps) => {
|
|
1964
856
|
switch (mode) {
|
|
1965
857
|
case "plugin-only":
|
|
1966
|
-
return createPluginAdapter(
|
|
858
|
+
return createPluginAdapter();
|
|
1967
859
|
case "server-companion":
|
|
1968
|
-
return createServerAdapter(
|
|
860
|
+
return createServerAdapter();
|
|
1969
861
|
case "sdk-control":
|
|
1970
|
-
return createSdkAdapter(
|
|
862
|
+
return createSdkAdapter();
|
|
1971
863
|
default: {
|
|
1972
864
|
const _exhaustive = mode;
|
|
1973
865
|
throw new Error(`Unknown deployment mode: ${String(_exhaustive)}`);
|
|
1974
866
|
}
|
|
1975
867
|
}
|
|
1976
868
|
};
|
|
1977
|
-
|
|
1978
|
-
// src/operator/reload.ts
|
|
1979
|
-
var computeConfigDiff = (oldConfig, newConfig) => {
|
|
1980
|
-
const oldTargets = oldConfig.targets ?? [];
|
|
1981
|
-
const newTargets = newConfig.targets ?? [];
|
|
1982
|
-
const oldIds = new Set(oldTargets.map((t) => t.target_id));
|
|
1983
|
-
const newIds = new Set(newTargets.map((t) => t.target_id));
|
|
1984
|
-
const oldMap = new Map(oldTargets.map((t) => [t.target_id, t]));
|
|
1985
|
-
const added = newTargets.filter((t) => !oldIds.has(t.target_id));
|
|
1986
|
-
const removed = oldTargets.filter((t) => !newIds.has(t.target_id)).map((t) => t.target_id);
|
|
1987
|
-
const modified = newTargets.filter((t) => {
|
|
1988
|
-
if (!oldIds.has(t.target_id)) {
|
|
1989
|
-
return false;
|
|
1990
|
-
}
|
|
1991
|
-
const old = oldMap.get(t.target_id);
|
|
1992
|
-
if (!old) {
|
|
1993
|
-
return false;
|
|
1994
|
-
}
|
|
1995
|
-
return hasConfigChanged(old, t);
|
|
1996
|
-
});
|
|
1997
|
-
return { added, removed, modified };
|
|
1998
|
-
};
|
|
1999
|
-
var hasConfigChanged = (oldTarget, newTarget) => {
|
|
2000
|
-
if (oldTarget.profile !== newTarget.profile) return true;
|
|
2001
|
-
if (oldTarget.enabled !== newTarget.enabled) return true;
|
|
2002
|
-
if (oldTarget.operator_priority !== newTarget.operator_priority) return true;
|
|
2003
|
-
if (JSON.stringify(oldTarget.policy_tags) !== JSON.stringify(newTarget.policy_tags)) return true;
|
|
2004
|
-
if (JSON.stringify(oldTarget.capabilities) !== JSON.stringify(newTarget.capabilities)) return true;
|
|
2005
|
-
if (oldTarget.retry_budget !== newTarget.retry_budget) return true;
|
|
2006
|
-
if (oldTarget.failover_budget !== newTarget.failover_budget) return true;
|
|
2007
|
-
if (oldTarget.concurrency_limit !== newTarget.concurrency_limit) return true;
|
|
2008
|
-
return false;
|
|
2009
|
-
};
|
|
2010
|
-
var applyConfigDiff = (registry, diff) => {
|
|
2011
|
-
for (const tc of diff.added) {
|
|
2012
|
-
const entry = {
|
|
2013
|
-
target_id: tc.target_id,
|
|
2014
|
-
provider_id: tc.provider_id,
|
|
2015
|
-
profile: tc.profile,
|
|
2016
|
-
endpoint_id: tc.endpoint_id,
|
|
2017
|
-
capabilities: [...tc.capabilities],
|
|
2018
|
-
enabled: tc.enabled,
|
|
2019
|
-
state: "Active",
|
|
2020
|
-
health_score: INITIAL_HEALTH_SCORE,
|
|
2021
|
-
cooldown_until: null,
|
|
2022
|
-
latency_ema_ms: 0,
|
|
2023
|
-
failure_score: 0,
|
|
2024
|
-
operator_priority: tc.operator_priority,
|
|
2025
|
-
policy_tags: [...tc.policy_tags]
|
|
2026
|
-
};
|
|
2027
|
-
registry.addTarget(entry);
|
|
2028
|
-
}
|
|
2029
|
-
for (const id of diff.removed) {
|
|
2030
|
-
registry.updateState(id, "Disabled");
|
|
2031
|
-
}
|
|
2032
|
-
for (const tc of diff.modified) {
|
|
2033
|
-
const existing = registry.getTarget(tc.target_id);
|
|
2034
|
-
if (existing) {
|
|
2035
|
-
const updated = {
|
|
2036
|
-
...existing,
|
|
2037
|
-
provider_id: tc.provider_id,
|
|
2038
|
-
profile: tc.profile,
|
|
2039
|
-
endpoint_id: tc.endpoint_id,
|
|
2040
|
-
capabilities: [...tc.capabilities],
|
|
2041
|
-
enabled: tc.enabled,
|
|
2042
|
-
operator_priority: tc.operator_priority,
|
|
2043
|
-
policy_tags: [...tc.policy_tags]
|
|
2044
|
-
};
|
|
2045
|
-
registry.removeTarget(tc.target_id);
|
|
2046
|
-
registry.addTarget(updated);
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
};
|
|
2050
|
-
|
|
2051
|
-
// src/operator/commands.ts
|
|
2052
|
-
var createRequestTraceBuffer = (capacity) => {
|
|
2053
|
-
const entries = /* @__PURE__ */ new Map();
|
|
2054
|
-
const order = [];
|
|
2055
|
-
return {
|
|
2056
|
-
record(entry) {
|
|
2057
|
-
if (entries.has(entry.request_id)) {
|
|
2058
|
-
const idx = order.indexOf(entry.request_id);
|
|
2059
|
-
if (idx !== -1) {
|
|
2060
|
-
order.splice(idx, 1);
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
while (order.length >= capacity) {
|
|
2064
|
-
const oldest = order.shift();
|
|
2065
|
-
if (oldest !== void 0) {
|
|
2066
|
-
entries.delete(oldest);
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
entries.set(entry.request_id, entry);
|
|
2070
|
-
order.push(entry.request_id);
|
|
2071
|
-
},
|
|
2072
|
-
lookup(requestId) {
|
|
2073
|
-
return entries.get(requestId);
|
|
2074
|
-
},
|
|
2075
|
-
size() {
|
|
2076
|
-
return entries.size;
|
|
2077
|
-
}
|
|
2078
|
-
};
|
|
2079
|
-
};
|
|
2080
|
-
var listTargets = (deps) => {
|
|
2081
|
-
const allTargets = deps.registry.getAllTargets();
|
|
2082
|
-
const targets = allTargets.map((t) => {
|
|
2083
|
-
const cb = deps.circuitBreakers.get(t.target_id);
|
|
2084
|
-
const cbState = cb ? cb.state() : "Active";
|
|
2085
|
-
return {
|
|
2086
|
-
target_id: t.target_id,
|
|
2087
|
-
provider_id: t.provider_id,
|
|
2088
|
-
profile: t.profile,
|
|
2089
|
-
state: t.state,
|
|
2090
|
-
health_score: t.health_score,
|
|
2091
|
-
circuit_breaker_state: cbState,
|
|
2092
|
-
cooldown_until: t.cooldown_until,
|
|
2093
|
-
enabled: t.enabled,
|
|
2094
|
-
latency_ema_ms: t.latency_ema_ms,
|
|
2095
|
-
failure_score: t.failure_score,
|
|
2096
|
-
operator_priority: t.operator_priority
|
|
2097
|
-
};
|
|
2098
|
-
});
|
|
2099
|
-
return { targets, count: targets.length };
|
|
2100
|
-
};
|
|
2101
|
-
var targetAction = (deps, targetId, action, newState) => {
|
|
2102
|
-
const updated = deps.registry.updateState(targetId, newState);
|
|
2103
|
-
if (!updated) {
|
|
2104
|
-
return { success: false, target_id: targetId, action, error: "target not found" };
|
|
2105
|
-
}
|
|
2106
|
-
return { success: true, target_id: targetId, action };
|
|
2107
|
-
};
|
|
2108
|
-
var pauseTarget = (deps, targetId) => targetAction(deps, targetId, "pause", "Disabled");
|
|
2109
|
-
var resumeTarget = (deps, targetId) => targetAction(deps, targetId, "resume", "Active");
|
|
2110
|
-
var drainTarget = (deps, targetId) => targetAction(deps, targetId, "drain", "Draining");
|
|
2111
|
-
var disableTarget = (deps, targetId) => targetAction(deps, targetId, "disable", "Disabled");
|
|
2112
|
-
var inspectRequest = (deps, requestId) => {
|
|
2113
|
-
const trace = deps.traceBuffer.lookup(requestId);
|
|
2114
|
-
if (!trace) {
|
|
2115
|
-
return { found: false, request_id: requestId };
|
|
2116
|
-
}
|
|
2117
|
-
return { found: true, request_id: requestId, trace };
|
|
2118
|
-
};
|
|
2119
|
-
var reloadConfig = (deps, rawConfig) => {
|
|
2120
|
-
try {
|
|
2121
|
-
const newConfig = validateConfig(rawConfig);
|
|
2122
|
-
const currentConfig = deps.configRef.current();
|
|
2123
|
-
const diff = computeConfigDiff(currentConfig, newConfig);
|
|
2124
|
-
applyConfigDiff(deps.registry, diff);
|
|
2125
|
-
deps.configRef.swap(newConfig);
|
|
2126
|
-
return {
|
|
2127
|
-
success: true,
|
|
2128
|
-
added: diff.added.map((t) => t.target_id),
|
|
2129
|
-
removed: [...diff.removed],
|
|
2130
|
-
modified: diff.modified.map((t) => t.target_id)
|
|
2131
|
-
};
|
|
2132
|
-
} catch (err) {
|
|
2133
|
-
if (err instanceof ConfigValidationError) {
|
|
2134
|
-
return {
|
|
2135
|
-
success: false,
|
|
2136
|
-
added: [],
|
|
2137
|
-
removed: [],
|
|
2138
|
-
modified: [],
|
|
2139
|
-
diagnostics: err.diagnostics
|
|
2140
|
-
};
|
|
2141
|
-
}
|
|
2142
|
-
throw err;
|
|
2143
|
-
}
|
|
2144
|
-
};
|
|
2145
|
-
|
|
2146
|
-
// src/operator/server-auth.ts
|
|
2147
|
-
var import_node_crypto2 = require("crypto");
|
|
2148
869
|
var validateBearerToken = (authHeader, expectedToken) => {
|
|
2149
870
|
if (authHeader === void 0) {
|
|
2150
871
|
return { authorized: false, reason: "missing Authorization header" };
|
|
@@ -2158,428 +879,363 @@ var validateBearerToken = (authHeader, expectedToken) => {
|
|
|
2158
879
|
}
|
|
2159
880
|
const tokenBuffer = Buffer.from(token);
|
|
2160
881
|
const expectedBuffer = Buffer.from(expectedToken);
|
|
2161
|
-
if (!
|
|
882
|
+
if (!crypto.timingSafeEqual(tokenBuffer, expectedBuffer)) {
|
|
2162
883
|
return { authorized: false, reason: "invalid token" };
|
|
2163
884
|
}
|
|
2164
885
|
return { authorized: true };
|
|
2165
886
|
};
|
|
2166
|
-
|
|
2167
|
-
// src/operator/plugin-tools.ts
|
|
2168
|
-
var import_tool = require("@opencode-ai/plugin/tool");
|
|
2169
|
-
var { schema: z3 } = import_tool.tool;
|
|
887
|
+
var { schema: z } = tool.tool;
|
|
2170
888
|
var createOperatorTools = (deps) => ({
|
|
2171
|
-
listTargets:
|
|
889
|
+
listTargets: tool.tool({
|
|
2172
890
|
description: "List all routing targets with health scores, states, and circuit breaker status.",
|
|
2173
891
|
args: {},
|
|
2174
892
|
async execute() {
|
|
2175
893
|
deps.logger.info({ op: "listTargets" }, "operator: listTargets");
|
|
2176
|
-
const result = listTargets(deps);
|
|
894
|
+
const result = chunkVABBGKSR_cjs.listTargets(deps);
|
|
2177
895
|
return JSON.stringify(result, null, 2);
|
|
2178
896
|
}
|
|
2179
897
|
}),
|
|
2180
|
-
pauseTarget:
|
|
898
|
+
pauseTarget: tool.tool({
|
|
2181
899
|
description: "Pause a target, preventing new requests from being routed to it.",
|
|
2182
|
-
args: { target_id:
|
|
900
|
+
args: { target_id: z.string().min(1) },
|
|
2183
901
|
async execute(args) {
|
|
2184
|
-
deps.logger.info(
|
|
2185
|
-
|
|
2186
|
-
"operator: pauseTarget"
|
|
2187
|
-
);
|
|
2188
|
-
const result = pauseTarget(deps, args.target_id);
|
|
902
|
+
deps.logger.info({ op: "pauseTarget", target_id: args.target_id }, "operator: pauseTarget");
|
|
903
|
+
const result = chunkVABBGKSR_cjs.pauseTarget(deps, args.target_id);
|
|
2189
904
|
return JSON.stringify(result, null, 2);
|
|
2190
905
|
}
|
|
2191
906
|
}),
|
|
2192
|
-
resumeTarget:
|
|
907
|
+
resumeTarget: tool.tool({
|
|
2193
908
|
description: "Resume a previously paused or disabled target, allowing new requests.",
|
|
2194
|
-
args: { target_id:
|
|
909
|
+
args: { target_id: z.string().min(1) },
|
|
2195
910
|
async execute(args) {
|
|
2196
|
-
deps.logger.info(
|
|
2197
|
-
|
|
2198
|
-
"operator: resumeTarget"
|
|
2199
|
-
);
|
|
2200
|
-
const result = resumeTarget(deps, args.target_id);
|
|
911
|
+
deps.logger.info({ op: "resumeTarget", target_id: args.target_id }, "operator: resumeTarget");
|
|
912
|
+
const result = chunkVABBGKSR_cjs.resumeTarget(deps, args.target_id);
|
|
2201
913
|
return JSON.stringify(result, null, 2);
|
|
2202
914
|
}
|
|
2203
915
|
}),
|
|
2204
|
-
drainTarget:
|
|
916
|
+
drainTarget: tool.tool({
|
|
2205
917
|
description: "Drain a target, allowing in-flight requests to complete but preventing new ones.",
|
|
2206
|
-
args: { target_id:
|
|
918
|
+
args: { target_id: z.string().min(1) },
|
|
2207
919
|
async execute(args) {
|
|
2208
|
-
deps.logger.info(
|
|
2209
|
-
|
|
2210
|
-
"operator: drainTarget"
|
|
2211
|
-
);
|
|
2212
|
-
const result = drainTarget(deps, args.target_id);
|
|
920
|
+
deps.logger.info({ op: "drainTarget", target_id: args.target_id }, "operator: drainTarget");
|
|
921
|
+
const result = chunkVABBGKSR_cjs.drainTarget(deps, args.target_id);
|
|
2213
922
|
return JSON.stringify(result, null, 2);
|
|
2214
923
|
}
|
|
2215
924
|
}),
|
|
2216
|
-
disableTarget:
|
|
925
|
+
disableTarget: tool.tool({
|
|
2217
926
|
description: "Disable a target entirely, removing it from routing.",
|
|
2218
|
-
args: { target_id:
|
|
927
|
+
args: { target_id: z.string().min(1) },
|
|
2219
928
|
async execute(args) {
|
|
2220
929
|
deps.logger.info(
|
|
2221
930
|
{ op: "disableTarget", target_id: args.target_id },
|
|
2222
931
|
"operator: disableTarget"
|
|
2223
932
|
);
|
|
2224
|
-
const result = disableTarget(deps, args.target_id);
|
|
933
|
+
const result = chunkVABBGKSR_cjs.disableTarget(deps, args.target_id);
|
|
2225
934
|
return JSON.stringify(result, null, 2);
|
|
2226
935
|
}
|
|
2227
936
|
}),
|
|
2228
|
-
inspectRequest:
|
|
937
|
+
inspectRequest: tool.tool({
|
|
2229
938
|
description: "Inspect a request trace by ID, showing attempts, segments, and outcome.",
|
|
2230
|
-
args: { request_id:
|
|
939
|
+
args: { request_id: z.string().min(1) },
|
|
2231
940
|
async execute(args) {
|
|
2232
941
|
deps.logger.info(
|
|
2233
942
|
{ op: "inspectRequest", request_id: args.request_id },
|
|
2234
943
|
"operator: inspectRequest"
|
|
2235
944
|
);
|
|
2236
|
-
const result = inspectRequest(deps, args.request_id);
|
|
945
|
+
const result = chunkVABBGKSR_cjs.inspectRequest(deps, args.request_id);
|
|
2237
946
|
return JSON.stringify(result, null, 2);
|
|
2238
947
|
}
|
|
2239
948
|
}),
|
|
2240
|
-
reloadConfig:
|
|
949
|
+
reloadConfig: tool.tool({
|
|
2241
950
|
description: "Reload routing configuration with diff-apply. Validates new config before applying.",
|
|
2242
|
-
args: { config:
|
|
951
|
+
args: { config: z.record(z.string(), z.unknown()) },
|
|
2243
952
|
async execute(args) {
|
|
2244
953
|
deps.logger.info({ op: "reloadConfig" }, "operator: reloadConfig");
|
|
2245
|
-
const result = reloadConfig(deps, args.config);
|
|
954
|
+
const result = chunkVABBGKSR_cjs.reloadConfig(deps, args.config);
|
|
2246
955
|
return JSON.stringify(result, null, 2);
|
|
2247
956
|
}
|
|
2248
957
|
})
|
|
2249
958
|
});
|
|
2250
959
|
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
return
|
|
2286
|
-
};
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
};
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
}
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
}
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
960
|
+
Object.defineProperty(exports, "ADMISSION_RESULTS", {
|
|
961
|
+
enumerable: true,
|
|
962
|
+
get: function () { return chunkVABBGKSR_cjs.ADMISSION_RESULTS; }
|
|
963
|
+
});
|
|
964
|
+
Object.defineProperty(exports, "BackoffConfigSchema", {
|
|
965
|
+
enumerable: true,
|
|
966
|
+
get: function () { return chunkVABBGKSR_cjs.BackoffConfigSchema; }
|
|
967
|
+
});
|
|
968
|
+
Object.defineProperty(exports, "ConfigValidationError", {
|
|
969
|
+
enumerable: true,
|
|
970
|
+
get: function () { return chunkVABBGKSR_cjs.ConfigValidationError; }
|
|
971
|
+
});
|
|
972
|
+
Object.defineProperty(exports, "DEFAULT_ALPHA", {
|
|
973
|
+
enumerable: true,
|
|
974
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_ALPHA; }
|
|
975
|
+
});
|
|
976
|
+
Object.defineProperty(exports, "DEFAULT_BACKOFF_BASE_MS", {
|
|
977
|
+
enumerable: true,
|
|
978
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_BACKOFF_BASE_MS; }
|
|
979
|
+
});
|
|
980
|
+
Object.defineProperty(exports, "DEFAULT_BACKOFF_JITTER", {
|
|
981
|
+
enumerable: true,
|
|
982
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_BACKOFF_JITTER; }
|
|
983
|
+
});
|
|
984
|
+
Object.defineProperty(exports, "DEFAULT_BACKOFF_MAX_MS", {
|
|
985
|
+
enumerable: true,
|
|
986
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_BACKOFF_MAX_MS; }
|
|
987
|
+
});
|
|
988
|
+
Object.defineProperty(exports, "DEFAULT_BACKOFF_MULTIPLIER", {
|
|
989
|
+
enumerable: true,
|
|
990
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_BACKOFF_MULTIPLIER; }
|
|
991
|
+
});
|
|
992
|
+
Object.defineProperty(exports, "DEFAULT_BACKOFF_PARAMS", {
|
|
993
|
+
enumerable: true,
|
|
994
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_BACKOFF_PARAMS; }
|
|
995
|
+
});
|
|
996
|
+
Object.defineProperty(exports, "DEFAULT_FAILOVER_BUDGET", {
|
|
997
|
+
enumerable: true,
|
|
998
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_FAILOVER_BUDGET; }
|
|
999
|
+
});
|
|
1000
|
+
Object.defineProperty(exports, "DEFAULT_RETRY", {
|
|
1001
|
+
enumerable: true,
|
|
1002
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_RETRY; }
|
|
1003
|
+
});
|
|
1004
|
+
Object.defineProperty(exports, "DEFAULT_RETRY_BUDGET", {
|
|
1005
|
+
enumerable: true,
|
|
1006
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_RETRY_BUDGET; }
|
|
1007
|
+
});
|
|
1008
|
+
Object.defineProperty(exports, "DEFAULT_TIMEOUT_MS", {
|
|
1009
|
+
enumerable: true,
|
|
1010
|
+
get: function () { return chunkVABBGKSR_cjs.DEFAULT_TIMEOUT_MS; }
|
|
1011
|
+
});
|
|
1012
|
+
Object.defineProperty(exports, "DualBreaker", {
|
|
1013
|
+
enumerable: true,
|
|
1014
|
+
get: function () { return chunkVABBGKSR_cjs.DualBreaker; }
|
|
1015
|
+
});
|
|
1016
|
+
Object.defineProperty(exports, "EXCLUSION_REASONS", {
|
|
1017
|
+
enumerable: true,
|
|
1018
|
+
get: function () { return chunkVABBGKSR_cjs.EXCLUSION_REASONS; }
|
|
1019
|
+
});
|
|
1020
|
+
Object.defineProperty(exports, "ErrorClassSchema", {
|
|
1021
|
+
enumerable: true,
|
|
1022
|
+
get: function () { return chunkVABBGKSR_cjs.ErrorClassSchema; }
|
|
1023
|
+
});
|
|
1024
|
+
Object.defineProperty(exports, "INITIAL_HEALTH_SCORE", {
|
|
1025
|
+
enumerable: true,
|
|
1026
|
+
get: function () { return chunkVABBGKSR_cjs.INITIAL_HEALTH_SCORE; }
|
|
1027
|
+
});
|
|
1028
|
+
Object.defineProperty(exports, "REDACT_PATHS", {
|
|
1029
|
+
enumerable: true,
|
|
1030
|
+
get: function () { return chunkVABBGKSR_cjs.REDACT_PATHS; }
|
|
1031
|
+
});
|
|
1032
|
+
Object.defineProperty(exports, "SwitcherConfigSchema", {
|
|
1033
|
+
enumerable: true,
|
|
1034
|
+
get: function () { return chunkVABBGKSR_cjs.SwitcherConfigSchema; }
|
|
1035
|
+
});
|
|
1036
|
+
Object.defineProperty(exports, "TARGET_STATES", {
|
|
1037
|
+
enumerable: true,
|
|
1038
|
+
get: function () { return chunkVABBGKSR_cjs.TARGET_STATES; }
|
|
1039
|
+
});
|
|
1040
|
+
Object.defineProperty(exports, "TargetConfigSchema", {
|
|
1041
|
+
enumerable: true,
|
|
1042
|
+
get: function () { return chunkVABBGKSR_cjs.TargetConfigSchema; }
|
|
1043
|
+
});
|
|
1044
|
+
Object.defineProperty(exports, "TargetRegistry", {
|
|
1045
|
+
enumerable: true,
|
|
1046
|
+
get: function () { return chunkVABBGKSR_cjs.TargetRegistry; }
|
|
1047
|
+
});
|
|
1048
|
+
Object.defineProperty(exports, "addProfile", {
|
|
1049
|
+
enumerable: true,
|
|
1050
|
+
get: function () { return chunkVABBGKSR_cjs.addProfile; }
|
|
1051
|
+
});
|
|
1052
|
+
Object.defineProperty(exports, "applyConfigDiff", {
|
|
1053
|
+
enumerable: true,
|
|
1054
|
+
get: function () { return chunkVABBGKSR_cjs.applyConfigDiff; }
|
|
1055
|
+
});
|
|
1056
|
+
Object.defineProperty(exports, "checkHardRejects", {
|
|
1057
|
+
enumerable: true,
|
|
1058
|
+
get: function () { return chunkVABBGKSR_cjs.checkHardRejects; }
|
|
1059
|
+
});
|
|
1060
|
+
Object.defineProperty(exports, "computeBackoffMs", {
|
|
1061
|
+
enumerable: true,
|
|
1062
|
+
get: function () { return chunkVABBGKSR_cjs.computeBackoffMs; }
|
|
1063
|
+
});
|
|
1064
|
+
Object.defineProperty(exports, "computeConfigDiff", {
|
|
1065
|
+
enumerable: true,
|
|
1066
|
+
get: function () { return chunkVABBGKSR_cjs.computeConfigDiff; }
|
|
1067
|
+
});
|
|
1068
|
+
Object.defineProperty(exports, "computeCooldownMs", {
|
|
1069
|
+
enumerable: true,
|
|
1070
|
+
get: function () { return chunkVABBGKSR_cjs.computeCooldownMs; }
|
|
1071
|
+
});
|
|
1072
|
+
Object.defineProperty(exports, "computeScore", {
|
|
1073
|
+
enumerable: true,
|
|
1074
|
+
get: function () { return chunkVABBGKSR_cjs.computeScore; }
|
|
1075
|
+
});
|
|
1076
|
+
Object.defineProperty(exports, "createAdmissionController", {
|
|
1077
|
+
enumerable: true,
|
|
1078
|
+
get: function () { return chunkVABBGKSR_cjs.createAdmissionController; }
|
|
1079
|
+
});
|
|
1080
|
+
Object.defineProperty(exports, "createAuditLogger", {
|
|
1081
|
+
enumerable: true,
|
|
1082
|
+
get: function () { return chunkVABBGKSR_cjs.createAuditLogger; }
|
|
1083
|
+
});
|
|
1084
|
+
Object.defineProperty(exports, "createAuthWatcher", {
|
|
1085
|
+
enumerable: true,
|
|
1086
|
+
get: function () { return chunkVABBGKSR_cjs.createAuthWatcher; }
|
|
1087
|
+
});
|
|
1088
|
+
Object.defineProperty(exports, "createCircuitBreaker", {
|
|
1089
|
+
enumerable: true,
|
|
1090
|
+
get: function () { return chunkVABBGKSR_cjs.createCircuitBreaker; }
|
|
1091
|
+
});
|
|
1092
|
+
Object.defineProperty(exports, "createConcurrencyTracker", {
|
|
1093
|
+
enumerable: true,
|
|
1094
|
+
get: function () { return chunkVABBGKSR_cjs.createConcurrencyTracker; }
|
|
1095
|
+
});
|
|
1096
|
+
Object.defineProperty(exports, "createCooldownManager", {
|
|
1097
|
+
enumerable: true,
|
|
1098
|
+
get: function () { return chunkVABBGKSR_cjs.createCooldownManager; }
|
|
1099
|
+
});
|
|
1100
|
+
Object.defineProperty(exports, "createFailoverOrchestrator", {
|
|
1101
|
+
enumerable: true,
|
|
1102
|
+
get: function () { return chunkVABBGKSR_cjs.createFailoverOrchestrator; }
|
|
1103
|
+
});
|
|
1104
|
+
Object.defineProperty(exports, "createLogSubscriber", {
|
|
1105
|
+
enumerable: true,
|
|
1106
|
+
get: function () { return chunkVABBGKSR_cjs.createLogSubscriber; }
|
|
1107
|
+
});
|
|
1108
|
+
Object.defineProperty(exports, "createProfileTools", {
|
|
1109
|
+
enumerable: true,
|
|
1110
|
+
get: function () { return chunkVABBGKSR_cjs.createProfileTools; }
|
|
1111
|
+
});
|
|
1112
|
+
Object.defineProperty(exports, "createRegistry", {
|
|
1113
|
+
enumerable: true,
|
|
1114
|
+
get: function () { return chunkVABBGKSR_cjs.createRegistry; }
|
|
1115
|
+
});
|
|
1116
|
+
Object.defineProperty(exports, "createRequestLogger", {
|
|
1117
|
+
enumerable: true,
|
|
1118
|
+
get: function () { return chunkVABBGKSR_cjs.createRequestLogger; }
|
|
1119
|
+
});
|
|
1120
|
+
Object.defineProperty(exports, "createRequestTraceBuffer", {
|
|
1121
|
+
enumerable: true,
|
|
1122
|
+
get: function () { return chunkVABBGKSR_cjs.createRequestTraceBuffer; }
|
|
1123
|
+
});
|
|
1124
|
+
Object.defineProperty(exports, "createRetryPolicy", {
|
|
1125
|
+
enumerable: true,
|
|
1126
|
+
get: function () { return chunkVABBGKSR_cjs.createRetryPolicy; }
|
|
1127
|
+
});
|
|
1128
|
+
Object.defineProperty(exports, "createRoutingEventBus", {
|
|
1129
|
+
enumerable: true,
|
|
1130
|
+
get: function () { return chunkVABBGKSR_cjs.createRoutingEventBus; }
|
|
1131
|
+
});
|
|
1132
|
+
Object.defineProperty(exports, "disableTarget", {
|
|
1133
|
+
enumerable: true,
|
|
1134
|
+
get: function () { return chunkVABBGKSR_cjs.disableTarget; }
|
|
1135
|
+
});
|
|
1136
|
+
Object.defineProperty(exports, "discoverTargets", {
|
|
1137
|
+
enumerable: true,
|
|
1138
|
+
get: function () { return chunkVABBGKSR_cjs.discoverTargets; }
|
|
1139
|
+
});
|
|
1140
|
+
Object.defineProperty(exports, "discoverTargetsFromProfiles", {
|
|
1141
|
+
enumerable: true,
|
|
1142
|
+
get: function () { return chunkVABBGKSR_cjs.discoverTargetsFromProfiles; }
|
|
1143
|
+
});
|
|
1144
|
+
Object.defineProperty(exports, "drainTarget", {
|
|
1145
|
+
enumerable: true,
|
|
1146
|
+
get: function () { return chunkVABBGKSR_cjs.drainTarget; }
|
|
1147
|
+
});
|
|
1148
|
+
Object.defineProperty(exports, "generateCorrelationId", {
|
|
1149
|
+
enumerable: true,
|
|
1150
|
+
get: function () { return chunkVABBGKSR_cjs.generateCorrelationId; }
|
|
1151
|
+
});
|
|
1152
|
+
Object.defineProperty(exports, "getExclusionReason", {
|
|
1153
|
+
enumerable: true,
|
|
1154
|
+
get: function () { return chunkVABBGKSR_cjs.getExclusionReason; }
|
|
1155
|
+
});
|
|
1156
|
+
Object.defineProperty(exports, "getTargetStateTransition", {
|
|
1157
|
+
enumerable: true,
|
|
1158
|
+
get: function () { return chunkVABBGKSR_cjs.getTargetStateTransition; }
|
|
1159
|
+
});
|
|
1160
|
+
Object.defineProperty(exports, "inspectRequest", {
|
|
1161
|
+
enumerable: true,
|
|
1162
|
+
get: function () { return chunkVABBGKSR_cjs.inspectRequest; }
|
|
1163
|
+
});
|
|
1164
|
+
Object.defineProperty(exports, "isRetryable", {
|
|
1165
|
+
enumerable: true,
|
|
1166
|
+
get: function () { return chunkVABBGKSR_cjs.isRetryable; }
|
|
1167
|
+
});
|
|
1168
|
+
Object.defineProperty(exports, "listProfiles", {
|
|
1169
|
+
enumerable: true,
|
|
1170
|
+
get: function () { return chunkVABBGKSR_cjs.listProfiles; }
|
|
1171
|
+
});
|
|
1172
|
+
Object.defineProperty(exports, "listTargets", {
|
|
1173
|
+
enumerable: true,
|
|
1174
|
+
get: function () { return chunkVABBGKSR_cjs.listTargets; }
|
|
1175
|
+
});
|
|
1176
|
+
Object.defineProperty(exports, "loadProfiles", {
|
|
1177
|
+
enumerable: true,
|
|
1178
|
+
get: function () { return chunkVABBGKSR_cjs.loadProfiles; }
|
|
1179
|
+
});
|
|
1180
|
+
Object.defineProperty(exports, "nextProfileId", {
|
|
1181
|
+
enumerable: true,
|
|
1182
|
+
get: function () { return chunkVABBGKSR_cjs.nextProfileId; }
|
|
1183
|
+
});
|
|
1184
|
+
Object.defineProperty(exports, "normalizeLatency", {
|
|
1185
|
+
enumerable: true,
|
|
1186
|
+
get: function () { return chunkVABBGKSR_cjs.normalizeLatency; }
|
|
1187
|
+
});
|
|
1188
|
+
Object.defineProperty(exports, "pauseTarget", {
|
|
1189
|
+
enumerable: true,
|
|
1190
|
+
get: function () { return chunkVABBGKSR_cjs.pauseTarget; }
|
|
1191
|
+
});
|
|
1192
|
+
Object.defineProperty(exports, "reloadConfig", {
|
|
1193
|
+
enumerable: true,
|
|
1194
|
+
get: function () { return chunkVABBGKSR_cjs.reloadConfig; }
|
|
1195
|
+
});
|
|
1196
|
+
Object.defineProperty(exports, "removeProfile", {
|
|
1197
|
+
enumerable: true,
|
|
1198
|
+
get: function () { return chunkVABBGKSR_cjs.removeProfile; }
|
|
1199
|
+
});
|
|
1200
|
+
Object.defineProperty(exports, "resumeTarget", {
|
|
1201
|
+
enumerable: true,
|
|
1202
|
+
get: function () { return chunkVABBGKSR_cjs.resumeTarget; }
|
|
1203
|
+
});
|
|
1204
|
+
Object.defineProperty(exports, "saveProfiles", {
|
|
1205
|
+
enumerable: true,
|
|
1206
|
+
get: function () { return chunkVABBGKSR_cjs.saveProfiles; }
|
|
1207
|
+
});
|
|
1208
|
+
Object.defineProperty(exports, "selectTarget", {
|
|
1209
|
+
enumerable: true,
|
|
1210
|
+
get: function () { return chunkVABBGKSR_cjs.selectTarget; }
|
|
1211
|
+
});
|
|
1212
|
+
Object.defineProperty(exports, "updateHealthScore", {
|
|
1213
|
+
enumerable: true,
|
|
1214
|
+
get: function () { return chunkVABBGKSR_cjs.updateHealthScore; }
|
|
1215
|
+
});
|
|
1216
|
+
Object.defineProperty(exports, "updateLatencyEma", {
|
|
1217
|
+
enumerable: true,
|
|
1218
|
+
get: function () { return chunkVABBGKSR_cjs.updateLatencyEma; }
|
|
1219
|
+
});
|
|
1220
|
+
Object.defineProperty(exports, "validateConfig", {
|
|
1221
|
+
enumerable: true,
|
|
1222
|
+
get: function () { return chunkVABBGKSR_cjs.validateConfig; }
|
|
2497
1223
|
});
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
HEURISTIC_PATTERNS,
|
|
2517
|
-
INITIAL_HEALTH_SCORE,
|
|
2518
|
-
PROVIDER_PATTERNS,
|
|
2519
|
-
REDACT_PATHS,
|
|
2520
|
-
SwitcherConfigSchema,
|
|
2521
|
-
TARGET_STATES,
|
|
2522
|
-
TEMPORAL_QUOTA_PATTERN,
|
|
2523
|
-
TargetConfigSchema,
|
|
2524
|
-
TargetRegistry,
|
|
2525
|
-
addProfile,
|
|
2526
|
-
applyConfigDiff,
|
|
2527
|
-
checkHardRejects,
|
|
2528
|
-
classify,
|
|
2529
|
-
computeBackoffMs,
|
|
2530
|
-
computeConfigDiff,
|
|
2531
|
-
computeCooldownMs,
|
|
2532
|
-
computeScore,
|
|
2533
|
-
createAdmissionController,
|
|
2534
|
-
createAuditCollector,
|
|
2535
|
-
createAuditLogger,
|
|
2536
|
-
createAuthWatcher,
|
|
2537
|
-
createCircuitBreaker,
|
|
2538
|
-
createConcurrencyTracker,
|
|
2539
|
-
createCooldownManager,
|
|
2540
|
-
createExecutionOrchestrator,
|
|
2541
|
-
createFailoverOrchestrator,
|
|
2542
|
-
createLogSubscriber,
|
|
2543
|
-
createModeAdapter,
|
|
2544
|
-
createOperatorTools,
|
|
2545
|
-
createProfileTools,
|
|
2546
|
-
createRegistry,
|
|
2547
|
-
createRequestLogger,
|
|
2548
|
-
createRequestTraceBuffer,
|
|
2549
|
-
createRetryPolicy,
|
|
2550
|
-
createRoutingEventBus,
|
|
2551
|
-
createStreamBuffer,
|
|
2552
|
-
createStreamStitcher,
|
|
2553
|
-
detectDeploymentMode,
|
|
2554
|
-
determineContinuationMode,
|
|
2555
|
-
directSignalFromResponse,
|
|
2556
|
-
disableTarget,
|
|
2557
|
-
discoverTargets,
|
|
2558
|
-
discoverTargetsFromProfiles,
|
|
2559
|
-
drainTarget,
|
|
2560
|
-
extractRetryAfterMs,
|
|
2561
|
-
generateCorrelationId,
|
|
2562
|
-
getExclusionReason,
|
|
2563
|
-
getModeCapabilities,
|
|
2564
|
-
getSignalFidelity,
|
|
2565
|
-
getTargetStateTransition,
|
|
2566
|
-
heuristicSignalFromEvent,
|
|
2567
|
-
inspectRequest,
|
|
2568
|
-
isRetryable,
|
|
2569
|
-
listProfiles,
|
|
2570
|
-
listTargets,
|
|
2571
|
-
loadProfiles,
|
|
2572
|
-
nextProfileId,
|
|
2573
|
-
normalizeLatency,
|
|
2574
|
-
pauseTarget,
|
|
2575
|
-
reloadConfig,
|
|
2576
|
-
removeProfile,
|
|
2577
|
-
resumeTarget,
|
|
2578
|
-
saveProfiles,
|
|
2579
|
-
selectTarget,
|
|
2580
|
-
updateHealthScore,
|
|
2581
|
-
updateLatencyEma,
|
|
2582
|
-
validateBearerToken,
|
|
2583
|
-
validateConfig
|
|
2584
|
-
});
|
|
2585
|
-
//# sourceMappingURL=index.cjs.map
|
|
1224
|
+
exports.HEURISTIC_PATTERNS = HEURISTIC_PATTERNS;
|
|
1225
|
+
exports.PROVIDER_PATTERNS = PROVIDER_PATTERNS;
|
|
1226
|
+
exports.TEMPORAL_QUOTA_PATTERN = TEMPORAL_QUOTA_PATTERN;
|
|
1227
|
+
exports.classify = classify;
|
|
1228
|
+
exports.createAuditCollector = createAuditCollector;
|
|
1229
|
+
exports.createExecutionOrchestrator = createExecutionOrchestrator;
|
|
1230
|
+
exports.createModeAdapter = createModeAdapter;
|
|
1231
|
+
exports.createOperatorTools = createOperatorTools;
|
|
1232
|
+
exports.createStreamBuffer = createStreamBuffer;
|
|
1233
|
+
exports.createStreamStitcher = createStreamStitcher;
|
|
1234
|
+
exports.detectDeploymentMode = detectDeploymentMode;
|
|
1235
|
+
exports.determineContinuationMode = determineContinuationMode;
|
|
1236
|
+
exports.directSignalFromResponse = directSignalFromResponse;
|
|
1237
|
+
exports.extractRetryAfterMs = extractRetryAfterMs;
|
|
1238
|
+
exports.getModeCapabilities = getModeCapabilities;
|
|
1239
|
+
exports.getSignalFidelity = getSignalFidelity;
|
|
1240
|
+
exports.heuristicSignalFromEvent = heuristicSignalFromEvent;
|
|
1241
|
+
exports.validateBearerToken = validateBearerToken;
|