@x12i/ai-dispatcher 3.2.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -17
- package/dist/index.cjs +412 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -6
- package/dist/index.d.ts +22 -6
- package/dist/index.js +405 -104
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -41,13 +41,19 @@ __export(index_exports, {
|
|
|
41
41
|
isImplementedAiProvider: () => isImplementedAiProvider,
|
|
42
42
|
normalizeMetadata: () => import_openrouter_runtime4.normalizeMetadata,
|
|
43
43
|
providerNotImplemented: () => providerNotImplemented,
|
|
44
|
-
registerHostIntents: () =>
|
|
45
|
-
resolveAIProfile: () =>
|
|
44
|
+
registerHostIntents: () => import_ai_profiles4.registerHostIntents,
|
|
45
|
+
resolveAIProfile: () => import_ai_profiles4.resolveAIProfile,
|
|
46
46
|
resolveProvider: () => resolveProvider,
|
|
47
47
|
stripReasoningHistoryFields: () => stripReasoningHistoryFields
|
|
48
48
|
});
|
|
49
49
|
module.exports = __toCommonJS(index_exports);
|
|
50
|
-
|
|
50
|
+
|
|
51
|
+
// ../node_modules/tsup/assets/cjs_shims.js
|
|
52
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
53
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
54
|
+
|
|
55
|
+
// src/index.ts
|
|
56
|
+
var import_ai_profiles4 = require("@x12i/ai-profiles");
|
|
51
57
|
var import_openrouter_runtime4 = require("@x12i/openrouter-runtime");
|
|
52
58
|
|
|
53
59
|
// src/create-dispatcher.ts
|
|
@@ -162,7 +168,7 @@ async function openTrack(settings, model) {
|
|
|
162
168
|
try {
|
|
163
169
|
tokenCounter = await loadTokenizer(tokenizer);
|
|
164
170
|
const framing = framingFor(settings);
|
|
165
|
-
const
|
|
171
|
+
const resolved2 = (0, import_core.resolveSettings)({
|
|
166
172
|
files: [],
|
|
167
173
|
env: {},
|
|
168
174
|
factory: {
|
|
@@ -177,8 +183,8 @@ async function openTrack(settings, model) {
|
|
|
177
183
|
});
|
|
178
184
|
const approvals = settings.approvals;
|
|
179
185
|
const client = (0, import_core.createCoreClient)({
|
|
180
|
-
config:
|
|
181
|
-
explanation:
|
|
186
|
+
config: resolved2.config,
|
|
187
|
+
explanation: resolved2.explanation,
|
|
182
188
|
...approvals && approvals.length > 0 ? { policy: { approvals: [...approvals] } } : {},
|
|
183
189
|
...tokenCounter ? { tokenCounter } : {},
|
|
184
190
|
warn: () => void 0
|
|
@@ -232,10 +238,10 @@ async function encodeRequestText(request, track) {
|
|
|
232
238
|
if (typeof request.input === "string") {
|
|
233
239
|
request.input = await encodeString(track, request.input);
|
|
234
240
|
} else if (Array.isArray(request.input)) {
|
|
235
|
-
for (let
|
|
236
|
-
const item = request.input[
|
|
241
|
+
for (let index2 = 0; index2 < request.input.length; index2 += 1) {
|
|
242
|
+
const item = request.input[index2];
|
|
237
243
|
if (typeof item === "string") {
|
|
238
|
-
request.input[
|
|
244
|
+
request.input[index2] = await encodeString(track, item);
|
|
239
245
|
} else if (item) {
|
|
240
246
|
await encodeContentRecord(item, track);
|
|
241
247
|
}
|
|
@@ -432,9 +438,9 @@ function walk(current, tokens) {
|
|
|
432
438
|
}
|
|
433
439
|
if (Array.isArray(current)) {
|
|
434
440
|
if (!/^\d+$/.test(head)) return [];
|
|
435
|
-
const
|
|
436
|
-
if (
|
|
437
|
-
return walk(current[
|
|
441
|
+
const index2 = Number(head);
|
|
442
|
+
if (index2 >= current.length) return [];
|
|
443
|
+
return walk(current[index2], rest);
|
|
438
444
|
}
|
|
439
445
|
if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
|
|
440
446
|
return walk(current[head], rest);
|
|
@@ -469,9 +475,9 @@ function collectParents(current, tokens) {
|
|
|
469
475
|
}
|
|
470
476
|
if (Array.isArray(current)) {
|
|
471
477
|
if (!/^\d+$/.test(head)) return [];
|
|
472
|
-
const
|
|
473
|
-
if (
|
|
474
|
-
return collectParents(current[
|
|
478
|
+
const index2 = Number(head);
|
|
479
|
+
if (index2 >= current.length) return [];
|
|
480
|
+
return collectParents(current[index2], rest);
|
|
475
481
|
}
|
|
476
482
|
if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
|
|
477
483
|
return collectParents(current[head], rest);
|
|
@@ -485,8 +491,8 @@ function deletePointer(root, pointer) {
|
|
|
485
491
|
for (const parent of parents) {
|
|
486
492
|
if (Array.isArray(parent)) {
|
|
487
493
|
if (!/^\d+$/.test(last)) continue;
|
|
488
|
-
const
|
|
489
|
-
if (
|
|
494
|
+
const index2 = Number(last);
|
|
495
|
+
if (index2 < parent.length) parent.splice(index2, 1);
|
|
490
496
|
continue;
|
|
491
497
|
}
|
|
492
498
|
if (isRecord2(parent) && Object.prototype.hasOwnProperty.call(parent, last)) {
|
|
@@ -518,6 +524,38 @@ function extractStreamReasoningText(event, response) {
|
|
|
518
524
|
}
|
|
519
525
|
return firstConcatenatedText(event, response.streamReasoningPaths);
|
|
520
526
|
}
|
|
527
|
+
function readReportedEffort(root) {
|
|
528
|
+
if (!isRecord3(root)) return void 0;
|
|
529
|
+
const fromRoot = effortOn(root.reasoning) ?? namedEffort(root.reasoning_effort);
|
|
530
|
+
if (fromRoot) return fromRoot;
|
|
531
|
+
if (Array.isArray(root.choices)) {
|
|
532
|
+
for (const choice of root.choices) {
|
|
533
|
+
if (!isRecord3(choice)) continue;
|
|
534
|
+
const message = isRecord3(choice.message) ? choice.message : void 0;
|
|
535
|
+
const fromMessage = message ? effortOn(message.reasoning) ?? namedEffort(message.reasoning_effort) : void 0;
|
|
536
|
+
if (fromMessage) return fromMessage;
|
|
537
|
+
const fromChoice = effortOn(choice.reasoning) ?? namedEffort(choice.reasoning_effort);
|
|
538
|
+
if (fromChoice) return fromChoice;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (Array.isArray(root.output)) {
|
|
542
|
+
for (const item of root.output) {
|
|
543
|
+
if (!isRecord3(item) || item.type !== "reasoning") continue;
|
|
544
|
+
const effort = namedEffort(item.effort);
|
|
545
|
+
if (effort) return effort;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return void 0;
|
|
549
|
+
}
|
|
550
|
+
function effortOn(value) {
|
|
551
|
+
if (!isRecord3(value)) return void 0;
|
|
552
|
+
return namedEffort(value.effort);
|
|
553
|
+
}
|
|
554
|
+
function namedEffort(value) {
|
|
555
|
+
if (typeof value !== "string") return void 0;
|
|
556
|
+
const trimmed = value.trim();
|
|
557
|
+
return trimmed || void 0;
|
|
558
|
+
}
|
|
521
559
|
function readReasoningTokens(root, paths) {
|
|
522
560
|
for (const path of paths) {
|
|
523
561
|
const absolute = firstNumber(root, [path]);
|
|
@@ -602,7 +640,10 @@ function splitThinkTags(text) {
|
|
|
602
640
|
// src/apply-resolution.ts
|
|
603
641
|
function applyResolution(response, prepared) {
|
|
604
642
|
const result = response;
|
|
605
|
-
if (prepared.resolution)
|
|
643
|
+
if (prepared.resolution) {
|
|
644
|
+
const reportedEffort = readReportedEffort(response.raw?.response);
|
|
645
|
+
result.reasoningResolution = reportedEffort ? { ...prepared.resolution, reportedEffort } : prepared.resolution;
|
|
646
|
+
}
|
|
606
647
|
if (prepared.cacheResolution) result.cacheResolution = prepared.cacheResolution;
|
|
607
648
|
if (prepared.cacheWarnings?.length) {
|
|
608
649
|
result.warnings = [...result.warnings, ...prepared.cacheWarnings];
|
|
@@ -984,7 +1025,7 @@ function isRecord5(value) {
|
|
|
984
1025
|
}
|
|
985
1026
|
|
|
986
1027
|
// src/prepare-request.ts
|
|
987
|
-
var
|
|
1028
|
+
var import_ai_profiles3 = require("@x12i/ai-profiles");
|
|
988
1029
|
|
|
989
1030
|
// src/cache-apply.ts
|
|
990
1031
|
var BREAKPOINT = { mode: "explicit" };
|
|
@@ -1067,38 +1108,38 @@ function placeBedrockBreakpoint(body, ttl) {
|
|
|
1067
1108
|
function markMessages(body, field, markerKey, markerValue, textType) {
|
|
1068
1109
|
const messages = body[field];
|
|
1069
1110
|
if (!Array.isArray(messages)) return { body, placed: false };
|
|
1070
|
-
const
|
|
1071
|
-
if (
|
|
1072
|
-
const marked = markMessage(messages[
|
|
1111
|
+
const index2 = stableMessageIndex(messages);
|
|
1112
|
+
if (index2 < 0) return { body, placed: false };
|
|
1113
|
+
const marked = markMessage(messages[index2], markerKey, markerValue, textType);
|
|
1073
1114
|
if (!marked) return { body, placed: false };
|
|
1074
1115
|
const next = messages.slice();
|
|
1075
|
-
next[
|
|
1116
|
+
next[index2] = marked;
|
|
1076
1117
|
return { placed: true, body: { ...body, [field]: next } };
|
|
1077
1118
|
}
|
|
1078
1119
|
function markInput(body, markerKey, markerValue, textType) {
|
|
1079
1120
|
if (!Array.isArray(body.input)) return { body, placed: false };
|
|
1080
|
-
const
|
|
1081
|
-
if (
|
|
1082
|
-
const marked = markMessage(body.input[
|
|
1121
|
+
const index2 = stableInputIndex(body.input);
|
|
1122
|
+
if (index2 < 0) return { body, placed: false };
|
|
1123
|
+
const marked = markMessage(body.input[index2], markerKey, markerValue, textType);
|
|
1083
1124
|
if (!marked) return { body, placed: false };
|
|
1084
1125
|
const next = body.input.slice();
|
|
1085
|
-
next[
|
|
1126
|
+
next[index2] = marked;
|
|
1086
1127
|
return { placed: true, body: { ...body, input: next } };
|
|
1087
1128
|
}
|
|
1088
1129
|
function stableMessageIndex(messages) {
|
|
1089
1130
|
let lastSystem = -1;
|
|
1090
|
-
for (let
|
|
1091
|
-
const message = messages[
|
|
1092
|
-
if (isPlainRecord(message) && message.role === "system" && hasText(message.content)) lastSystem =
|
|
1131
|
+
for (let index2 = 0; index2 < messages.length; index2 += 1) {
|
|
1132
|
+
const message = messages[index2];
|
|
1133
|
+
if (isPlainRecord(message) && message.role === "system" && hasText(message.content)) lastSystem = index2;
|
|
1093
1134
|
}
|
|
1094
1135
|
return lastSystem;
|
|
1095
1136
|
}
|
|
1096
1137
|
function stableInputIndex(items) {
|
|
1097
1138
|
let lastStable = -1;
|
|
1098
|
-
for (let
|
|
1099
|
-
const item = items[
|
|
1139
|
+
for (let index2 = 0; index2 < items.length; index2 += 1) {
|
|
1140
|
+
const item = items[index2];
|
|
1100
1141
|
if (!isPlainRecord(item) || !hasText(item.content)) continue;
|
|
1101
|
-
if (item.role === "system" || item.role === "developer") lastStable =
|
|
1142
|
+
if (item.role === "system" || item.role === "developer") lastStable = index2;
|
|
1102
1143
|
}
|
|
1103
1144
|
return lastStable;
|
|
1104
1145
|
}
|
|
@@ -1115,10 +1156,10 @@ function markContent(content, markerKey, markerValue, textType) {
|
|
|
1115
1156
|
}
|
|
1116
1157
|
if (!Array.isArray(content)) return void 0;
|
|
1117
1158
|
const parts = content.map((part) => isPlainRecord(part) ? { ...part } : part);
|
|
1118
|
-
for (let
|
|
1119
|
-
const part = parts[
|
|
1159
|
+
for (let index2 = parts.length - 1; index2 >= 0; index2 -= 1) {
|
|
1160
|
+
const part = parts[index2];
|
|
1120
1161
|
if (!isPlainRecord(part) || typeof part.text !== "string" || !part.text.trim()) continue;
|
|
1121
|
-
parts[
|
|
1162
|
+
parts[index2] = { ...part, [markerKey]: markerValue };
|
|
1122
1163
|
return parts;
|
|
1123
1164
|
}
|
|
1124
1165
|
return void 0;
|
|
@@ -1274,11 +1315,11 @@ function resolveCloudflarePromptCache(args) {
|
|
|
1274
1315
|
warnings: []
|
|
1275
1316
|
};
|
|
1276
1317
|
}
|
|
1277
|
-
const
|
|
1278
|
-
const ttl =
|
|
1318
|
+
const resolved2 = applyProfile({ input, mode, key, requestedTtl, resolutionBase, model, profile });
|
|
1319
|
+
const ttl = resolved2.plan.ttl ?? requestedTtl;
|
|
1279
1320
|
return {
|
|
1280
|
-
...
|
|
1281
|
-
plan: { ...
|
|
1321
|
+
...resolved2,
|
|
1322
|
+
plan: { ...resolved2.plan, gateway: gatewayDirective(false, ttl, key) }
|
|
1282
1323
|
};
|
|
1283
1324
|
}
|
|
1284
1325
|
function applyProfile(args) {
|
|
@@ -1483,22 +1524,22 @@ function restoreCloudflareModel(model, prefix) {
|
|
|
1483
1524
|
return `${prefix}${model}`;
|
|
1484
1525
|
}
|
|
1485
1526
|
function createCloudflareProviderAdapter(options = {}, packer) {
|
|
1486
|
-
const
|
|
1527
|
+
const resolved2 = resolveCloudflareOptions(options, packer);
|
|
1487
1528
|
return {
|
|
1488
1529
|
compile(request, call) {
|
|
1489
|
-
return compileCloudflareRequest(request,
|
|
1530
|
+
return compileCloudflareRequest(request, resolved2, call, false);
|
|
1490
1531
|
},
|
|
1491
1532
|
async run(request, call) {
|
|
1492
1533
|
const requestId = request.id ?? "cloudflare";
|
|
1493
1534
|
try {
|
|
1494
|
-
return await runCloudflare(request,
|
|
1535
|
+
return await runCloudflare(request, resolved2, call, requestId);
|
|
1495
1536
|
} catch (error) {
|
|
1496
1537
|
if (error instanceof AiDispatcherError && isConfigError(error.code)) throw error;
|
|
1497
1538
|
return failedResponse(request, requestId, error, "chat");
|
|
1498
1539
|
}
|
|
1499
1540
|
},
|
|
1500
1541
|
executeStreamingChat(request, call) {
|
|
1501
|
-
return streamCloudflare(request,
|
|
1542
|
+
return streamCloudflare(request, resolved2, call);
|
|
1502
1543
|
}
|
|
1503
1544
|
};
|
|
1504
1545
|
}
|
|
@@ -2646,6 +2687,258 @@ function isRecord6(value) {
|
|
|
2646
2687
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2647
2688
|
}
|
|
2648
2689
|
|
|
2690
|
+
// src/resolve-effort.ts
|
|
2691
|
+
var import_ai_profiles2 = require("@x12i/ai-profiles");
|
|
2692
|
+
|
|
2693
|
+
// src/catalog-efforts.ts
|
|
2694
|
+
var import_node_module = require("module");
|
|
2695
|
+
var import_node_fs = require("fs");
|
|
2696
|
+
var import_node_path = require("path");
|
|
2697
|
+
var import_ai_profiles = require("@x12i/ai-profiles");
|
|
2698
|
+
var index;
|
|
2699
|
+
function normalize(value) {
|
|
2700
|
+
return value.trim().toLowerCase();
|
|
2701
|
+
}
|
|
2702
|
+
function addKey(keys, key, row) {
|
|
2703
|
+
const normalized = normalize(key);
|
|
2704
|
+
if (!normalized) return;
|
|
2705
|
+
const existing = keys.get(normalized);
|
|
2706
|
+
if (!existing) {
|
|
2707
|
+
keys.set(normalized, row);
|
|
2708
|
+
return;
|
|
2709
|
+
}
|
|
2710
|
+
if (existing === "ambiguous") return;
|
|
2711
|
+
if (existing.modelId !== row.modelId) keys.set(normalized, "ambiguous");
|
|
2712
|
+
}
|
|
2713
|
+
function loadAssignmentAliases() {
|
|
2714
|
+
const require2 = (0, import_node_module.createRequire)(importMetaUrl);
|
|
2715
|
+
const entry = require2.resolve("@x12i/ai-profiles");
|
|
2716
|
+
const path = (0, import_node_path.join)((0, import_node_path.dirname)(entry), "data", "reasoning-directives.json");
|
|
2717
|
+
const document2 = JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
2718
|
+
return document2.assignments ?? [];
|
|
2719
|
+
}
|
|
2720
|
+
function effortList(entry) {
|
|
2721
|
+
const reasoning = entry.openrouter.reasoning;
|
|
2722
|
+
const modelId = entry.openrouter.modelId;
|
|
2723
|
+
if (!reasoning || !Object.prototype.hasOwnProperty.call(reasoning, "supportedEfforts")) {
|
|
2724
|
+
return { kind: "unspecified", modelId };
|
|
2725
|
+
}
|
|
2726
|
+
if (reasoning.supportedEfforts === null) return { kind: "any", modelId };
|
|
2727
|
+
if (Array.isArray(reasoning.supportedEfforts)) {
|
|
2728
|
+
return { kind: "listed", modelId, efforts: reasoning.supportedEfforts };
|
|
2729
|
+
}
|
|
2730
|
+
return { kind: "unspecified", modelId };
|
|
2731
|
+
}
|
|
2732
|
+
function buildIndex() {
|
|
2733
|
+
const catalog = (0, import_ai_profiles.loadBundledModelsCatalog)();
|
|
2734
|
+
const keys = /* @__PURE__ */ new Map();
|
|
2735
|
+
const byCatalogId = /* @__PURE__ */ new Map();
|
|
2736
|
+
for (const entry of catalog.models) {
|
|
2737
|
+
const row = effortList(entry);
|
|
2738
|
+
byCatalogId.set(normalize(entry.openrouter.modelId), row);
|
|
2739
|
+
addKey(keys, entry.openrouter.modelId, row);
|
|
2740
|
+
if (entry.openrouter.canonicalSlug) addKey(keys, entry.openrouter.canonicalSlug, row);
|
|
2741
|
+
addKey(keys, `${entry.direct.provider}/${entry.direct.modelId}`, row);
|
|
2742
|
+
addKey(keys, `openrouter/${entry.openrouter.modelId}`, row);
|
|
2743
|
+
addKey(keys, entry.direct.modelId, row);
|
|
2744
|
+
}
|
|
2745
|
+
for (const assignment of loadAssignmentAliases()) {
|
|
2746
|
+
const row = byCatalogId.get(normalize(assignment.catalogModelId));
|
|
2747
|
+
if (!row) continue;
|
|
2748
|
+
for (const alias of assignment.aliases ?? []) addKey(keys, alias, row);
|
|
2749
|
+
}
|
|
2750
|
+
return keys;
|
|
2751
|
+
}
|
|
2752
|
+
function lookupCatalogEfforts(model) {
|
|
2753
|
+
if (!index) index = buildIndex();
|
|
2754
|
+
const direct = index.get(normalize(model));
|
|
2755
|
+
if (direct && direct !== "ambiguous") return direct;
|
|
2756
|
+
const gateway = normalize(model);
|
|
2757
|
+
if (gateway.startsWith("openrouter/")) {
|
|
2758
|
+
const stripped = index.get(gateway.slice("openrouter/".length));
|
|
2759
|
+
if (stripped && stripped !== "ambiguous") return stripped;
|
|
2760
|
+
}
|
|
2761
|
+
return void 0;
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
// src/resolve-effort.ts
|
|
2765
|
+
var EMPTY_RESPONSE = {
|
|
2766
|
+
reasoningTextPaths: [],
|
|
2767
|
+
streamReasoningKeys: [],
|
|
2768
|
+
streamReasoningPaths: [],
|
|
2769
|
+
stripFromHistoryPaths: [],
|
|
2770
|
+
stripThinkTags: false
|
|
2771
|
+
};
|
|
2772
|
+
var MAPPER_EFFORTS = ["high", "xhigh", "max", "medium", "low", "minimal"];
|
|
2773
|
+
function isRecord7(value) {
|
|
2774
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2775
|
+
}
|
|
2776
|
+
function readBodyEffort(body) {
|
|
2777
|
+
const reasoning = body.reasoning;
|
|
2778
|
+
if (isRecord7(reasoning) && typeof reasoning.effort === "string") return reasoning.effort;
|
|
2779
|
+
const fields = body.additionalModelRequestFields;
|
|
2780
|
+
if (!isRecord7(fields)) return void 0;
|
|
2781
|
+
const output = fields.output_config;
|
|
2782
|
+
if (isRecord7(output) && typeof output.effort === "string") return output.effort;
|
|
2783
|
+
return void 0;
|
|
2784
|
+
}
|
|
2785
|
+
function writeBodyEffort(body, effort) {
|
|
2786
|
+
const reasoning = body.reasoning;
|
|
2787
|
+
if (isRecord7(reasoning) && typeof reasoning.effort === "string") {
|
|
2788
|
+
reasoning.effort = effort;
|
|
2789
|
+
return true;
|
|
2790
|
+
}
|
|
2791
|
+
const fields = body.additionalModelRequestFields;
|
|
2792
|
+
if (!isRecord7(fields)) return false;
|
|
2793
|
+
const output = fields.output_config;
|
|
2794
|
+
if (isRecord7(output) && typeof output.effort === "string") {
|
|
2795
|
+
output.effort = effort;
|
|
2796
|
+
return true;
|
|
2797
|
+
}
|
|
2798
|
+
return false;
|
|
2799
|
+
}
|
|
2800
|
+
function unsupported(model, effort, supported) {
|
|
2801
|
+
return new AiDispatcherError(
|
|
2802
|
+
"EFFORT_UNSUPPORTED",
|
|
2803
|
+
`Model '${model}' does not accept reasoning effort '${effort}'. Supported efforts: ${supported.join(", ")}.`,
|
|
2804
|
+
{ model, effort, supportedEfforts: [...supported] }
|
|
2805
|
+
);
|
|
2806
|
+
}
|
|
2807
|
+
function ignoredDirective() {
|
|
2808
|
+
return {
|
|
2809
|
+
outcome: "ignored",
|
|
2810
|
+
body: {},
|
|
2811
|
+
response: {
|
|
2812
|
+
reasoningTextPaths: [...EMPTY_RESPONSE.reasoningTextPaths],
|
|
2813
|
+
streamReasoningKeys: [...EMPTY_RESPONSE.streamReasoningKeys],
|
|
2814
|
+
streamReasoningPaths: [...EMPTY_RESPONSE.streamReasoningPaths],
|
|
2815
|
+
stripFromHistoryPaths: [...EMPTY_RESPONSE.stripFromHistoryPaths],
|
|
2816
|
+
stripThinkTags: EMPTY_RESPONSE.stripThinkTags
|
|
2817
|
+
}
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
function toDispatcherError(error) {
|
|
2821
|
+
return new AiDispatcherError(error.code, error.message, error.details);
|
|
2822
|
+
}
|
|
2823
|
+
function resolveMapping(input, ignoreUnknown) {
|
|
2824
|
+
try {
|
|
2825
|
+
return (0, import_ai_profiles2.resolveReasoning)({
|
|
2826
|
+
target: input.target,
|
|
2827
|
+
model: input.model,
|
|
2828
|
+
effort: input.effort
|
|
2829
|
+
});
|
|
2830
|
+
} catch (error) {
|
|
2831
|
+
if (!(error instanceof import_ai_profiles2.AIProfilesError)) throw error;
|
|
2832
|
+
if (ignoreUnknown && (error.code === "UNKNOWN_MODEL" || error.code === "REASONING_MAPPING_MISSING")) {
|
|
2833
|
+
return ignoredDirective();
|
|
2834
|
+
}
|
|
2835
|
+
if (error.code === "INVALID_EFFORT") return "bad-key";
|
|
2836
|
+
if (error.code === "REASONING_MAPPING_INVALID" && error.message.includes("missing effort")) return "bad-key";
|
|
2837
|
+
throw toDispatcherError(error);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
function mappingOrThrow(input, ignoreUnknown) {
|
|
2841
|
+
const mapped = resolveMapping(input, ignoreUnknown);
|
|
2842
|
+
if (mapped === "bad-key") {
|
|
2843
|
+
throw new AiDispatcherError(
|
|
2844
|
+
"INVALID_EFFORT",
|
|
2845
|
+
`Invalid reasoning effort '${input.effort}'.`,
|
|
2846
|
+
{ target: input.target, effort: input.effort, model: input.model }
|
|
2847
|
+
);
|
|
2848
|
+
}
|
|
2849
|
+
return mapped;
|
|
2850
|
+
}
|
|
2851
|
+
function sendAsWritten(directive, effort, target) {
|
|
2852
|
+
if (directive.outcome === "ignored") return directive;
|
|
2853
|
+
const copy = structuredClone(directive);
|
|
2854
|
+
const wrote = writeBodyEffort(copy.body, effort);
|
|
2855
|
+
if (!wrote && target !== "bedrock") {
|
|
2856
|
+
const reasoning = isRecord7(copy.body.reasoning) ? copy.body.reasoning : {};
|
|
2857
|
+
copy.body = { ...copy.body, reasoning: { ...reasoning, effort } };
|
|
2858
|
+
}
|
|
2859
|
+
copy.outcome = "applied";
|
|
2860
|
+
return copy;
|
|
2861
|
+
}
|
|
2862
|
+
function directiveForListedEffort(input) {
|
|
2863
|
+
const direct = resolveMapping(input, input.ignoreUnknown);
|
|
2864
|
+
if (direct !== "bad-key") {
|
|
2865
|
+
if (direct.outcome === "ignored") return direct;
|
|
2866
|
+
const sent = readBodyEffort(direct.body);
|
|
2867
|
+
if (sent === input.effort) {
|
|
2868
|
+
if (direct.outcome === "degraded") {
|
|
2869
|
+
const copy = structuredClone(direct);
|
|
2870
|
+
copy.outcome = "applied";
|
|
2871
|
+
return copy;
|
|
2872
|
+
}
|
|
2873
|
+
return direct;
|
|
2874
|
+
}
|
|
2875
|
+
if (sent) return sendAsWritten(direct, input.effort, input.target);
|
|
2876
|
+
}
|
|
2877
|
+
const proxies = MAPPER_EFFORTS.filter((candidate) => {
|
|
2878
|
+
if (candidate === input.effort) return false;
|
|
2879
|
+
if (input.supported === null) return true;
|
|
2880
|
+
return input.supported.includes(candidate);
|
|
2881
|
+
});
|
|
2882
|
+
for (const proxy of proxies) {
|
|
2883
|
+
const mapped = resolveMapping({ ...input, effort: proxy }, input.ignoreUnknown);
|
|
2884
|
+
if (mapped === "bad-key" || mapped.outcome === "ignored") continue;
|
|
2885
|
+
if (!readBodyEffort(mapped.body)) continue;
|
|
2886
|
+
return sendAsWritten(mapped, input.effort, input.target);
|
|
2887
|
+
}
|
|
2888
|
+
return mappingOrThrow(input, input.ignoreUnknown);
|
|
2889
|
+
}
|
|
2890
|
+
function sentOf(directive) {
|
|
2891
|
+
if (directive.outcome === "ignored") return void 0;
|
|
2892
|
+
return readBodyEffort(directive.body);
|
|
2893
|
+
}
|
|
2894
|
+
function resolved(directive) {
|
|
2895
|
+
const sentEffort = sentOf(directive);
|
|
2896
|
+
return sentEffort ? { directive, sentEffort } : { directive };
|
|
2897
|
+
}
|
|
2898
|
+
function resolveEffortDirective(input) {
|
|
2899
|
+
const effort = input.effort.trim();
|
|
2900
|
+
const row = lookupCatalogEfforts(input.model);
|
|
2901
|
+
if (!row) {
|
|
2902
|
+
return resolved(mappingOrThrow(input, input.ignoreUnknown));
|
|
2903
|
+
}
|
|
2904
|
+
if (row.kind === "unspecified") {
|
|
2905
|
+
const directive2 = mappingOrThrow({ ...input, effort }, input.ignoreUnknown);
|
|
2906
|
+
const sent = sentOf(directive2);
|
|
2907
|
+
if (!input.degrade && directive2.outcome === "degraded" && sent && sent !== effort) {
|
|
2908
|
+
throw new AiDispatcherError(
|
|
2909
|
+
"EFFORT_UNSUPPORTED",
|
|
2910
|
+
`Model '${input.model}' does not accept reasoning effort '${effort}' unless degradeReasoningEffort is set.`,
|
|
2911
|
+
{ model: input.model, effort, catalogModelId: row.modelId }
|
|
2912
|
+
);
|
|
2913
|
+
}
|
|
2914
|
+
return resolved(directive2);
|
|
2915
|
+
}
|
|
2916
|
+
const supported = row.kind === "listed" ? row.efforts : null;
|
|
2917
|
+
const allowed = supported === null || supported.includes(effort);
|
|
2918
|
+
if (!allowed && supported) {
|
|
2919
|
+
if (!input.degrade) throw unsupported(input.model, effort, supported);
|
|
2920
|
+
const mapped = resolveMapping({ ...input, effort }, input.ignoreUnknown);
|
|
2921
|
+
if (mapped === "bad-key") throw unsupported(input.model, effort, supported);
|
|
2922
|
+
if (mapped.outcome === "ignored") return { directive: mapped };
|
|
2923
|
+
const sent = readBodyEffort(mapped.body);
|
|
2924
|
+
if (!sent || !supported.includes(sent)) throw unsupported(input.model, effort, supported);
|
|
2925
|
+
if (sent !== effort) {
|
|
2926
|
+
const copy = structuredClone(mapped);
|
|
2927
|
+
copy.outcome = "degraded";
|
|
2928
|
+
return { directive: copy, sentEffort: sent };
|
|
2929
|
+
}
|
|
2930
|
+
return { directive: mapped, sentEffort: sent };
|
|
2931
|
+
}
|
|
2932
|
+
const directive = directiveForListedEffort({
|
|
2933
|
+
target: input.target,
|
|
2934
|
+
model: input.model,
|
|
2935
|
+
effort,
|
|
2936
|
+
ignoreUnknown: input.ignoreUnknown,
|
|
2937
|
+
supported
|
|
2938
|
+
});
|
|
2939
|
+
return resolved(directive);
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2649
2942
|
// src/prepare-request.ts
|
|
2650
2943
|
function prepareDispatchRequest(params) {
|
|
2651
2944
|
const cloned = cloneRequest(params.request);
|
|
@@ -2655,11 +2948,13 @@ function prepareDispatchRequest(params) {
|
|
|
2655
2948
|
applyDispatchGate(cloned);
|
|
2656
2949
|
const provider = params.provider;
|
|
2657
2950
|
const reasoningEffort = cloned.reasoningEffort;
|
|
2951
|
+
const degradeReasoningEffort = cloned.degradeReasoningEffort === true;
|
|
2658
2952
|
const bedrockControls = cloned.bedrockControls;
|
|
2659
2953
|
const cachePolicy = cloned.cache;
|
|
2660
2954
|
const cloudflareRequest = cloned.cloudflare;
|
|
2661
2955
|
delete cloned.provider;
|
|
2662
2956
|
delete cloned.reasoningEffort;
|
|
2957
|
+
delete cloned.degradeReasoningEffort;
|
|
2663
2958
|
delete cloned.bedrockControls;
|
|
2664
2959
|
delete cloned.cache;
|
|
2665
2960
|
delete cloned.cloudflare;
|
|
@@ -2677,6 +2972,7 @@ function prepareDispatchRequest(params) {
|
|
|
2677
2972
|
const requestedModel = cloned.model ?? defaultModelFor(provider, params.options) ?? "";
|
|
2678
2973
|
const explicit = hasExplicitControl(provider, cloned, bedrockControls);
|
|
2679
2974
|
let directive;
|
|
2975
|
+
let sentEffort;
|
|
2680
2976
|
let catalogPrefix;
|
|
2681
2977
|
if (!explicit && reasoningEffort !== void 0) {
|
|
2682
2978
|
if (!requestedModel) {
|
|
@@ -2688,13 +2984,29 @@ function prepareDispatchRequest(params) {
|
|
|
2688
2984
|
if (provider === "cloudflare") {
|
|
2689
2985
|
const query = cloudflareCatalogQuery(requestedModel);
|
|
2690
2986
|
catalogPrefix = query.prefix;
|
|
2691
|
-
|
|
2987
|
+
const resolved2 = resolveEffortDirective({
|
|
2988
|
+
target: query.target,
|
|
2989
|
+
model: query.model,
|
|
2990
|
+
effort: reasoningEffort,
|
|
2991
|
+
ignoreUnknown: true,
|
|
2992
|
+
degrade: degradeReasoningEffort
|
|
2993
|
+
});
|
|
2994
|
+
directive = resolved2.directive;
|
|
2995
|
+
sentEffort = resolved2.sentEffort;
|
|
2692
2996
|
} else if (isReasoningTarget(provider)) {
|
|
2693
|
-
|
|
2997
|
+
const resolved2 = resolveEffortDirective({
|
|
2998
|
+
target: provider,
|
|
2999
|
+
model: requestedModel,
|
|
3000
|
+
effort: reasoningEffort,
|
|
3001
|
+
ignoreUnknown: false,
|
|
3002
|
+
degrade: degradeReasoningEffort
|
|
3003
|
+
});
|
|
3004
|
+
directive = resolved2.directive;
|
|
3005
|
+
sentEffort = resolved2.sentEffort;
|
|
2694
3006
|
}
|
|
2695
3007
|
}
|
|
2696
3008
|
if (provider === "openrouter") {
|
|
2697
|
-
applyNestedReasoning(cloned, reasoningEffort);
|
|
3009
|
+
applyNestedReasoning(cloned, reasoningEffort, degradeReasoningEffort);
|
|
2698
3010
|
}
|
|
2699
3011
|
if (directive?.model) {
|
|
2700
3012
|
cloned.model = provider === "cloudflare" ? restoreCloudflareModel(directive.model, catalogPrefix) : directive.model;
|
|
@@ -2728,7 +3040,7 @@ function prepareDispatchRequest(params) {
|
|
|
2728
3040
|
if (overlay || cacheTouchesBody) {
|
|
2729
3041
|
const bodyOverlay = overlay;
|
|
2730
3042
|
call.finalizeBody = (body) => {
|
|
2731
|
-
const merged = bodyOverlay ? (0,
|
|
3043
|
+
const merged = bodyOverlay ? (0, import_ai_profiles3.mergeReasoningBody)(body, bodyOverlay) : body;
|
|
2732
3044
|
if (!cacheTouchesBody || !cachePlan) return merged;
|
|
2733
3045
|
const applied = applyPromptCache(merged, cachePlan);
|
|
2734
3046
|
if (cachePlan.placeBreakpoint && !applied.placed) {
|
|
@@ -2755,6 +3067,7 @@ function prepareDispatchRequest(params) {
|
|
|
2755
3067
|
}
|
|
2756
3068
|
const resolution = reasoningEffort !== void 0 || explicit ? buildResolution({
|
|
2757
3069
|
requestedEffort: reasoningEffort,
|
|
3070
|
+
sentEffort: explicit ? explicitSentEffort(provider, cloned, bedrockControls) : sentEffort,
|
|
2758
3071
|
target: provider,
|
|
2759
3072
|
requestedModel,
|
|
2760
3073
|
effectiveModel,
|
|
@@ -2787,29 +3100,6 @@ function noteUnplacedCache(resolution, warnings, target, model) {
|
|
|
2787
3100
|
details: { target, model }
|
|
2788
3101
|
});
|
|
2789
3102
|
}
|
|
2790
|
-
function resolveCatalog(input, ignoreUnknown) {
|
|
2791
|
-
try {
|
|
2792
|
-
return (0, import_ai_profiles.resolveReasoning)(input);
|
|
2793
|
-
} catch (error) {
|
|
2794
|
-
if (error instanceof import_ai_profiles.AIProfilesError) {
|
|
2795
|
-
if (ignoreUnknown && (error.code === "UNKNOWN_MODEL" || error.code === "REASONING_MAPPING_MISSING")) {
|
|
2796
|
-
return {
|
|
2797
|
-
outcome: "ignored",
|
|
2798
|
-
body: {},
|
|
2799
|
-
response: {
|
|
2800
|
-
reasoningTextPaths: [],
|
|
2801
|
-
streamReasoningKeys: [],
|
|
2802
|
-
streamReasoningPaths: [],
|
|
2803
|
-
stripFromHistoryPaths: [],
|
|
2804
|
-
stripThinkTags: false
|
|
2805
|
-
}
|
|
2806
|
-
};
|
|
2807
|
-
}
|
|
2808
|
-
throw new AiDispatcherError(error.code, error.message, error.details);
|
|
2809
|
-
}
|
|
2810
|
-
throw error;
|
|
2811
|
-
}
|
|
2812
|
-
}
|
|
2813
3103
|
function isReasoningTarget(provider) {
|
|
2814
3104
|
return provider === "openrouter" || provider === "bedrock" || provider === "openai";
|
|
2815
3105
|
}
|
|
@@ -2817,6 +3107,15 @@ function hasExplicitControl(provider, request, bedrockControls) {
|
|
|
2817
3107
|
if (provider === "bedrock") return bedrockControls?.additionalModelRequestFields !== void 0;
|
|
2818
3108
|
return request.reasoning !== void 0;
|
|
2819
3109
|
}
|
|
3110
|
+
function explicitSentEffort(provider, request, bedrockControls) {
|
|
3111
|
+
if (provider === "bedrock") {
|
|
3112
|
+
const output = bedrockControls?.additionalModelRequestFields?.output_config;
|
|
3113
|
+
if (isRecord8(output) && typeof output.effort === "string") return output.effort;
|
|
3114
|
+
return void 0;
|
|
3115
|
+
}
|
|
3116
|
+
if (isRecord8(request.reasoning) && typeof request.reasoning.effort === "string") return request.reasoning.effort;
|
|
3117
|
+
return void 0;
|
|
3118
|
+
}
|
|
2820
3119
|
function buildResolution(params) {
|
|
2821
3120
|
return {
|
|
2822
3121
|
target: params.target,
|
|
@@ -2824,19 +3123,20 @@ function buildResolution(params) {
|
|
|
2824
3123
|
effectiveModel: params.effectiveModel,
|
|
2825
3124
|
bypassed: params.bypassed,
|
|
2826
3125
|
...params.requestedEffort ? { requestedEffort: params.requestedEffort } : {},
|
|
3126
|
+
...params.sentEffort ? { sentEffort: params.sentEffort } : {},
|
|
2827
3127
|
...params.outcome ? { outcome: params.outcome } : {}
|
|
2828
3128
|
};
|
|
2829
3129
|
}
|
|
2830
|
-
function applyNestedReasoning(request, parentEffort) {
|
|
3130
|
+
function applyNestedReasoning(request, parentEffort, degrade) {
|
|
2831
3131
|
const serverTools = request.serverTools;
|
|
2832
3132
|
if (!serverTools) return;
|
|
2833
|
-
if (serverTools.fusion) serverTools.fusion = settleNested(serverTools.fusion, "fusion", parentEffort);
|
|
3133
|
+
if (serverTools.fusion) serverTools.fusion = settleNested(serverTools.fusion, "fusion", parentEffort, degrade);
|
|
2834
3134
|
if (serverTools.advisor) {
|
|
2835
|
-
serverTools.advisor = Array.isArray(serverTools.advisor) ? serverTools.advisor.map((advisor) => settleNested(advisor, "advisor", parentEffort)) : settleNested(serverTools.advisor, "advisor", parentEffort);
|
|
3135
|
+
serverTools.advisor = Array.isArray(serverTools.advisor) ? serverTools.advisor.map((advisor) => settleNested(advisor, "advisor", parentEffort, degrade)) : settleNested(serverTools.advisor, "advisor", parentEffort, degrade);
|
|
2836
3136
|
}
|
|
2837
|
-
if (serverTools.subagent) serverTools.subagent = settleNested(serverTools.subagent, "subagent", parentEffort);
|
|
3137
|
+
if (serverTools.subagent) serverTools.subagent = settleNested(serverTools.subagent, "subagent", parentEffort, degrade);
|
|
2838
3138
|
}
|
|
2839
|
-
function settleNested(policy, kind, parentEffort) {
|
|
3139
|
+
function settleNested(policy, kind, parentEffort, degrade) {
|
|
2840
3140
|
const current = policy;
|
|
2841
3141
|
const childEffort = current.reasoningEffort;
|
|
2842
3142
|
const next = { ...current };
|
|
@@ -2846,12 +3146,18 @@ function settleNested(policy, kind, parentEffort) {
|
|
|
2846
3146
|
if (!effort) return next;
|
|
2847
3147
|
const model = kind === "fusion" ? next.judgeModel : next.model;
|
|
2848
3148
|
if (!model) return next;
|
|
2849
|
-
const directive =
|
|
3149
|
+
const directive = resolveEffortDirective({
|
|
3150
|
+
target: "openrouter",
|
|
3151
|
+
model,
|
|
3152
|
+
effort,
|
|
3153
|
+
ignoreUnknown: false,
|
|
3154
|
+
degrade
|
|
3155
|
+
}).directive;
|
|
2850
3156
|
if (directive.model) {
|
|
2851
3157
|
if (kind === "fusion") next.judgeModel = directive.model;
|
|
2852
3158
|
else next.model = directive.model;
|
|
2853
3159
|
}
|
|
2854
|
-
if (
|
|
3160
|
+
if (isRecord8(directive.body.reasoning)) next.reasoning = directive.body.reasoning;
|
|
2855
3161
|
return next;
|
|
2856
3162
|
}
|
|
2857
3163
|
function applyPromptPrefix(request, prefix) {
|
|
@@ -2888,10 +3194,10 @@ function prefixMessages(messages, prefix) {
|
|
|
2888
3194
|
return false;
|
|
2889
3195
|
}
|
|
2890
3196
|
function prefixInputItems(items, prefix) {
|
|
2891
|
-
for (let
|
|
2892
|
-
const item = items[
|
|
3197
|
+
for (let index2 = 0; index2 < items.length; index2 += 1) {
|
|
3198
|
+
const item = items[index2];
|
|
2893
3199
|
if (typeof item === "string") {
|
|
2894
|
-
items[
|
|
3200
|
+
items[index2] = prefix + item;
|
|
2895
3201
|
return true;
|
|
2896
3202
|
}
|
|
2897
3203
|
if (!item || item.role === "system") continue;
|
|
@@ -2901,7 +3207,7 @@ function prefixInputItems(items, prefix) {
|
|
|
2901
3207
|
}
|
|
2902
3208
|
if (!Array.isArray(item.content)) continue;
|
|
2903
3209
|
for (const part of item.content) {
|
|
2904
|
-
if (!
|
|
3210
|
+
if (!isRecord8(part) || typeof part.text !== "string") continue;
|
|
2905
3211
|
if (part.type === "text" || part.type === "input_text") {
|
|
2906
3212
|
part.text = prefix + part.text;
|
|
2907
3213
|
return true;
|
|
@@ -2962,7 +3268,7 @@ var ROLE_STAMP_FIELDS = ["role", "roleLayer", "roleDigest", "profileChoice"];
|
|
|
2962
3268
|
function applyRoleStamp(request) {
|
|
2963
3269
|
const stamp = request.role;
|
|
2964
3270
|
delete request.role;
|
|
2965
|
-
if (!
|
|
3271
|
+
if (!isRecord8(stamp)) return;
|
|
2966
3272
|
const identity = {};
|
|
2967
3273
|
for (const field of ROLE_STAMP_FIELDS) {
|
|
2968
3274
|
const value = stamp[field];
|
|
@@ -2977,8 +3283,8 @@ function applyRoleStamp(request) {
|
|
|
2977
3283
|
}
|
|
2978
3284
|
function absorbOverrideMetadata(request) {
|
|
2979
3285
|
const overrides = request.rawOpenRouterOverrides;
|
|
2980
|
-
if (!
|
|
2981
|
-
if (
|
|
3286
|
+
if (!isRecord8(overrides) || !Object.prototype.hasOwnProperty.call(overrides, "metadata")) return;
|
|
3287
|
+
if (isRecord8(overrides.metadata)) {
|
|
2982
3288
|
const current = { ...request.metadata ?? {} };
|
|
2983
3289
|
const extra = {};
|
|
2984
3290
|
for (const [key, value] of Object.entries(overrides.metadata)) {
|
|
@@ -3023,7 +3329,7 @@ function hasOwnKeys(value) {
|
|
|
3023
3329
|
function hasStreamMetadata(directive) {
|
|
3024
3330
|
return directive.response.streamReasoningKeys.length > 0 || directive.response.streamReasoningPaths.length > 0;
|
|
3025
3331
|
}
|
|
3026
|
-
function
|
|
3332
|
+
function isRecord8(value) {
|
|
3027
3333
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3028
3334
|
}
|
|
3029
3335
|
function readEnv2(name) {
|
|
@@ -3170,22 +3476,22 @@ var import_openrouter_runtime2 = require("@x12i/openrouter-runtime");
|
|
|
3170
3476
|
var DEFAULT_BASE_URL2 = "https://api.openai.com/v1";
|
|
3171
3477
|
var DEFAULT_TIMEOUT_MS2 = 12e4;
|
|
3172
3478
|
function createOpenAiProviderAdapter(options = {}, packer) {
|
|
3173
|
-
const
|
|
3479
|
+
const resolved2 = resolveOpenAiOptions(options, packer);
|
|
3174
3480
|
return {
|
|
3175
3481
|
compile(request, call) {
|
|
3176
|
-
return compileOpenAiRequest(request,
|
|
3482
|
+
return compileOpenAiRequest(request, resolved2, call, false);
|
|
3177
3483
|
},
|
|
3178
3484
|
async run(request, call) {
|
|
3179
3485
|
const requestId = request.id ?? "openai";
|
|
3180
3486
|
try {
|
|
3181
|
-
return await runOpenAi(request,
|
|
3487
|
+
return await runOpenAi(request, resolved2, call, requestId);
|
|
3182
3488
|
} catch (error) {
|
|
3183
3489
|
if (error instanceof AiDispatcherError && isConfigError2(error.code)) throw error;
|
|
3184
3490
|
return failedResponse2(request, requestId, error);
|
|
3185
3491
|
}
|
|
3186
3492
|
},
|
|
3187
3493
|
executeStreamingChat(request, call) {
|
|
3188
|
-
return streamOpenAi(request,
|
|
3494
|
+
return streamOpenAi(request, resolved2, call);
|
|
3189
3495
|
}
|
|
3190
3496
|
};
|
|
3191
3497
|
}
|
|
@@ -3342,7 +3648,7 @@ async function runOpenAi(request, options, call, requestId) {
|
|
|
3342
3648
|
let response;
|
|
3343
3649
|
for (let iteration = 0; iteration <= maxIterations; iteration += 1) {
|
|
3344
3650
|
response = await sendWithRetries2(active, options, timeoutFor2(request, options));
|
|
3345
|
-
const calls = functionCalls(
|
|
3651
|
+
const calls = functionCalls(isRecord9(response) ? response : {});
|
|
3346
3652
|
if (!calls.length) break;
|
|
3347
3653
|
if (!calls.every((item) => resolveExecutor2(item.name, request, options))) {
|
|
3348
3654
|
return normalizeOpenAiResponse({
|
|
@@ -3362,7 +3668,7 @@ async function runOpenAi(request, options, call, requestId) {
|
|
|
3362
3668
|
results.push(await executeOpenAiTool(item, request, options));
|
|
3363
3669
|
}
|
|
3364
3670
|
functionUsage.push(...results);
|
|
3365
|
-
const record2 =
|
|
3671
|
+
const record2 = isRecord9(response) ? response : {};
|
|
3366
3672
|
active = {
|
|
3367
3673
|
...active,
|
|
3368
3674
|
body: clean2({
|
|
@@ -3477,7 +3783,7 @@ async function* streamOpenAi(request, options, call) {
|
|
|
3477
3783
|
throw failure;
|
|
3478
3784
|
}
|
|
3479
3785
|
for await (const event of parseSse2(response)) {
|
|
3480
|
-
if (!
|
|
3786
|
+
if (!isRecord9(event)) continue;
|
|
3481
3787
|
if (event.type === "response.output_text.delta" && typeof event.delta === "string" && event.delta) {
|
|
3482
3788
|
text += event.delta;
|
|
3483
3789
|
yield { type: "stream.text.delta", requestId, data: { text: event.delta } };
|
|
@@ -3496,7 +3802,7 @@ async function* streamOpenAi(request, options, call) {
|
|
|
3496
3802
|
argumentsDelta: event.delta
|
|
3497
3803
|
}
|
|
3498
3804
|
};
|
|
3499
|
-
} else if (event.type === "response.completed" &&
|
|
3805
|
+
} else if (event.type === "response.completed" && isRecord9(event.response)) {
|
|
3500
3806
|
const usage = normalizeUsage2(event.response.usage);
|
|
3501
3807
|
if (usage) yield { type: "stream.usage", requestId, data: { usage } };
|
|
3502
3808
|
} else if (event.type === "error") {
|
|
@@ -3590,7 +3896,7 @@ function isConfigError2(code) {
|
|
|
3590
3896
|
}
|
|
3591
3897
|
function asTerminalError2(error) {
|
|
3592
3898
|
if (error instanceof AiDispatcherError && error.code === "PROVIDER_RETRYABLE") {
|
|
3593
|
-
const status =
|
|
3899
|
+
const status = isRecord9(error.details) ? error.details.status : void 0;
|
|
3594
3900
|
if (status === 429) return new AiDispatcherError("PROVIDER_RATE_LIMITED", error.message, error.details);
|
|
3595
3901
|
return new AiDispatcherError("PROVIDER_GATEWAY_UNREACHABLE", error.message, error.details);
|
|
3596
3902
|
}
|
|
@@ -3598,7 +3904,7 @@ function asTerminalError2(error) {
|
|
|
3598
3904
|
return new AiDispatcherError("PROVIDER_REQUEST_FAILED", error instanceof Error ? error.message : String(error));
|
|
3599
3905
|
}
|
|
3600
3906
|
function normalizeOpenAiResponse(params) {
|
|
3601
|
-
const record2 =
|
|
3907
|
+
const record2 = isRecord9(params.response) ? params.response : {};
|
|
3602
3908
|
const text = answerText2(record2);
|
|
3603
3909
|
const calls = params.functionTools ?? functionCalls(record2);
|
|
3604
3910
|
const usage = normalizeUsage2(record2.usage);
|
|
@@ -3625,9 +3931,9 @@ function answerText2(response) {
|
|
|
3625
3931
|
if (Array.isArray(output)) {
|
|
3626
3932
|
const parts = [];
|
|
3627
3933
|
for (const item of output) {
|
|
3628
|
-
if (!
|
|
3934
|
+
if (!isRecord9(item) || item.type === "reasoning" || item.type !== "message" || !Array.isArray(item.content)) continue;
|
|
3629
3935
|
for (const part of item.content) {
|
|
3630
|
-
if (
|
|
3936
|
+
if (isRecord9(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
|
|
3631
3937
|
}
|
|
3632
3938
|
}
|
|
3633
3939
|
if (parts.length > 0) return parts.join("");
|
|
@@ -3638,7 +3944,7 @@ function functionCalls(response) {
|
|
|
3638
3944
|
if (!Array.isArray(response.output)) return [];
|
|
3639
3945
|
const calls = [];
|
|
3640
3946
|
for (const item of response.output) {
|
|
3641
|
-
if (!
|
|
3947
|
+
if (!isRecord9(item) || item.type !== "function_call") continue;
|
|
3642
3948
|
const name = typeof item.name === "string" ? item.name : "function";
|
|
3643
3949
|
const callId = typeof item.call_id === "string" ? item.call_id : name;
|
|
3644
3950
|
let args = item.arguments;
|
|
@@ -3670,7 +3976,7 @@ function toolUsage(calls) {
|
|
|
3670
3976
|
};
|
|
3671
3977
|
}
|
|
3672
3978
|
function normalizeUsage2(usage) {
|
|
3673
|
-
if (!
|
|
3979
|
+
if (!isRecord9(usage)) return void 0;
|
|
3674
3980
|
const inputTokens = numberValue2(usage.input_tokens);
|
|
3675
3981
|
const outputTokens = numberValue2(usage.output_tokens);
|
|
3676
3982
|
const totalTokens = numberValue2(usage.total_tokens) ?? (inputTokens !== void 0 || outputTokens !== void 0 ? (inputTokens ?? 0) + (outputTokens ?? 0) : void 0);
|
|
@@ -3722,16 +4028,16 @@ function modelOf2(compiled) {
|
|
|
3722
4028
|
return typeof compiled.body.model === "string" ? compiled.body.model : "";
|
|
3723
4029
|
}
|
|
3724
4030
|
function messageFrom2(body) {
|
|
3725
|
-
if (!
|
|
4031
|
+
if (!isRecord9(body)) return void 0;
|
|
3726
4032
|
if (typeof body.message === "string") return body.message;
|
|
3727
|
-
if (
|
|
4033
|
+
if (isRecord9(body.error) && typeof body.error.message === "string") return body.error.message;
|
|
3728
4034
|
return void 0;
|
|
3729
4035
|
}
|
|
3730
4036
|
function numberValue2(value) {
|
|
3731
4037
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3732
4038
|
}
|
|
3733
4039
|
function attachProviderMetadata(body, request, packer) {
|
|
3734
|
-
const fromBody =
|
|
4040
|
+
const fromBody = isRecord9(body.metadata) ? body.metadata : void 0;
|
|
3735
4041
|
const packed = (0, import_openrouter_runtime2.packProviderRecord)(request.metadata, request.agentId, fromBody, packer);
|
|
3736
4042
|
if (packed.wire) return { body: { ...body, metadata: packed.wire }, ...packed.warning ? { warning: packed.warning } : {} };
|
|
3737
4043
|
if (body.metadata === void 0) return { body, ...packed.warning ? { warning: packed.warning } : {} };
|
|
@@ -3805,7 +4111,7 @@ function readEnv3(name) {
|
|
|
3805
4111
|
if (typeof process === "undefined") return void 0;
|
|
3806
4112
|
return process.env[name];
|
|
3807
4113
|
}
|
|
3808
|
-
function
|
|
4114
|
+
function isRecord9(value) {
|
|
3809
4115
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3810
4116
|
}
|
|
3811
4117
|
|
|
@@ -3987,7 +4293,7 @@ function callOf(call) {
|
|
|
3987
4293
|
}
|
|
3988
4294
|
function attachCompileMeta(prepared, compiled) {
|
|
3989
4295
|
const record2 = compiled;
|
|
3990
|
-
const headers =
|
|
4296
|
+
const headers = isRecord10(record2.headers) ? redactHeaders(record2.headers) : void 0;
|
|
3991
4297
|
const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
|
|
3992
4298
|
return {
|
|
3993
4299
|
...record2,
|
|
@@ -4023,7 +4329,7 @@ function log(options, event, prepared, entrypoint, streaming) {
|
|
|
4023
4329
|
if (event.endsWith("compiled")) options.logger?.debug?.(event, payload);
|
|
4024
4330
|
else options.logger?.info?.(event, payload);
|
|
4025
4331
|
}
|
|
4026
|
-
function
|
|
4332
|
+
function isRecord10(value) {
|
|
4027
4333
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4028
4334
|
}
|
|
4029
4335
|
|