@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/dist/index.js CHANGED
@@ -1,72 +1,7 @@
1
- import {
2
- ADMISSION_RESULTS,
3
- BackoffConfigSchema,
4
- ConfigValidationError,
5
- DEFAULT_ALPHA,
6
- DEFAULT_BACKOFF_BASE_MS,
7
- DEFAULT_BACKOFF_JITTER,
8
- DEFAULT_BACKOFF_MAX_MS,
9
- DEFAULT_BACKOFF_MULTIPLIER,
10
- DEFAULT_BACKOFF_PARAMS,
11
- DEFAULT_FAILOVER_BUDGET,
12
- DEFAULT_RETRY,
13
- DEFAULT_RETRY_BUDGET,
14
- DEFAULT_TIMEOUT_MS,
15
- DualBreaker,
16
- EXCLUSION_REASONS,
17
- ErrorClassSchema,
18
- INITIAL_HEALTH_SCORE,
19
- REDACT_PATHS,
20
- SwitcherConfigSchema,
21
- TARGET_STATES,
22
- TargetConfigSchema,
23
- TargetRegistry,
24
- addProfile,
25
- applyConfigDiff,
26
- checkHardRejects,
27
- computeBackoffMs,
28
- computeConfigDiff,
29
- computeCooldownMs,
30
- computeScore,
31
- createAdmissionController,
32
- createAuditLogger,
33
- createAuthWatcher,
34
- createCircuitBreaker,
35
- createConcurrencyTracker,
36
- createCooldownManager,
37
- createFailoverOrchestrator,
38
- createLogSubscriber,
39
- createOperatorTools,
40
- createProfileTools,
41
- createRegistry,
42
- createRequestLogger,
43
- createRequestTraceBuffer,
44
- createRetryPolicy,
45
- createRoutingEventBus,
46
- disableTarget,
47
- discoverTargets,
48
- discoverTargetsFromProfiles,
49
- drainTarget,
50
- generateCorrelationId,
51
- getExclusionReason,
52
- getTargetStateTransition,
53
- inspectRequest,
54
- isRetryable,
55
- listProfiles,
56
- listTargets,
57
- loadProfiles,
58
- nextProfileId,
59
- normalizeLatency,
60
- pauseTarget,
61
- reloadConfig,
62
- removeProfile,
63
- resumeTarget,
64
- saveProfiles,
65
- selectTarget,
66
- updateHealthScore,
67
- updateLatencyEma,
68
- validateConfig
69
- } from "./chunk-BTDKGS7P.js";
1
+ import { createRequestLogger, generateCorrelationId, reloadConfig, inspectRequest, disableTarget, drainTarget, resumeTarget, pauseTarget, listTargets } from './chunk-IKNWSNAS.js';
2
+ export { ADMISSION_RESULTS, BackoffConfigSchema, ConfigValidationError, DEFAULT_ALPHA, DEFAULT_BACKOFF_BASE_MS, DEFAULT_BACKOFF_JITTER, DEFAULT_BACKOFF_MAX_MS, DEFAULT_BACKOFF_MULTIPLIER, DEFAULT_BACKOFF_PARAMS, DEFAULT_FAILOVER_BUDGET, DEFAULT_RETRY, DEFAULT_RETRY_BUDGET, DEFAULT_TIMEOUT_MS, DualBreaker, EXCLUSION_REASONS, ErrorClassSchema, INITIAL_HEALTH_SCORE, REDACT_PATHS, SwitcherConfigSchema, TARGET_STATES, TargetConfigSchema, TargetRegistry, addProfile, applyConfigDiff, checkHardRejects, computeBackoffMs, computeConfigDiff, computeCooldownMs, computeScore, createAdmissionController, createAuditLogger, createAuthWatcher, createCircuitBreaker, createConcurrencyTracker, createCooldownManager, createFailoverOrchestrator, createLogSubscriber, createProfileTools, createRegistry, createRequestLogger, createRequestTraceBuffer, createRetryPolicy, createRoutingEventBus, disableTarget, discoverTargets, discoverTargetsFromProfiles, drainTarget, generateCorrelationId, getExclusionReason, getTargetStateTransition, inspectRequest, isRetryable, listProfiles, listTargets, loadProfiles, nextProfileId, normalizeLatency, pauseTarget, reloadConfig, removeProfile, resumeTarget, saveProfiles, selectTarget, updateHealthScore, updateLatencyEma, validateConfig } from './chunk-IKNWSNAS.js';
3
+ import { timingSafeEqual } from 'crypto';
4
+ import { tool } from '@opencode-ai/plugin/tool';
70
5
 
71
6
  // src/mode/detection.ts
72
7
  var detectDeploymentMode = (hint) => {
@@ -103,51 +38,245 @@ var getModeCapabilities = (mode) => {
103
38
  // src/errors/corpus.ts
104
39
  var PROVIDER_PATTERNS = [
105
40
  // Anthropic
106
- { provider: "anthropic", http_status: 400, error_type_field: "error.type", error_type_value: "invalid_request_error", error_class: "PolicyFailure" },
107
- { provider: "anthropic", http_status: 401, error_type_field: "error.type", error_type_value: "authentication_error", error_class: "AuthFailure" },
108
- { provider: "anthropic", http_status: 402, error_type_field: "error.type", error_type_value: "billing_error", error_class: "QuotaExhausted" },
109
- { provider: "anthropic", http_status: 403, error_type_field: "error.type", error_type_value: "permission_error", error_class: "PermissionFailure" },
110
- { provider: "anthropic", http_status: 404, error_type_field: "error.type", error_type_value: "not_found_error", error_class: "ModelUnavailable" },
111
- { provider: "anthropic", http_status: 429, error_type_field: "error.type", error_type_value: "rate_limit_error", error_class: "RateLimited" },
112
- { provider: "anthropic", http_status: 500, error_type_field: "error.type", error_type_value: "api_error", error_class: "TransientServerFailure" },
113
- { provider: "anthropic", http_status: 504, error_type_field: "error.type", error_type_value: "timeout_error", error_class: "TransportFailure" },
114
- { provider: "anthropic", http_status: 529, error_type_field: "error.type", error_type_value: "overloaded_error", error_class: "RateLimited", notes: "Server capacity exhaustion; backoff on same provider, do NOT failover" },
41
+ {
42
+ provider: "anthropic",
43
+ http_status: 400,
44
+ error_type_field: "error.type",
45
+ error_type_value: "invalid_request_error",
46
+ error_class: "PolicyFailure"
47
+ },
48
+ {
49
+ provider: "anthropic",
50
+ http_status: 401,
51
+ error_type_field: "error.type",
52
+ error_type_value: "authentication_error",
53
+ error_class: "AuthFailure"
54
+ },
55
+ {
56
+ provider: "anthropic",
57
+ http_status: 402,
58
+ error_type_field: "error.type",
59
+ error_type_value: "billing_error",
60
+ error_class: "QuotaExhausted"
61
+ },
62
+ {
63
+ provider: "anthropic",
64
+ http_status: 403,
65
+ error_type_field: "error.type",
66
+ error_type_value: "permission_error",
67
+ error_class: "PermissionFailure"
68
+ },
69
+ {
70
+ provider: "anthropic",
71
+ http_status: 404,
72
+ error_type_field: "error.type",
73
+ error_type_value: "not_found_error",
74
+ error_class: "ModelUnavailable"
75
+ },
76
+ {
77
+ provider: "anthropic",
78
+ http_status: 429,
79
+ error_type_field: "error.type",
80
+ error_type_value: "rate_limit_error",
81
+ error_class: "RateLimited"
82
+ },
83
+ {
84
+ provider: "anthropic",
85
+ http_status: 500,
86
+ error_type_field: "error.type",
87
+ error_type_value: "api_error",
88
+ error_class: "TransientServerFailure"
89
+ },
90
+ {
91
+ provider: "anthropic",
92
+ http_status: 504,
93
+ error_type_field: "error.type",
94
+ error_type_value: "timeout_error",
95
+ error_class: "TransportFailure"
96
+ },
97
+ {
98
+ provider: "anthropic",
99
+ http_status: 529,
100
+ error_type_field: "error.type",
101
+ error_type_value: "overloaded_error",
102
+ error_class: "RateLimited",
103
+ notes: "Server capacity exhaustion; backoff on same provider, do NOT failover"
104
+ },
115
105
  // OpenAI
116
- { provider: "openai", http_status: 400, error_type_field: "error.code", error_type_value: "", error_class: "PolicyFailure" },
117
- { provider: "openai", http_status: 401, error_type_field: "error.code", error_type_value: "invalid_api_key", error_class: "AuthFailure" },
118
- { provider: "openai", http_status: 403, error_type_field: "error.code", error_type_value: "unsupported_country_region_territory", error_class: "RegionRestriction", notes: "GeoIP block \u2014 collected 2026-04-11 from real API" },
119
- { provider: "openai", http_status: 403, error_type_field: "error.code", error_type_value: "", error_class: "PermissionFailure" },
120
- { provider: "openai", http_status: 429, error_type_field: "error.code", error_type_value: "rate_limit_exceeded", error_class: "RateLimited" },
121
- { provider: "openai", http_status: 429, error_type_field: "error.code", error_type_value: "insufficient_quota", error_class: "QuotaExhausted", notes: "Billing exhausted -- NOT retryable" },
122
- { provider: "openai", http_status: 500, error_type_field: "error.code", error_type_value: "", error_class: "TransientServerFailure" },
123
- { provider: "openai", http_status: 503, error_type_field: "error.code", error_type_value: "", error_class: "TransientServerFailure" },
106
+ {
107
+ provider: "openai",
108
+ http_status: 400,
109
+ error_type_field: "error.code",
110
+ error_type_value: "",
111
+ error_class: "PolicyFailure"
112
+ },
113
+ {
114
+ provider: "openai",
115
+ http_status: 401,
116
+ error_type_field: "error.code",
117
+ error_type_value: "invalid_api_key",
118
+ error_class: "AuthFailure"
119
+ },
120
+ {
121
+ provider: "openai",
122
+ http_status: 403,
123
+ error_type_field: "error.code",
124
+ error_type_value: "unsupported_country_region_territory",
125
+ error_class: "RegionRestriction",
126
+ notes: "GeoIP block \u2014 collected 2026-04-11 from real API"
127
+ },
128
+ {
129
+ provider: "openai",
130
+ http_status: 403,
131
+ error_type_field: "error.code",
132
+ error_type_value: "",
133
+ error_class: "PermissionFailure"
134
+ },
135
+ {
136
+ provider: "openai",
137
+ http_status: 429,
138
+ error_type_field: "error.code",
139
+ error_type_value: "rate_limit_exceeded",
140
+ error_class: "RateLimited"
141
+ },
142
+ {
143
+ provider: "openai",
144
+ http_status: 429,
145
+ error_type_field: "error.code",
146
+ error_type_value: "insufficient_quota",
147
+ error_class: "QuotaExhausted",
148
+ notes: "Billing exhausted -- NOT retryable"
149
+ },
150
+ {
151
+ provider: "openai",
152
+ http_status: 500,
153
+ error_type_field: "error.code",
154
+ error_type_value: "",
155
+ error_class: "TransientServerFailure"
156
+ },
157
+ {
158
+ provider: "openai",
159
+ http_status: 503,
160
+ error_type_field: "error.code",
161
+ error_type_value: "",
162
+ error_class: "TransientServerFailure"
163
+ },
124
164
  // Google Vertex AI / Gemini
125
- { provider: "google", http_status: 400, error_type_field: "error.status", error_type_value: "INVALID_ARGUMENT", error_class: "PolicyFailure" },
126
- { provider: "google", http_status: 403, error_type_field: "error.status", error_type_value: "PERMISSION_DENIED", error_class: "PermissionFailure" },
127
- { provider: "google", http_status: 429, error_type_field: "error.status", error_type_value: "RESOURCE_EXHAUSTED", error_class: "RateLimited" },
128
- { provider: "google", http_status: 500, error_type_field: "error.status", error_type_value: "INTERNAL", error_class: "TransientServerFailure" },
129
- { provider: "google", http_status: 503, error_type_field: "error.status", error_type_value: "UNAVAILABLE", error_class: "TransientServerFailure" },
165
+ {
166
+ provider: "google",
167
+ http_status: 400,
168
+ error_type_field: "error.status",
169
+ error_type_value: "INVALID_ARGUMENT",
170
+ error_class: "PolicyFailure"
171
+ },
172
+ {
173
+ provider: "google",
174
+ http_status: 403,
175
+ error_type_field: "error.status",
176
+ error_type_value: "PERMISSION_DENIED",
177
+ error_class: "PermissionFailure"
178
+ },
179
+ {
180
+ provider: "google",
181
+ http_status: 429,
182
+ error_type_field: "error.status",
183
+ error_type_value: "RESOURCE_EXHAUSTED",
184
+ error_class: "RateLimited"
185
+ },
186
+ {
187
+ provider: "google",
188
+ http_status: 500,
189
+ error_type_field: "error.status",
190
+ error_type_value: "INTERNAL",
191
+ error_class: "TransientServerFailure"
192
+ },
193
+ {
194
+ provider: "google",
195
+ http_status: 503,
196
+ error_type_field: "error.status",
197
+ error_type_value: "UNAVAILABLE",
198
+ error_class: "TransientServerFailure"
199
+ },
130
200
  // AWS Bedrock
131
- { provider: "bedrock", http_status: 429, error_type_field: "__type", error_type_value: "ThrottlingException", error_class: "RateLimited" },
132
- { provider: "bedrock", http_status: 408, error_type_field: "__type", error_type_value: "ModelTimeoutException", error_class: "TransportFailure" },
133
- { provider: "bedrock", http_status: 424, error_type_field: "__type", error_type_value: "ModelNotReadyException", error_class: "ModelUnavailable" },
134
- { provider: "bedrock", http_status: 403, error_type_field: "__type", error_type_value: "AccessDeniedException", error_class: "PermissionFailure" },
135
- { provider: "bedrock", http_status: 400, error_type_field: "__type", error_type_value: "ValidationException", error_class: "PolicyFailure" },
136
- { provider: "bedrock", http_status: 500, error_type_field: "__type", error_type_value: "InternalServerException", error_class: "TransientServerFailure" }
201
+ {
202
+ provider: "bedrock",
203
+ http_status: 429,
204
+ error_type_field: "__type",
205
+ error_type_value: "ThrottlingException",
206
+ error_class: "RateLimited"
207
+ },
208
+ {
209
+ provider: "bedrock",
210
+ http_status: 408,
211
+ error_type_field: "__type",
212
+ error_type_value: "ModelTimeoutException",
213
+ error_class: "TransportFailure"
214
+ },
215
+ {
216
+ provider: "bedrock",
217
+ http_status: 424,
218
+ error_type_field: "__type",
219
+ error_type_value: "ModelNotReadyException",
220
+ error_class: "ModelUnavailable"
221
+ },
222
+ {
223
+ provider: "bedrock",
224
+ http_status: 403,
225
+ error_type_field: "__type",
226
+ error_type_value: "AccessDeniedException",
227
+ error_class: "PermissionFailure"
228
+ },
229
+ {
230
+ provider: "bedrock",
231
+ http_status: 400,
232
+ error_type_field: "__type",
233
+ error_type_value: "ValidationException",
234
+ error_class: "PolicyFailure"
235
+ },
236
+ {
237
+ provider: "bedrock",
238
+ http_status: 500,
239
+ error_type_field: "__type",
240
+ error_type_value: "InternalServerException",
241
+ error_class: "TransientServerFailure"
242
+ }
137
243
  ];
138
244
  var HEURISTIC_PATTERNS = [
139
245
  // Transport errors (high confidence -- these are unambiguous)
140
- { pattern: /ECONNREFUSED|ECONNRESET|ETIMEDOUT/, error_class: "TransportFailure", confidence: "high" },
246
+ {
247
+ pattern: /ECONNREFUSED|ECONNRESET|ETIMEDOUT/,
248
+ error_class: "TransportFailure",
249
+ confidence: "high"
250
+ },
141
251
  // Quota patterns (before rate limit to avoid misclassification -- Pitfall 2/3)
142
- { pattern: /quota\s*(?:exceeded|exhausted)/i, error_class: "QuotaExhausted", confidence: "medium" },
143
- { pattern: /insufficient\s*quota/i, error_class: "QuotaExhausted", confidence: "medium", provider: "openai" },
252
+ {
253
+ pattern: /quota\s*(?:exceeded|exhausted)/i,
254
+ error_class: "QuotaExhausted",
255
+ confidence: "medium"
256
+ },
257
+ {
258
+ pattern: /insufficient\s*quota/i,
259
+ error_class: "QuotaExhausted",
260
+ confidence: "medium",
261
+ provider: "openai"
262
+ },
144
263
  { pattern: /billing/i, error_class: "QuotaExhausted", confidence: "low", provider: "openai" },
145
264
  // Rate limit patterns
146
265
  { pattern: /rate\s*limit/i, error_class: "RateLimited", confidence: "medium" },
147
266
  { pattern: /too many requests/i, error_class: "RateLimited", confidence: "medium" },
148
267
  { pattern: /retry\s*after/i, error_class: "RateLimited", confidence: "medium" },
149
- { pattern: /overloaded/i, error_class: "RateLimited", confidence: "medium", provider: "anthropic" },
150
- { pattern: /resource\s*exhausted/i, error_class: "RateLimited", confidence: "medium", provider: "google" },
268
+ {
269
+ pattern: /overloaded/i,
270
+ error_class: "RateLimited",
271
+ confidence: "medium",
272
+ provider: "anthropic"
273
+ },
274
+ {
275
+ pattern: /resource\s*exhausted/i,
276
+ error_class: "RateLimited",
277
+ confidence: "medium",
278
+ provider: "google"
279
+ },
151
280
  // Auth patterns
152
281
  { pattern: /authentication/i, error_class: "AuthFailure", confidence: "medium" },
153
282
  { pattern: /invalid\s*api\s*key/i, error_class: "AuthFailure", confidence: "medium" },
@@ -156,14 +285,31 @@ var HEURISTIC_PATTERNS = [
156
285
  { pattern: /permission\s*denied/i, error_class: "PermissionFailure", confidence: "medium" },
157
286
  { pattern: /forbidden/i, error_class: "PermissionFailure", confidence: "low" },
158
287
  // Model availability patterns
159
- { pattern: /model\s*not\s*(?:available|ready|found)/i, error_class: "ModelUnavailable", confidence: "medium" },
288
+ {
289
+ pattern: /model\s*not\s*(?:available|ready|found)/i,
290
+ error_class: "ModelUnavailable",
291
+ confidence: "medium"
292
+ },
160
293
  { pattern: /not\s*found/i, error_class: "ModelUnavailable", confidence: "low" },
161
294
  // Transport patterns (lower confidence than ECONNREFUSED)
162
295
  { pattern: /timeout/i, error_class: "TransportFailure", confidence: "low" },
163
296
  // Region restriction (requires both keywords)
164
- { pattern: /unsupported.country.*region.*territory/i, error_class: "RegionRestriction", confidence: "high", notes: "OpenAI GeoIP block \u2014 collected 2026-04-11" },
165
- { pattern: /country.*region.*not supported/i, error_class: "RegionRestriction", confidence: "high" },
166
- { pattern: /region.*restrict|restrict.*region/i, error_class: "RegionRestriction", confidence: "low" }
297
+ {
298
+ pattern: /unsupported.country.*region.*territory/i,
299
+ error_class: "RegionRestriction",
300
+ confidence: "high",
301
+ notes: "OpenAI GeoIP block \u2014 collected 2026-04-11"
302
+ },
303
+ {
304
+ pattern: /country.*region.*not supported/i,
305
+ error_class: "RegionRestriction",
306
+ confidence: "high"
307
+ },
308
+ {
309
+ pattern: /region.*restrict|restrict.*region/i,
310
+ error_class: "RegionRestriction",
311
+ confidence: "low"
312
+ }
167
313
  ];
168
314
  var TEMPORAL_QUOTA_PATTERN = /too many tokens per (?:day|month|hour|week)/i;
169
315
 
@@ -451,10 +597,7 @@ var createStreamStitcher = (_requestId) => {
451
597
  * @param provenance - Segment provenance without visible_offset (computed here).
452
598
  */
453
599
  addSegment(buffer, provenance) {
454
- const visibleOffset = segments.reduce(
455
- (sum, entry) => sum + entry.text.length,
456
- 0
457
- );
600
+ const visibleOffset = segments.reduce((sum, entry) => sum + entry.text.length, 0);
458
601
  segments.push({
459
602
  text: buffer.snapshot(),
460
603
  provenance: { ...provenance, visible_offset: visibleOffset }
@@ -520,7 +663,7 @@ var createExecutionOrchestrator = (deps) => ({
520
663
  async execute(request) {
521
664
  const requestId = request.request_id || generateCorrelationId();
522
665
  const auditCollector = createAuditCollector(deps.logger, requestId);
523
- const stitcher = createStreamStitcher(requestId);
666
+ const stitcher = createStreamStitcher();
524
667
  const startMs = Date.now();
525
668
  const heuristicFlags = [];
526
669
  let outcome = "failure";
@@ -538,9 +681,7 @@ var createExecutionOrchestrator = (deps) => ({
538
681
  for (const chunk of adapterResult.chunks) {
539
682
  buffer.append(chunk);
540
683
  }
541
- heuristicFlags.push(
542
- adapterResult.detection_mode === "heuristic"
543
- );
684
+ heuristicFlags.push(adapterResult.detection_mode === "heuristic");
544
685
  const value = { buffer, adapterResult };
545
686
  return {
546
687
  success: adapterResult.success,
@@ -577,12 +718,8 @@ var createExecutionOrchestrator = (deps) => ({
577
718
  const stitchedOutput = stitcher.assemble();
578
719
  const isDegraded2 = deps.mode === "plugin-only";
579
720
  const isHeuristic2 = heuristicFlags.some(Boolean);
580
- const uniqueModes = [
581
- ...new Set(stitchedOutput.segments.map((s) => s.continuation_mode))
582
- ];
583
- const uniqueTargets = [
584
- ...new Set(stitchedOutput.segments.map((s) => s.source_target_id))
585
- ];
721
+ const uniqueModes = [...new Set(stitchedOutput.segments.map((s) => s.continuation_mode))];
722
+ const uniqueTargets = [...new Set(stitchedOutput.segments.map((s) => s.source_target_id))];
586
723
  const provenance2 = {
587
724
  request_id: requestId,
588
725
  segments: stitchedOutput.segments,
@@ -620,17 +757,20 @@ var createExecutionOrchestrator = (deps) => ({
620
757
  auditCollector.flush(outcome, finalTarget);
621
758
  const requestLogger = createRequestLogger(deps.logger, requestId);
622
759
  const endMs = Date.now();
623
- requestLogger.info({
624
- event: "request_summary",
625
- component: "execution",
626
- outcome,
627
- total_attempts: summaryAttempts,
628
- total_failovers: summaryFailovers,
629
- total_retries: summaryRetries,
630
- latency_ms: endMs - startMs,
631
- targets_used: summaryTargets,
632
- final_target: finalTarget ?? null
633
- }, "Request complete");
760
+ requestLogger.info(
761
+ {
762
+ event: "request_summary",
763
+ component: "execution",
764
+ outcome,
765
+ total_attempts: summaryAttempts,
766
+ total_failovers: summaryFailovers,
767
+ total_retries: summaryRetries,
768
+ latency_ms: endMs - startMs,
769
+ targets_used: summaryTargets,
770
+ final_target: finalTarget ?? null
771
+ },
772
+ "Request complete"
773
+ );
634
774
  }
635
775
  }
636
776
  });
@@ -714,20 +854,17 @@ var createSdkAdapter = (_deps) => ({
714
854
  var createModeAdapter = (mode, deps) => {
715
855
  switch (mode) {
716
856
  case "plugin-only":
717
- return createPluginAdapter(deps);
857
+ return createPluginAdapter();
718
858
  case "server-companion":
719
- return createServerAdapter(deps);
859
+ return createServerAdapter();
720
860
  case "sdk-control":
721
- return createSdkAdapter(deps);
861
+ return createSdkAdapter();
722
862
  default: {
723
863
  const _exhaustive = mode;
724
864
  throw new Error(`Unknown deployment mode: ${String(_exhaustive)}`);
725
865
  }
726
866
  }
727
867
  };
728
-
729
- // src/operator/server-auth.ts
730
- import { timingSafeEqual } from "crypto";
731
868
  var validateBearerToken = (authHeader, expectedToken) => {
732
869
  if (authHeader === void 0) {
733
870
  return { authorized: false, reason: "missing Authorization header" };
@@ -746,90 +883,77 @@ var validateBearerToken = (authHeader, expectedToken) => {
746
883
  }
747
884
  return { authorized: true };
748
885
  };
749
- export {
750
- ADMISSION_RESULTS,
751
- BackoffConfigSchema,
752
- ConfigValidationError,
753
- DEFAULT_ALPHA,
754
- DEFAULT_BACKOFF_BASE_MS,
755
- DEFAULT_BACKOFF_JITTER,
756
- DEFAULT_BACKOFF_MAX_MS,
757
- DEFAULT_BACKOFF_MULTIPLIER,
758
- DEFAULT_BACKOFF_PARAMS,
759
- DEFAULT_FAILOVER_BUDGET,
760
- DEFAULT_RETRY,
761
- DEFAULT_RETRY_BUDGET,
762
- DEFAULT_TIMEOUT_MS,
763
- DualBreaker,
764
- EXCLUSION_REASONS,
765
- ErrorClassSchema,
766
- HEURISTIC_PATTERNS,
767
- INITIAL_HEALTH_SCORE,
768
- PROVIDER_PATTERNS,
769
- REDACT_PATHS,
770
- SwitcherConfigSchema,
771
- TARGET_STATES,
772
- TEMPORAL_QUOTA_PATTERN,
773
- TargetConfigSchema,
774
- TargetRegistry,
775
- addProfile,
776
- applyConfigDiff,
777
- checkHardRejects,
778
- classify,
779
- computeBackoffMs,
780
- computeConfigDiff,
781
- computeCooldownMs,
782
- computeScore,
783
- createAdmissionController,
784
- createAuditCollector,
785
- createAuditLogger,
786
- createAuthWatcher,
787
- createCircuitBreaker,
788
- createConcurrencyTracker,
789
- createCooldownManager,
790
- createExecutionOrchestrator,
791
- createFailoverOrchestrator,
792
- createLogSubscriber,
793
- createModeAdapter,
794
- createOperatorTools,
795
- createProfileTools,
796
- createRegistry,
797
- createRequestLogger,
798
- createRequestTraceBuffer,
799
- createRetryPolicy,
800
- createRoutingEventBus,
801
- createStreamBuffer,
802
- createStreamStitcher,
803
- detectDeploymentMode,
804
- determineContinuationMode,
805
- directSignalFromResponse,
806
- disableTarget,
807
- discoverTargets,
808
- discoverTargetsFromProfiles,
809
- drainTarget,
810
- extractRetryAfterMs,
811
- generateCorrelationId,
812
- getExclusionReason,
813
- getModeCapabilities,
814
- getSignalFidelity,
815
- getTargetStateTransition,
816
- heuristicSignalFromEvent,
817
- inspectRequest,
818
- isRetryable,
819
- listProfiles,
820
- listTargets,
821
- loadProfiles,
822
- nextProfileId,
823
- normalizeLatency,
824
- pauseTarget,
825
- reloadConfig,
826
- removeProfile,
827
- resumeTarget,
828
- saveProfiles,
829
- selectTarget,
830
- updateHealthScore,
831
- updateLatencyEma,
832
- validateBearerToken,
833
- validateConfig
834
- };
835
- //# sourceMappingURL=index.js.map
886
+ var { schema: z } = tool;
887
+ var createOperatorTools = (deps) => ({
888
+ listTargets: tool({
889
+ description: "List all routing targets with health scores, states, and circuit breaker status.",
890
+ args: {},
891
+ async execute() {
892
+ deps.logger.info({ op: "listTargets" }, "operator: listTargets");
893
+ const result = listTargets(deps);
894
+ return JSON.stringify(result, null, 2);
895
+ }
896
+ }),
897
+ pauseTarget: tool({
898
+ description: "Pause a target, preventing new requests from being routed to it.",
899
+ args: { target_id: z.string().min(1) },
900
+ async execute(args) {
901
+ deps.logger.info({ op: "pauseTarget", target_id: args.target_id }, "operator: pauseTarget");
902
+ const result = pauseTarget(deps, args.target_id);
903
+ return JSON.stringify(result, null, 2);
904
+ }
905
+ }),
906
+ resumeTarget: tool({
907
+ description: "Resume a previously paused or disabled target, allowing new requests.",
908
+ args: { target_id: z.string().min(1) },
909
+ async execute(args) {
910
+ deps.logger.info({ op: "resumeTarget", target_id: args.target_id }, "operator: resumeTarget");
911
+ const result = resumeTarget(deps, args.target_id);
912
+ return JSON.stringify(result, null, 2);
913
+ }
914
+ }),
915
+ drainTarget: tool({
916
+ description: "Drain a target, allowing in-flight requests to complete but preventing new ones.",
917
+ args: { target_id: z.string().min(1) },
918
+ async execute(args) {
919
+ deps.logger.info({ op: "drainTarget", target_id: args.target_id }, "operator: drainTarget");
920
+ const result = drainTarget(deps, args.target_id);
921
+ return JSON.stringify(result, null, 2);
922
+ }
923
+ }),
924
+ disableTarget: tool({
925
+ description: "Disable a target entirely, removing it from routing.",
926
+ args: { target_id: z.string().min(1) },
927
+ async execute(args) {
928
+ deps.logger.info(
929
+ { op: "disableTarget", target_id: args.target_id },
930
+ "operator: disableTarget"
931
+ );
932
+ const result = disableTarget(deps, args.target_id);
933
+ return JSON.stringify(result, null, 2);
934
+ }
935
+ }),
936
+ inspectRequest: tool({
937
+ description: "Inspect a request trace by ID, showing attempts, segments, and outcome.",
938
+ args: { request_id: z.string().min(1) },
939
+ async execute(args) {
940
+ deps.logger.info(
941
+ { op: "inspectRequest", request_id: args.request_id },
942
+ "operator: inspectRequest"
943
+ );
944
+ const result = inspectRequest(deps, args.request_id);
945
+ return JSON.stringify(result, null, 2);
946
+ }
947
+ }),
948
+ reloadConfig: tool({
949
+ description: "Reload routing configuration with diff-apply. Validates new config before applying.",
950
+ args: { config: z.record(z.string(), z.unknown()) },
951
+ async execute(args) {
952
+ deps.logger.info({ op: "reloadConfig" }, "operator: reloadConfig");
953
+ const result = reloadConfig(deps, args.config);
954
+ return JSON.stringify(result, null, 2);
955
+ }
956
+ })
957
+ });
958
+
959
+ export { HEURISTIC_PATTERNS, PROVIDER_PATTERNS, TEMPORAL_QUOTA_PATTERN, classify, createAuditCollector, createExecutionOrchestrator, createModeAdapter, createOperatorTools, createStreamBuffer, createStreamStitcher, detectDeploymentMode, determineContinuationMode, directSignalFromResponse, extractRetryAfterMs, getModeCapabilities, getSignalFidelity, heuristicSignalFromEvent, validateBearerToken };