@x12i/ai-dispatcher 2.4.1 → 3.0.0

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 CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -41,6 +51,314 @@ var import_openrouter_runtime4 = require("@x12i/openrouter-runtime");
41
51
  // src/create-dispatcher.ts
42
52
  var import_provider_metadata = require("@x12i/provider-metadata");
43
53
 
54
+ // src/ai-input.ts
55
+ var import_node_async_hooks = require("async_hooks");
56
+ var import_core = require("@x12i/ai-input/core");
57
+
58
+ // src/types/providers.ts
59
+ var IMPLEMENTED_AI_PROVIDERS = ["openrouter", "bedrock", "openai", "cloudflare"];
60
+ function isImplementedAiProvider(provider) {
61
+ return IMPLEMENTED_AI_PROVIDERS.includes(provider);
62
+ }
63
+
64
+ // src/errors.ts
65
+ var AiDispatcherError = class extends Error {
66
+ constructor(code, message, details) {
67
+ super(message);
68
+ this.code = code;
69
+ this.details = details;
70
+ this.name = "AiDispatcherError";
71
+ }
72
+ code;
73
+ details;
74
+ };
75
+ function providerNotImplemented(provider) {
76
+ const implemented = [...IMPLEMENTED_AI_PROVIDERS];
77
+ return new AiDispatcherError(
78
+ "PROVIDER_NOT_IMPLEMENTED",
79
+ `AI provider "${provider}" is not implemented yet. Supported by @x12i/ai-dispatcher: ${implemented.map((id) => `"${id}"`).join(", ")}.`,
80
+ {
81
+ provider,
82
+ implementedProviders: implemented,
83
+ operatorHint: `Pass provider: "${implemented[0]}" (or omit provider to use the default).`
84
+ }
85
+ );
86
+ }
87
+
88
+ // src/ai-input.ts
89
+ var GPT_ENCODINGS = /* @__PURE__ */ new Set(["o200k_base", "cl100k_base", "p50k_base", "p50k_edit", "r50k_base"]);
90
+ var inputStorage = new import_node_async_hooks.AsyncLocalStorage();
91
+ function mergeAiInput(factory, request) {
92
+ if (request === false) return false;
93
+ if (request === void 0) {
94
+ if (factory === false) return false;
95
+ return factory ?? {};
96
+ }
97
+ const base = typeof factory === "object" ? factory : {};
98
+ const { approvals: requestApprovals, ...requestRest } = request;
99
+ return {
100
+ ...base,
101
+ ...requestRest,
102
+ ...requestApprovals !== void 0 ? { approvals: requestApprovals } : base.approvals !== void 0 ? { approvals: base.approvals } : {}
103
+ };
104
+ }
105
+ function visibleInputResolution(track) {
106
+ if (!track.enabled) return { enabled: false, changed: false };
107
+ const baseline = isBaselineCodec(track.codec) && track.representation === "value";
108
+ if (!track.changed && baseline && !track.surfaced) return void 0;
109
+ return {
110
+ enabled: true,
111
+ ...track.model ? { model: track.model } : {},
112
+ mode: track.mode,
113
+ codec: track.codec,
114
+ representation: track.representation,
115
+ approvalSource: track.approvalSource,
116
+ changed: track.changed
117
+ };
118
+ }
119
+ function wrapToolRegistry(tools) {
120
+ const wrapped = {};
121
+ for (const [name, executor] of Object.entries(tools)) {
122
+ if (!executor) continue;
123
+ wrapped[name] = wrapProviderExecutor(executor);
124
+ }
125
+ return wrapped;
126
+ }
127
+ function wrapProviderExecutor(executor) {
128
+ return async (args, context) => {
129
+ const result = await executor(args, context);
130
+ const track = inputStorage.getStore();
131
+ if (!track?.enabled || !track.client) return result;
132
+ return applyEncodedResult(track, result);
133
+ };
134
+ }
135
+ async function applyAiInput(params) {
136
+ const requestSetting = params.request.aiInput;
137
+ delete params.request.aiInput;
138
+ const settings = mergeAiInput(params.factory, requestSetting);
139
+ if (settings === false) return disabledTrack();
140
+ const track = await openTrack(settings, lookupModel(settings.model, params.effectiveModel));
141
+ await encodeRequestText(params.request, track);
142
+ wrapRequestTools(params.request, track);
143
+ return track;
144
+ }
145
+ function disabledTrack() {
146
+ return {
147
+ enabled: false,
148
+ mode: "compact",
149
+ codec: "text",
150
+ representation: "value",
151
+ approvalSource: "baseline",
152
+ changed: false,
153
+ surfaced: false
154
+ };
155
+ }
156
+ async function openTrack(settings, model) {
157
+ const tokenizer = settings.tokenizer ?? "none";
158
+ const mode = settings.mode ?? "compact";
159
+ let tokenCounter;
160
+ try {
161
+ tokenCounter = await loadTokenizer(tokenizer);
162
+ const framing = framingFor(settings);
163
+ const resolved = (0, import_core.resolveSettings)({
164
+ files: [],
165
+ env: {},
166
+ factory: {
167
+ mode,
168
+ codec: settings.codec ?? "auto",
169
+ readableFormat: settings.readableFormat ?? "auto",
170
+ sharing: settings.sharing ?? "auto",
171
+ tokenizer: tokenCounter?.id ?? "none",
172
+ framing,
173
+ ...model ? { model } : {}
174
+ }
175
+ });
176
+ const approvals = settings.approvals;
177
+ const client = (0, import_core.createCoreClient)({
178
+ config: resolved.config,
179
+ explanation: resolved.explanation,
180
+ ...approvals && approvals.length > 0 ? { policy: { approvals: [...approvals] } } : {},
181
+ ...tokenCounter ? { tokenCounter } : {},
182
+ warn: () => void 0
183
+ });
184
+ return {
185
+ enabled: true,
186
+ client,
187
+ ...model ? { model } : {},
188
+ mode,
189
+ codec: "text",
190
+ representation: "value",
191
+ approvalSource: "baseline",
192
+ changed: false,
193
+ surfaced: false
194
+ };
195
+ } catch (error) {
196
+ throw mapAiInputError(error);
197
+ }
198
+ }
199
+ function lookupModel(override, effectiveModel) {
200
+ const explicit = override?.trim();
201
+ const chosen = explicit ? explicit : effectiveModel.trim();
202
+ return chosen.length > 0 ? chosen : void 0;
203
+ }
204
+ function framingFor(settings) {
205
+ if (settings.framing) return settings.framing;
206
+ const tokenizer = settings.tokenizer ?? "none";
207
+ if (tokenizer !== "none" && (settings.approvals?.length ?? 0) > 0) return "self-describing";
208
+ return "raw";
209
+ }
210
+ async function loadTokenizer(tokenizer) {
211
+ if (tokenizer === "none") return void 0;
212
+ if (!tokenizer.startsWith("gpt:")) {
213
+ throw new AiDispatcherError("AI_INPUT_FAILED", `Unsupported tokenizer "${tokenizer}".`, {
214
+ code: "INVALID_CONFIG"
215
+ });
216
+ }
217
+ const encoding = tokenizer.slice("gpt:".length);
218
+ if (!GPT_ENCODINGS.has(encoding)) {
219
+ throw new AiDispatcherError("AI_INPUT_FAILED", `Unsupported tokenizer "${tokenizer}".`, {
220
+ code: "INVALID_CONFIG"
221
+ });
222
+ }
223
+ const gpt = await import("@x12i/ai-input/tokenizers/gpt");
224
+ return gpt.createGptTokenCounter(encoding);
225
+ }
226
+ async function encodeRequestText(request, track) {
227
+ if (typeof request.prompt === "string") request.prompt = await encodeString(track, request.prompt);
228
+ if (typeof request.system === "string") request.system = await encodeString(track, request.system);
229
+ if (typeof request.instructions === "string") request.instructions = await encodeString(track, request.instructions);
230
+ if (typeof request.input === "string") {
231
+ request.input = await encodeString(track, request.input);
232
+ } else if (Array.isArray(request.input)) {
233
+ for (let index = 0; index < request.input.length; index += 1) {
234
+ const item = request.input[index];
235
+ if (typeof item === "string") {
236
+ request.input[index] = await encodeString(track, item);
237
+ } else if (item) {
238
+ await encodeContentRecord(item, track);
239
+ }
240
+ }
241
+ }
242
+ if (request.messages) {
243
+ for (const message of request.messages) {
244
+ await encodeMessage(message, track);
245
+ }
246
+ }
247
+ }
248
+ async function encodeMessage(message, track) {
249
+ if (typeof message.content === "string") {
250
+ message.content = await encodeString(track, message.content);
251
+ return;
252
+ }
253
+ for (const part of message.content) {
254
+ if (part.type === "text") part.text = await encodeString(track, part.text);
255
+ }
256
+ }
257
+ async function encodeContentRecord(record2, track) {
258
+ if (typeof record2.content === "string") {
259
+ record2.content = await encodeString(track, record2.content);
260
+ return;
261
+ }
262
+ if (!Array.isArray(record2.content)) return;
263
+ for (const part of record2.content) {
264
+ if (!isRecord(part) || typeof part.text !== "string") continue;
265
+ if (part.type === "text" || part.type === "input_text") {
266
+ part.text = await encodeString(track, part.text);
267
+ }
268
+ }
269
+ }
270
+ function wrapRequestTools(request, track) {
271
+ if (!request.functionTools) return;
272
+ request.functionTools = request.functionTools.map((tool) => {
273
+ if (!tool.executor) return tool;
274
+ const executor = tool.executor;
275
+ return {
276
+ ...tool,
277
+ executor: async (args, context) => applyEncodedResult(track, await executor(args, context))
278
+ };
279
+ });
280
+ }
281
+ async function encodeString(track, value) {
282
+ const encoded = await applyEncodedResult(track, value);
283
+ return typeof encoded === "string" ? encoded : value;
284
+ }
285
+ async function applyEncodedResult(track, value) {
286
+ if (!track.enabled || !track.client) return value;
287
+ let prepared;
288
+ try {
289
+ prepared = await track.client.prepare(value);
290
+ } catch (error) {
291
+ const failure = readPackageFailure(error);
292
+ if (failure?.code === "UNSUPPORTED_VALUE") return value;
293
+ throw mapAiInputError(error);
294
+ }
295
+ const wire = unframedBaseline(prepared);
296
+ note(track, prepared, value, wire);
297
+ if (wire === canonicalWire(value)) return value;
298
+ return wire;
299
+ }
300
+ function unframedBaseline(prepared) {
301
+ const baseline = isBaselineCodec(prepared.codec) && prepared.representation === "value";
302
+ if (!baseline || prepared.framing === "raw") return prepared.text;
303
+ const newline = prepared.text.indexOf("\n");
304
+ if (!prepared.text.startsWith("@ai-input/") || newline < 0) return prepared.text;
305
+ return prepared.text.slice(newline + 1);
306
+ }
307
+ function isBaselineCodec(codec) {
308
+ return codec === "json" || codec === "text" || codec === "outline";
309
+ }
310
+ function note(track, prepared, source, wire) {
311
+ const changed = wire !== canonicalWire(source);
312
+ if (changed) track.changed = true;
313
+ const alternate = prepared.codec === "toon" || prepared.representation !== "value";
314
+ if (alternate || !track.surfaced) {
315
+ track.codec = prepared.codec;
316
+ track.representation = prepared.representation;
317
+ track.approvalSource = prepared.receipt.approvalSource;
318
+ track.mode = prepared.mode;
319
+ }
320
+ if (alternate) track.surfaced = true;
321
+ }
322
+ function canonicalWire(value) {
323
+ if (typeof value === "string") return value;
324
+ return JSON.stringify(value);
325
+ }
326
+ function mapAiInputError(error) {
327
+ if (error instanceof AiDispatcherError) return error;
328
+ const failure = readPackageFailure(error);
329
+ if (failure) {
330
+ return new AiDispatcherError("AI_INPUT_FAILED", failure.message, {
331
+ code: failure.code,
332
+ ...failure.path !== void 0 ? { path: failure.path } : {},
333
+ ...failure.details !== void 0 ? { details: failure.details } : {}
334
+ });
335
+ }
336
+ const message = error instanceof Error ? error.message : "Input preparation failed.";
337
+ return new AiDispatcherError("AI_INPUT_FAILED", message);
338
+ }
339
+ function readPackageFailure(error) {
340
+ if ((0, import_core.isAiInputError)(error)) {
341
+ return {
342
+ code: error.code,
343
+ message: error.message,
344
+ ...error.path !== void 0 ? { path: error.path } : {},
345
+ ...error.details !== void 0 ? { details: error.details } : {}
346
+ };
347
+ }
348
+ if (!(error instanceof Error) || error.name !== "AiInputError") return void 0;
349
+ const coded = error;
350
+ if (typeof coded.code !== "string") return void 0;
351
+ return {
352
+ code: coded.code,
353
+ message: error.message,
354
+ ...typeof coded.path === "string" ? { path: coded.path } : {},
355
+ ...coded.details !== void 0 ? { details: coded.details } : {}
356
+ };
357
+ }
358
+ function isRecord(value) {
359
+ return typeof value === "object" && value !== null && !Array.isArray(value);
360
+ }
361
+
44
362
  // src/cache-usage.ts
45
363
  function readCacheTokens(source) {
46
364
  const cached = [];
@@ -89,7 +407,7 @@ function record(value) {
89
407
 
90
408
  // src/json-pointer.ts
91
409
  var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
92
- function isRecord(value) {
410
+ function isRecord2(value) {
93
411
  return typeof value === "object" && value !== null && !Array.isArray(value);
94
412
  }
95
413
  function unescapeToken(token) {
@@ -116,7 +434,7 @@ function walk(current, tokens) {
116
434
  if (index >= current.length) return [];
117
435
  return walk(current[index], rest);
118
436
  }
119
- if (!isRecord(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
437
+ if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
120
438
  return walk(current[head], rest);
121
439
  }
122
440
  function valuesAtPointer(root, pointer) {
@@ -153,7 +471,7 @@ function collectParents(current, tokens) {
153
471
  if (index >= current.length) return [];
154
472
  return collectParents(current[index], rest);
155
473
  }
156
- if (!isRecord(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
474
+ if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
157
475
  return collectParents(current[head], rest);
158
476
  }
159
477
  function deletePointer(root, pointer) {
@@ -169,27 +487,27 @@ function deletePointer(root, pointer) {
169
487
  if (index < parent.length) parent.splice(index, 1);
170
488
  continue;
171
489
  }
172
- if (isRecord(parent) && Object.prototype.hasOwnProperty.call(parent, last)) {
490
+ if (isRecord2(parent) && Object.prototype.hasOwnProperty.call(parent, last)) {
173
491
  delete parent[last];
174
492
  }
175
493
  }
176
494
  }
177
495
 
178
496
  // src/reasoning-extract.ts
179
- function isRecord2(value) {
497
+ function isRecord3(value) {
180
498
  return typeof value === "object" && value !== null && !Array.isArray(value);
181
499
  }
182
500
  function textFromValue(value) {
183
501
  if (typeof value === "string") return value;
184
502
  if (Array.isArray(value)) return value.map(textFromValue).join("");
185
- if (!isRecord2(value)) return "";
503
+ if (!isRecord3(value)) return "";
186
504
  if (typeof value.text === "string") return value.text;
187
505
  if (typeof value.summary === "string") return value.summary;
188
506
  return "";
189
507
  }
190
508
  function extractStreamReasoningText(event, response) {
191
509
  if (response.streamReasoningKeys.length > 0) {
192
- if (!isRecord2(event)) return void 0;
510
+ if (!isRecord3(event)) return void 0;
193
511
  for (const key of response.streamReasoningKeys) {
194
512
  const text = textFromValue(event[key]);
195
513
  if (text) return text;
@@ -287,6 +605,8 @@ function applyResolution(response, prepared) {
287
605
  if (prepared.cacheWarnings?.length) {
288
606
  result.warnings = [...result.warnings, ...prepared.cacheWarnings];
289
607
  }
608
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
609
+ if (inputResolution) result.inputResolution = inputResolution;
290
610
  applyCacheUsage(result);
291
611
  const directive = prepared.directive;
292
612
  if (!directive) return result;
@@ -330,7 +650,7 @@ function applyUsage(response, raw, directive) {
330
650
  }
331
651
 
332
652
  // src/decorate-stream.ts
333
- function isRecord3(value) {
653
+ function isRecord4(value) {
334
654
  return typeof value === "object" && value !== null && !Array.isArray(value);
335
655
  }
336
656
  async function* decorateStream(prepared, source) {
@@ -388,11 +708,13 @@ async function* decorateStream(prepared, source) {
388
708
  };
389
709
  }
390
710
  }
391
- const data = isRecord3(event.data) ? { ...event.data } : {};
711
+ const data = isRecord4(event.data) ? { ...event.data } : {};
392
712
  if (splitter) data.text = splitter.answer;
393
713
  if (reasoningText) data.reasoningText = reasoningText;
394
714
  if (prepared.resolution) data.reasoningResolution = prepared.resolution;
395
715
  if (prepared.cacheResolution) data.cacheResolution = prepared.cacheResolution;
716
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
717
+ if (inputResolution) data.inputResolution = inputResolution;
396
718
  yield { ...event, data };
397
719
  continue;
398
720
  }
@@ -400,18 +722,20 @@ async function* decorateStream(prepared, source) {
400
722
  }
401
723
  }
402
724
  function withResolution(event, prepared) {
403
- if (!prepared.resolution && !prepared.cacheResolution) return event;
404
- const data = isRecord3(event.data) ? { ...event.data } : {};
725
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
726
+ if (!prepared.resolution && !prepared.cacheResolution && !inputResolution) return event;
727
+ const data = isRecord4(event.data) ? { ...event.data } : {};
405
728
  if (prepared.resolution) data.reasoningResolution = prepared.resolution;
406
729
  if (prepared.cacheResolution) data.cacheResolution = prepared.cacheResolution;
730
+ if (inputResolution) data.inputResolution = inputResolution;
407
731
  return { ...event, data };
408
732
  }
409
733
  function textOf(event) {
410
- if (!isRecord3(event.data) || typeof event.data.text !== "string") return "";
734
+ if (!isRecord4(event.data) || typeof event.data.text !== "string") return "";
411
735
  return event.data.text;
412
736
  }
413
737
  function adjustUsageEvent(event, prepared) {
414
- if (!isRecord3(event.data) || !isRecord3(event.data.usage)) return event;
738
+ if (!isRecord4(event.data) || !isRecord4(event.data.usage)) return event;
415
739
  const paths = prepared.directive?.usage?.reasoningTokenPaths;
416
740
  const usage = { ...event.data.usage };
417
741
  let changed = false;
@@ -440,36 +764,6 @@ function adjustUsageEvent(event, prepared) {
440
764
  return { ...event, data: { ...event.data, usage } };
441
765
  }
442
766
 
443
- // src/types/providers.ts
444
- var IMPLEMENTED_AI_PROVIDERS = ["openrouter", "bedrock", "openai", "cloudflare"];
445
- function isImplementedAiProvider(provider) {
446
- return IMPLEMENTED_AI_PROVIDERS.includes(provider);
447
- }
448
-
449
- // src/errors.ts
450
- var AiDispatcherError = class extends Error {
451
- constructor(code, message, details) {
452
- super(message);
453
- this.code = code;
454
- this.details = details;
455
- this.name = "AiDispatcherError";
456
- }
457
- code;
458
- details;
459
- };
460
- function providerNotImplemented(provider) {
461
- const implemented = [...IMPLEMENTED_AI_PROVIDERS];
462
- return new AiDispatcherError(
463
- "PROVIDER_NOT_IMPLEMENTED",
464
- `AI provider "${provider}" is not implemented yet. Supported by @x12i/ai-dispatcher: ${implemented.map((id) => `"${id}"`).join(", ")}.`,
465
- {
466
- provider,
467
- implementedProviders: implemented,
468
- operatorHint: `Pass provider: "${implemented[0]}" (or omit provider to use the default).`
469
- }
470
- );
471
- }
472
-
473
767
  // src/mcp.ts
474
768
  var TOOL_TOKEN = /^[A-Za-z0-9_-]+$/;
475
769
  var MAX_EXPOSED_NAME_LENGTH = 64;
@@ -491,7 +785,7 @@ function indexMcpServers(servers) {
491
785
  for (const server of servers) {
492
786
  assertServer(server, seenServers);
493
787
  for (const tool of server.tools) {
494
- if (!isRecord4(tool)) {
788
+ if (!isRecord5(tool)) {
495
789
  throw new AiDispatcherError(
496
790
  "MCP_TOOL_NAME_INVALID",
497
791
  `MCP server "${server.id}" has a tool that is not an object.`
@@ -578,18 +872,17 @@ function applyMcpCatalog(params) {
578
872
  function createMcpExecutor(server, rawName) {
579
873
  return async (args, context) => {
580
874
  const result = await server.callTool(rawName, toArgs(args), context);
581
- return flattenMcpResult(result);
875
+ return mcpModelValue(result);
582
876
  };
583
877
  }
584
- function flattenMcpResult(result) {
585
- if (typeof result === "string") return result;
586
- if (!isRecord4(result)) return stringify(result);
878
+ function mcpModelValue(result) {
879
+ if (typeof result === "string" || !isRecord5(result)) return result;
587
880
  const text = textContent(result.content);
588
881
  if (result.isError === true) {
589
882
  throw new Error(text ?? stringify(result));
590
883
  }
591
884
  if (text !== void 0) return text;
592
- return stringify(result);
885
+ return result;
593
886
  }
594
887
  function resolveAllowlist(filter, tools) {
595
888
  if (filter === void 0) return void 0;
@@ -608,7 +901,7 @@ function resolveAllowlist(filter, tools) {
608
901
  return new Set(filter);
609
902
  }
610
903
  function assertServer(server, seen) {
611
- if (!isRecord4(server) || typeof server.id !== "string" || server.id.length === 0 || !Array.isArray(server.tools) || typeof server.callTool !== "function") {
904
+ if (!isRecord5(server) || typeof server.id !== "string" || server.id.length === 0 || !Array.isArray(server.tools) || typeof server.callTool !== "function") {
612
905
  throw new AiDispatcherError(
613
906
  "MCP_SERVER_INVALID",
614
907
  "An MCP server needs an id, a tools array, and a callTool function."
@@ -653,7 +946,7 @@ function toolDescription(tool) {
653
946
  }
654
947
  function toolParameters(tool) {
655
948
  if (tool.inputSchema === void 0) return { ...DEFAULT_PARAMETERS, properties: {} };
656
- if (!isRecord4(tool.inputSchema)) {
949
+ if (!isRecord5(tool.inputSchema)) {
657
950
  throw new AiDispatcherError(
658
951
  "MCP_TOOL_NAME_INVALID",
659
952
  `MCP tool "${tool.name}" inputSchema must be an object.`
@@ -665,14 +958,14 @@ function textContent(content) {
665
958
  if (!Array.isArray(content)) return void 0;
666
959
  const parts = [];
667
960
  for (const part of content) {
668
- if (!isRecord4(part) || part.type !== "text" || typeof part.text !== "string") continue;
961
+ if (!isRecord5(part) || part.type !== "text" || typeof part.text !== "string") continue;
669
962
  parts.push(part.text);
670
963
  }
671
964
  if (!parts.length) return void 0;
672
965
  return parts.join("\n");
673
966
  }
674
967
  function toArgs(args) {
675
- if (isRecord4(args)) return args;
968
+ if (isRecord5(args)) return args;
676
969
  return {};
677
970
  }
678
971
  function listFailed(serverId, error) {
@@ -684,7 +977,7 @@ function stringify(result) {
684
977
  const serialized = JSON.stringify(result);
685
978
  return serialized === void 0 ? "null" : serialized;
686
979
  }
687
- function isRecord4(value) {
980
+ function isRecord5(value) {
688
981
  return typeof value === "object" && value !== null && !Array.isArray(value);
689
982
  }
690
983
 
@@ -1240,7 +1533,7 @@ function compileCloudflareRequest(request, options, call, streaming) {
1240
1533
  if (call?.finalizeBody) body = call.finalizeBody(body);
1241
1534
  if (endpoint !== "run") body = { ...body, stream: streaming };
1242
1535
  const gateway = mergeGateway(options.gateway, call?.cloudflare?.gateway);
1243
- const fromBody = isRecord5(body.metadata) ? body.metadata : void 0;
1536
+ const fromBody = isRecord6(body.metadata) ? body.metadata : void 0;
1244
1537
  const packed = (0, import_openrouter_runtime.packProviderRecord)(
1245
1538
  request.metadata,
1246
1539
  request.agentId,
@@ -1494,7 +1787,7 @@ function messagesFromInput(request) {
1494
1787
  messages.push({ role: "user", content: item });
1495
1788
  continue;
1496
1789
  }
1497
- if (!isRecord5(item)) continue;
1790
+ if (!isRecord6(item)) continue;
1498
1791
  const role = item.role === "assistant" || item.role === "tool" || item.role === "system" ? item.role : "user";
1499
1792
  if (role === "system") continue;
1500
1793
  const content = inputContent(item.content);
@@ -1511,12 +1804,12 @@ function inputContent(content) {
1511
1804
  if (!Array.isArray(content)) return void 0;
1512
1805
  const parts = [];
1513
1806
  for (const part of content) {
1514
- if (!isRecord5(part)) continue;
1807
+ if (!isRecord6(part)) continue;
1515
1808
  if ((part.type === "text" || part.type === "input_text") && typeof part.text === "string") {
1516
1809
  parts.push({ type: "text", text: part.text });
1517
1810
  } else if (part.type === "image_url" && typeof part.imageUrl === "string") {
1518
1811
  parts.push({ type: "image_url", imageUrl: part.imageUrl });
1519
- } else if (part.type === "image_url" && isRecord5(part.image_url) && typeof part.image_url.url === "string") {
1812
+ } else if (part.type === "image_url" && isRecord6(part.image_url) && typeof part.image_url.url === "string") {
1520
1813
  parts.push({ type: "image_url", imageUrl: part.image_url.url });
1521
1814
  } else if (part.type === "input_image" && typeof part.image_url === "string") {
1522
1815
  parts.push({ type: "image_url", imageUrl: part.image_url });
@@ -1735,7 +2028,7 @@ function continueMessages(body, response, results) {
1735
2028
  return { ...body, messages };
1736
2029
  }
1737
2030
  function continueRun(body, response, results) {
1738
- const input = isRecord5(body.input) ? body.input : {};
2031
+ const input = isRecord6(body.input) ? body.input : {};
1739
2032
  const continued = continueChat({ messages: input.messages }, response, results);
1740
2033
  return { ...body, input: { ...input, messages: continued.messages } };
1741
2034
  }
@@ -1824,7 +2117,7 @@ async function* streamCloudflare(request, options, call) {
1824
2117
  throw failure;
1825
2118
  }
1826
2119
  for await (const event of parseSse(response)) {
1827
- if (!isRecord5(event)) continue;
2120
+ if (!isRecord6(event)) continue;
1828
2121
  const catalogReasoning = call?.extractStreamReasoning?.(event);
1829
2122
  const reasoningText = catalogReasoning || reasoningDelta(event);
1830
2123
  if (reasoningText) yield { type: "stream.reasoning.delta", requestId, data: { text: reasoningText } };
@@ -1887,7 +2180,7 @@ async function sendOnce(compiled, options, timeoutMs) {
1887
2180
  if (!response.ok) throw await readFailure(response);
1888
2181
  const text = await response.text();
1889
2182
  const parsed = text ? JSON.parse(text) : {};
1890
- if (isRecord5(parsed) && parsed.success === false) {
2183
+ if (isRecord6(parsed) && parsed.success === false) {
1891
2184
  throw new AiDispatcherError(
1892
2185
  "PROVIDER_REQUEST_FAILED",
1893
2186
  messageFrom(parsed) ?? "Cloudflare request failed.",
@@ -1938,7 +2231,7 @@ function isConfigError(code) {
1938
2231
  }
1939
2232
  function asTerminalError(error) {
1940
2233
  if (error instanceof AiDispatcherError && error.code === "PROVIDER_RETRYABLE") {
1941
- const status = isRecord5(error.details) ? error.details.status : void 0;
2234
+ const status = isRecord6(error.details) ? error.details.status : void 0;
1942
2235
  if (status === 429) return new AiDispatcherError("PROVIDER_RATE_LIMITED", error.message, error.details);
1943
2236
  return new AiDispatcherError("PROVIDER_GATEWAY_UNREACHABLE", error.message, error.details);
1944
2237
  }
@@ -1948,7 +2241,7 @@ function asTerminalError(error) {
1948
2241
  function normalizeCloudflareResponse(params) {
1949
2242
  const payload = unwrap(params.response);
1950
2243
  const calls = params.functionTools ?? extractCalls(params.compiled.endpoint, params.response);
1951
- const usage = normalizeUsage(payload.usage) ?? normalizeUsage(isRecord5(params.response) ? params.response.usage : void 0);
2244
+ const usage = normalizeUsage(payload.usage) ?? normalizeUsage(isRecord6(params.response) ? params.response.usage : void 0);
1952
2245
  const status = params.status ?? (calls.length ? "requires_action" : "completed");
1953
2246
  return {
1954
2247
  id: typeof payload.id === "string" ? payload.id : params.requestId,
@@ -1981,16 +2274,16 @@ function answerText(response) {
1981
2274
  if (chat) return chat;
1982
2275
  const anthropic = anthropicAnswer(response);
1983
2276
  if (anthropic) return anthropic;
1984
- if (isRecord5(response.result)) return answerText(response.result);
2277
+ if (isRecord6(response.result)) return answerText(response.result);
1985
2278
  return "";
1986
2279
  }
1987
2280
  function responsesAnswer(response) {
1988
2281
  if (!Array.isArray(response.output)) return "";
1989
2282
  const parts = [];
1990
2283
  for (const item of response.output) {
1991
- if (!isRecord5(item) || item.type !== "message" || !Array.isArray(item.content)) continue;
2284
+ if (!isRecord6(item) || item.type !== "message" || !Array.isArray(item.content)) continue;
1992
2285
  for (const part of item.content) {
1993
- if (isRecord5(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
2286
+ if (isRecord6(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
1994
2287
  }
1995
2288
  }
1996
2289
  return parts.join("");
@@ -2001,16 +2294,16 @@ function chatAnswer(response) {
2001
2294
  const content = message.content;
2002
2295
  if (typeof content === "string") return content;
2003
2296
  if (!Array.isArray(content)) return "";
2004
- return content.map((part) => isRecord5(part) && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
2297
+ return content.map((part) => isRecord6(part) && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
2005
2298
  }
2006
2299
  function anthropicAnswer(response) {
2007
2300
  if (!Array.isArray(response.content)) return "";
2008
- return response.content.map((part) => isRecord5(part) && part.type === "text" && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
2301
+ return response.content.map((part) => isRecord6(part) && part.type === "text" && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
2009
2302
  }
2010
2303
  function chatAssistantMessage(response) {
2011
- if (!Array.isArray(response.choices) || !isRecord5(response.choices[0])) return void 0;
2304
+ if (!Array.isArray(response.choices) || !isRecord6(response.choices[0])) return void 0;
2012
2305
  const message = response.choices[0].message;
2013
- return isRecord5(message) ? message : void 0;
2306
+ return isRecord6(message) ? message : void 0;
2014
2307
  }
2015
2308
  function extractCalls(endpoint, response) {
2016
2309
  const record2 = unwrap(response);
@@ -2022,7 +2315,7 @@ function responsesCalls(response) {
2022
2315
  if (!Array.isArray(response.output)) return [];
2023
2316
  const calls = [];
2024
2317
  for (const item of response.output) {
2025
- if (!isRecord5(item) || item.type !== "function_call") continue;
2318
+ if (!isRecord6(item) || item.type !== "function_call") continue;
2026
2319
  calls.push(callUsage(
2027
2320
  typeof item.name === "string" ? item.name : "function",
2028
2321
  typeof item.call_id === "string" ? item.call_id : "function",
@@ -2036,7 +2329,7 @@ function chatCalls(response) {
2036
2329
  if (!message || !Array.isArray(message.tool_calls)) return [];
2037
2330
  const calls = [];
2038
2331
  for (const item of message.tool_calls) {
2039
- if (!isRecord5(item) || !isRecord5(item.function)) continue;
2332
+ if (!isRecord6(item) || !isRecord6(item.function)) continue;
2040
2333
  const name = typeof item.function.name === "string" ? item.function.name : "function";
2041
2334
  calls.push(callUsage(
2042
2335
  name,
@@ -2050,7 +2343,7 @@ function anthropicCalls(response) {
2050
2343
  if (!Array.isArray(response.content)) return [];
2051
2344
  const calls = [];
2052
2345
  for (const item of response.content) {
2053
- if (!isRecord5(item) || item.type !== "tool_use") continue;
2346
+ if (!isRecord6(item) || item.type !== "tool_use") continue;
2054
2347
  const name = typeof item.name === "string" ? item.name : "function";
2055
2348
  calls.push({
2056
2349
  name,
@@ -2089,7 +2382,7 @@ function emptyToolUsage(calls) {
2089
2382
  };
2090
2383
  }
2091
2384
  function normalizeUsage(usage) {
2092
- if (!isRecord5(usage)) return void 0;
2385
+ if (!isRecord6(usage)) return void 0;
2093
2386
  const inputTokens = numberValue(usage.input_tokens) ?? numberValue(usage.prompt_tokens);
2094
2387
  const outputTokens = numberValue(usage.output_tokens) ?? numberValue(usage.completion_tokens);
2095
2388
  const totalTokens = numberValue(usage.total_tokens) ?? (inputTokens !== void 0 || outputTokens !== void 0 ? (inputTokens ?? 0) + (outputTokens ?? 0) : void 0);
@@ -2140,7 +2433,7 @@ function errorEvent(requestId, error) {
2140
2433
  }
2141
2434
  function textDelta(event) {
2142
2435
  if (event.type === "response.output_text.delta" && typeof event.delta === "string" && event.delta) return event.delta;
2143
- if (event.type === "content_block_delta" && isRecord5(event.delta) && event.delta.type === "text_delta" && typeof event.delta.text === "string" && event.delta.text) {
2436
+ if (event.type === "content_block_delta" && isRecord6(event.delta) && event.delta.type === "text_delta" && typeof event.delta.text === "string" && event.delta.text) {
2144
2437
  return event.delta.text;
2145
2438
  }
2146
2439
  const choice = firstChoiceDelta(event);
@@ -2149,7 +2442,7 @@ function textDelta(event) {
2149
2442
  }
2150
2443
  function reasoningDelta(event) {
2151
2444
  if (event.type === "response.reasoning_summary_text.delta" && typeof event.delta === "string" && event.delta) return event.delta;
2152
- if (event.type === "content_block_delta" && isRecord5(event.delta) && event.delta.type === "thinking_delta" && typeof event.delta.thinking === "string" && event.delta.thinking) {
2445
+ if (event.type === "content_block_delta" && isRecord6(event.delta) && event.delta.type === "thinking_delta" && typeof event.delta.thinking === "string" && event.delta.thinking) {
2153
2446
  return event.delta.thinking;
2154
2447
  }
2155
2448
  const choice = firstChoiceDelta(event);
@@ -2166,13 +2459,13 @@ function toolCallDelta(event) {
2166
2459
  argumentsDelta: event.delta
2167
2460
  };
2168
2461
  }
2169
- if (event.type === "content_block_delta" && isRecord5(event.delta) && event.delta.type === "input_json_delta" && typeof event.delta.partial_json === "string") {
2462
+ if (event.type === "content_block_delta" && isRecord6(event.delta) && event.delta.type === "input_json_delta" && typeof event.delta.partial_json === "string") {
2170
2463
  return { index: typeof event.index === "number" ? event.index : 0, argumentsDelta: event.delta.partial_json };
2171
2464
  }
2172
2465
  const choice = firstChoiceDelta(event);
2173
- if (!choice || !Array.isArray(choice.tool_calls) || !isRecord5(choice.tool_calls[0])) return void 0;
2466
+ if (!choice || !Array.isArray(choice.tool_calls) || !isRecord6(choice.tool_calls[0])) return void 0;
2174
2467
  const tool = choice.tool_calls[0];
2175
- const fn = isRecord5(tool.function) ? tool.function : void 0;
2468
+ const fn = isRecord6(tool.function) ? tool.function : void 0;
2176
2469
  const args = fn && typeof fn.arguments === "string" ? fn.arguments : void 0;
2177
2470
  if (!args && !(fn && typeof fn.name === "string")) return void 0;
2178
2471
  return {
@@ -2182,18 +2475,18 @@ function toolCallDelta(event) {
2182
2475
  };
2183
2476
  }
2184
2477
  function streamUsage(event) {
2185
- if (event.type === "response.completed" && isRecord5(event.response)) return normalizeUsage(event.response.usage);
2186
- if (isRecord5(event.usage)) return normalizeUsage(event.usage);
2478
+ if (event.type === "response.completed" && isRecord6(event.response)) return normalizeUsage(event.response.usage);
2479
+ if (isRecord6(event.usage)) return normalizeUsage(event.usage);
2187
2480
  return void 0;
2188
2481
  }
2189
2482
  function firstChoiceDelta(event) {
2190
- if (!Array.isArray(event.choices) || !isRecord5(event.choices[0])) return void 0;
2483
+ if (!Array.isArray(event.choices) || !isRecord6(event.choices[0])) return void 0;
2191
2484
  const delta = event.choices[0].delta;
2192
- return isRecord5(delta) ? delta : void 0;
2485
+ return isRecord6(delta) ? delta : void 0;
2193
2486
  }
2194
2487
  function unwrap(response) {
2195
- if (!isRecord5(response)) return {};
2196
- if (response.success === true && isRecord5(response.result)) return response.result;
2488
+ if (!isRecord6(response)) return {};
2489
+ if (response.success === true && isRecord6(response.result)) return response.result;
2197
2490
  return response;
2198
2491
  }
2199
2492
  function modelOf(compiled) {
@@ -2201,12 +2494,12 @@ function modelOf(compiled) {
2201
2494
  return "";
2202
2495
  }
2203
2496
  function messageFrom(body) {
2204
- if (!isRecord5(body)) return void 0;
2497
+ if (!isRecord6(body)) return void 0;
2205
2498
  if (typeof body.message === "string") return body.message;
2206
- if (isRecord5(body.error) && typeof body.error.message === "string") return body.error.message;
2499
+ if (isRecord6(body.error) && typeof body.error.message === "string") return body.error.message;
2207
2500
  if (Array.isArray(body.errors)) {
2208
2501
  for (const error of body.errors) {
2209
- if (isRecord5(error) && typeof error.message === "string") return error.message;
2502
+ if (isRecord6(error) && typeof error.message === "string") return error.message;
2210
2503
  }
2211
2504
  }
2212
2505
  return void 0;
@@ -2347,7 +2640,7 @@ function readEnv(name) {
2347
2640
  if (typeof process === "undefined") return void 0;
2348
2641
  return process.env[name];
2349
2642
  }
2350
- function isRecord5(value) {
2643
+ function isRecord6(value) {
2351
2644
  return typeof value === "object" && value !== null && !Array.isArray(value);
2352
2645
  }
2353
2646
 
@@ -2555,7 +2848,7 @@ function settleNested(policy, kind, parentEffort) {
2555
2848
  if (kind === "fusion") next.judgeModel = directive.model;
2556
2849
  else next.model = directive.model;
2557
2850
  }
2558
- if (isRecord6(directive.body.reasoning)) next.reasoning = directive.body.reasoning;
2851
+ if (isRecord7(directive.body.reasoning)) next.reasoning = directive.body.reasoning;
2559
2852
  return next;
2560
2853
  }
2561
2854
  function applyPromptPrefix(request, prefix) {
@@ -2605,7 +2898,7 @@ function prefixInputItems(items, prefix) {
2605
2898
  }
2606
2899
  if (!Array.isArray(item.content)) continue;
2607
2900
  for (const part of item.content) {
2608
- if (!isRecord6(part) || typeof part.text !== "string") continue;
2901
+ if (!isRecord7(part) || typeof part.text !== "string") continue;
2609
2902
  if (part.type === "text" || part.type === "input_text") {
2610
2903
  part.text = prefix + part.text;
2611
2904
  return true;
@@ -2666,7 +2959,7 @@ var ROLE_STAMP_FIELDS = ["role", "roleLayer", "roleDigest", "profileChoice"];
2666
2959
  function applyRoleStamp(request) {
2667
2960
  const stamp = request.role;
2668
2961
  delete request.role;
2669
- if (!isRecord6(stamp)) return;
2962
+ if (!isRecord7(stamp)) return;
2670
2963
  const identity = {};
2671
2964
  for (const field of ROLE_STAMP_FIELDS) {
2672
2965
  const value = stamp[field];
@@ -2681,8 +2974,8 @@ function applyRoleStamp(request) {
2681
2974
  }
2682
2975
  function absorbOverrideMetadata(request) {
2683
2976
  const overrides = request.rawOpenRouterOverrides;
2684
- if (!isRecord6(overrides) || !Object.prototype.hasOwnProperty.call(overrides, "metadata")) return;
2685
- if (isRecord6(overrides.metadata)) {
2977
+ if (!isRecord7(overrides) || !Object.prototype.hasOwnProperty.call(overrides, "metadata")) return;
2978
+ if (isRecord7(overrides.metadata)) {
2686
2979
  const current = { ...request.metadata ?? {} };
2687
2980
  const extra = {};
2688
2981
  for (const [key, value] of Object.entries(overrides.metadata)) {
@@ -2721,7 +3014,7 @@ function hasOwnKeys(value) {
2721
3014
  function hasStreamMetadata(directive) {
2722
3015
  return directive.response.streamReasoningKeys.length > 0 || directive.response.streamReasoningPaths.length > 0;
2723
3016
  }
2724
- function isRecord6(value) {
3017
+ function isRecord7(value) {
2725
3018
  return typeof value === "object" && value !== null && !Array.isArray(value);
2726
3019
  }
2727
3020
  function readEnv2(name) {
@@ -3040,7 +3333,7 @@ async function runOpenAi(request, options, call, requestId) {
3040
3333
  let response;
3041
3334
  for (let iteration = 0; iteration <= maxIterations; iteration += 1) {
3042
3335
  response = await sendWithRetries2(active, options, timeoutFor2(request, options));
3043
- const calls = functionCalls(isRecord7(response) ? response : {});
3336
+ const calls = functionCalls(isRecord8(response) ? response : {});
3044
3337
  if (!calls.length) break;
3045
3338
  if (!calls.every((item) => resolveExecutor2(item.name, request, options))) {
3046
3339
  return normalizeOpenAiResponse({
@@ -3060,7 +3353,7 @@ async function runOpenAi(request, options, call, requestId) {
3060
3353
  results.push(await executeOpenAiTool(item, request, options));
3061
3354
  }
3062
3355
  functionUsage.push(...results);
3063
- const record2 = isRecord7(response) ? response : {};
3356
+ const record2 = isRecord8(response) ? response : {};
3064
3357
  active = {
3065
3358
  ...active,
3066
3359
  body: clean2({
@@ -3175,7 +3468,7 @@ async function* streamOpenAi(request, options, call) {
3175
3468
  throw failure;
3176
3469
  }
3177
3470
  for await (const event of parseSse2(response)) {
3178
- if (!isRecord7(event)) continue;
3471
+ if (!isRecord8(event)) continue;
3179
3472
  if (event.type === "response.output_text.delta" && typeof event.delta === "string" && event.delta) {
3180
3473
  text += event.delta;
3181
3474
  yield { type: "stream.text.delta", requestId, data: { text: event.delta } };
@@ -3194,7 +3487,7 @@ async function* streamOpenAi(request, options, call) {
3194
3487
  argumentsDelta: event.delta
3195
3488
  }
3196
3489
  };
3197
- } else if (event.type === "response.completed" && isRecord7(event.response)) {
3490
+ } else if (event.type === "response.completed" && isRecord8(event.response)) {
3198
3491
  const usage = normalizeUsage2(event.response.usage);
3199
3492
  if (usage) yield { type: "stream.usage", requestId, data: { usage } };
3200
3493
  } else if (event.type === "error") {
@@ -3288,7 +3581,7 @@ function isConfigError2(code) {
3288
3581
  }
3289
3582
  function asTerminalError2(error) {
3290
3583
  if (error instanceof AiDispatcherError && error.code === "PROVIDER_RETRYABLE") {
3291
- const status = isRecord7(error.details) ? error.details.status : void 0;
3584
+ const status = isRecord8(error.details) ? error.details.status : void 0;
3292
3585
  if (status === 429) return new AiDispatcherError("PROVIDER_RATE_LIMITED", error.message, error.details);
3293
3586
  return new AiDispatcherError("PROVIDER_GATEWAY_UNREACHABLE", error.message, error.details);
3294
3587
  }
@@ -3296,7 +3589,7 @@ function asTerminalError2(error) {
3296
3589
  return new AiDispatcherError("PROVIDER_REQUEST_FAILED", error instanceof Error ? error.message : String(error));
3297
3590
  }
3298
3591
  function normalizeOpenAiResponse(params) {
3299
- const record2 = isRecord7(params.response) ? params.response : {};
3592
+ const record2 = isRecord8(params.response) ? params.response : {};
3300
3593
  const text = answerText2(record2);
3301
3594
  const calls = params.functionTools ?? functionCalls(record2);
3302
3595
  const usage = normalizeUsage2(record2.usage);
@@ -3323,9 +3616,9 @@ function answerText2(response) {
3323
3616
  if (Array.isArray(output)) {
3324
3617
  const parts = [];
3325
3618
  for (const item of output) {
3326
- if (!isRecord7(item) || item.type === "reasoning" || item.type !== "message" || !Array.isArray(item.content)) continue;
3619
+ if (!isRecord8(item) || item.type === "reasoning" || item.type !== "message" || !Array.isArray(item.content)) continue;
3327
3620
  for (const part of item.content) {
3328
- if (isRecord7(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
3621
+ if (isRecord8(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
3329
3622
  }
3330
3623
  }
3331
3624
  if (parts.length > 0) return parts.join("");
@@ -3336,7 +3629,7 @@ function functionCalls(response) {
3336
3629
  if (!Array.isArray(response.output)) return [];
3337
3630
  const calls = [];
3338
3631
  for (const item of response.output) {
3339
- if (!isRecord7(item) || item.type !== "function_call") continue;
3632
+ if (!isRecord8(item) || item.type !== "function_call") continue;
3340
3633
  const name = typeof item.name === "string" ? item.name : "function";
3341
3634
  const callId = typeof item.call_id === "string" ? item.call_id : name;
3342
3635
  let args = item.arguments;
@@ -3368,7 +3661,7 @@ function toolUsage(calls) {
3368
3661
  };
3369
3662
  }
3370
3663
  function normalizeUsage2(usage) {
3371
- if (!isRecord7(usage)) return void 0;
3664
+ if (!isRecord8(usage)) return void 0;
3372
3665
  const inputTokens = numberValue2(usage.input_tokens);
3373
3666
  const outputTokens = numberValue2(usage.output_tokens);
3374
3667
  const totalTokens = numberValue2(usage.total_tokens) ?? (inputTokens !== void 0 || outputTokens !== void 0 ? (inputTokens ?? 0) + (outputTokens ?? 0) : void 0);
@@ -3420,16 +3713,16 @@ function modelOf2(compiled) {
3420
3713
  return typeof compiled.body.model === "string" ? compiled.body.model : "";
3421
3714
  }
3422
3715
  function messageFrom2(body) {
3423
- if (!isRecord7(body)) return void 0;
3716
+ if (!isRecord8(body)) return void 0;
3424
3717
  if (typeof body.message === "string") return body.message;
3425
- if (isRecord7(body.error) && typeof body.error.message === "string") return body.error.message;
3718
+ if (isRecord8(body.error) && typeof body.error.message === "string") return body.error.message;
3426
3719
  return void 0;
3427
3720
  }
3428
3721
  function numberValue2(value) {
3429
3722
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3430
3723
  }
3431
3724
  function attachProviderMetadata(body, request, packer) {
3432
- const fromBody = isRecord7(body.metadata) ? body.metadata : void 0;
3725
+ const fromBody = isRecord8(body.metadata) ? body.metadata : void 0;
3433
3726
  const packed = (0, import_openrouter_runtime2.packProviderRecord)(request.metadata, request.agentId, fromBody, packer);
3434
3727
  if (packed.wire) return { body: { ...body, metadata: packed.wire }, ...packed.warning ? { warning: packed.warning } : {} };
3435
3728
  if (body.metadata === void 0) return { body, ...packed.warning ? { warning: packed.warning } : {} };
@@ -3503,7 +3796,7 @@ function readEnv3(name) {
3503
3796
  if (typeof process === "undefined") return void 0;
3504
3797
  return process.env[name];
3505
3798
  }
3506
- function isRecord7(value) {
3799
+ function isRecord8(value) {
3507
3800
  return typeof value === "object" && value !== null && !Array.isArray(value);
3508
3801
  }
3509
3802
 
@@ -3571,6 +3864,7 @@ function createAiDispatcher(options = {}) {
3571
3864
  if (provider === "openrouter") {
3572
3865
  const openrouterOptions = {
3573
3866
  ...options.openrouter,
3867
+ ...options.openrouter?.tools ? { tools: wrapToolRegistry(options.openrouter.tools) } : {},
3574
3868
  metadataPacker: packer,
3575
3869
  ...options.logger && !options.openrouter?.logger ? { logger: options.logger } : {}
3576
3870
  };
@@ -3579,6 +3873,7 @@ function createAiDispatcher(options = {}) {
3579
3873
  if (provider === "bedrock") {
3580
3874
  const bedrockOptions = {
3581
3875
  ...options.bedrock,
3876
+ ...options.bedrock?.tools ? { tools: wrapToolRegistry(options.bedrock.tools) } : {},
3582
3877
  metadataPacker: packer,
3583
3878
  ...options.logger && !options.bedrock?.logger ? { logger: options.logger } : {}
3584
3879
  };
@@ -3587,6 +3882,7 @@ function createAiDispatcher(options = {}) {
3587
3882
  if (provider === "openai") {
3588
3883
  const openaiOptions = {
3589
3884
  ...options.openai,
3885
+ ...options.openai?.tools ? { tools: wrapToolRegistry(options.openai.tools) } : {},
3590
3886
  ...options.logger && !options.openai?.logger ? { logger: options.logger } : {}
3591
3887
  };
3592
3888
  return createOpenAiProviderAdapter(openaiOptions, packer);
@@ -3594,6 +3890,7 @@ function createAiDispatcher(options = {}) {
3594
3890
  if (provider === "cloudflare") {
3595
3891
  const cloudflareOptions = {
3596
3892
  ...options.cloudflare,
3893
+ ...options.cloudflare?.tools ? { tools: wrapToolRegistry(options.cloudflare.tools) } : {},
3597
3894
  ...options.logger && !options.cloudflare?.logger ? { logger: options.logger } : {}
3598
3895
  };
3599
3896
  return createCloudflareProviderAdapter(cloudflareOptions, packer);
@@ -3615,21 +3912,27 @@ function createAiDispatcher(options = {}) {
3615
3912
  return {
3616
3913
  provider: defaultProvider,
3617
3914
  async run(request) {
3618
- const prepared = prepare(request, true);
3915
+ const prepared = await prepare(request, true);
3619
3916
  log(options, "ai-dispatcher.request.started", prepared, "run", false);
3620
- const response = await getAdapter(prepared.provider).run(prepared.request, callOf(prepared.call));
3917
+ const response = await inputStorage.run(
3918
+ prepared.inputTrack,
3919
+ () => getAdapter(prepared.provider).run(prepared.request, callOf(prepared.call))
3920
+ );
3621
3921
  return applyResolution(response, prepared);
3622
3922
  },
3623
3923
  executeStreamingChat(request) {
3624
- const prepared = prepare(request, false);
3625
- log(options, "ai-dispatcher.request.started", prepared, "executeStreamingChat", true);
3626
- return decorateStream(
3627
- prepared,
3628
- getAdapter(prepared.provider).executeStreamingChat(prepared.request, callOf(prepared.call))
3629
- );
3924
+ return (async function* () {
3925
+ const prepared = await prepare(request, false);
3926
+ log(options, "ai-dispatcher.request.started", prepared, "executeStreamingChat", true);
3927
+ if (prepared.inputTrack) inputStorage.enterWith(prepared.inputTrack);
3928
+ yield* decorateStream(
3929
+ prepared,
3930
+ getAdapter(prepared.provider).executeStreamingChat(prepared.request, callOf(prepared.call))
3931
+ );
3932
+ })();
3630
3933
  },
3631
- compile(request) {
3632
- const prepared = prepare(request, true);
3934
+ async compile(request) {
3935
+ const prepared = await prepare(request, true);
3633
3936
  log(options, "ai-dispatcher.request.compiled", prepared, "compile", false);
3634
3937
  const compiled = getAdapter(prepared.provider).compile(prepared.request, callOf(prepared.call));
3635
3938
  return attachCompileMeta(prepared, compiled);
@@ -3643,7 +3946,7 @@ function createAiDispatcher(options = {}) {
3643
3946
  return pending;
3644
3947
  }
3645
3948
  };
3646
- function prepare(request, includeMcp) {
3949
+ async function prepare(request, includeMcp) {
3647
3950
  const provider = resolveProvider(request.provider, defaultProvider);
3648
3951
  const prepared = prepareDispatchRequest({ request, provider, options });
3649
3952
  const tools = providerTools(provider, options);
@@ -3653,6 +3956,11 @@ function createAiDispatcher(options = {}) {
3653
3956
  ...tools ? { providerTools: tools } : {},
3654
3957
  includeMcp
3655
3958
  });
3959
+ prepared.inputTrack = await applyAiInput({
3960
+ request: prepared.request,
3961
+ effectiveModel: prepared.effectiveModel,
3962
+ factory: options.aiInput
3963
+ });
3656
3964
  return prepared;
3657
3965
  }
3658
3966
  }
@@ -3670,7 +3978,8 @@ function callOf(call) {
3670
3978
  }
3671
3979
  function attachCompileMeta(prepared, compiled) {
3672
3980
  const record2 = compiled;
3673
- const headers = isRecord8(record2.headers) ? redactHeaders(record2.headers) : void 0;
3981
+ const headers = isRecord9(record2.headers) ? redactHeaders(record2.headers) : void 0;
3982
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
3674
3983
  return {
3675
3984
  ...record2,
3676
3985
  ...headers ? { headers } : {},
@@ -3679,6 +3988,7 @@ function attachCompileMeta(prepared, compiled) {
3679
3988
  effectiveModel: prepared.effectiveModel,
3680
3989
  ...prepared.resolution ? { reasoningResolution: prepared.resolution } : {},
3681
3990
  ...prepared.cacheResolution ? { cacheResolution: prepared.cacheResolution } : {},
3991
+ ...inputResolution ? { inputResolution } : {},
3682
3992
  ...prepared.cacheWarnings?.length ? { warnings: [...Array.isArray(record2.warnings) ? record2.warnings : [], ...prepared.cacheWarnings] } : {}
3683
3993
  };
3684
3994
  }
@@ -3704,7 +4014,7 @@ function log(options, event, prepared, entrypoint, streaming) {
3704
4014
  if (event.endsWith("compiled")) options.logger?.debug?.(event, payload);
3705
4015
  else options.logger?.info?.(event, payload);
3706
4016
  }
3707
- function isRecord8(value) {
4017
+ function isRecord9(value) {
3708
4018
  return typeof value === "object" && value !== null && !Array.isArray(value);
3709
4019
  }
3710
4020