@vostride/agent-qa-model 0.0.0-stage → 0.2.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.cjs ADDED
@@ -0,0 +1,1701 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ FAMILIES: () => FAMILIES,
24
+ MODEL_CALL_EVENT_KINDS: () => MODEL_CALL_EVENT_KINDS,
25
+ MODEL_CALL_REPORT_ORIGINS: () => MODEL_CALL_REPORT_ORIGINS,
26
+ MODEL_CATALOG: () => MODEL_CATALOG,
27
+ UNKNOWN_FLOOR: () => UNKNOWN_FLOOR,
28
+ anthropicCompatible: () => anthropicCompatible,
29
+ anthropicSubscription: () => anthropicSubscription,
30
+ capabilityKey: () => capabilityKey,
31
+ capabilityUpdateMiddleware: () => capabilityUpdateMiddleware,
32
+ clearProviderRegistry: () => clearProviderRegistry,
33
+ compactLogs: () => compactLogs,
34
+ createModel: () => createModel,
35
+ createTokenAccounting: () => createTokenAccounting,
36
+ debugLoggingMiddleware: () => debugLoggingMiddleware,
37
+ deriveExamplesMiddleware: () => deriveExamplesMiddleware,
38
+ deriveTransport: () => deriveTransport,
39
+ dropEmptyMessagesMiddleware: () => dropEmptyMessagesMiddleware,
40
+ extractJsonStrategy: () => extractJsonStrategy,
41
+ fetchLiveModels: () => fetchLiveModels,
42
+ gemini: () => gemini,
43
+ getModelCatalog: () => getModelCatalog,
44
+ getObservedWindow: () => getObservedWindow,
45
+ getProvider: () => getProvider,
46
+ getProviderOptions: () => getProviderOptions,
47
+ guardBlob: () => guardBlob,
48
+ guardToolOutput: () => guardToolOutput,
49
+ isContextLengthOverflow: () => isContextOverflow,
50
+ isContextOverflow: () => isContextOverflow,
51
+ listProviders: () => listProviders,
52
+ matchFamily: () => matchFamily,
53
+ mergeCatalog: () => mergeCatalog,
54
+ openaiCompatible: () => openaiCompatible,
55
+ openaiSubscription: () => openaiSubscription,
56
+ overrideStore: () => overrideStore,
57
+ parseRealWindow: () => parseRealWindow,
58
+ registerProvider: () => registerProvider,
59
+ repairMiddleware: () => repairMiddleware,
60
+ resolveCapabilities: () => resolveCapabilities,
61
+ resolveVisionConfig: () => resolveVisionConfig,
62
+ resolveVisionGate: () => resolveVisionGate,
63
+ retryMiddleware: () => retryMiddleware,
64
+ stripUnsupportedParamsMiddleware: () => stripUnsupportedParamsMiddleware,
65
+ toolSchemaMiddleware: () => toolSchemaMiddleware,
66
+ validateProfile: () => validateProfile,
67
+ visionFromConfig: () => visionFromConfig
68
+ });
69
+ module.exports = __toCommonJS(index_exports);
70
+
71
+ // src/adapters/anthropic.ts
72
+ var import_anthropic = require("@ai-sdk/anthropic");
73
+
74
+ // src/auth.ts
75
+ var import_ai = require("ai");
76
+ function deriveTransport(profile, auth) {
77
+ const transport = {
78
+ ...profile.baseURL ? { baseURL: profile.baseURL } : {},
79
+ ...profile.headers ? { headers: profile.headers } : {},
80
+ ...profile.providerOptions ? { providerOptions: profile.providerOptions } : {}
81
+ };
82
+ switch (auth.kind) {
83
+ case "api-key":
84
+ return { ...transport, apiKey: auth.apiKey };
85
+ case "bearer-token":
86
+ return { ...transport, authToken: auth.token };
87
+ case "auth-fetch":
88
+ return { ...transport, apiKey: placeholderApiKey(profile.provider), fetch: auth.fetch };
89
+ case "none":
90
+ return { ...transport, apiKey: placeholderApiKey(profile.provider) };
91
+ }
92
+ }
93
+ function applyProviderOptions(model, transport) {
94
+ if (!transport.providerOptions) return model;
95
+ return (0, import_ai.wrapLanguageModel)({
96
+ model,
97
+ middleware: (0, import_ai.defaultSettingsMiddleware)({
98
+ settings: {
99
+ providerOptions: transport.providerOptions
100
+ }
101
+ })
102
+ });
103
+ }
104
+ function placeholderApiKey(provider) {
105
+ switch (provider) {
106
+ case "openai-compatible":
107
+ return "openai-compatible";
108
+ case "anthropic-compatible":
109
+ return "anthropic-compatible";
110
+ default:
111
+ return "placeholder";
112
+ }
113
+ }
114
+
115
+ // src/adapters/anthropic.ts
116
+ function anthropicCompatible(transport, modelId) {
117
+ return applyProviderOptions(
118
+ (0, import_anthropic.createAnthropic)({
119
+ baseURL: transport.baseURL,
120
+ headers: transport.headers,
121
+ fetch: transport.fetch,
122
+ ...transport.authToken ? { authToken: transport.authToken } : { apiKey: transport.apiKey ?? "anthropic-compatible" }
123
+ })(modelId),
124
+ transport
125
+ );
126
+ }
127
+ function anthropicSubscription(transport, modelId) {
128
+ return applyProviderOptions(
129
+ (0, import_anthropic.createAnthropic)({
130
+ apiKey: transport.apiKey ?? "placeholder",
131
+ fetch: transport.fetch
132
+ })(modelId),
133
+ transport
134
+ );
135
+ }
136
+
137
+ // src/adapters/gemini.ts
138
+ var import_google = require("@ai-sdk/google");
139
+ function gemini(transport, modelId) {
140
+ return applyProviderOptions(
141
+ (0, import_google.createGoogleGenerativeAI)({
142
+ apiKey: transport.apiKey,
143
+ fetch: transport.fetch
144
+ })(modelId),
145
+ transport
146
+ );
147
+ }
148
+
149
+ // src/adapters/openai.ts
150
+ var import_openai = require("@ai-sdk/openai");
151
+ function openaiCompatible(transport, modelId) {
152
+ return applyProviderOptions(
153
+ (0, import_openai.createOpenAI)({
154
+ apiKey: transport.apiKey ?? "openai-compatible",
155
+ baseURL: transport.baseURL,
156
+ fetch: transport.fetch,
157
+ ...transport.headers ? { headers: transport.headers } : {}
158
+ }).chat(modelId),
159
+ transport
160
+ );
161
+ }
162
+ function openaiSubscription(transport, modelId) {
163
+ return applyProviderOptions(
164
+ (0, import_openai.createOpenAI)({
165
+ apiKey: transport.apiKey ?? "placeholder",
166
+ fetch: transport.fetch
167
+ }).responses(modelId),
168
+ transport
169
+ );
170
+ }
171
+ function getProviderOptions(config) {
172
+ if (config.fetch && (config.modelAdapter === "openai-responses" || !config.modelAdapter && config.provider === "openai-subscription")) {
173
+ return {
174
+ openai: {
175
+ instructions: "You are a helpful assistant.",
176
+ store: false
177
+ }
178
+ };
179
+ }
180
+ return void 0;
181
+ }
182
+
183
+ // src/accounting/compact.ts
184
+ var DEFAULT_LEVEL = "log";
185
+ var MAX_SAMPLES = 5;
186
+ var SAMPLE_PREFIX = " \xB7 ";
187
+ var TRUNCATION_MARKER = "\u2026[truncated to fit context budget]";
188
+ var BLOB_CEILING = 8e3;
189
+ var PLACEHOLDER = "<*>";
190
+ var NORMALIZERS = [
191
+ /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,
192
+ // UUID
193
+ /\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?/g,
194
+ // ISO timestamp
195
+ /\b(?:[0-9a-f]{1,4}:){2,}[0-9a-f]{0,4}\b/gi,
196
+ // IPv6-ish
197
+ /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g,
198
+ // IPv4
199
+ /\b0x[0-9a-f]+\b/gi,
200
+ // hex literal
201
+ /\b[0-9a-f]{7,}\b/gi,
202
+ // long bare hex id
203
+ /\b\d+(?:\.\d+)?\b/g
204
+ // bare number (last)
205
+ ];
206
+ function normalize(message) {
207
+ let out = message;
208
+ for (const pattern of NORMALIZERS) out = out.replace(pattern, PLACEHOLDER);
209
+ return out;
210
+ }
211
+ function compactLogs(entries) {
212
+ const classes = /* @__PURE__ */ new Map();
213
+ for (const entry of entries) {
214
+ const level = entry.level ?? DEFAULT_LEVEL;
215
+ const normalized = normalize(entry.message);
216
+ const key = `${entry.source}::${level}::${normalized}`;
217
+ const existing = classes.get(key);
218
+ if (existing) {
219
+ existing.count++;
220
+ if (existing.samples.length < MAX_SAMPLES) existing.samples.push(entry.message);
221
+ } else {
222
+ classes.set(key, { source: entry.source, level, normalized, count: 1, samples: [entry.message] });
223
+ }
224
+ }
225
+ const sortedKeys = [...classes.keys()].sort();
226
+ const blocks = [];
227
+ for (const key of sortedKeys) {
228
+ const klass = classes.get(key);
229
+ if (klass === void 0) continue;
230
+ const header = `[${klass.source}] ${klass.level} \xD7${klass.count}: ${klass.normalized}`;
231
+ const lines = klass.samples.map((sample) => `${SAMPLE_PREFIX}${sample}`);
232
+ blocks.push([header, ...lines].join("\n"));
233
+ }
234
+ return blocks.join("\n");
235
+ }
236
+ function guardBlob(value) {
237
+ if (value === void 0) return void 0;
238
+ const str = safeStringify(value);
239
+ if (str.length <= BLOB_CEILING) return str;
240
+ return str.slice(0, BLOB_CEILING) + TRUNCATION_MARKER;
241
+ }
242
+ function asLogEntry(value) {
243
+ if (typeof value !== "object" || value === null) return void 0;
244
+ const c = value;
245
+ const text = typeof c.text === "string" ? c.text : typeof c.message === "string" ? c.message : void 0;
246
+ if (text !== void 0) {
247
+ return {
248
+ source: typeof c.source === "string" ? c.source : "console",
249
+ level: typeof c.level === "string" ? c.level : void 0,
250
+ message: text
251
+ };
252
+ }
253
+ const n = value;
254
+ if (typeof n.url === "string" && typeof n.method === "string") {
255
+ return {
256
+ source: "network",
257
+ level: n.status === void 0 ? void 0 : String(n.status),
258
+ message: `${n.method} ${n.url}`
259
+ };
260
+ }
261
+ return void 0;
262
+ }
263
+ function guardToolOutput(value) {
264
+ if (Array.isArray(value) && value.length > 0) {
265
+ const entries = value.map(asLogEntry);
266
+ if (entries.every((e) => e !== void 0)) {
267
+ const compacted = compactLogs(entries);
268
+ if (compacted.length <= BLOB_CEILING) return compacted;
269
+ return compacted.slice(0, BLOB_CEILING) + TRUNCATION_MARKER;
270
+ }
271
+ }
272
+ return guardBlob(value);
273
+ }
274
+ function safeStringify(value) {
275
+ const seen = /* @__PURE__ */ new WeakSet();
276
+ try {
277
+ return JSON.stringify(value, (_key, node) => {
278
+ if (typeof node === "object" && node !== null) {
279
+ if (seen.has(node)) return "[Circular]";
280
+ seen.add(node);
281
+ }
282
+ return node;
283
+ }) ?? "undefined";
284
+ } catch {
285
+ return "[unserializable]";
286
+ }
287
+ }
288
+
289
+ // src/capability/overflow-parse.ts
290
+ var import_provider = require("@ai-sdk/provider");
291
+ var PATTERNS = [
292
+ /maximum context length is (\d+) tokens/i,
293
+ />\s*(\d+)\s*maximum/i,
294
+ /maximum number of tokens allowed \((\d+)\)/i
295
+ ];
296
+ var MIN_WINDOW = 512;
297
+ var MAX_WINDOW = 1e7;
298
+ function parseRealWindow(error) {
299
+ if (!import_provider.APICallError.isInstance(error) || error.statusCode !== 400) return void 0;
300
+ const text = `${error.message ?? ""}
301
+ ${error.responseBody ?? ""}`;
302
+ for (const pattern of PATTERNS) {
303
+ const match = pattern.exec(text);
304
+ if (!match) continue;
305
+ const parsed = Number.parseInt(match[1], 10);
306
+ if (Number.isFinite(parsed) && parsed >= MIN_WINDOW && parsed <= MAX_WINDOW) {
307
+ return parsed;
308
+ }
309
+ }
310
+ return void 0;
311
+ }
312
+ function isContextOverflow(error) {
313
+ return parseRealWindow(error) !== void 0;
314
+ }
315
+
316
+ // src/accounting/degrade.ts
317
+ var import_ai2 = require("ai");
318
+ var SCREENSHOT_OMITTED = "\u2026[historical screenshot omitted]";
319
+ var DUPLICATE_ELIDED = "\u2026[duplicate tool result elided]";
320
+ var TRUNCATION_MARKER2 = "\u2026[truncated to fit context budget]";
321
+ function degrade(messages, options) {
322
+ const estimate = options.estimate ?? defaultEstimate;
323
+ let working = runHygiene(messages);
324
+ if (estimate(protectedMessages(working, options)) > options.budget) {
325
+ return { ok: false, reason: "pinned-content-exceeds-budget", messages: working };
326
+ }
327
+ while (estimate(working) > options.budget) {
328
+ const evicted = evictOldestExchange(working, options);
329
+ if (!evicted) break;
330
+ working = evicted;
331
+ }
332
+ const exhausted = /* @__PURE__ */ new Set();
333
+ while (estimate(working) > options.budget) {
334
+ const isProtectedAt = makeIsProtected(working, options);
335
+ let targetIndex = -1;
336
+ let targetLength = 0;
337
+ working.forEach((message, index) => {
338
+ if (isProtectedAt(index) || exhausted.has(index)) return;
339
+ const length = messageTextLength(message);
340
+ if (length > targetLength) {
341
+ targetLength = length;
342
+ targetIndex = index;
343
+ }
344
+ });
345
+ if (targetIndex === -1 || targetLength === 0) break;
346
+ const overshootChars = Math.max(1, (estimate(working) - options.budget) * 4);
347
+ const keepChars = Math.max(0, targetLength - overshootChars);
348
+ const truncatedMessage = truncateMessage(working[targetIndex], keepChars);
349
+ if (messageTextLength(truncatedMessage) >= messageTextLength(working[targetIndex])) {
350
+ exhausted.add(targetIndex);
351
+ continue;
352
+ }
353
+ working = working.map((message, index) => index === targetIndex ? truncatedMessage : message);
354
+ if (keepChars === 0) exhausted.add(targetIndex);
355
+ }
356
+ return { ok: true, messages: working };
357
+ }
358
+ function defaultEstimate(messages) {
359
+ let chars = 0;
360
+ for (const message of messages) chars += messageTextLength(message);
361
+ return Math.ceil(chars / 4);
362
+ }
363
+ function makeIsProtected(messages, options) {
364
+ const lastIndex = messages.length - 1;
365
+ return (index) => {
366
+ const message = messages[index];
367
+ if (message.role === "system") return true;
368
+ if (index === lastIndex) return true;
369
+ return options.pin ? options.pin(message, index) === true : false;
370
+ };
371
+ }
372
+ function protectedMessages(messages, options) {
373
+ const isProtectedAt = makeIsProtected(messages, options);
374
+ return messages.filter((_, index) => isProtectedAt(index));
375
+ }
376
+ function toolCallIdsOf(message) {
377
+ if (message.role !== "assistant" || !Array.isArray(message.content)) return [];
378
+ const ids = [];
379
+ for (const part of message.content) if (part.type === "tool-call") ids.push(part.toolCallId);
380
+ return ids;
381
+ }
382
+ function resultIdsOf(message) {
383
+ const ids = [];
384
+ if (message.role === "tool") {
385
+ for (const part of message.content) if (part.type === "tool-result") ids.push(part.toolCallId);
386
+ } else if (message.role === "assistant" && Array.isArray(message.content)) {
387
+ for (const part of message.content) if (part.type === "tool-result") ids.push(part.toolCallId);
388
+ }
389
+ return ids;
390
+ }
391
+ function evictOldestExchange(messages, options) {
392
+ const isProtectedAt = makeIsProtected(messages, options);
393
+ for (let i = 0; i < messages.length; i++) {
394
+ const callIds = toolCallIdsOf(messages[i]);
395
+ if (callIds.length === 0) continue;
396
+ const idSet = new Set(callIds);
397
+ const exchange = /* @__PURE__ */ new Set([i]);
398
+ for (let j = 0; j < messages.length; j++) {
399
+ if (j === i) continue;
400
+ if (resultIdsOf(messages[j]).some((id) => idSet.has(id))) exchange.add(j);
401
+ }
402
+ let evictable = true;
403
+ for (const index of exchange) {
404
+ if (isProtectedAt(index)) {
405
+ evictable = false;
406
+ break;
407
+ }
408
+ }
409
+ if (!evictable) continue;
410
+ return messages.filter((_, index) => !exchange.has(index));
411
+ }
412
+ return void 0;
413
+ }
414
+ function isRecord(value) {
415
+ return typeof value === "object" && value !== null;
416
+ }
417
+ function messageTextLength(message) {
418
+ const content = message.content;
419
+ if (typeof content === "string") return content.length;
420
+ let total = 0;
421
+ for (const part of content) total += partTextLength(part);
422
+ return total;
423
+ }
424
+ function partTextLength(part) {
425
+ if (!isRecord(part)) return 0;
426
+ if (part.type === "text" && typeof part.text === "string") return part.text.length;
427
+ if (part.type === "tool-result") return outputTextLength(part.output);
428
+ return 0;
429
+ }
430
+ function outputTextLength(output) {
431
+ if (!isRecord(output)) return 0;
432
+ if ((output.type === "text" || output.type === "error-text") && typeof output.value === "string") {
433
+ return output.value.length;
434
+ }
435
+ if (output.type === "content" && Array.isArray(output.value)) {
436
+ let total = 0;
437
+ for (const item of output.value) {
438
+ if (isRecord(item) && item.type === "text" && typeof item.text === "string") total += item.text.length;
439
+ }
440
+ return total;
441
+ }
442
+ return 0;
443
+ }
444
+ function truncateMessage(message, keepChars) {
445
+ const content = message.content;
446
+ if (typeof content === "string") {
447
+ return { ...message, content: sliceWithMarker(content, keepChars) };
448
+ }
449
+ const parts = content;
450
+ let largestIndex = -1;
451
+ let largestLength = -1;
452
+ parts.forEach((part, index) => {
453
+ const length = partTextLength(part);
454
+ if (length > largestLength) {
455
+ largestLength = length;
456
+ largestIndex = index;
457
+ }
458
+ });
459
+ if (largestIndex === -1 || largestLength <= 0) return message;
460
+ const removeTarget = Math.max(0, messageTextLength(message) - Math.max(0, keepChars));
461
+ const partKeep = Math.max(0, largestLength - removeTarget);
462
+ const newParts = parts.map((part, index) => index === largestIndex ? truncatePart(part, partKeep) : part);
463
+ return { ...message, content: newParts };
464
+ }
465
+ function sliceWithMarker(text, keep) {
466
+ const base = text.endsWith(TRUNCATION_MARKER2) ? text.slice(0, text.length - TRUNCATION_MARKER2.length) : text;
467
+ return base.slice(0, Math.max(0, keep)) + TRUNCATION_MARKER2;
468
+ }
469
+ function truncatePart(part, keep) {
470
+ if (!isRecord(part)) return part;
471
+ if (part.type === "text" && typeof part.text === "string") {
472
+ return { ...part, text: sliceWithMarker(part.text, keep) };
473
+ }
474
+ if (part.type === "tool-result") {
475
+ return { ...part, output: truncateOutput(part.output, keep) };
476
+ }
477
+ return part;
478
+ }
479
+ function truncateOutput(output, keep) {
480
+ if (!isRecord(output)) return output;
481
+ if ((output.type === "text" || output.type === "error-text") && typeof output.value === "string") {
482
+ return { ...output, value: sliceWithMarker(output.value, keep) };
483
+ }
484
+ return output;
485
+ }
486
+ function runHygiene(messages) {
487
+ const pruned = (0, import_ai2.pruneMessages)({
488
+ messages,
489
+ reasoning: "before-last-message",
490
+ emptyMessages: "remove"
491
+ });
492
+ return clearHistoricalToolResults(pruned);
493
+ }
494
+ function clearHistoricalToolResults(messages) {
495
+ let lastToolIndex = -1;
496
+ for (let i = messages.length - 1; i >= 0; i--) {
497
+ if (messages[i].role === "tool") {
498
+ lastToolIndex = i;
499
+ break;
500
+ }
501
+ }
502
+ const seenHashes = /* @__PURE__ */ new Set();
503
+ return messages.map((message, index) => {
504
+ if (message.role !== "tool" || index === lastToolIndex) return message;
505
+ const rewritten = message.content.map((part) => rewriteHistoricalPart(part, seenHashes));
506
+ return { ...message, content: rewritten };
507
+ });
508
+ }
509
+ function rewriteHistoricalPart(part, seenHashes) {
510
+ if (part.type !== "tool-result") return part;
511
+ const hash = contentHash(part.output);
512
+ if (seenHashes.has(hash)) {
513
+ return { ...part, output: { type: "text", value: DUPLICATE_ELIDED } };
514
+ }
515
+ seenHashes.add(hash);
516
+ const stripped = stripScreenshots(part.output);
517
+ return stripped === part.output ? part : { ...part, output: stripped };
518
+ }
519
+ function stripScreenshots(output) {
520
+ if (output.type !== "content") return output;
521
+ let changed = false;
522
+ const value = output.value.map((item) => {
523
+ if (item.type === "image-data" || item.type === "media") {
524
+ changed = true;
525
+ return { type: "text", text: SCREENSHOT_OMITTED };
526
+ }
527
+ return item;
528
+ });
529
+ return changed ? { type: "content", value } : output;
530
+ }
531
+ function contentHash(value) {
532
+ const str = safeStringify2(value);
533
+ let hash = 2166136261;
534
+ for (let i = 0; i < str.length; i++) {
535
+ hash ^= str.charCodeAt(i);
536
+ hash = Math.imul(hash, 16777619);
537
+ }
538
+ return (hash >>> 0).toString(16);
539
+ }
540
+ function safeStringify2(value) {
541
+ const ancestors = [];
542
+ const walk = (node) => {
543
+ if (node === null || typeof node !== "object") return node;
544
+ if (ancestors.includes(node)) return "[Circular]";
545
+ ancestors.push(node);
546
+ let result;
547
+ if (Array.isArray(node)) {
548
+ result = node.map(walk);
549
+ } else {
550
+ const sortedKeys = Object.keys(node).sort();
551
+ const obj = {};
552
+ for (const key of sortedKeys) obj[key] = walk(node[key]);
553
+ result = obj;
554
+ }
555
+ ancestors.pop();
556
+ return result;
557
+ };
558
+ try {
559
+ return JSON.stringify(walk(value)) ?? "undefined";
560
+ } catch {
561
+ return "[unserializable]";
562
+ }
563
+ }
564
+
565
+ // src/accounting/token-accounting.ts
566
+ var DEFAULT_PER_IMAGE_TOKENS = 1600;
567
+ function createTokenAccounting(options) {
568
+ const perImageTokens = options.perImageTokens ?? DEFAULT_PER_IMAGE_TOKENS;
569
+ let anchor;
570
+ function estimate(messages) {
571
+ let chars = 0;
572
+ let images = 0;
573
+ for (const message of messages) {
574
+ chars += messageTextChars(message);
575
+ images += messageImageCount(message);
576
+ }
577
+ let textTokens = Math.ceil(chars / 4);
578
+ if (anchor !== void 0 && prefixMatches(messages, anchor)) {
579
+ textTokens = Math.max(textTokens, anchor.promptTokens);
580
+ }
581
+ return textTokens + images * perImageTokens;
582
+ }
583
+ function recordUsage(usage, messages) {
584
+ const inputTokens = usage.inputTokens;
585
+ if (inputTokens === void 0) return;
586
+ anchor = { promptTokens: inputTokens, prefixLength: messages.length, prefixDigest: digestPrefix(messages) };
587
+ }
588
+ function getCeilings() {
589
+ const c = options.getCapabilities();
590
+ return { contextWindow: c.contextWindow, maxOutput: c.maxOutput };
591
+ }
592
+ function degrade2(messages, opts) {
593
+ return degrade(messages, { ...opts, estimate });
594
+ }
595
+ return { estimate, recordUsage, getCeilings, degrade: degrade2 };
596
+ }
597
+ function prefixMatches(messages, anchor) {
598
+ if (messages.length < anchor.prefixLength) return false;
599
+ const prefix = messages.length === anchor.prefixLength ? messages : messages.slice(0, anchor.prefixLength);
600
+ return digestPrefix(prefix) === anchor.prefixDigest;
601
+ }
602
+ function messageTextChars(message) {
603
+ const content = message.content;
604
+ if (typeof content === "string") return content.length;
605
+ let total = 0;
606
+ for (const part of content) total += partTextChars(part);
607
+ return total;
608
+ }
609
+ function partTextChars(part) {
610
+ if (!isRecord2(part)) return 0;
611
+ if (part.type === "text" && typeof part.text === "string") return part.text.length;
612
+ if (part.type === "tool-result") return outputTextChars(part.output);
613
+ return 0;
614
+ }
615
+ function outputTextChars(output) {
616
+ if (!isRecord2(output)) return 0;
617
+ if ((output.type === "text" || output.type === "error-text") && typeof output.value === "string") {
618
+ return output.value.length;
619
+ }
620
+ if (output.type === "content" && Array.isArray(output.value)) {
621
+ let total = 0;
622
+ for (const item of output.value) {
623
+ if (isRecord2(item) && item.type === "text" && typeof item.text === "string") total += item.text.length;
624
+ }
625
+ return total;
626
+ }
627
+ return 0;
628
+ }
629
+ function messageImageCount(message) {
630
+ const content = message.content;
631
+ if (typeof content === "string") return 0;
632
+ let count2 = 0;
633
+ for (const part of content) {
634
+ if (!isRecord2(part)) continue;
635
+ if (part.type === "image") count2 += 1;
636
+ else if (part.type === "tool-result") count2 += outputImageCount(part.output);
637
+ }
638
+ return count2;
639
+ }
640
+ function outputImageCount(output) {
641
+ if (!isRecord2(output) || output.type !== "content" || !Array.isArray(output.value)) return 0;
642
+ let count2 = 0;
643
+ for (const item of output.value) {
644
+ if (isRecord2(item) && (item.type === "image-data" || item.type === "media")) count2 += 1;
645
+ }
646
+ return count2;
647
+ }
648
+ function isRecord2(value) {
649
+ return typeof value === "object" && value !== null;
650
+ }
651
+ function digestPrefix(messages) {
652
+ const str = safeStringify3(messages);
653
+ let hash = 2166136261;
654
+ for (let i = 0; i < str.length; i++) {
655
+ hash ^= str.charCodeAt(i);
656
+ hash = Math.imul(hash, 16777619);
657
+ }
658
+ return `${messages.length}:${(hash >>> 0).toString(16)}`;
659
+ }
660
+ function safeStringify3(value) {
661
+ const ancestors = [];
662
+ const walk = (node) => {
663
+ if (node === null || typeof node !== "object") return node;
664
+ if (ancestors.includes(node)) return "[Circular]";
665
+ ancestors.push(node);
666
+ let result;
667
+ if (Array.isArray(node)) {
668
+ result = node.map(walk);
669
+ } else {
670
+ const sortedKeys = Object.keys(node).sort();
671
+ const obj = {};
672
+ for (const key of sortedKeys) obj[key] = walk(node[key]);
673
+ result = obj;
674
+ }
675
+ ancestors.pop();
676
+ return result;
677
+ };
678
+ try {
679
+ return JSON.stringify(walk(value)) ?? "undefined";
680
+ } catch {
681
+ return "[unserializable]";
682
+ }
683
+ }
684
+
685
+ // src/capability/family-table.ts
686
+ function caps(contextWindow, maxOutput, vision, visionToolMessages) {
687
+ return {
688
+ text: true,
689
+ vision,
690
+ visionToolMessages,
691
+ toolCalling: true,
692
+ structuredOutput: true,
693
+ streaming: true,
694
+ contextWindow,
695
+ maxOutput
696
+ };
697
+ }
698
+ var UNKNOWN_FLOOR = caps(8192, 4096, false, false);
699
+ var FAMILIES = [
700
+ { match: ["claude-3-5-haiku", "claude-haiku"], caps: caps(2e5, 8192, true, true) },
701
+ { match: ["claude-opus", "claude-sonnet", "claude-"], caps: caps(2e5, 32e3, true, true) },
702
+ { match: ["gpt-4o"], caps: caps(128e3, 16384, true, false) },
703
+ { match: ["gpt-4.1"], caps: caps(1047576, 32768, true, false) },
704
+ { match: ["gpt-5"], caps: caps(4e5, 128e3, true, false) },
705
+ { match: ["o1", "o3", "o4"], caps: caps(2e5, 1e5, true, false) },
706
+ { match: ["gpt-4"], caps: caps(8192, 4096, false, false) },
707
+ { match: ["gpt-3.5"], caps: caps(16385, 4096, false, false) },
708
+ { match: ["gpt-"], caps: caps(128e3, 16384, true, false) },
709
+ { match: ["gemini-2.5", "gemini-3", "gemini-1.5", "gemini-"], caps: caps(1048576, 65536, true, true) },
710
+ { match: ["gemini-2.0-flash"], caps: caps(1048576, 8192, true, true) },
711
+ { match: ["deepseek-chat", "deepseek-r1", "deepseek-"], caps: caps(65536, 8192, false, false) },
712
+ { match: ["qwen2.5-vl", "qwen-vl", "qwen2-vl"], caps: caps(32768, 8192, true, false) },
713
+ { match: ["qwen"], caps: caps(32768, 8192, false, false) },
714
+ { match: ["llava"], caps: caps(8192, 4096, true, false) },
715
+ { match: ["llama-3-vision", "llama3.2-vision", "vision"], caps: caps(128e3, 8192, true, false) },
716
+ { match: ["llama-3", "llama3"], caps: caps(128e3, 8192, false, false) },
717
+ { match: ["llama"], caps: caps(8192, 4096, false, false) },
718
+ { match: ["pixtral"], caps: caps(128e3, 8192, true, false) },
719
+ { match: ["mixtral", "mistral"], caps: caps(32768, 8192, false, false) }
720
+ ];
721
+ var BOUNDARIES = /* @__PURE__ */ new Set(["-", "_", ".", "/", ":"]);
722
+ function matchesAtBoundary(id, token) {
723
+ let from = 0;
724
+ for (; ; ) {
725
+ const idx = id.indexOf(token, from);
726
+ if (idx === -1) return false;
727
+ if (idx === 0 || BOUNDARIES.has(id[idx - 1])) return true;
728
+ from = idx + 1;
729
+ }
730
+ }
731
+ function matchFamily(model) {
732
+ const id = model.toLowerCase();
733
+ let best;
734
+ for (const family of FAMILIES) {
735
+ for (const match of family.match) {
736
+ const normalized = match.toLowerCase();
737
+ if (!matchesAtBoundary(id, normalized)) continue;
738
+ if (!best || normalized.length > best.length) {
739
+ best = { length: normalized.length, caps: family.caps };
740
+ }
741
+ }
742
+ }
743
+ return best?.caps;
744
+ }
745
+
746
+ // src/capability/override-store.ts
747
+ var overrideStore = /* @__PURE__ */ new Map();
748
+ function capabilityKey(provider, model) {
749
+ return `${provider}:${model.toLowerCase().trim()}`;
750
+ }
751
+ function getObservedWindow(key) {
752
+ return overrideStore.get(key);
753
+ }
754
+
755
+ // src/capability/resolve.ts
756
+ function resolveCapabilities(profile) {
757
+ const base = matchFamily(profile.model) ?? UNKNOWN_FLOOR;
758
+ const declared = { ...base, ...profile.capabilities ?? {} };
759
+ const observed = getObservedWindow(capabilityKey(profile.provider, profile.model));
760
+ if (observed !== void 0) {
761
+ return { ...declared, contextWindow: observed };
762
+ }
763
+ return declared;
764
+ }
765
+
766
+ // src/catalog/catalog.ts
767
+ function deriveVision(id, override) {
768
+ return override ?? matchFamily(id)?.vision ?? false;
769
+ }
770
+ function expose(entry) {
771
+ return {
772
+ id: entry.id,
773
+ label: entry.label,
774
+ vision: deriveVision(entry.id, entry.vision),
775
+ ...entry.notes ? { notes: entry.notes } : {}
776
+ };
777
+ }
778
+ var CLAUDE = [
779
+ { id: "claude-opus-4-8", label: "Claude Opus 4.8" },
780
+ { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6" },
781
+ { id: "claude-haiku-4-5", label: "Claude Haiku 4.5" }
782
+ ];
783
+ var OPENAI_CLOUD = [
784
+ { id: "gpt-5.5", label: "GPT-5.5" },
785
+ { id: "gpt-4.1", label: "GPT-4.1" },
786
+ { id: "o3", label: "o3" },
787
+ { id: "o4-mini", label: "o4-mini" }
788
+ ];
789
+ var LOCAL_OPENAI_WIRE = [
790
+ {
791
+ id: "deepseek-chat",
792
+ label: "DeepSeek Chat",
793
+ notes: "text-only model; use accessibility tree and DOM context."
794
+ },
795
+ { id: "deepseek-r1", label: "DeepSeek R1", notes: "Text-only reasoning model." },
796
+ { id: "qwen2.5-vl", label: "Qwen2.5 VL" },
797
+ { id: "llava", label: "LLaVA" },
798
+ { id: "llama3.2-vision", label: "Llama 3.2 Vision" }
799
+ ];
800
+ var GEMINI = [
801
+ { id: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview" },
802
+ { id: "gemini-2.5-pro", label: "Gemini 2.5 Pro" },
803
+ { id: "gemini-2.5-flash", label: "Gemini 2.5 Flash" }
804
+ ];
805
+ var AUTHORED = {
806
+ "openai-compatible": [...OPENAI_CLOUD, ...LOCAL_OPENAI_WIRE],
807
+ "anthropic-compatible": CLAUDE,
808
+ "openai-subscription": OPENAI_CLOUD,
809
+ "anthropic-subscription": CLAUDE,
810
+ gemini: GEMINI
811
+ };
812
+ function exposeCatalog() {
813
+ return {
814
+ "openai-compatible": AUTHORED["openai-compatible"].map(expose),
815
+ "anthropic-compatible": AUTHORED["anthropic-compatible"].map(expose),
816
+ "openai-subscription": AUTHORED["openai-subscription"].map(expose),
817
+ "anthropic-subscription": AUTHORED["anthropic-subscription"].map(expose),
818
+ gemini: AUTHORED.gemini.map(expose)
819
+ };
820
+ }
821
+ var MODEL_CATALOG = exposeCatalog();
822
+ function getModelCatalog() {
823
+ return {
824
+ "openai-compatible": MODEL_CATALOG["openai-compatible"].map((entry) => ({ ...entry })),
825
+ "anthropic-compatible": MODEL_CATALOG["anthropic-compatible"].map((entry) => ({ ...entry })),
826
+ "openai-subscription": MODEL_CATALOG["openai-subscription"].map((entry) => ({ ...entry })),
827
+ "anthropic-subscription": MODEL_CATALOG["anthropic-subscription"].map((entry) => ({ ...entry })),
828
+ gemini: MODEL_CATALOG.gemini.map((entry) => ({ ...entry }))
829
+ };
830
+ }
831
+
832
+ // src/catalog/live.ts
833
+ var liveCache = /* @__PURE__ */ new Map();
834
+ var DEFAULT_TIMEOUT_MS = 2500;
835
+ var DEFAULT_TTL_MS = 6e4;
836
+ var MAX_LIVE_MODELS = 1e3;
837
+ function normalizeBaseURL(baseURL) {
838
+ return baseURL.trim().replace(/\/+$/, "");
839
+ }
840
+ function cacheKey(baseURL) {
841
+ return normalizeBaseURL(baseURL).toLowerCase();
842
+ }
843
+ function liveEntry(id) {
844
+ return {
845
+ id,
846
+ label: id,
847
+ vision: matchFamily(id)?.vision ?? false
848
+ };
849
+ }
850
+ function parseLiveBody(body) {
851
+ if (!body || typeof body !== "object" || !Array.isArray(body.data)) {
852
+ return [];
853
+ }
854
+ return body.data.slice(0, MAX_LIVE_MODELS).flatMap((model) => {
855
+ if (!model || typeof model !== "object") return [];
856
+ const id = model.id;
857
+ return typeof id === "string" && id.trim() ? [liveEntry(id)] : [];
858
+ });
859
+ }
860
+ async function fetchLiveModels(opts) {
861
+ const normalized = normalizeBaseURL(opts.baseURL);
862
+ if (!normalized) return [];
863
+ const now = Date.now();
864
+ const key = cacheKey(normalized);
865
+ const cached = liveCache.get(key);
866
+ if (cached && cached.expiresAt > now) return cached.entries;
867
+ const controller = new AbortController();
868
+ const timeout = setTimeout(() => controller.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
869
+ try {
870
+ const doFetch = opts.fetchImpl ?? globalThis.fetch;
871
+ const res = await doFetch(`${normalized}/models`, {
872
+ signal: controller.signal,
873
+ ...opts.headers ? { headers: opts.headers } : {}
874
+ });
875
+ if (!res.ok) return [];
876
+ const entries = parseLiveBody(await res.json());
877
+ liveCache.set(key, {
878
+ entries,
879
+ expiresAt: Date.now() + (opts.ttlMs ?? DEFAULT_TTL_MS)
880
+ });
881
+ return entries;
882
+ } catch {
883
+ return [];
884
+ } finally {
885
+ clearTimeout(timeout);
886
+ }
887
+ }
888
+ function mergeCatalog(staticEntries, live) {
889
+ const seen = new Set(staticEntries.map((entry) => entry.id.toLowerCase()));
890
+ return [...staticEntries, ...live.filter((entry) => !seen.has(entry.id.toLowerCase()))];
891
+ }
892
+
893
+ // src/middleware.ts
894
+ var toolSchemaMiddleware = {
895
+ specificationVersion: "v3",
896
+ transformParams: async ({ params }) => {
897
+ if (!params.tools) return params;
898
+ return {
899
+ ...params,
900
+ tools: params.tools.map((t) => {
901
+ if (t.type !== "function") return t;
902
+ const schema = { ...t.inputSchema };
903
+ if ("$schema" in schema) delete schema.$schema;
904
+ if (!schema.type) schema.type = "object";
905
+ return { ...t, inputSchema: schema };
906
+ })
907
+ };
908
+ }
909
+ };
910
+
911
+ // src/middleware/capability-update.ts
912
+ function capabilityUpdateMiddleware(profile) {
913
+ const key = capabilityKey(profile.provider, profile.model);
914
+ async function observe(call) {
915
+ try {
916
+ return await call();
917
+ } catch (error) {
918
+ const observedWindow = parseRealWindow(error);
919
+ if (observedWindow !== void 0) {
920
+ overrideStore.set(key, observedWindow);
921
+ }
922
+ throw error;
923
+ }
924
+ }
925
+ return {
926
+ specificationVersion: "v3",
927
+ wrapGenerate: ({ doGenerate }) => observe(doGenerate),
928
+ wrapStream: ({ doStream }) => observe(doStream)
929
+ };
930
+ }
931
+
932
+ // src/middleware/debug-logging.ts
933
+ var REQUEST_PREFIX = "[agent-qa:llm] request";
934
+ var ERROR_PREFIX = "[agent-qa:llm] provider-error";
935
+ function isEnvEnabled() {
936
+ const raw = typeof process !== "undefined" ? process.env?.AGENT_QA_DEBUG_LLM : void 0;
937
+ if (typeof raw !== "string") return false;
938
+ const value = raw.trim().toLowerCase();
939
+ return value !== "" && value !== "0" && value !== "false" && value !== "off" && value !== "no";
940
+ }
941
+ function modelIdOf(model) {
942
+ if (model && typeof model === "object" && "modelId" in model) {
943
+ const id = model.modelId;
944
+ if (typeof id === "string" && id.length > 0) return id;
945
+ }
946
+ return "unknown";
947
+ }
948
+ function requestShapeLine(params, model) {
949
+ const record = params;
950
+ const prompt = record.prompt;
951
+ const messages = Array.isArray(prompt) ? prompt : [];
952
+ const roles = messages.map((message) => message.role ?? "?").join(",");
953
+ const toolCount = Array.isArray(record.tools) ? record.tools.length : 0;
954
+ const paramKeys = Object.keys(record).filter((key) => key !== "prompt" && key !== "tools").join(",");
955
+ return `${REQUEST_PREFIX} model=${modelIdOf(model)} messages=${messages.length} roles=[${roles}] tools=${toolCount} params=[${paramKeys}]`;
956
+ }
957
+ function compactRequestBodyValues(value) {
958
+ if (value === null || typeof value !== "object") return void 0;
959
+ const record = value;
960
+ const model = typeof record.model === "string" ? record.model : void 0;
961
+ const items = Array.isArray(record.input) ? record.input : Array.isArray(record.messages) ? record.messages : void 0;
962
+ const roles = items?.map(
963
+ (item) => item && typeof item === "object" && "role" in item ? String(item.role) : "?"
964
+ );
965
+ const parts = [];
966
+ if (model) parts.push(`model=${model}`);
967
+ if (roles) parts.push(`roles=[${roles.join(",")}]`);
968
+ return parts.length > 0 ? `{${parts.join(",")}}` : void 0;
969
+ }
970
+ function originAndPath(url) {
971
+ if (typeof url !== "string") return void 0;
972
+ try {
973
+ const parsed = new URL(url);
974
+ return `${parsed.origin}${parsed.pathname}`;
975
+ } catch {
976
+ return void 0;
977
+ }
978
+ }
979
+ function stringField(record, key) {
980
+ if (record === null || typeof record !== "object") return void 0;
981
+ const value = record[key];
982
+ return typeof value === "string" ? value : void 0;
983
+ }
984
+ function providerErrorLine(err) {
985
+ const e = err ?? {};
986
+ const statusCode = typeof e.statusCode === "number" ? e.statusCode : void 0;
987
+ const url = originAndPath(e.url);
988
+ const responseBody = typeof e.responseBody === "string" ? e.responseBody : void 0;
989
+ const request = compactRequestBodyValues(e.requestBodyValues);
990
+ const nested = e.data !== null && typeof e.data === "object" ? e.data.error : void 0;
991
+ const type = stringField(nested, "type") ?? stringField(e.data, "type");
992
+ const code = stringField(nested, "code") ?? stringField(e.data, "code");
993
+ const headerNames = e.responseHeaders !== null && typeof e.responseHeaders === "object" ? Object.keys(e.responseHeaders) : void 0;
994
+ const parts = [ERROR_PREFIX];
995
+ if (statusCode !== void 0) parts.push(`statusCode=${statusCode}`);
996
+ if (typeof e.name === "string") parts.push(`name=${e.name}`);
997
+ if (typeof e.isRetryable === "boolean") parts.push(`isRetryable=${e.isRetryable}`);
998
+ if (url !== void 0) parts.push(`url=${url}`);
999
+ if (type !== void 0) parts.push(`type=${type}`);
1000
+ if (code !== void 0) parts.push(`code=${code}`);
1001
+ if (headerNames !== void 0) parts.push(`responseHeaders=[${headerNames.join(",")}]`);
1002
+ if (responseBody !== void 0) parts.push(`responseBodyLength=${responseBody.length}`);
1003
+ if (request !== void 0) parts.push(`request=${request}`);
1004
+ if (statusCode === void 0 && responseBody === void 0) {
1005
+ const message = e.message !== void 0 ? String(e.message) : String(err);
1006
+ parts.push(`messageLength=${message.length}`);
1007
+ }
1008
+ return parts.join(" ");
1009
+ }
1010
+ function debugLoggingMiddleware(options = {}) {
1011
+ const enabled = options.enabled ?? isEnvEnabled();
1012
+ if (!enabled) {
1013
+ return { specificationVersion: "v3" };
1014
+ }
1015
+ const sink = options.sink ?? ((line) => {
1016
+ process.stderr.write(`${line}
1017
+ `);
1018
+ });
1019
+ const emit = (line) => {
1020
+ sink(line);
1021
+ };
1022
+ return {
1023
+ specificationVersion: "v3",
1024
+ wrapGenerate: async ({ doGenerate, params, model }) => {
1025
+ emit(requestShapeLine(params, model));
1026
+ try {
1027
+ return await doGenerate();
1028
+ } catch (err) {
1029
+ emit(providerErrorLine(err));
1030
+ throw err;
1031
+ }
1032
+ },
1033
+ wrapStream: async ({ doStream, params, model }) => {
1034
+ emit(requestShapeLine(params, model));
1035
+ try {
1036
+ return await doStream();
1037
+ } catch (err) {
1038
+ emit(providerErrorLine(err));
1039
+ throw err;
1040
+ }
1041
+ }
1042
+ };
1043
+ }
1044
+
1045
+ // src/middleware/drop-empty-messages.ts
1046
+ function isEmptyMessage(message) {
1047
+ if (message.role === "system") {
1048
+ return typeof message.content === "string" && message.content.trim().length === 0;
1049
+ }
1050
+ const parts = message.content;
1051
+ if (!Array.isArray(parts) || parts.length === 0) return true;
1052
+ for (const part of parts) {
1053
+ if (part.type === "text" || part.type === "reasoning") {
1054
+ if (typeof part.text === "string" && part.text.trim().length > 0) return false;
1055
+ } else {
1056
+ return false;
1057
+ }
1058
+ }
1059
+ return true;
1060
+ }
1061
+ function dropEmptyMessagesMiddleware() {
1062
+ return {
1063
+ specificationVersion: "v3",
1064
+ transformParams: async ({ params }) => {
1065
+ const prompt = params.prompt;
1066
+ if (!prompt) return params;
1067
+ const filtered = prompt.filter((message) => !isEmptyMessage(message));
1068
+ if (filtered.length === prompt.length) return params;
1069
+ return { ...params, prompt: filtered };
1070
+ }
1071
+ };
1072
+ }
1073
+
1074
+ // src/middleware/examples.ts
1075
+ function deriveExamplesMiddleware() {
1076
+ return {
1077
+ specificationVersion: "v3",
1078
+ transformParams: async ({ params }) => {
1079
+ if (!params.tools) return params;
1080
+ return {
1081
+ ...params,
1082
+ tools: params.tools.map((t) => {
1083
+ if (t.type !== "function") return t;
1084
+ if (t.inputExamples?.length) return t;
1085
+ const input = sampleFromSchema(t.inputSchema);
1086
+ if (!input || Object.keys(input).length === 0) return t;
1087
+ return { ...t, inputExamples: [{ input }] };
1088
+ })
1089
+ };
1090
+ }
1091
+ };
1092
+ }
1093
+ function sampleFromSchema(inputSchema) {
1094
+ const properties = inputSchema?.properties;
1095
+ if (!properties || Object.keys(properties).length === 0) return void 0;
1096
+ const fields = inputSchema?.required && inputSchema.required.length > 0 ? inputSchema.required : Object.keys(properties);
1097
+ const input = {};
1098
+ for (const field of fields) {
1099
+ if (!properties[field]) continue;
1100
+ input[field] = sampleValue(properties[field]);
1101
+ }
1102
+ return Object.keys(input).length > 0 ? input : void 0;
1103
+ }
1104
+ function sampleValue(schema) {
1105
+ const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
1106
+ switch (type) {
1107
+ case "string":
1108
+ return "";
1109
+ case "number":
1110
+ case "integer":
1111
+ return 0;
1112
+ case "boolean":
1113
+ return false;
1114
+ case "array":
1115
+ return [];
1116
+ case "object":
1117
+ return {};
1118
+ default:
1119
+ return null;
1120
+ }
1121
+ }
1122
+
1123
+ // src/middleware/extract-json.ts
1124
+ var MAX_SCAN_LENGTH = 2e5;
1125
+ function extractJsonStrategy(text) {
1126
+ const bounded = text.slice(0, MAX_SCAN_LENGTH);
1127
+ const fenced = bounded.match(/```(?:json)?[^\S\r\n]*(?:\r?\n)?([\s\S]*?)```/i);
1128
+ if (fenced?.[1] !== void 0) return fenced[1].trim();
1129
+ const span = firstJsonSpan(bounded);
1130
+ if (span) return span.trim();
1131
+ return bounded.trim();
1132
+ }
1133
+ function firstJsonSpan(text) {
1134
+ const start = firstJsonStart(text);
1135
+ if (start < 0) return void 0;
1136
+ const opener = text[start];
1137
+ const closer = opener === "{" ? "}" : "]";
1138
+ let depth = 0;
1139
+ let inString = false;
1140
+ let escaped = false;
1141
+ for (let index = start; index < text.length; index += 1) {
1142
+ const char = text[index];
1143
+ if (inString) {
1144
+ if (escaped) {
1145
+ escaped = false;
1146
+ } else if (char === "\\") {
1147
+ escaped = true;
1148
+ } else if (char === '"') {
1149
+ inString = false;
1150
+ }
1151
+ continue;
1152
+ }
1153
+ if (char === '"') {
1154
+ inString = true;
1155
+ } else if (char === opener) {
1156
+ depth += 1;
1157
+ } else if (char === closer) {
1158
+ depth -= 1;
1159
+ if (depth === 0) return text.slice(start, index + 1);
1160
+ }
1161
+ }
1162
+ return void 0;
1163
+ }
1164
+ function firstJsonStart(text) {
1165
+ const objectStart = text.indexOf("{");
1166
+ const arrayStart = text.indexOf("[");
1167
+ if (objectStart < 0) return arrayStart;
1168
+ if (arrayStart < 0) return objectStart;
1169
+ return Math.min(objectStart, arrayStart);
1170
+ }
1171
+
1172
+ // src/middleware/repair.ts
1173
+ var import_ai3 = require("ai");
1174
+ function repairMiddleware() {
1175
+ return {
1176
+ specificationVersion: "v3",
1177
+ async wrapGenerate({ doGenerate }) {
1178
+ const result = await doGenerate();
1179
+ const content = await Promise.all(
1180
+ result.content.map(async (part) => {
1181
+ if (part.type !== "tool-call" || typeof part.input !== "string") return part;
1182
+ try {
1183
+ JSON.parse(part.input);
1184
+ return part;
1185
+ } catch {
1186
+ const repaired = await (0, import_ai3.parsePartialJson)(part.input);
1187
+ if ((repaired.state === "repaired-parse" || repaired.state === "successful-parse") && repaired.value !== void 0) {
1188
+ return { ...part, input: JSON.stringify(repaired.value) };
1189
+ }
1190
+ return part;
1191
+ }
1192
+ })
1193
+ );
1194
+ return { ...result, content };
1195
+ },
1196
+ wrapStream({ doStream }) {
1197
+ return doStream();
1198
+ }
1199
+ };
1200
+ }
1201
+
1202
+ // src/middleware/retry.ts
1203
+ var import_provider3 = require("@ai-sdk/provider");
1204
+
1205
+ // src/middleware/classify.ts
1206
+ var import_provider2 = require("@ai-sdk/provider");
1207
+ var TRANSIENT_NETWORK_CODES = /* @__PURE__ */ new Set(["ECONNRESET", "ETIMEDOUT", "ECONNREFUSED", "EPIPE"]);
1208
+ function isTransientError(error) {
1209
+ return import_provider2.APICallError.isInstance(error) && error.isRetryable === true || isTransientNetworkError(error);
1210
+ }
1211
+ function isTransientNetworkError(error) {
1212
+ if (!error || typeof error !== "object") return false;
1213
+ const code = error.code;
1214
+ if (typeof code === "string" && TRANSIENT_NETWORK_CODES.has(code)) return true;
1215
+ if (error instanceof TypeError) {
1216
+ return /fetch failed|network|ECONNRESET|ETIMEDOUT|ECONNREFUSED|EPIPE/i.test(error.message);
1217
+ }
1218
+ return false;
1219
+ }
1220
+
1221
+ // src/middleware/retry.ts
1222
+ function retryMiddleware({
1223
+ maxRetries = 2,
1224
+ initialDelayInMs = 1e3,
1225
+ backoffFactor = 2
1226
+ } = {}) {
1227
+ async function run(call) {
1228
+ let delay = initialDelayInMs;
1229
+ for (let attempt = 0; ; attempt += 1) {
1230
+ try {
1231
+ return await call();
1232
+ } catch (error) {
1233
+ if (isAbortError(error)) throw error;
1234
+ if (!isTransientError(error) || attempt >= maxRetries) throw error;
1235
+ const headerDelay = retryAfterMs(error, delay);
1236
+ await sleep(headerDelay ?? delay);
1237
+ delay *= backoffFactor;
1238
+ }
1239
+ }
1240
+ }
1241
+ return {
1242
+ specificationVersion: "v3",
1243
+ wrapGenerate: ({ doGenerate }) => run(doGenerate),
1244
+ wrapStream: ({ doStream }) => run(doStream)
1245
+ };
1246
+ }
1247
+ function isAbortError(error) {
1248
+ return !!error && typeof error === "object" && error.name === "AbortError";
1249
+ }
1250
+ function retryAfterMs(error, delay) {
1251
+ if (!import_provider3.APICallError.isInstance(error)) return void 0;
1252
+ const headerMs = parseMs(error.responseHeaders?.["retry-after-ms"]);
1253
+ if (headerMs !== void 0 && shouldHonorRetryAfter(headerMs, delay)) return headerMs;
1254
+ const retryAfter = error.responseHeaders?.["retry-after"];
1255
+ const seconds = parseSeconds(retryAfter);
1256
+ if (seconds !== void 0 && shouldHonorRetryAfter(seconds, delay)) return seconds;
1257
+ return void 0;
1258
+ }
1259
+ function parseMs(value) {
1260
+ if (!value) return void 0;
1261
+ const parsed = Number.parseInt(value, 10);
1262
+ return Number.isFinite(parsed) ? parsed : void 0;
1263
+ }
1264
+ function parseSeconds(value) {
1265
+ if (!value) return void 0;
1266
+ const seconds = Number.parseFloat(value);
1267
+ if (Number.isFinite(seconds)) return Math.round(seconds * 1e3);
1268
+ const date = Date.parse(value);
1269
+ if (Number.isNaN(date)) return void 0;
1270
+ return date - Date.now();
1271
+ }
1272
+ function shouldHonorRetryAfter(ms, delay) {
1273
+ return ms >= 0 && (ms < 6e4 || ms < delay);
1274
+ }
1275
+ function sleep(ms) {
1276
+ if (ms <= 0) return Promise.resolve();
1277
+ return new Promise((resolve) => setTimeout(resolve, ms));
1278
+ }
1279
+
1280
+ // src/middleware/strip-unsupported-params.ts
1281
+ function stripUnsupportedParamsMiddleware(params) {
1282
+ return {
1283
+ specificationVersion: "v3",
1284
+ transformParams: async ({ params: callOptions }) => {
1285
+ const present = params.filter((name) => name in callOptions);
1286
+ if (present.length === 0) return callOptions;
1287
+ const next = { ...callOptions };
1288
+ for (const name of present) {
1289
+ delete next[name];
1290
+ }
1291
+ return next;
1292
+ }
1293
+ };
1294
+ }
1295
+
1296
+ // src/providers/builtins.ts
1297
+ function seedBuiltins() {
1298
+ registerProvider({
1299
+ id: "openai-compatible",
1300
+ label: "OpenAI-compatible",
1301
+ adapter: openaiCompatible,
1302
+ needsBaseURL: true,
1303
+ authModes: ["api-key"],
1304
+ credentialOptional: true,
1305
+ modelAdapter: "openai-responses",
1306
+ baseURLPlaceholder: "https://openrouter.ai/api/v1",
1307
+ defaultModel: "gpt-5.5"
1308
+ });
1309
+ registerProvider({
1310
+ id: "anthropic-compatible",
1311
+ label: "Anthropic-compatible",
1312
+ adapter: anthropicCompatible,
1313
+ needsBaseURL: true,
1314
+ authModes: ["api-key", "bearer-token"],
1315
+ credentialOptional: true,
1316
+ modelAdapter: "anthropic-messages",
1317
+ baseURLPlaceholder: "https://anthropic-proxy.example/messages",
1318
+ defaultModel: "claude-sonnet-4-6"
1319
+ });
1320
+ registerProvider({
1321
+ id: "openai-subscription",
1322
+ label: "OpenAI subscription",
1323
+ adapter: openaiSubscription,
1324
+ needsBaseURL: false,
1325
+ authModes: ["subscription"],
1326
+ subscription: true,
1327
+ modelAdapter: "openai-responses",
1328
+ defaultModel: "gpt-6.1-sol",
1329
+ // RUNX-01: the codex/ChatGPT-subscription Responses backend rejects the output cap
1330
+ // (`max_output_tokens`) with HTTP 400. Strip it at egress for this provider ONLY —
1331
+ // standard OpenAI-compatible `.chat()` endpoints and Anthropic support the cap.
1332
+ // 2026-10-20 (446-11, D-18): it also answers 400 "Unsupported parameter: temperature".
1333
+ unsupportedParams: ["maxOutputTokens", "temperature"]
1334
+ });
1335
+ registerProvider({
1336
+ id: "anthropic-subscription",
1337
+ label: "Anthropic subscription",
1338
+ adapter: anthropicSubscription,
1339
+ needsBaseURL: false,
1340
+ authModes: ["subscription"],
1341
+ subscription: true,
1342
+ modelAdapter: "anthropic-messages",
1343
+ defaultModel: "claude-sonnet-5-5"
1344
+ });
1345
+ registerProvider({
1346
+ id: "gemini",
1347
+ label: "Gemini",
1348
+ adapter: gemini,
1349
+ needsBaseURL: false,
1350
+ authModes: ["api-key"],
1351
+ defaultModel: "gemini-3-flash-preview"
1352
+ });
1353
+ }
1354
+
1355
+ // src/providers/registry.ts
1356
+ var registry = /* @__PURE__ */ new Map();
1357
+ function validateDescriptor(descriptor) {
1358
+ if (!descriptor.id?.trim()) {
1359
+ throw new Error("Provider descriptor id is required");
1360
+ }
1361
+ if (!descriptor.label?.trim()) {
1362
+ throw new Error(`Provider descriptor "${descriptor.id}" label is required`);
1363
+ }
1364
+ if (typeof descriptor.adapter !== "function") {
1365
+ throw new Error(`Provider descriptor "${descriptor.id}" adapter is required`);
1366
+ }
1367
+ if (!Array.isArray(descriptor.authModes) || descriptor.authModes.length === 0) {
1368
+ throw new Error(`Provider descriptor "${descriptor.id}" authModes must be a non-empty array`);
1369
+ }
1370
+ }
1371
+ function registerProvider(descriptor) {
1372
+ validateDescriptor(descriptor);
1373
+ registry.set(descriptor.id, descriptor);
1374
+ }
1375
+ function getProvider(id) {
1376
+ return registry.get(id);
1377
+ }
1378
+ function listProviders() {
1379
+ return [...registry.values()];
1380
+ }
1381
+ function clearProviderRegistry() {
1382
+ registry.clear();
1383
+ seedBuiltins();
1384
+ }
1385
+ seedBuiltins();
1386
+
1387
+ // src/registry.ts
1388
+ var import_ai4 = require("ai");
1389
+ var import_agent_qa_safety = require("@vostride/agent-qa-safety");
1390
+
1391
+ // src/validate.ts
1392
+ function validateProfile(profile) {
1393
+ if (profile.provider === "openai-compatible" && !profile.baseURL?.trim()) {
1394
+ throw new Error("OpenAI-Compatible provider requires a baseURL");
1395
+ }
1396
+ if (profile.provider === "anthropic-compatible" && !profile.baseURL?.trim()) {
1397
+ throw new Error("Anthropic-Compatible provider requires a baseURL");
1398
+ }
1399
+ if (profile.headers && profile.provider !== "anthropic-compatible" && profile.provider !== "openai-compatible") {
1400
+ throw new Error(
1401
+ `${displayProvider(profile.provider)} provider custom headers are only supported on anthropic-compatible`
1402
+ );
1403
+ }
1404
+ }
1405
+ function displayProvider(provider) {
1406
+ switch (provider) {
1407
+ case "openai-compatible":
1408
+ return "OpenAI-Compatible";
1409
+ case "anthropic-compatible":
1410
+ return "Anthropic-Compatible";
1411
+ case "openai-subscription":
1412
+ return "OpenAI Subscription";
1413
+ case "anthropic-subscription":
1414
+ return "Anthropic Subscription";
1415
+ case "gemini":
1416
+ return "Gemini";
1417
+ default:
1418
+ return provider;
1419
+ }
1420
+ }
1421
+
1422
+ // src/provider-call-report.ts
1423
+ var MODEL_CALL_EVENT_KINDS = [
1424
+ "start",
1425
+ "success",
1426
+ "failure"
1427
+ ];
1428
+ var MODEL_CALL_REPORT_ORIGINS = [
1429
+ "openai-chat",
1430
+ "openai-responses",
1431
+ "anthropic-messages",
1432
+ "gemini"
1433
+ ];
1434
+ function count(value) {
1435
+ return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : void 0;
1436
+ }
1437
+ function object(value) {
1438
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1439
+ }
1440
+ function providerCallReport(result, origin, mask) {
1441
+ const inputTokens = count(result.usage.inputTokens.total);
1442
+ const outputTokens = count(result.usage.outputTokens.total);
1443
+ const cachedInputTokens = rawCacheCount(result.usage, origin);
1444
+ const modelId = origin === void 0 ? void 0 : result.response?.modelId ?? (origin === "gemini" ? object(result.response?.body)?.modelVersion : void 0);
1445
+ const respondingModelId = typeof modelId === "string" && modelId.length > 0 ? mask(modelId) : void 0;
1446
+ return {
1447
+ ...inputTokens === void 0 ? {} : { inputTokens },
1448
+ ...outputTokens === void 0 ? {} : { outputTokens },
1449
+ ...cachedInputTokens === void 0 ? {} : { cachedInputTokens },
1450
+ ...respondingModelId === void 0 ? {} : { respondingModelId }
1451
+ };
1452
+ }
1453
+ function rawCacheCount(usage, origin) {
1454
+ const raw = object(usage.raw);
1455
+ if (!raw) return void 0;
1456
+ switch (origin) {
1457
+ case "openai-chat":
1458
+ return count(object(raw.prompt_tokens_details)?.cached_tokens);
1459
+ case "openai-responses":
1460
+ return count(object(raw.input_tokens_details)?.cached_tokens);
1461
+ case "anthropic-messages":
1462
+ return count(raw.cache_read_input_tokens);
1463
+ case "gemini":
1464
+ return count(raw.cachedContentTokenCount);
1465
+ case void 0:
1466
+ return void 0;
1467
+ default: {
1468
+ const exhaustive = origin;
1469
+ return exhaustive;
1470
+ }
1471
+ }
1472
+ }
1473
+
1474
+ // src/registry.ts
1475
+ var MIDDLEWARE = [
1476
+ retryMiddleware(),
1477
+ repairMiddleware(),
1478
+ (0, import_ai4.extractJsonMiddleware)({ transform: extractJsonStrategy }),
1479
+ toolSchemaMiddleware,
1480
+ deriveExamplesMiddleware(),
1481
+ (0, import_ai4.addToolInputExamplesMiddleware)(),
1482
+ // RUNX-04: flag-gated debug logging (AGENT_QA_DEBUG_LLM); catches the raw APICallError first.
1483
+ debugLoggingMiddleware(),
1484
+ // RUNX-01: strip empty-content messages just before the wire.
1485
+ dropEmptyMessagesMiddleware()
1486
+ ];
1487
+ function createModel(profile, auth, mask, overrides = {}, observation = {}) {
1488
+ validateProfile(profile);
1489
+ profile.capabilities ??= resolveCapabilities(profile);
1490
+ const transport = deriveTransport(profile, auth);
1491
+ const descriptor = getProvider(profile.provider);
1492
+ if (!descriptor) {
1493
+ throw new Error(
1494
+ `Unknown provider "${profile.provider}". Supported: ${listProviders().map((provider2) => provider2.id).join(", ")}.`
1495
+ );
1496
+ }
1497
+ const baseProvider = toProviderV3((modelId) => descriptor.adapter(transport, modelId));
1498
+ const provider = (0, import_ai4.customProvider)({
1499
+ languageModels: overrides.languageModels ?? {},
1500
+ fallbackProvider: baseProvider
1501
+ });
1502
+ const onProviderCall = observation.onProviderCall;
1503
+ const onCall = observation.onCall;
1504
+ const origin = overrides.providerReportOrigin ?? (overrides.languageModels?.[profile.model] ? void 0 : descriptor.adapter === openaiCompatible ? "openai-chat" : descriptor.adapter === openaiSubscription ? "openai-responses" : descriptor.adapter === anthropicCompatible || descriptor.adapter === anthropicSubscription ? "anthropic-messages" : descriptor.adapter === gemini ? "gemini" : void 0);
1505
+ const observe = (event) => {
1506
+ try {
1507
+ Promise.resolve(onCall?.(event)).catch(() => {
1508
+ });
1509
+ } catch {
1510
+ }
1511
+ };
1512
+ const start = () => {
1513
+ try {
1514
+ Promise.resolve(onProviderCall?.()).catch(() => {
1515
+ });
1516
+ } catch {
1517
+ }
1518
+ observe({ kind: "start" });
1519
+ };
1520
+ const observedProvider = onProviderCall === void 0 && onCall === void 0 ? provider : (0, import_ai4.wrapProvider)({
1521
+ provider,
1522
+ languageModelMiddleware: {
1523
+ specificationVersion: "v3",
1524
+ wrapGenerate: async ({ doGenerate }) => {
1525
+ start();
1526
+ try {
1527
+ const result = await doGenerate();
1528
+ try {
1529
+ observe({ kind: "success", report: providerCallReport(result, origin, mask) });
1530
+ } catch {
1531
+ observe({ kind: "success", report: {} });
1532
+ }
1533
+ return result;
1534
+ } catch (error) {
1535
+ observe({ kind: "failure" });
1536
+ throw error;
1537
+ }
1538
+ },
1539
+ wrapStream: async ({ doStream }) => {
1540
+ start();
1541
+ try {
1542
+ const result = await doStream();
1543
+ if (onCall === void 0) return result;
1544
+ const reader = result.stream.getReader();
1545
+ let terminal = false;
1546
+ let modelId;
1547
+ const failure = () => {
1548
+ if (!terminal) {
1549
+ terminal = true;
1550
+ observe({ kind: "failure" });
1551
+ }
1552
+ };
1553
+ return {
1554
+ ...result,
1555
+ stream: new ReadableStream({
1556
+ async pull(controller) {
1557
+ try {
1558
+ const next = await reader.read();
1559
+ if (next.done) {
1560
+ failure();
1561
+ controller.close();
1562
+ return;
1563
+ }
1564
+ const part = next.value;
1565
+ if (part.type === "response-metadata") modelId = part.modelId;
1566
+ if (part.type === "error") failure();
1567
+ if (part.type === "finish" && !terminal) {
1568
+ terminal = true;
1569
+ try {
1570
+ observe({ kind: "success", report: providerCallReport({
1571
+ usage: part.usage,
1572
+ response: { modelId }
1573
+ }, origin, mask) });
1574
+ } catch {
1575
+ observe({ kind: "success", report: {} });
1576
+ }
1577
+ }
1578
+ controller.enqueue(part);
1579
+ } catch (error) {
1580
+ failure();
1581
+ controller.error(error);
1582
+ }
1583
+ },
1584
+ async cancel(reason) {
1585
+ failure();
1586
+ await reader.cancel(reason);
1587
+ }
1588
+ }, { highWaterMark: 0 })
1589
+ };
1590
+ } catch (error) {
1591
+ observe({ kind: "failure" });
1592
+ throw error;
1593
+ }
1594
+ }
1595
+ }
1596
+ });
1597
+ const middleware = [
1598
+ capabilityUpdateMiddleware(profile),
1599
+ ...descriptor.unsupportedParams?.length ? [stripUnsupportedParamsMiddleware(descriptor.unsupportedParams)] : [],
1600
+ ...MIDDLEWARE,
1601
+ (0, import_agent_qa_safety.createMaskingMiddleware)(mask)
1602
+ ];
1603
+ const registry2 = (0, import_ai4.createProviderRegistry)(
1604
+ { [profile.provider]: observedProvider },
1605
+ { languageModelMiddleware: middleware }
1606
+ );
1607
+ return registry2.languageModel(`${profile.provider}:${profile.model}`);
1608
+ }
1609
+ function toProviderV3(build) {
1610
+ return {
1611
+ specificationVersion: "v3",
1612
+ languageModel: build,
1613
+ embeddingModel(modelId) {
1614
+ throw new Error(`No embedding model for provider model "${modelId}"`);
1615
+ },
1616
+ imageModel(modelId) {
1617
+ throw new Error(`No image model for provider model "${modelId}"`);
1618
+ }
1619
+ };
1620
+ }
1621
+
1622
+ // src/vision/resolve-config.ts
1623
+ function resolveVisionConfig(servicesVision) {
1624
+ return {
1625
+ screenshotSize: servicesVision?.screenshotSize,
1626
+ effectiveResolution: servicesVision?.effectiveResolution
1627
+ };
1628
+ }
1629
+
1630
+ // src/vision/resolve-gate.ts
1631
+ var TEXT_ONLY_PROMPT_NOTE = [
1632
+ "Visual screenshot is unavailable for this step.",
1633
+ "Rely on the accessibility tree and DOM context for element identification, including roles, names, values, refs, and URLs.",
1634
+ "Verify functional state from the available structured context rather than purely visual appearance."
1635
+ ].join(" ");
1636
+ function visionFromConfig(configured, capabilities) {
1637
+ return configured ?? capabilities.vision;
1638
+ }
1639
+ function resolveVisionGate(model) {
1640
+ if (model.vision) {
1641
+ return {
1642
+ attachImage: true,
1643
+ captureMode: "full",
1644
+ promptNote: ""
1645
+ };
1646
+ }
1647
+ return {
1648
+ attachImage: false,
1649
+ captureMode: "textOnly",
1650
+ promptNote: TEXT_ONLY_PROMPT_NOTE
1651
+ };
1652
+ }
1653
+ // Annotate the CommonJS export names for ESM import in node:
1654
+ 0 && (module.exports = {
1655
+ FAMILIES,
1656
+ MODEL_CALL_EVENT_KINDS,
1657
+ MODEL_CALL_REPORT_ORIGINS,
1658
+ MODEL_CATALOG,
1659
+ UNKNOWN_FLOOR,
1660
+ anthropicCompatible,
1661
+ anthropicSubscription,
1662
+ capabilityKey,
1663
+ capabilityUpdateMiddleware,
1664
+ clearProviderRegistry,
1665
+ compactLogs,
1666
+ createModel,
1667
+ createTokenAccounting,
1668
+ debugLoggingMiddleware,
1669
+ deriveExamplesMiddleware,
1670
+ deriveTransport,
1671
+ dropEmptyMessagesMiddleware,
1672
+ extractJsonStrategy,
1673
+ fetchLiveModels,
1674
+ gemini,
1675
+ getModelCatalog,
1676
+ getObservedWindow,
1677
+ getProvider,
1678
+ getProviderOptions,
1679
+ guardBlob,
1680
+ guardToolOutput,
1681
+ isContextLengthOverflow,
1682
+ isContextOverflow,
1683
+ listProviders,
1684
+ matchFamily,
1685
+ mergeCatalog,
1686
+ openaiCompatible,
1687
+ openaiSubscription,
1688
+ overrideStore,
1689
+ parseRealWindow,
1690
+ registerProvider,
1691
+ repairMiddleware,
1692
+ resolveCapabilities,
1693
+ resolveVisionConfig,
1694
+ resolveVisionGate,
1695
+ retryMiddleware,
1696
+ stripUnsupportedParamsMiddleware,
1697
+ toolSchemaMiddleware,
1698
+ validateProfile,
1699
+ visionFromConfig
1700
+ });
1701
+ //# sourceMappingURL=index.cjs.map