@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.js
CHANGED
|
@@ -1,72 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{
|
|
114
|
-
|
|
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
|
-
{
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
{
|
|
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
|
-
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
{
|
|
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
|
-
{
|
|
143
|
-
|
|
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
|
-
{
|
|
150
|
-
|
|
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
|
-
{
|
|
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
|
-
{
|
|
165
|
-
|
|
166
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
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(
|
|
857
|
+
return createPluginAdapter();
|
|
718
858
|
case "server-companion":
|
|
719
|
-
return createServerAdapter(
|
|
859
|
+
return createServerAdapter();
|
|
720
860
|
case "sdk-control":
|
|
721
|
-
return createSdkAdapter(
|
|
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
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
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 };
|