@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.js CHANGED
@@ -10,6 +10,318 @@ import {
10
10
  // src/create-dispatcher.ts
11
11
  import { createMetadataPacker } from "@x12i/provider-metadata";
12
12
 
13
+ // src/ai-input.ts
14
+ import { AsyncLocalStorage } from "async_hooks";
15
+ import {
16
+ createCoreClient,
17
+ isAiInputError,
18
+ resolveSettings
19
+ } from "@x12i/ai-input/core";
20
+
21
+ // src/types/providers.ts
22
+ var IMPLEMENTED_AI_PROVIDERS = ["openrouter", "bedrock", "openai", "cloudflare"];
23
+ function isImplementedAiProvider(provider) {
24
+ return IMPLEMENTED_AI_PROVIDERS.includes(provider);
25
+ }
26
+
27
+ // src/errors.ts
28
+ var AiDispatcherError = class extends Error {
29
+ constructor(code, message, details) {
30
+ super(message);
31
+ this.code = code;
32
+ this.details = details;
33
+ this.name = "AiDispatcherError";
34
+ }
35
+ code;
36
+ details;
37
+ };
38
+ function providerNotImplemented(provider) {
39
+ const implemented = [...IMPLEMENTED_AI_PROVIDERS];
40
+ return new AiDispatcherError(
41
+ "PROVIDER_NOT_IMPLEMENTED",
42
+ `AI provider "${provider}" is not implemented yet. Supported by @x12i/ai-dispatcher: ${implemented.map((id) => `"${id}"`).join(", ")}.`,
43
+ {
44
+ provider,
45
+ implementedProviders: implemented,
46
+ operatorHint: `Pass provider: "${implemented[0]}" (or omit provider to use the default).`
47
+ }
48
+ );
49
+ }
50
+
51
+ // src/ai-input.ts
52
+ var GPT_ENCODINGS = /* @__PURE__ */ new Set(["o200k_base", "cl100k_base", "p50k_base", "p50k_edit", "r50k_base"]);
53
+ var inputStorage = new AsyncLocalStorage();
54
+ function mergeAiInput(factory, request) {
55
+ if (request === false) return false;
56
+ if (request === void 0) {
57
+ if (factory === false) return false;
58
+ return factory ?? {};
59
+ }
60
+ const base = typeof factory === "object" ? factory : {};
61
+ const { approvals: requestApprovals, ...requestRest } = request;
62
+ return {
63
+ ...base,
64
+ ...requestRest,
65
+ ...requestApprovals !== void 0 ? { approvals: requestApprovals } : base.approvals !== void 0 ? { approvals: base.approvals } : {}
66
+ };
67
+ }
68
+ function visibleInputResolution(track) {
69
+ if (!track.enabled) return { enabled: false, changed: false };
70
+ const baseline = isBaselineCodec(track.codec) && track.representation === "value";
71
+ if (!track.changed && baseline && !track.surfaced) return void 0;
72
+ return {
73
+ enabled: true,
74
+ ...track.model ? { model: track.model } : {},
75
+ mode: track.mode,
76
+ codec: track.codec,
77
+ representation: track.representation,
78
+ approvalSource: track.approvalSource,
79
+ changed: track.changed
80
+ };
81
+ }
82
+ function wrapToolRegistry(tools) {
83
+ const wrapped = {};
84
+ for (const [name, executor] of Object.entries(tools)) {
85
+ if (!executor) continue;
86
+ wrapped[name] = wrapProviderExecutor(executor);
87
+ }
88
+ return wrapped;
89
+ }
90
+ function wrapProviderExecutor(executor) {
91
+ return async (args, context) => {
92
+ const result = await executor(args, context);
93
+ const track = inputStorage.getStore();
94
+ if (!track?.enabled || !track.client) return result;
95
+ return applyEncodedResult(track, result);
96
+ };
97
+ }
98
+ async function applyAiInput(params) {
99
+ const requestSetting = params.request.aiInput;
100
+ delete params.request.aiInput;
101
+ const settings = mergeAiInput(params.factory, requestSetting);
102
+ if (settings === false) return disabledTrack();
103
+ const track = await openTrack(settings, lookupModel(settings.model, params.effectiveModel));
104
+ await encodeRequestText(params.request, track);
105
+ wrapRequestTools(params.request, track);
106
+ return track;
107
+ }
108
+ function disabledTrack() {
109
+ return {
110
+ enabled: false,
111
+ mode: "compact",
112
+ codec: "text",
113
+ representation: "value",
114
+ approvalSource: "baseline",
115
+ changed: false,
116
+ surfaced: false
117
+ };
118
+ }
119
+ async function openTrack(settings, model) {
120
+ const tokenizer = settings.tokenizer ?? "none";
121
+ const mode = settings.mode ?? "compact";
122
+ let tokenCounter;
123
+ try {
124
+ tokenCounter = await loadTokenizer(tokenizer);
125
+ const framing = framingFor(settings);
126
+ const resolved = resolveSettings({
127
+ files: [],
128
+ env: {},
129
+ factory: {
130
+ mode,
131
+ codec: settings.codec ?? "auto",
132
+ readableFormat: settings.readableFormat ?? "auto",
133
+ sharing: settings.sharing ?? "auto",
134
+ tokenizer: tokenCounter?.id ?? "none",
135
+ framing,
136
+ ...model ? { model } : {}
137
+ }
138
+ });
139
+ const approvals = settings.approvals;
140
+ const client = createCoreClient({
141
+ config: resolved.config,
142
+ explanation: resolved.explanation,
143
+ ...approvals && approvals.length > 0 ? { policy: { approvals: [...approvals] } } : {},
144
+ ...tokenCounter ? { tokenCounter } : {},
145
+ warn: () => void 0
146
+ });
147
+ return {
148
+ enabled: true,
149
+ client,
150
+ ...model ? { model } : {},
151
+ mode,
152
+ codec: "text",
153
+ representation: "value",
154
+ approvalSource: "baseline",
155
+ changed: false,
156
+ surfaced: false
157
+ };
158
+ } catch (error) {
159
+ throw mapAiInputError(error);
160
+ }
161
+ }
162
+ function lookupModel(override, effectiveModel) {
163
+ const explicit = override?.trim();
164
+ const chosen = explicit ? explicit : effectiveModel.trim();
165
+ return chosen.length > 0 ? chosen : void 0;
166
+ }
167
+ function framingFor(settings) {
168
+ if (settings.framing) return settings.framing;
169
+ const tokenizer = settings.tokenizer ?? "none";
170
+ if (tokenizer !== "none" && (settings.approvals?.length ?? 0) > 0) return "self-describing";
171
+ return "raw";
172
+ }
173
+ async function loadTokenizer(tokenizer) {
174
+ if (tokenizer === "none") return void 0;
175
+ if (!tokenizer.startsWith("gpt:")) {
176
+ throw new AiDispatcherError("AI_INPUT_FAILED", `Unsupported tokenizer "${tokenizer}".`, {
177
+ code: "INVALID_CONFIG"
178
+ });
179
+ }
180
+ const encoding = tokenizer.slice("gpt:".length);
181
+ if (!GPT_ENCODINGS.has(encoding)) {
182
+ throw new AiDispatcherError("AI_INPUT_FAILED", `Unsupported tokenizer "${tokenizer}".`, {
183
+ code: "INVALID_CONFIG"
184
+ });
185
+ }
186
+ const gpt = await import("@x12i/ai-input/tokenizers/gpt");
187
+ return gpt.createGptTokenCounter(encoding);
188
+ }
189
+ async function encodeRequestText(request, track) {
190
+ if (typeof request.prompt === "string") request.prompt = await encodeString(track, request.prompt);
191
+ if (typeof request.system === "string") request.system = await encodeString(track, request.system);
192
+ if (typeof request.instructions === "string") request.instructions = await encodeString(track, request.instructions);
193
+ if (typeof request.input === "string") {
194
+ request.input = await encodeString(track, request.input);
195
+ } else if (Array.isArray(request.input)) {
196
+ for (let index = 0; index < request.input.length; index += 1) {
197
+ const item = request.input[index];
198
+ if (typeof item === "string") {
199
+ request.input[index] = await encodeString(track, item);
200
+ } else if (item) {
201
+ await encodeContentRecord(item, track);
202
+ }
203
+ }
204
+ }
205
+ if (request.messages) {
206
+ for (const message of request.messages) {
207
+ await encodeMessage(message, track);
208
+ }
209
+ }
210
+ }
211
+ async function encodeMessage(message, track) {
212
+ if (typeof message.content === "string") {
213
+ message.content = await encodeString(track, message.content);
214
+ return;
215
+ }
216
+ for (const part of message.content) {
217
+ if (part.type === "text") part.text = await encodeString(track, part.text);
218
+ }
219
+ }
220
+ async function encodeContentRecord(record2, track) {
221
+ if (typeof record2.content === "string") {
222
+ record2.content = await encodeString(track, record2.content);
223
+ return;
224
+ }
225
+ if (!Array.isArray(record2.content)) return;
226
+ for (const part of record2.content) {
227
+ if (!isRecord(part) || typeof part.text !== "string") continue;
228
+ if (part.type === "text" || part.type === "input_text") {
229
+ part.text = await encodeString(track, part.text);
230
+ }
231
+ }
232
+ }
233
+ function wrapRequestTools(request, track) {
234
+ if (!request.functionTools) return;
235
+ request.functionTools = request.functionTools.map((tool) => {
236
+ if (!tool.executor) return tool;
237
+ const executor = tool.executor;
238
+ return {
239
+ ...tool,
240
+ executor: async (args, context) => applyEncodedResult(track, await executor(args, context))
241
+ };
242
+ });
243
+ }
244
+ async function encodeString(track, value) {
245
+ const encoded = await applyEncodedResult(track, value);
246
+ return typeof encoded === "string" ? encoded : value;
247
+ }
248
+ async function applyEncodedResult(track, value) {
249
+ if (!track.enabled || !track.client) return value;
250
+ let prepared;
251
+ try {
252
+ prepared = await track.client.prepare(value);
253
+ } catch (error) {
254
+ const failure = readPackageFailure(error);
255
+ if (failure?.code === "UNSUPPORTED_VALUE") return value;
256
+ throw mapAiInputError(error);
257
+ }
258
+ const wire = unframedBaseline(prepared);
259
+ note(track, prepared, value, wire);
260
+ if (wire === canonicalWire(value)) return value;
261
+ return wire;
262
+ }
263
+ function unframedBaseline(prepared) {
264
+ const baseline = isBaselineCodec(prepared.codec) && prepared.representation === "value";
265
+ if (!baseline || prepared.framing === "raw") return prepared.text;
266
+ const newline = prepared.text.indexOf("\n");
267
+ if (!prepared.text.startsWith("@ai-input/") || newline < 0) return prepared.text;
268
+ return prepared.text.slice(newline + 1);
269
+ }
270
+ function isBaselineCodec(codec) {
271
+ return codec === "json" || codec === "text" || codec === "outline";
272
+ }
273
+ function note(track, prepared, source, wire) {
274
+ const changed = wire !== canonicalWire(source);
275
+ if (changed) track.changed = true;
276
+ const alternate = prepared.codec === "toon" || prepared.representation !== "value";
277
+ if (alternate || !track.surfaced) {
278
+ track.codec = prepared.codec;
279
+ track.representation = prepared.representation;
280
+ track.approvalSource = prepared.receipt.approvalSource;
281
+ track.mode = prepared.mode;
282
+ }
283
+ if (alternate) track.surfaced = true;
284
+ }
285
+ function canonicalWire(value) {
286
+ if (typeof value === "string") return value;
287
+ return JSON.stringify(value);
288
+ }
289
+ function mapAiInputError(error) {
290
+ if (error instanceof AiDispatcherError) return error;
291
+ const failure = readPackageFailure(error);
292
+ if (failure) {
293
+ return new AiDispatcherError("AI_INPUT_FAILED", failure.message, {
294
+ code: failure.code,
295
+ ...failure.path !== void 0 ? { path: failure.path } : {},
296
+ ...failure.details !== void 0 ? { details: failure.details } : {}
297
+ });
298
+ }
299
+ const message = error instanceof Error ? error.message : "Input preparation failed.";
300
+ return new AiDispatcherError("AI_INPUT_FAILED", message);
301
+ }
302
+ function readPackageFailure(error) {
303
+ if (isAiInputError(error)) {
304
+ return {
305
+ code: error.code,
306
+ message: error.message,
307
+ ...error.path !== void 0 ? { path: error.path } : {},
308
+ ...error.details !== void 0 ? { details: error.details } : {}
309
+ };
310
+ }
311
+ if (!(error instanceof Error) || error.name !== "AiInputError") return void 0;
312
+ const coded = error;
313
+ if (typeof coded.code !== "string") return void 0;
314
+ return {
315
+ code: coded.code,
316
+ message: error.message,
317
+ ...typeof coded.path === "string" ? { path: coded.path } : {},
318
+ ...coded.details !== void 0 ? { details: coded.details } : {}
319
+ };
320
+ }
321
+ function isRecord(value) {
322
+ return typeof value === "object" && value !== null && !Array.isArray(value);
323
+ }
324
+
13
325
  // src/cache-usage.ts
14
326
  function readCacheTokens(source) {
15
327
  const cached = [];
@@ -58,7 +370,7 @@ function record(value) {
58
370
 
59
371
  // src/json-pointer.ts
60
372
  var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
61
- function isRecord(value) {
373
+ function isRecord2(value) {
62
374
  return typeof value === "object" && value !== null && !Array.isArray(value);
63
375
  }
64
376
  function unescapeToken(token) {
@@ -85,7 +397,7 @@ function walk(current, tokens) {
85
397
  if (index >= current.length) return [];
86
398
  return walk(current[index], rest);
87
399
  }
88
- if (!isRecord(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
400
+ if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
89
401
  return walk(current[head], rest);
90
402
  }
91
403
  function valuesAtPointer(root, pointer) {
@@ -122,7 +434,7 @@ function collectParents(current, tokens) {
122
434
  if (index >= current.length) return [];
123
435
  return collectParents(current[index], rest);
124
436
  }
125
- if (!isRecord(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
437
+ if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
126
438
  return collectParents(current[head], rest);
127
439
  }
128
440
  function deletePointer(root, pointer) {
@@ -138,27 +450,27 @@ function deletePointer(root, pointer) {
138
450
  if (index < parent.length) parent.splice(index, 1);
139
451
  continue;
140
452
  }
141
- if (isRecord(parent) && Object.prototype.hasOwnProperty.call(parent, last)) {
453
+ if (isRecord2(parent) && Object.prototype.hasOwnProperty.call(parent, last)) {
142
454
  delete parent[last];
143
455
  }
144
456
  }
145
457
  }
146
458
 
147
459
  // src/reasoning-extract.ts
148
- function isRecord2(value) {
460
+ function isRecord3(value) {
149
461
  return typeof value === "object" && value !== null && !Array.isArray(value);
150
462
  }
151
463
  function textFromValue(value) {
152
464
  if (typeof value === "string") return value;
153
465
  if (Array.isArray(value)) return value.map(textFromValue).join("");
154
- if (!isRecord2(value)) return "";
466
+ if (!isRecord3(value)) return "";
155
467
  if (typeof value.text === "string") return value.text;
156
468
  if (typeof value.summary === "string") return value.summary;
157
469
  return "";
158
470
  }
159
471
  function extractStreamReasoningText(event, response) {
160
472
  if (response.streamReasoningKeys.length > 0) {
161
- if (!isRecord2(event)) return void 0;
473
+ if (!isRecord3(event)) return void 0;
162
474
  for (const key of response.streamReasoningKeys) {
163
475
  const text = textFromValue(event[key]);
164
476
  if (text) return text;
@@ -256,6 +568,8 @@ function applyResolution(response, prepared) {
256
568
  if (prepared.cacheWarnings?.length) {
257
569
  result.warnings = [...result.warnings, ...prepared.cacheWarnings];
258
570
  }
571
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
572
+ if (inputResolution) result.inputResolution = inputResolution;
259
573
  applyCacheUsage(result);
260
574
  const directive = prepared.directive;
261
575
  if (!directive) return result;
@@ -299,7 +613,7 @@ function applyUsage(response, raw, directive) {
299
613
  }
300
614
 
301
615
  // src/decorate-stream.ts
302
- function isRecord3(value) {
616
+ function isRecord4(value) {
303
617
  return typeof value === "object" && value !== null && !Array.isArray(value);
304
618
  }
305
619
  async function* decorateStream(prepared, source) {
@@ -357,11 +671,13 @@ async function* decorateStream(prepared, source) {
357
671
  };
358
672
  }
359
673
  }
360
- const data = isRecord3(event.data) ? { ...event.data } : {};
674
+ const data = isRecord4(event.data) ? { ...event.data } : {};
361
675
  if (splitter) data.text = splitter.answer;
362
676
  if (reasoningText) data.reasoningText = reasoningText;
363
677
  if (prepared.resolution) data.reasoningResolution = prepared.resolution;
364
678
  if (prepared.cacheResolution) data.cacheResolution = prepared.cacheResolution;
679
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
680
+ if (inputResolution) data.inputResolution = inputResolution;
365
681
  yield { ...event, data };
366
682
  continue;
367
683
  }
@@ -369,18 +685,20 @@ async function* decorateStream(prepared, source) {
369
685
  }
370
686
  }
371
687
  function withResolution(event, prepared) {
372
- if (!prepared.resolution && !prepared.cacheResolution) return event;
373
- const data = isRecord3(event.data) ? { ...event.data } : {};
688
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
689
+ if (!prepared.resolution && !prepared.cacheResolution && !inputResolution) return event;
690
+ const data = isRecord4(event.data) ? { ...event.data } : {};
374
691
  if (prepared.resolution) data.reasoningResolution = prepared.resolution;
375
692
  if (prepared.cacheResolution) data.cacheResolution = prepared.cacheResolution;
693
+ if (inputResolution) data.inputResolution = inputResolution;
376
694
  return { ...event, data };
377
695
  }
378
696
  function textOf(event) {
379
- if (!isRecord3(event.data) || typeof event.data.text !== "string") return "";
697
+ if (!isRecord4(event.data) || typeof event.data.text !== "string") return "";
380
698
  return event.data.text;
381
699
  }
382
700
  function adjustUsageEvent(event, prepared) {
383
- if (!isRecord3(event.data) || !isRecord3(event.data.usage)) return event;
701
+ if (!isRecord4(event.data) || !isRecord4(event.data.usage)) return event;
384
702
  const paths = prepared.directive?.usage?.reasoningTokenPaths;
385
703
  const usage = { ...event.data.usage };
386
704
  let changed = false;
@@ -409,36 +727,6 @@ function adjustUsageEvent(event, prepared) {
409
727
  return { ...event, data: { ...event.data, usage } };
410
728
  }
411
729
 
412
- // src/types/providers.ts
413
- var IMPLEMENTED_AI_PROVIDERS = ["openrouter", "bedrock", "openai", "cloudflare"];
414
- function isImplementedAiProvider(provider) {
415
- return IMPLEMENTED_AI_PROVIDERS.includes(provider);
416
- }
417
-
418
- // src/errors.ts
419
- var AiDispatcherError = class extends Error {
420
- constructor(code, message, details) {
421
- super(message);
422
- this.code = code;
423
- this.details = details;
424
- this.name = "AiDispatcherError";
425
- }
426
- code;
427
- details;
428
- };
429
- function providerNotImplemented(provider) {
430
- const implemented = [...IMPLEMENTED_AI_PROVIDERS];
431
- return new AiDispatcherError(
432
- "PROVIDER_NOT_IMPLEMENTED",
433
- `AI provider "${provider}" is not implemented yet. Supported by @x12i/ai-dispatcher: ${implemented.map((id) => `"${id}"`).join(", ")}.`,
434
- {
435
- provider,
436
- implementedProviders: implemented,
437
- operatorHint: `Pass provider: "${implemented[0]}" (or omit provider to use the default).`
438
- }
439
- );
440
- }
441
-
442
730
  // src/mcp.ts
443
731
  var TOOL_TOKEN = /^[A-Za-z0-9_-]+$/;
444
732
  var MAX_EXPOSED_NAME_LENGTH = 64;
@@ -460,7 +748,7 @@ function indexMcpServers(servers) {
460
748
  for (const server of servers) {
461
749
  assertServer(server, seenServers);
462
750
  for (const tool of server.tools) {
463
- if (!isRecord4(tool)) {
751
+ if (!isRecord5(tool)) {
464
752
  throw new AiDispatcherError(
465
753
  "MCP_TOOL_NAME_INVALID",
466
754
  `MCP server "${server.id}" has a tool that is not an object.`
@@ -547,18 +835,17 @@ function applyMcpCatalog(params) {
547
835
  function createMcpExecutor(server, rawName) {
548
836
  return async (args, context) => {
549
837
  const result = await server.callTool(rawName, toArgs(args), context);
550
- return flattenMcpResult(result);
838
+ return mcpModelValue(result);
551
839
  };
552
840
  }
553
- function flattenMcpResult(result) {
554
- if (typeof result === "string") return result;
555
- if (!isRecord4(result)) return stringify(result);
841
+ function mcpModelValue(result) {
842
+ if (typeof result === "string" || !isRecord5(result)) return result;
556
843
  const text = textContent(result.content);
557
844
  if (result.isError === true) {
558
845
  throw new Error(text ?? stringify(result));
559
846
  }
560
847
  if (text !== void 0) return text;
561
- return stringify(result);
848
+ return result;
562
849
  }
563
850
  function resolveAllowlist(filter, tools) {
564
851
  if (filter === void 0) return void 0;
@@ -577,7 +864,7 @@ function resolveAllowlist(filter, tools) {
577
864
  return new Set(filter);
578
865
  }
579
866
  function assertServer(server, seen) {
580
- if (!isRecord4(server) || typeof server.id !== "string" || server.id.length === 0 || !Array.isArray(server.tools) || typeof server.callTool !== "function") {
867
+ if (!isRecord5(server) || typeof server.id !== "string" || server.id.length === 0 || !Array.isArray(server.tools) || typeof server.callTool !== "function") {
581
868
  throw new AiDispatcherError(
582
869
  "MCP_SERVER_INVALID",
583
870
  "An MCP server needs an id, a tools array, and a callTool function."
@@ -622,7 +909,7 @@ function toolDescription(tool) {
622
909
  }
623
910
  function toolParameters(tool) {
624
911
  if (tool.inputSchema === void 0) return { ...DEFAULT_PARAMETERS, properties: {} };
625
- if (!isRecord4(tool.inputSchema)) {
912
+ if (!isRecord5(tool.inputSchema)) {
626
913
  throw new AiDispatcherError(
627
914
  "MCP_TOOL_NAME_INVALID",
628
915
  `MCP tool "${tool.name}" inputSchema must be an object.`
@@ -634,14 +921,14 @@ function textContent(content) {
634
921
  if (!Array.isArray(content)) return void 0;
635
922
  const parts = [];
636
923
  for (const part of content) {
637
- if (!isRecord4(part) || part.type !== "text" || typeof part.text !== "string") continue;
924
+ if (!isRecord5(part) || part.type !== "text" || typeof part.text !== "string") continue;
638
925
  parts.push(part.text);
639
926
  }
640
927
  if (!parts.length) return void 0;
641
928
  return parts.join("\n");
642
929
  }
643
930
  function toArgs(args) {
644
- if (isRecord4(args)) return args;
931
+ if (isRecord5(args)) return args;
645
932
  return {};
646
933
  }
647
934
  function listFailed(serverId, error) {
@@ -653,7 +940,7 @@ function stringify(result) {
653
940
  const serialized = JSON.stringify(result);
654
941
  return serialized === void 0 ? "null" : serialized;
655
942
  }
656
- function isRecord4(value) {
943
+ function isRecord5(value) {
657
944
  return typeof value === "object" && value !== null && !Array.isArray(value);
658
945
  }
659
946
 
@@ -1215,7 +1502,7 @@ function compileCloudflareRequest(request, options, call, streaming) {
1215
1502
  if (call?.finalizeBody) body = call.finalizeBody(body);
1216
1503
  if (endpoint !== "run") body = { ...body, stream: streaming };
1217
1504
  const gateway = mergeGateway(options.gateway, call?.cloudflare?.gateway);
1218
- const fromBody = isRecord5(body.metadata) ? body.metadata : void 0;
1505
+ const fromBody = isRecord6(body.metadata) ? body.metadata : void 0;
1219
1506
  const packed = packProviderRecord(
1220
1507
  request.metadata,
1221
1508
  request.agentId,
@@ -1469,7 +1756,7 @@ function messagesFromInput(request) {
1469
1756
  messages.push({ role: "user", content: item });
1470
1757
  continue;
1471
1758
  }
1472
- if (!isRecord5(item)) continue;
1759
+ if (!isRecord6(item)) continue;
1473
1760
  const role = item.role === "assistant" || item.role === "tool" || item.role === "system" ? item.role : "user";
1474
1761
  if (role === "system") continue;
1475
1762
  const content = inputContent(item.content);
@@ -1486,12 +1773,12 @@ function inputContent(content) {
1486
1773
  if (!Array.isArray(content)) return void 0;
1487
1774
  const parts = [];
1488
1775
  for (const part of content) {
1489
- if (!isRecord5(part)) continue;
1776
+ if (!isRecord6(part)) continue;
1490
1777
  if ((part.type === "text" || part.type === "input_text") && typeof part.text === "string") {
1491
1778
  parts.push({ type: "text", text: part.text });
1492
1779
  } else if (part.type === "image_url" && typeof part.imageUrl === "string") {
1493
1780
  parts.push({ type: "image_url", imageUrl: part.imageUrl });
1494
- } else if (part.type === "image_url" && isRecord5(part.image_url) && typeof part.image_url.url === "string") {
1781
+ } else if (part.type === "image_url" && isRecord6(part.image_url) && typeof part.image_url.url === "string") {
1495
1782
  parts.push({ type: "image_url", imageUrl: part.image_url.url });
1496
1783
  } else if (part.type === "input_image" && typeof part.image_url === "string") {
1497
1784
  parts.push({ type: "image_url", imageUrl: part.image_url });
@@ -1710,7 +1997,7 @@ function continueMessages(body, response, results) {
1710
1997
  return { ...body, messages };
1711
1998
  }
1712
1999
  function continueRun(body, response, results) {
1713
- const input = isRecord5(body.input) ? body.input : {};
2000
+ const input = isRecord6(body.input) ? body.input : {};
1714
2001
  const continued = continueChat({ messages: input.messages }, response, results);
1715
2002
  return { ...body, input: { ...input, messages: continued.messages } };
1716
2003
  }
@@ -1799,7 +2086,7 @@ async function* streamCloudflare(request, options, call) {
1799
2086
  throw failure;
1800
2087
  }
1801
2088
  for await (const event of parseSse(response)) {
1802
- if (!isRecord5(event)) continue;
2089
+ if (!isRecord6(event)) continue;
1803
2090
  const catalogReasoning = call?.extractStreamReasoning?.(event);
1804
2091
  const reasoningText = catalogReasoning || reasoningDelta(event);
1805
2092
  if (reasoningText) yield { type: "stream.reasoning.delta", requestId, data: { text: reasoningText } };
@@ -1862,7 +2149,7 @@ async function sendOnce(compiled, options, timeoutMs) {
1862
2149
  if (!response.ok) throw await readFailure(response);
1863
2150
  const text = await response.text();
1864
2151
  const parsed = text ? JSON.parse(text) : {};
1865
- if (isRecord5(parsed) && parsed.success === false) {
2152
+ if (isRecord6(parsed) && parsed.success === false) {
1866
2153
  throw new AiDispatcherError(
1867
2154
  "PROVIDER_REQUEST_FAILED",
1868
2155
  messageFrom(parsed) ?? "Cloudflare request failed.",
@@ -1913,7 +2200,7 @@ function isConfigError(code) {
1913
2200
  }
1914
2201
  function asTerminalError(error) {
1915
2202
  if (error instanceof AiDispatcherError && error.code === "PROVIDER_RETRYABLE") {
1916
- const status = isRecord5(error.details) ? error.details.status : void 0;
2203
+ const status = isRecord6(error.details) ? error.details.status : void 0;
1917
2204
  if (status === 429) return new AiDispatcherError("PROVIDER_RATE_LIMITED", error.message, error.details);
1918
2205
  return new AiDispatcherError("PROVIDER_GATEWAY_UNREACHABLE", error.message, error.details);
1919
2206
  }
@@ -1923,7 +2210,7 @@ function asTerminalError(error) {
1923
2210
  function normalizeCloudflareResponse(params) {
1924
2211
  const payload = unwrap(params.response);
1925
2212
  const calls = params.functionTools ?? extractCalls(params.compiled.endpoint, params.response);
1926
- const usage = normalizeUsage(payload.usage) ?? normalizeUsage(isRecord5(params.response) ? params.response.usage : void 0);
2213
+ const usage = normalizeUsage(payload.usage) ?? normalizeUsage(isRecord6(params.response) ? params.response.usage : void 0);
1927
2214
  const status = params.status ?? (calls.length ? "requires_action" : "completed");
1928
2215
  return {
1929
2216
  id: typeof payload.id === "string" ? payload.id : params.requestId,
@@ -1956,16 +2243,16 @@ function answerText(response) {
1956
2243
  if (chat) return chat;
1957
2244
  const anthropic = anthropicAnswer(response);
1958
2245
  if (anthropic) return anthropic;
1959
- if (isRecord5(response.result)) return answerText(response.result);
2246
+ if (isRecord6(response.result)) return answerText(response.result);
1960
2247
  return "";
1961
2248
  }
1962
2249
  function responsesAnswer(response) {
1963
2250
  if (!Array.isArray(response.output)) return "";
1964
2251
  const parts = [];
1965
2252
  for (const item of response.output) {
1966
- if (!isRecord5(item) || item.type !== "message" || !Array.isArray(item.content)) continue;
2253
+ if (!isRecord6(item) || item.type !== "message" || !Array.isArray(item.content)) continue;
1967
2254
  for (const part of item.content) {
1968
- if (isRecord5(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
2255
+ if (isRecord6(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
1969
2256
  }
1970
2257
  }
1971
2258
  return parts.join("");
@@ -1976,16 +2263,16 @@ function chatAnswer(response) {
1976
2263
  const content = message.content;
1977
2264
  if (typeof content === "string") return content;
1978
2265
  if (!Array.isArray(content)) return "";
1979
- return content.map((part) => isRecord5(part) && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
2266
+ return content.map((part) => isRecord6(part) && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
1980
2267
  }
1981
2268
  function anthropicAnswer(response) {
1982
2269
  if (!Array.isArray(response.content)) return "";
1983
- return response.content.map((part) => isRecord5(part) && part.type === "text" && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
2270
+ return response.content.map((part) => isRecord6(part) && part.type === "text" && typeof part.text === "string" ? part.text : "").filter(Boolean).join("");
1984
2271
  }
1985
2272
  function chatAssistantMessage(response) {
1986
- if (!Array.isArray(response.choices) || !isRecord5(response.choices[0])) return void 0;
2273
+ if (!Array.isArray(response.choices) || !isRecord6(response.choices[0])) return void 0;
1987
2274
  const message = response.choices[0].message;
1988
- return isRecord5(message) ? message : void 0;
2275
+ return isRecord6(message) ? message : void 0;
1989
2276
  }
1990
2277
  function extractCalls(endpoint, response) {
1991
2278
  const record2 = unwrap(response);
@@ -1997,7 +2284,7 @@ function responsesCalls(response) {
1997
2284
  if (!Array.isArray(response.output)) return [];
1998
2285
  const calls = [];
1999
2286
  for (const item of response.output) {
2000
- if (!isRecord5(item) || item.type !== "function_call") continue;
2287
+ if (!isRecord6(item) || item.type !== "function_call") continue;
2001
2288
  calls.push(callUsage(
2002
2289
  typeof item.name === "string" ? item.name : "function",
2003
2290
  typeof item.call_id === "string" ? item.call_id : "function",
@@ -2011,7 +2298,7 @@ function chatCalls(response) {
2011
2298
  if (!message || !Array.isArray(message.tool_calls)) return [];
2012
2299
  const calls = [];
2013
2300
  for (const item of message.tool_calls) {
2014
- if (!isRecord5(item) || !isRecord5(item.function)) continue;
2301
+ if (!isRecord6(item) || !isRecord6(item.function)) continue;
2015
2302
  const name = typeof item.function.name === "string" ? item.function.name : "function";
2016
2303
  calls.push(callUsage(
2017
2304
  name,
@@ -2025,7 +2312,7 @@ function anthropicCalls(response) {
2025
2312
  if (!Array.isArray(response.content)) return [];
2026
2313
  const calls = [];
2027
2314
  for (const item of response.content) {
2028
- if (!isRecord5(item) || item.type !== "tool_use") continue;
2315
+ if (!isRecord6(item) || item.type !== "tool_use") continue;
2029
2316
  const name = typeof item.name === "string" ? item.name : "function";
2030
2317
  calls.push({
2031
2318
  name,
@@ -2064,7 +2351,7 @@ function emptyToolUsage(calls) {
2064
2351
  };
2065
2352
  }
2066
2353
  function normalizeUsage(usage) {
2067
- if (!isRecord5(usage)) return void 0;
2354
+ if (!isRecord6(usage)) return void 0;
2068
2355
  const inputTokens = numberValue(usage.input_tokens) ?? numberValue(usage.prompt_tokens);
2069
2356
  const outputTokens = numberValue(usage.output_tokens) ?? numberValue(usage.completion_tokens);
2070
2357
  const totalTokens = numberValue(usage.total_tokens) ?? (inputTokens !== void 0 || outputTokens !== void 0 ? (inputTokens ?? 0) + (outputTokens ?? 0) : void 0);
@@ -2115,7 +2402,7 @@ function errorEvent(requestId, error) {
2115
2402
  }
2116
2403
  function textDelta(event) {
2117
2404
  if (event.type === "response.output_text.delta" && typeof event.delta === "string" && event.delta) return event.delta;
2118
- if (event.type === "content_block_delta" && isRecord5(event.delta) && event.delta.type === "text_delta" && typeof event.delta.text === "string" && event.delta.text) {
2405
+ if (event.type === "content_block_delta" && isRecord6(event.delta) && event.delta.type === "text_delta" && typeof event.delta.text === "string" && event.delta.text) {
2119
2406
  return event.delta.text;
2120
2407
  }
2121
2408
  const choice = firstChoiceDelta(event);
@@ -2124,7 +2411,7 @@ function textDelta(event) {
2124
2411
  }
2125
2412
  function reasoningDelta(event) {
2126
2413
  if (event.type === "response.reasoning_summary_text.delta" && typeof event.delta === "string" && event.delta) return event.delta;
2127
- if (event.type === "content_block_delta" && isRecord5(event.delta) && event.delta.type === "thinking_delta" && typeof event.delta.thinking === "string" && event.delta.thinking) {
2414
+ if (event.type === "content_block_delta" && isRecord6(event.delta) && event.delta.type === "thinking_delta" && typeof event.delta.thinking === "string" && event.delta.thinking) {
2128
2415
  return event.delta.thinking;
2129
2416
  }
2130
2417
  const choice = firstChoiceDelta(event);
@@ -2141,13 +2428,13 @@ function toolCallDelta(event) {
2141
2428
  argumentsDelta: event.delta
2142
2429
  };
2143
2430
  }
2144
- if (event.type === "content_block_delta" && isRecord5(event.delta) && event.delta.type === "input_json_delta" && typeof event.delta.partial_json === "string") {
2431
+ if (event.type === "content_block_delta" && isRecord6(event.delta) && event.delta.type === "input_json_delta" && typeof event.delta.partial_json === "string") {
2145
2432
  return { index: typeof event.index === "number" ? event.index : 0, argumentsDelta: event.delta.partial_json };
2146
2433
  }
2147
2434
  const choice = firstChoiceDelta(event);
2148
- if (!choice || !Array.isArray(choice.tool_calls) || !isRecord5(choice.tool_calls[0])) return void 0;
2435
+ if (!choice || !Array.isArray(choice.tool_calls) || !isRecord6(choice.tool_calls[0])) return void 0;
2149
2436
  const tool = choice.tool_calls[0];
2150
- const fn = isRecord5(tool.function) ? tool.function : void 0;
2437
+ const fn = isRecord6(tool.function) ? tool.function : void 0;
2151
2438
  const args = fn && typeof fn.arguments === "string" ? fn.arguments : void 0;
2152
2439
  if (!args && !(fn && typeof fn.name === "string")) return void 0;
2153
2440
  return {
@@ -2157,18 +2444,18 @@ function toolCallDelta(event) {
2157
2444
  };
2158
2445
  }
2159
2446
  function streamUsage(event) {
2160
- if (event.type === "response.completed" && isRecord5(event.response)) return normalizeUsage(event.response.usage);
2161
- if (isRecord5(event.usage)) return normalizeUsage(event.usage);
2447
+ if (event.type === "response.completed" && isRecord6(event.response)) return normalizeUsage(event.response.usage);
2448
+ if (isRecord6(event.usage)) return normalizeUsage(event.usage);
2162
2449
  return void 0;
2163
2450
  }
2164
2451
  function firstChoiceDelta(event) {
2165
- if (!Array.isArray(event.choices) || !isRecord5(event.choices[0])) return void 0;
2452
+ if (!Array.isArray(event.choices) || !isRecord6(event.choices[0])) return void 0;
2166
2453
  const delta = event.choices[0].delta;
2167
- return isRecord5(delta) ? delta : void 0;
2454
+ return isRecord6(delta) ? delta : void 0;
2168
2455
  }
2169
2456
  function unwrap(response) {
2170
- if (!isRecord5(response)) return {};
2171
- if (response.success === true && isRecord5(response.result)) return response.result;
2457
+ if (!isRecord6(response)) return {};
2458
+ if (response.success === true && isRecord6(response.result)) return response.result;
2172
2459
  return response;
2173
2460
  }
2174
2461
  function modelOf(compiled) {
@@ -2176,12 +2463,12 @@ function modelOf(compiled) {
2176
2463
  return "";
2177
2464
  }
2178
2465
  function messageFrom(body) {
2179
- if (!isRecord5(body)) return void 0;
2466
+ if (!isRecord6(body)) return void 0;
2180
2467
  if (typeof body.message === "string") return body.message;
2181
- if (isRecord5(body.error) && typeof body.error.message === "string") return body.error.message;
2468
+ if (isRecord6(body.error) && typeof body.error.message === "string") return body.error.message;
2182
2469
  if (Array.isArray(body.errors)) {
2183
2470
  for (const error of body.errors) {
2184
- if (isRecord5(error) && typeof error.message === "string") return error.message;
2471
+ if (isRecord6(error) && typeof error.message === "string") return error.message;
2185
2472
  }
2186
2473
  }
2187
2474
  return void 0;
@@ -2322,7 +2609,7 @@ function readEnv(name) {
2322
2609
  if (typeof process === "undefined") return void 0;
2323
2610
  return process.env[name];
2324
2611
  }
2325
- function isRecord5(value) {
2612
+ function isRecord6(value) {
2326
2613
  return typeof value === "object" && value !== null && !Array.isArray(value);
2327
2614
  }
2328
2615
 
@@ -2530,7 +2817,7 @@ function settleNested(policy, kind, parentEffort) {
2530
2817
  if (kind === "fusion") next.judgeModel = directive.model;
2531
2818
  else next.model = directive.model;
2532
2819
  }
2533
- if (isRecord6(directive.body.reasoning)) next.reasoning = directive.body.reasoning;
2820
+ if (isRecord7(directive.body.reasoning)) next.reasoning = directive.body.reasoning;
2534
2821
  return next;
2535
2822
  }
2536
2823
  function applyPromptPrefix(request, prefix) {
@@ -2580,7 +2867,7 @@ function prefixInputItems(items, prefix) {
2580
2867
  }
2581
2868
  if (!Array.isArray(item.content)) continue;
2582
2869
  for (const part of item.content) {
2583
- if (!isRecord6(part) || typeof part.text !== "string") continue;
2870
+ if (!isRecord7(part) || typeof part.text !== "string") continue;
2584
2871
  if (part.type === "text" || part.type === "input_text") {
2585
2872
  part.text = prefix + part.text;
2586
2873
  return true;
@@ -2641,7 +2928,7 @@ var ROLE_STAMP_FIELDS = ["role", "roleLayer", "roleDigest", "profileChoice"];
2641
2928
  function applyRoleStamp(request) {
2642
2929
  const stamp = request.role;
2643
2930
  delete request.role;
2644
- if (!isRecord6(stamp)) return;
2931
+ if (!isRecord7(stamp)) return;
2645
2932
  const identity = {};
2646
2933
  for (const field of ROLE_STAMP_FIELDS) {
2647
2934
  const value = stamp[field];
@@ -2656,8 +2943,8 @@ function applyRoleStamp(request) {
2656
2943
  }
2657
2944
  function absorbOverrideMetadata(request) {
2658
2945
  const overrides = request.rawOpenRouterOverrides;
2659
- if (!isRecord6(overrides) || !Object.prototype.hasOwnProperty.call(overrides, "metadata")) return;
2660
- if (isRecord6(overrides.metadata)) {
2946
+ if (!isRecord7(overrides) || !Object.prototype.hasOwnProperty.call(overrides, "metadata")) return;
2947
+ if (isRecord7(overrides.metadata)) {
2661
2948
  const current = { ...request.metadata ?? {} };
2662
2949
  const extra = {};
2663
2950
  for (const [key, value] of Object.entries(overrides.metadata)) {
@@ -2696,7 +2983,7 @@ function hasOwnKeys(value) {
2696
2983
  function hasStreamMetadata(directive) {
2697
2984
  return directive.response.streamReasoningKeys.length > 0 || directive.response.streamReasoningPaths.length > 0;
2698
2985
  }
2699
- function isRecord6(value) {
2986
+ function isRecord7(value) {
2700
2987
  return typeof value === "object" && value !== null && !Array.isArray(value);
2701
2988
  }
2702
2989
  function readEnv2(name) {
@@ -3019,7 +3306,7 @@ async function runOpenAi(request, options, call, requestId) {
3019
3306
  let response;
3020
3307
  for (let iteration = 0; iteration <= maxIterations; iteration += 1) {
3021
3308
  response = await sendWithRetries2(active, options, timeoutFor2(request, options));
3022
- const calls = functionCalls(isRecord7(response) ? response : {});
3309
+ const calls = functionCalls(isRecord8(response) ? response : {});
3023
3310
  if (!calls.length) break;
3024
3311
  if (!calls.every((item) => resolveExecutor2(item.name, request, options))) {
3025
3312
  return normalizeOpenAiResponse({
@@ -3039,7 +3326,7 @@ async function runOpenAi(request, options, call, requestId) {
3039
3326
  results.push(await executeOpenAiTool(item, request, options));
3040
3327
  }
3041
3328
  functionUsage.push(...results);
3042
- const record2 = isRecord7(response) ? response : {};
3329
+ const record2 = isRecord8(response) ? response : {};
3043
3330
  active = {
3044
3331
  ...active,
3045
3332
  body: clean2({
@@ -3154,7 +3441,7 @@ async function* streamOpenAi(request, options, call) {
3154
3441
  throw failure;
3155
3442
  }
3156
3443
  for await (const event of parseSse2(response)) {
3157
- if (!isRecord7(event)) continue;
3444
+ if (!isRecord8(event)) continue;
3158
3445
  if (event.type === "response.output_text.delta" && typeof event.delta === "string" && event.delta) {
3159
3446
  text += event.delta;
3160
3447
  yield { type: "stream.text.delta", requestId, data: { text: event.delta } };
@@ -3173,7 +3460,7 @@ async function* streamOpenAi(request, options, call) {
3173
3460
  argumentsDelta: event.delta
3174
3461
  }
3175
3462
  };
3176
- } else if (event.type === "response.completed" && isRecord7(event.response)) {
3463
+ } else if (event.type === "response.completed" && isRecord8(event.response)) {
3177
3464
  const usage = normalizeUsage2(event.response.usage);
3178
3465
  if (usage) yield { type: "stream.usage", requestId, data: { usage } };
3179
3466
  } else if (event.type === "error") {
@@ -3267,7 +3554,7 @@ function isConfigError2(code) {
3267
3554
  }
3268
3555
  function asTerminalError2(error) {
3269
3556
  if (error instanceof AiDispatcherError && error.code === "PROVIDER_RETRYABLE") {
3270
- const status = isRecord7(error.details) ? error.details.status : void 0;
3557
+ const status = isRecord8(error.details) ? error.details.status : void 0;
3271
3558
  if (status === 429) return new AiDispatcherError("PROVIDER_RATE_LIMITED", error.message, error.details);
3272
3559
  return new AiDispatcherError("PROVIDER_GATEWAY_UNREACHABLE", error.message, error.details);
3273
3560
  }
@@ -3275,7 +3562,7 @@ function asTerminalError2(error) {
3275
3562
  return new AiDispatcherError("PROVIDER_REQUEST_FAILED", error instanceof Error ? error.message : String(error));
3276
3563
  }
3277
3564
  function normalizeOpenAiResponse(params) {
3278
- const record2 = isRecord7(params.response) ? params.response : {};
3565
+ const record2 = isRecord8(params.response) ? params.response : {};
3279
3566
  const text = answerText2(record2);
3280
3567
  const calls = params.functionTools ?? functionCalls(record2);
3281
3568
  const usage = normalizeUsage2(record2.usage);
@@ -3302,9 +3589,9 @@ function answerText2(response) {
3302
3589
  if (Array.isArray(output)) {
3303
3590
  const parts = [];
3304
3591
  for (const item of output) {
3305
- if (!isRecord7(item) || item.type === "reasoning" || item.type !== "message" || !Array.isArray(item.content)) continue;
3592
+ if (!isRecord8(item) || item.type === "reasoning" || item.type !== "message" || !Array.isArray(item.content)) continue;
3306
3593
  for (const part of item.content) {
3307
- if (isRecord7(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
3594
+ if (isRecord8(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
3308
3595
  }
3309
3596
  }
3310
3597
  if (parts.length > 0) return parts.join("");
@@ -3315,7 +3602,7 @@ function functionCalls(response) {
3315
3602
  if (!Array.isArray(response.output)) return [];
3316
3603
  const calls = [];
3317
3604
  for (const item of response.output) {
3318
- if (!isRecord7(item) || item.type !== "function_call") continue;
3605
+ if (!isRecord8(item) || item.type !== "function_call") continue;
3319
3606
  const name = typeof item.name === "string" ? item.name : "function";
3320
3607
  const callId = typeof item.call_id === "string" ? item.call_id : name;
3321
3608
  let args = item.arguments;
@@ -3347,7 +3634,7 @@ function toolUsage(calls) {
3347
3634
  };
3348
3635
  }
3349
3636
  function normalizeUsage2(usage) {
3350
- if (!isRecord7(usage)) return void 0;
3637
+ if (!isRecord8(usage)) return void 0;
3351
3638
  const inputTokens = numberValue2(usage.input_tokens);
3352
3639
  const outputTokens = numberValue2(usage.output_tokens);
3353
3640
  const totalTokens = numberValue2(usage.total_tokens) ?? (inputTokens !== void 0 || outputTokens !== void 0 ? (inputTokens ?? 0) + (outputTokens ?? 0) : void 0);
@@ -3399,16 +3686,16 @@ function modelOf2(compiled) {
3399
3686
  return typeof compiled.body.model === "string" ? compiled.body.model : "";
3400
3687
  }
3401
3688
  function messageFrom2(body) {
3402
- if (!isRecord7(body)) return void 0;
3689
+ if (!isRecord8(body)) return void 0;
3403
3690
  if (typeof body.message === "string") return body.message;
3404
- if (isRecord7(body.error) && typeof body.error.message === "string") return body.error.message;
3691
+ if (isRecord8(body.error) && typeof body.error.message === "string") return body.error.message;
3405
3692
  return void 0;
3406
3693
  }
3407
3694
  function numberValue2(value) {
3408
3695
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3409
3696
  }
3410
3697
  function attachProviderMetadata(body, request, packer) {
3411
- const fromBody = isRecord7(body.metadata) ? body.metadata : void 0;
3698
+ const fromBody = isRecord8(body.metadata) ? body.metadata : void 0;
3412
3699
  const packed = packProviderRecord2(request.metadata, request.agentId, fromBody, packer);
3413
3700
  if (packed.wire) return { body: { ...body, metadata: packed.wire }, ...packed.warning ? { warning: packed.warning } : {} };
3414
3701
  if (body.metadata === void 0) return { body, ...packed.warning ? { warning: packed.warning } : {} };
@@ -3482,7 +3769,7 @@ function readEnv3(name) {
3482
3769
  if (typeof process === "undefined") return void 0;
3483
3770
  return process.env[name];
3484
3771
  }
3485
- function isRecord7(value) {
3772
+ function isRecord8(value) {
3486
3773
  return typeof value === "object" && value !== null && !Array.isArray(value);
3487
3774
  }
3488
3775
 
@@ -3552,6 +3839,7 @@ function createAiDispatcher(options = {}) {
3552
3839
  if (provider === "openrouter") {
3553
3840
  const openrouterOptions = {
3554
3841
  ...options.openrouter,
3842
+ ...options.openrouter?.tools ? { tools: wrapToolRegistry(options.openrouter.tools) } : {},
3555
3843
  metadataPacker: packer,
3556
3844
  ...options.logger && !options.openrouter?.logger ? { logger: options.logger } : {}
3557
3845
  };
@@ -3560,6 +3848,7 @@ function createAiDispatcher(options = {}) {
3560
3848
  if (provider === "bedrock") {
3561
3849
  const bedrockOptions = {
3562
3850
  ...options.bedrock,
3851
+ ...options.bedrock?.tools ? { tools: wrapToolRegistry(options.bedrock.tools) } : {},
3563
3852
  metadataPacker: packer,
3564
3853
  ...options.logger && !options.bedrock?.logger ? { logger: options.logger } : {}
3565
3854
  };
@@ -3568,6 +3857,7 @@ function createAiDispatcher(options = {}) {
3568
3857
  if (provider === "openai") {
3569
3858
  const openaiOptions = {
3570
3859
  ...options.openai,
3860
+ ...options.openai?.tools ? { tools: wrapToolRegistry(options.openai.tools) } : {},
3571
3861
  ...options.logger && !options.openai?.logger ? { logger: options.logger } : {}
3572
3862
  };
3573
3863
  return createOpenAiProviderAdapter(openaiOptions, packer);
@@ -3575,6 +3865,7 @@ function createAiDispatcher(options = {}) {
3575
3865
  if (provider === "cloudflare") {
3576
3866
  const cloudflareOptions = {
3577
3867
  ...options.cloudflare,
3868
+ ...options.cloudflare?.tools ? { tools: wrapToolRegistry(options.cloudflare.tools) } : {},
3578
3869
  ...options.logger && !options.cloudflare?.logger ? { logger: options.logger } : {}
3579
3870
  };
3580
3871
  return createCloudflareProviderAdapter(cloudflareOptions, packer);
@@ -3596,21 +3887,27 @@ function createAiDispatcher(options = {}) {
3596
3887
  return {
3597
3888
  provider: defaultProvider,
3598
3889
  async run(request) {
3599
- const prepared = prepare(request, true);
3890
+ const prepared = await prepare(request, true);
3600
3891
  log(options, "ai-dispatcher.request.started", prepared, "run", false);
3601
- const response = await getAdapter(prepared.provider).run(prepared.request, callOf(prepared.call));
3892
+ const response = await inputStorage.run(
3893
+ prepared.inputTrack,
3894
+ () => getAdapter(prepared.provider).run(prepared.request, callOf(prepared.call))
3895
+ );
3602
3896
  return applyResolution(response, prepared);
3603
3897
  },
3604
3898
  executeStreamingChat(request) {
3605
- const prepared = prepare(request, false);
3606
- log(options, "ai-dispatcher.request.started", prepared, "executeStreamingChat", true);
3607
- return decorateStream(
3608
- prepared,
3609
- getAdapter(prepared.provider).executeStreamingChat(prepared.request, callOf(prepared.call))
3610
- );
3899
+ return (async function* () {
3900
+ const prepared = await prepare(request, false);
3901
+ log(options, "ai-dispatcher.request.started", prepared, "executeStreamingChat", true);
3902
+ if (prepared.inputTrack) inputStorage.enterWith(prepared.inputTrack);
3903
+ yield* decorateStream(
3904
+ prepared,
3905
+ getAdapter(prepared.provider).executeStreamingChat(prepared.request, callOf(prepared.call))
3906
+ );
3907
+ })();
3611
3908
  },
3612
- compile(request) {
3613
- const prepared = prepare(request, true);
3909
+ async compile(request) {
3910
+ const prepared = await prepare(request, true);
3614
3911
  log(options, "ai-dispatcher.request.compiled", prepared, "compile", false);
3615
3912
  const compiled = getAdapter(prepared.provider).compile(prepared.request, callOf(prepared.call));
3616
3913
  return attachCompileMeta(prepared, compiled);
@@ -3624,7 +3921,7 @@ function createAiDispatcher(options = {}) {
3624
3921
  return pending;
3625
3922
  }
3626
3923
  };
3627
- function prepare(request, includeMcp) {
3924
+ async function prepare(request, includeMcp) {
3628
3925
  const provider = resolveProvider(request.provider, defaultProvider);
3629
3926
  const prepared = prepareDispatchRequest({ request, provider, options });
3630
3927
  const tools = providerTools(provider, options);
@@ -3634,6 +3931,11 @@ function createAiDispatcher(options = {}) {
3634
3931
  ...tools ? { providerTools: tools } : {},
3635
3932
  includeMcp
3636
3933
  });
3934
+ prepared.inputTrack = await applyAiInput({
3935
+ request: prepared.request,
3936
+ effectiveModel: prepared.effectiveModel,
3937
+ factory: options.aiInput
3938
+ });
3637
3939
  return prepared;
3638
3940
  }
3639
3941
  }
@@ -3651,7 +3953,8 @@ function callOf(call) {
3651
3953
  }
3652
3954
  function attachCompileMeta(prepared, compiled) {
3653
3955
  const record2 = compiled;
3654
- const headers = isRecord8(record2.headers) ? redactHeaders(record2.headers) : void 0;
3956
+ const headers = isRecord9(record2.headers) ? redactHeaders(record2.headers) : void 0;
3957
+ const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
3655
3958
  return {
3656
3959
  ...record2,
3657
3960
  ...headers ? { headers } : {},
@@ -3660,6 +3963,7 @@ function attachCompileMeta(prepared, compiled) {
3660
3963
  effectiveModel: prepared.effectiveModel,
3661
3964
  ...prepared.resolution ? { reasoningResolution: prepared.resolution } : {},
3662
3965
  ...prepared.cacheResolution ? { cacheResolution: prepared.cacheResolution } : {},
3966
+ ...inputResolution ? { inputResolution } : {},
3663
3967
  ...prepared.cacheWarnings?.length ? { warnings: [...Array.isArray(record2.warnings) ? record2.warnings : [], ...prepared.cacheWarnings] } : {}
3664
3968
  };
3665
3969
  }
@@ -3685,7 +3989,7 @@ function log(options, event, prepared, entrypoint, streaming) {
3685
3989
  if (event.endsWith("compiled")) options.logger?.debug?.(event, payload);
3686
3990
  else options.logger?.info?.(event, payload);
3687
3991
  }
3688
- function isRecord8(value) {
3992
+ function isRecord9(value) {
3689
3993
  return typeof value === "object" && value !== null && !Array.isArray(value);
3690
3994
  }
3691
3995