@x12i/ai-dispatcher 3.2.0 → 3.3.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/README.md +22 -17
- package/dist/index.cjs +407 -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,13 @@ __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
|
-
var
|
|
50
|
+
var import_ai_profiles4 = require("@x12i/ai-profiles");
|
|
51
51
|
var import_openrouter_runtime4 = require("@x12i/openrouter-runtime");
|
|
52
52
|
|
|
53
53
|
// src/create-dispatcher.ts
|
|
@@ -162,7 +162,7 @@ async function openTrack(settings, model) {
|
|
|
162
162
|
try {
|
|
163
163
|
tokenCounter = await loadTokenizer(tokenizer);
|
|
164
164
|
const framing = framingFor(settings);
|
|
165
|
-
const
|
|
165
|
+
const resolved2 = (0, import_core.resolveSettings)({
|
|
166
166
|
files: [],
|
|
167
167
|
env: {},
|
|
168
168
|
factory: {
|
|
@@ -177,8 +177,8 @@ async function openTrack(settings, model) {
|
|
|
177
177
|
});
|
|
178
178
|
const approvals = settings.approvals;
|
|
179
179
|
const client = (0, import_core.createCoreClient)({
|
|
180
|
-
config:
|
|
181
|
-
explanation:
|
|
180
|
+
config: resolved2.config,
|
|
181
|
+
explanation: resolved2.explanation,
|
|
182
182
|
...approvals && approvals.length > 0 ? { policy: { approvals: [...approvals] } } : {},
|
|
183
183
|
...tokenCounter ? { tokenCounter } : {},
|
|
184
184
|
warn: () => void 0
|
|
@@ -232,10 +232,10 @@ async function encodeRequestText(request, track) {
|
|
|
232
232
|
if (typeof request.input === "string") {
|
|
233
233
|
request.input = await encodeString(track, request.input);
|
|
234
234
|
} else if (Array.isArray(request.input)) {
|
|
235
|
-
for (let
|
|
236
|
-
const item = request.input[
|
|
235
|
+
for (let index2 = 0; index2 < request.input.length; index2 += 1) {
|
|
236
|
+
const item = request.input[index2];
|
|
237
237
|
if (typeof item === "string") {
|
|
238
|
-
request.input[
|
|
238
|
+
request.input[index2] = await encodeString(track, item);
|
|
239
239
|
} else if (item) {
|
|
240
240
|
await encodeContentRecord(item, track);
|
|
241
241
|
}
|
|
@@ -432,9 +432,9 @@ function walk(current, tokens) {
|
|
|
432
432
|
}
|
|
433
433
|
if (Array.isArray(current)) {
|
|
434
434
|
if (!/^\d+$/.test(head)) return [];
|
|
435
|
-
const
|
|
436
|
-
if (
|
|
437
|
-
return walk(current[
|
|
435
|
+
const index2 = Number(head);
|
|
436
|
+
if (index2 >= current.length) return [];
|
|
437
|
+
return walk(current[index2], rest);
|
|
438
438
|
}
|
|
439
439
|
if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
|
|
440
440
|
return walk(current[head], rest);
|
|
@@ -469,9 +469,9 @@ function collectParents(current, tokens) {
|
|
|
469
469
|
}
|
|
470
470
|
if (Array.isArray(current)) {
|
|
471
471
|
if (!/^\d+$/.test(head)) return [];
|
|
472
|
-
const
|
|
473
|
-
if (
|
|
474
|
-
return collectParents(current[
|
|
472
|
+
const index2 = Number(head);
|
|
473
|
+
if (index2 >= current.length) return [];
|
|
474
|
+
return collectParents(current[index2], rest);
|
|
475
475
|
}
|
|
476
476
|
if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
|
|
477
477
|
return collectParents(current[head], rest);
|
|
@@ -485,8 +485,8 @@ function deletePointer(root, pointer) {
|
|
|
485
485
|
for (const parent of parents) {
|
|
486
486
|
if (Array.isArray(parent)) {
|
|
487
487
|
if (!/^\d+$/.test(last)) continue;
|
|
488
|
-
const
|
|
489
|
-
if (
|
|
488
|
+
const index2 = Number(last);
|
|
489
|
+
if (index2 < parent.length) parent.splice(index2, 1);
|
|
490
490
|
continue;
|
|
491
491
|
}
|
|
492
492
|
if (isRecord2(parent) && Object.prototype.hasOwnProperty.call(parent, last)) {
|
|
@@ -518,6 +518,38 @@ function extractStreamReasoningText(event, response) {
|
|
|
518
518
|
}
|
|
519
519
|
return firstConcatenatedText(event, response.streamReasoningPaths);
|
|
520
520
|
}
|
|
521
|
+
function readReportedEffort(root) {
|
|
522
|
+
if (!isRecord3(root)) return void 0;
|
|
523
|
+
const fromRoot = effortOn(root.reasoning) ?? namedEffort(root.reasoning_effort);
|
|
524
|
+
if (fromRoot) return fromRoot;
|
|
525
|
+
if (Array.isArray(root.choices)) {
|
|
526
|
+
for (const choice of root.choices) {
|
|
527
|
+
if (!isRecord3(choice)) continue;
|
|
528
|
+
const message = isRecord3(choice.message) ? choice.message : void 0;
|
|
529
|
+
const fromMessage = message ? effortOn(message.reasoning) ?? namedEffort(message.reasoning_effort) : void 0;
|
|
530
|
+
if (fromMessage) return fromMessage;
|
|
531
|
+
const fromChoice = effortOn(choice.reasoning) ?? namedEffort(choice.reasoning_effort);
|
|
532
|
+
if (fromChoice) return fromChoice;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (Array.isArray(root.output)) {
|
|
536
|
+
for (const item of root.output) {
|
|
537
|
+
if (!isRecord3(item) || item.type !== "reasoning") continue;
|
|
538
|
+
const effort = namedEffort(item.effort);
|
|
539
|
+
if (effort) return effort;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return void 0;
|
|
543
|
+
}
|
|
544
|
+
function effortOn(value) {
|
|
545
|
+
if (!isRecord3(value)) return void 0;
|
|
546
|
+
return namedEffort(value.effort);
|
|
547
|
+
}
|
|
548
|
+
function namedEffort(value) {
|
|
549
|
+
if (typeof value !== "string") return void 0;
|
|
550
|
+
const trimmed = value.trim();
|
|
551
|
+
return trimmed || void 0;
|
|
552
|
+
}
|
|
521
553
|
function readReasoningTokens(root, paths) {
|
|
522
554
|
for (const path of paths) {
|
|
523
555
|
const absolute = firstNumber(root, [path]);
|
|
@@ -602,7 +634,10 @@ function splitThinkTags(text) {
|
|
|
602
634
|
// src/apply-resolution.ts
|
|
603
635
|
function applyResolution(response, prepared) {
|
|
604
636
|
const result = response;
|
|
605
|
-
if (prepared.resolution)
|
|
637
|
+
if (prepared.resolution) {
|
|
638
|
+
const reportedEffort = readReportedEffort(response.raw?.response);
|
|
639
|
+
result.reasoningResolution = reportedEffort ? { ...prepared.resolution, reportedEffort } : prepared.resolution;
|
|
640
|
+
}
|
|
606
641
|
if (prepared.cacheResolution) result.cacheResolution = prepared.cacheResolution;
|
|
607
642
|
if (prepared.cacheWarnings?.length) {
|
|
608
643
|
result.warnings = [...result.warnings, ...prepared.cacheWarnings];
|
|
@@ -984,7 +1019,7 @@ function isRecord5(value) {
|
|
|
984
1019
|
}
|
|
985
1020
|
|
|
986
1021
|
// src/prepare-request.ts
|
|
987
|
-
var
|
|
1022
|
+
var import_ai_profiles3 = require("@x12i/ai-profiles");
|
|
988
1023
|
|
|
989
1024
|
// src/cache-apply.ts
|
|
990
1025
|
var BREAKPOINT = { mode: "explicit" };
|
|
@@ -1067,38 +1102,38 @@ function placeBedrockBreakpoint(body, ttl) {
|
|
|
1067
1102
|
function markMessages(body, field, markerKey, markerValue, textType) {
|
|
1068
1103
|
const messages = body[field];
|
|
1069
1104
|
if (!Array.isArray(messages)) return { body, placed: false };
|
|
1070
|
-
const
|
|
1071
|
-
if (
|
|
1072
|
-
const marked = markMessage(messages[
|
|
1105
|
+
const index2 = stableMessageIndex(messages);
|
|
1106
|
+
if (index2 < 0) return { body, placed: false };
|
|
1107
|
+
const marked = markMessage(messages[index2], markerKey, markerValue, textType);
|
|
1073
1108
|
if (!marked) return { body, placed: false };
|
|
1074
1109
|
const next = messages.slice();
|
|
1075
|
-
next[
|
|
1110
|
+
next[index2] = marked;
|
|
1076
1111
|
return { placed: true, body: { ...body, [field]: next } };
|
|
1077
1112
|
}
|
|
1078
1113
|
function markInput(body, markerKey, markerValue, textType) {
|
|
1079
1114
|
if (!Array.isArray(body.input)) return { body, placed: false };
|
|
1080
|
-
const
|
|
1081
|
-
if (
|
|
1082
|
-
const marked = markMessage(body.input[
|
|
1115
|
+
const index2 = stableInputIndex(body.input);
|
|
1116
|
+
if (index2 < 0) return { body, placed: false };
|
|
1117
|
+
const marked = markMessage(body.input[index2], markerKey, markerValue, textType);
|
|
1083
1118
|
if (!marked) return { body, placed: false };
|
|
1084
1119
|
const next = body.input.slice();
|
|
1085
|
-
next[
|
|
1120
|
+
next[index2] = marked;
|
|
1086
1121
|
return { placed: true, body: { ...body, input: next } };
|
|
1087
1122
|
}
|
|
1088
1123
|
function stableMessageIndex(messages) {
|
|
1089
1124
|
let lastSystem = -1;
|
|
1090
|
-
for (let
|
|
1091
|
-
const message = messages[
|
|
1092
|
-
if (isPlainRecord(message) && message.role === "system" && hasText(message.content)) lastSystem =
|
|
1125
|
+
for (let index2 = 0; index2 < messages.length; index2 += 1) {
|
|
1126
|
+
const message = messages[index2];
|
|
1127
|
+
if (isPlainRecord(message) && message.role === "system" && hasText(message.content)) lastSystem = index2;
|
|
1093
1128
|
}
|
|
1094
1129
|
return lastSystem;
|
|
1095
1130
|
}
|
|
1096
1131
|
function stableInputIndex(items) {
|
|
1097
1132
|
let lastStable = -1;
|
|
1098
|
-
for (let
|
|
1099
|
-
const item = items[
|
|
1133
|
+
for (let index2 = 0; index2 < items.length; index2 += 1) {
|
|
1134
|
+
const item = items[index2];
|
|
1100
1135
|
if (!isPlainRecord(item) || !hasText(item.content)) continue;
|
|
1101
|
-
if (item.role === "system" || item.role === "developer") lastStable =
|
|
1136
|
+
if (item.role === "system" || item.role === "developer") lastStable = index2;
|
|
1102
1137
|
}
|
|
1103
1138
|
return lastStable;
|
|
1104
1139
|
}
|
|
@@ -1115,10 +1150,10 @@ function markContent(content, markerKey, markerValue, textType) {
|
|
|
1115
1150
|
}
|
|
1116
1151
|
if (!Array.isArray(content)) return void 0;
|
|
1117
1152
|
const parts = content.map((part) => isPlainRecord(part) ? { ...part } : part);
|
|
1118
|
-
for (let
|
|
1119
|
-
const part = parts[
|
|
1153
|
+
for (let index2 = parts.length - 1; index2 >= 0; index2 -= 1) {
|
|
1154
|
+
const part = parts[index2];
|
|
1120
1155
|
if (!isPlainRecord(part) || typeof part.text !== "string" || !part.text.trim()) continue;
|
|
1121
|
-
parts[
|
|
1156
|
+
parts[index2] = { ...part, [markerKey]: markerValue };
|
|
1122
1157
|
return parts;
|
|
1123
1158
|
}
|
|
1124
1159
|
return void 0;
|
|
@@ -1274,11 +1309,11 @@ function resolveCloudflarePromptCache(args) {
|
|
|
1274
1309
|
warnings: []
|
|
1275
1310
|
};
|
|
1276
1311
|
}
|
|
1277
|
-
const
|
|
1278
|
-
const ttl =
|
|
1312
|
+
const resolved2 = applyProfile({ input, mode, key, requestedTtl, resolutionBase, model, profile });
|
|
1313
|
+
const ttl = resolved2.plan.ttl ?? requestedTtl;
|
|
1279
1314
|
return {
|
|
1280
|
-
...
|
|
1281
|
-
plan: { ...
|
|
1315
|
+
...resolved2,
|
|
1316
|
+
plan: { ...resolved2.plan, gateway: gatewayDirective(false, ttl, key) }
|
|
1282
1317
|
};
|
|
1283
1318
|
}
|
|
1284
1319
|
function applyProfile(args) {
|
|
@@ -1483,22 +1518,22 @@ function restoreCloudflareModel(model, prefix) {
|
|
|
1483
1518
|
return `${prefix}${model}`;
|
|
1484
1519
|
}
|
|
1485
1520
|
function createCloudflareProviderAdapter(options = {}, packer) {
|
|
1486
|
-
const
|
|
1521
|
+
const resolved2 = resolveCloudflareOptions(options, packer);
|
|
1487
1522
|
return {
|
|
1488
1523
|
compile(request, call) {
|
|
1489
|
-
return compileCloudflareRequest(request,
|
|
1524
|
+
return compileCloudflareRequest(request, resolved2, call, false);
|
|
1490
1525
|
},
|
|
1491
1526
|
async run(request, call) {
|
|
1492
1527
|
const requestId = request.id ?? "cloudflare";
|
|
1493
1528
|
try {
|
|
1494
|
-
return await runCloudflare(request,
|
|
1529
|
+
return await runCloudflare(request, resolved2, call, requestId);
|
|
1495
1530
|
} catch (error) {
|
|
1496
1531
|
if (error instanceof AiDispatcherError && isConfigError(error.code)) throw error;
|
|
1497
1532
|
return failedResponse(request, requestId, error, "chat");
|
|
1498
1533
|
}
|
|
1499
1534
|
},
|
|
1500
1535
|
executeStreamingChat(request, call) {
|
|
1501
|
-
return streamCloudflare(request,
|
|
1536
|
+
return streamCloudflare(request, resolved2, call);
|
|
1502
1537
|
}
|
|
1503
1538
|
};
|
|
1504
1539
|
}
|
|
@@ -2646,6 +2681,259 @@ function isRecord6(value) {
|
|
|
2646
2681
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2647
2682
|
}
|
|
2648
2683
|
|
|
2684
|
+
// src/resolve-effort.ts
|
|
2685
|
+
var import_ai_profiles2 = require("@x12i/ai-profiles");
|
|
2686
|
+
|
|
2687
|
+
// src/catalog-efforts.ts
|
|
2688
|
+
var import_node_module = require("module");
|
|
2689
|
+
var import_node_fs = require("fs");
|
|
2690
|
+
var import_node_path = require("path");
|
|
2691
|
+
var import_ai_profiles = require("@x12i/ai-profiles");
|
|
2692
|
+
var import_meta = {};
|
|
2693
|
+
var index;
|
|
2694
|
+
function normalize(value) {
|
|
2695
|
+
return value.trim().toLowerCase();
|
|
2696
|
+
}
|
|
2697
|
+
function addKey(keys, key, row) {
|
|
2698
|
+
const normalized = normalize(key);
|
|
2699
|
+
if (!normalized) return;
|
|
2700
|
+
const existing = keys.get(normalized);
|
|
2701
|
+
if (!existing) {
|
|
2702
|
+
keys.set(normalized, row);
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
if (existing === "ambiguous") return;
|
|
2706
|
+
if (existing.modelId !== row.modelId) keys.set(normalized, "ambiguous");
|
|
2707
|
+
}
|
|
2708
|
+
function loadAssignmentAliases() {
|
|
2709
|
+
const require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
2710
|
+
const entry = require2.resolve("@x12i/ai-profiles");
|
|
2711
|
+
const path = (0, import_node_path.join)((0, import_node_path.dirname)(entry), "data", "reasoning-directives.json");
|
|
2712
|
+
const document = JSON.parse((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
2713
|
+
return document.assignments ?? [];
|
|
2714
|
+
}
|
|
2715
|
+
function effortList(entry) {
|
|
2716
|
+
const reasoning = entry.openrouter.reasoning;
|
|
2717
|
+
const modelId = entry.openrouter.modelId;
|
|
2718
|
+
if (!reasoning || !Object.prototype.hasOwnProperty.call(reasoning, "supportedEfforts")) {
|
|
2719
|
+
return { kind: "unspecified", modelId };
|
|
2720
|
+
}
|
|
2721
|
+
if (reasoning.supportedEfforts === null) return { kind: "any", modelId };
|
|
2722
|
+
if (Array.isArray(reasoning.supportedEfforts)) {
|
|
2723
|
+
return { kind: "listed", modelId, efforts: reasoning.supportedEfforts };
|
|
2724
|
+
}
|
|
2725
|
+
return { kind: "unspecified", modelId };
|
|
2726
|
+
}
|
|
2727
|
+
function buildIndex() {
|
|
2728
|
+
const catalog = (0, import_ai_profiles.loadBundledModelsCatalog)();
|
|
2729
|
+
const keys = /* @__PURE__ */ new Map();
|
|
2730
|
+
const byCatalogId = /* @__PURE__ */ new Map();
|
|
2731
|
+
for (const entry of catalog.models) {
|
|
2732
|
+
const row = effortList(entry);
|
|
2733
|
+
byCatalogId.set(normalize(entry.openrouter.modelId), row);
|
|
2734
|
+
addKey(keys, entry.openrouter.modelId, row);
|
|
2735
|
+
if (entry.openrouter.canonicalSlug) addKey(keys, entry.openrouter.canonicalSlug, row);
|
|
2736
|
+
addKey(keys, `${entry.direct.provider}/${entry.direct.modelId}`, row);
|
|
2737
|
+
addKey(keys, `openrouter/${entry.openrouter.modelId}`, row);
|
|
2738
|
+
addKey(keys, entry.direct.modelId, row);
|
|
2739
|
+
}
|
|
2740
|
+
for (const assignment of loadAssignmentAliases()) {
|
|
2741
|
+
const row = byCatalogId.get(normalize(assignment.catalogModelId));
|
|
2742
|
+
if (!row) continue;
|
|
2743
|
+
for (const alias of assignment.aliases ?? []) addKey(keys, alias, row);
|
|
2744
|
+
}
|
|
2745
|
+
return keys;
|
|
2746
|
+
}
|
|
2747
|
+
function lookupCatalogEfforts(model) {
|
|
2748
|
+
if (!index) index = buildIndex();
|
|
2749
|
+
const direct = index.get(normalize(model));
|
|
2750
|
+
if (direct && direct !== "ambiguous") return direct;
|
|
2751
|
+
const gateway = normalize(model);
|
|
2752
|
+
if (gateway.startsWith("openrouter/")) {
|
|
2753
|
+
const stripped = index.get(gateway.slice("openrouter/".length));
|
|
2754
|
+
if (stripped && stripped !== "ambiguous") return stripped;
|
|
2755
|
+
}
|
|
2756
|
+
return void 0;
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
// src/resolve-effort.ts
|
|
2760
|
+
var EMPTY_RESPONSE = {
|
|
2761
|
+
reasoningTextPaths: [],
|
|
2762
|
+
streamReasoningKeys: [],
|
|
2763
|
+
streamReasoningPaths: [],
|
|
2764
|
+
stripFromHistoryPaths: [],
|
|
2765
|
+
stripThinkTags: false
|
|
2766
|
+
};
|
|
2767
|
+
var MAPPER_EFFORTS = ["high", "xhigh", "max", "medium", "low", "minimal"];
|
|
2768
|
+
function isRecord7(value) {
|
|
2769
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2770
|
+
}
|
|
2771
|
+
function readBodyEffort(body) {
|
|
2772
|
+
const reasoning = body.reasoning;
|
|
2773
|
+
if (isRecord7(reasoning) && typeof reasoning.effort === "string") return reasoning.effort;
|
|
2774
|
+
const fields = body.additionalModelRequestFields;
|
|
2775
|
+
if (!isRecord7(fields)) return void 0;
|
|
2776
|
+
const output = fields.output_config;
|
|
2777
|
+
if (isRecord7(output) && typeof output.effort === "string") return output.effort;
|
|
2778
|
+
return void 0;
|
|
2779
|
+
}
|
|
2780
|
+
function writeBodyEffort(body, effort) {
|
|
2781
|
+
const reasoning = body.reasoning;
|
|
2782
|
+
if (isRecord7(reasoning) && typeof reasoning.effort === "string") {
|
|
2783
|
+
reasoning.effort = effort;
|
|
2784
|
+
return true;
|
|
2785
|
+
}
|
|
2786
|
+
const fields = body.additionalModelRequestFields;
|
|
2787
|
+
if (!isRecord7(fields)) return false;
|
|
2788
|
+
const output = fields.output_config;
|
|
2789
|
+
if (isRecord7(output) && typeof output.effort === "string") {
|
|
2790
|
+
output.effort = effort;
|
|
2791
|
+
return true;
|
|
2792
|
+
}
|
|
2793
|
+
return false;
|
|
2794
|
+
}
|
|
2795
|
+
function unsupported(model, effort, supported) {
|
|
2796
|
+
return new AiDispatcherError(
|
|
2797
|
+
"EFFORT_UNSUPPORTED",
|
|
2798
|
+
`Model '${model}' does not accept reasoning effort '${effort}'. Supported efforts: ${supported.join(", ")}.`,
|
|
2799
|
+
{ model, effort, supportedEfforts: [...supported] }
|
|
2800
|
+
);
|
|
2801
|
+
}
|
|
2802
|
+
function ignoredDirective() {
|
|
2803
|
+
return {
|
|
2804
|
+
outcome: "ignored",
|
|
2805
|
+
body: {},
|
|
2806
|
+
response: {
|
|
2807
|
+
reasoningTextPaths: [...EMPTY_RESPONSE.reasoningTextPaths],
|
|
2808
|
+
streamReasoningKeys: [...EMPTY_RESPONSE.streamReasoningKeys],
|
|
2809
|
+
streamReasoningPaths: [...EMPTY_RESPONSE.streamReasoningPaths],
|
|
2810
|
+
stripFromHistoryPaths: [...EMPTY_RESPONSE.stripFromHistoryPaths],
|
|
2811
|
+
stripThinkTags: EMPTY_RESPONSE.stripThinkTags
|
|
2812
|
+
}
|
|
2813
|
+
};
|
|
2814
|
+
}
|
|
2815
|
+
function toDispatcherError(error) {
|
|
2816
|
+
return new AiDispatcherError(error.code, error.message, error.details);
|
|
2817
|
+
}
|
|
2818
|
+
function resolveMapping(input, ignoreUnknown) {
|
|
2819
|
+
try {
|
|
2820
|
+
return (0, import_ai_profiles2.resolveReasoning)({
|
|
2821
|
+
target: input.target,
|
|
2822
|
+
model: input.model,
|
|
2823
|
+
effort: input.effort
|
|
2824
|
+
});
|
|
2825
|
+
} catch (error) {
|
|
2826
|
+
if (!(error instanceof import_ai_profiles2.AIProfilesError)) throw error;
|
|
2827
|
+
if (ignoreUnknown && (error.code === "UNKNOWN_MODEL" || error.code === "REASONING_MAPPING_MISSING")) {
|
|
2828
|
+
return ignoredDirective();
|
|
2829
|
+
}
|
|
2830
|
+
if (error.code === "INVALID_EFFORT") return "bad-key";
|
|
2831
|
+
if (error.code === "REASONING_MAPPING_INVALID" && error.message.includes("missing effort")) return "bad-key";
|
|
2832
|
+
throw toDispatcherError(error);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
function mappingOrThrow(input, ignoreUnknown) {
|
|
2836
|
+
const mapped = resolveMapping(input, ignoreUnknown);
|
|
2837
|
+
if (mapped === "bad-key") {
|
|
2838
|
+
throw new AiDispatcherError(
|
|
2839
|
+
"INVALID_EFFORT",
|
|
2840
|
+
`Invalid reasoning effort '${input.effort}'.`,
|
|
2841
|
+
{ target: input.target, effort: input.effort, model: input.model }
|
|
2842
|
+
);
|
|
2843
|
+
}
|
|
2844
|
+
return mapped;
|
|
2845
|
+
}
|
|
2846
|
+
function sendAsWritten(directive, effort, target) {
|
|
2847
|
+
if (directive.outcome === "ignored") return directive;
|
|
2848
|
+
const copy = structuredClone(directive);
|
|
2849
|
+
const wrote = writeBodyEffort(copy.body, effort);
|
|
2850
|
+
if (!wrote && target !== "bedrock") {
|
|
2851
|
+
const reasoning = isRecord7(copy.body.reasoning) ? copy.body.reasoning : {};
|
|
2852
|
+
copy.body = { ...copy.body, reasoning: { ...reasoning, effort } };
|
|
2853
|
+
}
|
|
2854
|
+
copy.outcome = "applied";
|
|
2855
|
+
return copy;
|
|
2856
|
+
}
|
|
2857
|
+
function directiveForListedEffort(input) {
|
|
2858
|
+
const direct = resolveMapping(input, input.ignoreUnknown);
|
|
2859
|
+
if (direct !== "bad-key") {
|
|
2860
|
+
if (direct.outcome === "ignored") return direct;
|
|
2861
|
+
const sent = readBodyEffort(direct.body);
|
|
2862
|
+
if (sent === input.effort) {
|
|
2863
|
+
if (direct.outcome === "degraded") {
|
|
2864
|
+
const copy = structuredClone(direct);
|
|
2865
|
+
copy.outcome = "applied";
|
|
2866
|
+
return copy;
|
|
2867
|
+
}
|
|
2868
|
+
return direct;
|
|
2869
|
+
}
|
|
2870
|
+
if (sent) return sendAsWritten(direct, input.effort, input.target);
|
|
2871
|
+
}
|
|
2872
|
+
const proxies = MAPPER_EFFORTS.filter((candidate) => {
|
|
2873
|
+
if (candidate === input.effort) return false;
|
|
2874
|
+
if (input.supported === null) return true;
|
|
2875
|
+
return input.supported.includes(candidate);
|
|
2876
|
+
});
|
|
2877
|
+
for (const proxy of proxies) {
|
|
2878
|
+
const mapped = resolveMapping({ ...input, effort: proxy }, input.ignoreUnknown);
|
|
2879
|
+
if (mapped === "bad-key" || mapped.outcome === "ignored") continue;
|
|
2880
|
+
if (!readBodyEffort(mapped.body)) continue;
|
|
2881
|
+
return sendAsWritten(mapped, input.effort, input.target);
|
|
2882
|
+
}
|
|
2883
|
+
return mappingOrThrow(input, input.ignoreUnknown);
|
|
2884
|
+
}
|
|
2885
|
+
function sentOf(directive) {
|
|
2886
|
+
if (directive.outcome === "ignored") return void 0;
|
|
2887
|
+
return readBodyEffort(directive.body);
|
|
2888
|
+
}
|
|
2889
|
+
function resolved(directive) {
|
|
2890
|
+
const sentEffort = sentOf(directive);
|
|
2891
|
+
return sentEffort ? { directive, sentEffort } : { directive };
|
|
2892
|
+
}
|
|
2893
|
+
function resolveEffortDirective(input) {
|
|
2894
|
+
const effort = input.effort.trim();
|
|
2895
|
+
const row = lookupCatalogEfforts(input.model);
|
|
2896
|
+
if (!row) {
|
|
2897
|
+
return resolved(mappingOrThrow(input, input.ignoreUnknown));
|
|
2898
|
+
}
|
|
2899
|
+
if (row.kind === "unspecified") {
|
|
2900
|
+
const directive2 = mappingOrThrow({ ...input, effort }, input.ignoreUnknown);
|
|
2901
|
+
const sent = sentOf(directive2);
|
|
2902
|
+
if (!input.degrade && directive2.outcome === "degraded" && sent && sent !== effort) {
|
|
2903
|
+
throw new AiDispatcherError(
|
|
2904
|
+
"EFFORT_UNSUPPORTED",
|
|
2905
|
+
`Model '${input.model}' does not accept reasoning effort '${effort}' unless degradeReasoningEffort is set.`,
|
|
2906
|
+
{ model: input.model, effort, catalogModelId: row.modelId }
|
|
2907
|
+
);
|
|
2908
|
+
}
|
|
2909
|
+
return resolved(directive2);
|
|
2910
|
+
}
|
|
2911
|
+
const supported = row.kind === "listed" ? row.efforts : null;
|
|
2912
|
+
const allowed = supported === null || supported.includes(effort);
|
|
2913
|
+
if (!allowed && supported) {
|
|
2914
|
+
if (!input.degrade) throw unsupported(input.model, effort, supported);
|
|
2915
|
+
const mapped = resolveMapping({ ...input, effort }, input.ignoreUnknown);
|
|
2916
|
+
if (mapped === "bad-key") throw unsupported(input.model, effort, supported);
|
|
2917
|
+
if (mapped.outcome === "ignored") return { directive: mapped };
|
|
2918
|
+
const sent = readBodyEffort(mapped.body);
|
|
2919
|
+
if (!sent || !supported.includes(sent)) throw unsupported(input.model, effort, supported);
|
|
2920
|
+
if (sent !== effort) {
|
|
2921
|
+
const copy = structuredClone(mapped);
|
|
2922
|
+
copy.outcome = "degraded";
|
|
2923
|
+
return { directive: copy, sentEffort: sent };
|
|
2924
|
+
}
|
|
2925
|
+
return { directive: mapped, sentEffort: sent };
|
|
2926
|
+
}
|
|
2927
|
+
const directive = directiveForListedEffort({
|
|
2928
|
+
target: input.target,
|
|
2929
|
+
model: input.model,
|
|
2930
|
+
effort,
|
|
2931
|
+
ignoreUnknown: input.ignoreUnknown,
|
|
2932
|
+
supported
|
|
2933
|
+
});
|
|
2934
|
+
return resolved(directive);
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2649
2937
|
// src/prepare-request.ts
|
|
2650
2938
|
function prepareDispatchRequest(params) {
|
|
2651
2939
|
const cloned = cloneRequest(params.request);
|
|
@@ -2655,11 +2943,13 @@ function prepareDispatchRequest(params) {
|
|
|
2655
2943
|
applyDispatchGate(cloned);
|
|
2656
2944
|
const provider = params.provider;
|
|
2657
2945
|
const reasoningEffort = cloned.reasoningEffort;
|
|
2946
|
+
const degradeReasoningEffort = cloned.degradeReasoningEffort === true;
|
|
2658
2947
|
const bedrockControls = cloned.bedrockControls;
|
|
2659
2948
|
const cachePolicy = cloned.cache;
|
|
2660
2949
|
const cloudflareRequest = cloned.cloudflare;
|
|
2661
2950
|
delete cloned.provider;
|
|
2662
2951
|
delete cloned.reasoningEffort;
|
|
2952
|
+
delete cloned.degradeReasoningEffort;
|
|
2663
2953
|
delete cloned.bedrockControls;
|
|
2664
2954
|
delete cloned.cache;
|
|
2665
2955
|
delete cloned.cloudflare;
|
|
@@ -2677,6 +2967,7 @@ function prepareDispatchRequest(params) {
|
|
|
2677
2967
|
const requestedModel = cloned.model ?? defaultModelFor(provider, params.options) ?? "";
|
|
2678
2968
|
const explicit = hasExplicitControl(provider, cloned, bedrockControls);
|
|
2679
2969
|
let directive;
|
|
2970
|
+
let sentEffort;
|
|
2680
2971
|
let catalogPrefix;
|
|
2681
2972
|
if (!explicit && reasoningEffort !== void 0) {
|
|
2682
2973
|
if (!requestedModel) {
|
|
@@ -2688,13 +2979,29 @@ function prepareDispatchRequest(params) {
|
|
|
2688
2979
|
if (provider === "cloudflare") {
|
|
2689
2980
|
const query = cloudflareCatalogQuery(requestedModel);
|
|
2690
2981
|
catalogPrefix = query.prefix;
|
|
2691
|
-
|
|
2982
|
+
const resolved2 = resolveEffortDirective({
|
|
2983
|
+
target: query.target,
|
|
2984
|
+
model: query.model,
|
|
2985
|
+
effort: reasoningEffort,
|
|
2986
|
+
ignoreUnknown: true,
|
|
2987
|
+
degrade: degradeReasoningEffort
|
|
2988
|
+
});
|
|
2989
|
+
directive = resolved2.directive;
|
|
2990
|
+
sentEffort = resolved2.sentEffort;
|
|
2692
2991
|
} else if (isReasoningTarget(provider)) {
|
|
2693
|
-
|
|
2992
|
+
const resolved2 = resolveEffortDirective({
|
|
2993
|
+
target: provider,
|
|
2994
|
+
model: requestedModel,
|
|
2995
|
+
effort: reasoningEffort,
|
|
2996
|
+
ignoreUnknown: false,
|
|
2997
|
+
degrade: degradeReasoningEffort
|
|
2998
|
+
});
|
|
2999
|
+
directive = resolved2.directive;
|
|
3000
|
+
sentEffort = resolved2.sentEffort;
|
|
2694
3001
|
}
|
|
2695
3002
|
}
|
|
2696
3003
|
if (provider === "openrouter") {
|
|
2697
|
-
applyNestedReasoning(cloned, reasoningEffort);
|
|
3004
|
+
applyNestedReasoning(cloned, reasoningEffort, degradeReasoningEffort);
|
|
2698
3005
|
}
|
|
2699
3006
|
if (directive?.model) {
|
|
2700
3007
|
cloned.model = provider === "cloudflare" ? restoreCloudflareModel(directive.model, catalogPrefix) : directive.model;
|
|
@@ -2728,7 +3035,7 @@ function prepareDispatchRequest(params) {
|
|
|
2728
3035
|
if (overlay || cacheTouchesBody) {
|
|
2729
3036
|
const bodyOverlay = overlay;
|
|
2730
3037
|
call.finalizeBody = (body) => {
|
|
2731
|
-
const merged = bodyOverlay ? (0,
|
|
3038
|
+
const merged = bodyOverlay ? (0, import_ai_profiles3.mergeReasoningBody)(body, bodyOverlay) : body;
|
|
2732
3039
|
if (!cacheTouchesBody || !cachePlan) return merged;
|
|
2733
3040
|
const applied = applyPromptCache(merged, cachePlan);
|
|
2734
3041
|
if (cachePlan.placeBreakpoint && !applied.placed) {
|
|
@@ -2755,6 +3062,7 @@ function prepareDispatchRequest(params) {
|
|
|
2755
3062
|
}
|
|
2756
3063
|
const resolution = reasoningEffort !== void 0 || explicit ? buildResolution({
|
|
2757
3064
|
requestedEffort: reasoningEffort,
|
|
3065
|
+
sentEffort: explicit ? explicitSentEffort(provider, cloned, bedrockControls) : sentEffort,
|
|
2758
3066
|
target: provider,
|
|
2759
3067
|
requestedModel,
|
|
2760
3068
|
effectiveModel,
|
|
@@ -2787,29 +3095,6 @@ function noteUnplacedCache(resolution, warnings, target, model) {
|
|
|
2787
3095
|
details: { target, model }
|
|
2788
3096
|
});
|
|
2789
3097
|
}
|
|
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
3098
|
function isReasoningTarget(provider) {
|
|
2814
3099
|
return provider === "openrouter" || provider === "bedrock" || provider === "openai";
|
|
2815
3100
|
}
|
|
@@ -2817,6 +3102,15 @@ function hasExplicitControl(provider, request, bedrockControls) {
|
|
|
2817
3102
|
if (provider === "bedrock") return bedrockControls?.additionalModelRequestFields !== void 0;
|
|
2818
3103
|
return request.reasoning !== void 0;
|
|
2819
3104
|
}
|
|
3105
|
+
function explicitSentEffort(provider, request, bedrockControls) {
|
|
3106
|
+
if (provider === "bedrock") {
|
|
3107
|
+
const output = bedrockControls?.additionalModelRequestFields?.output_config;
|
|
3108
|
+
if (isRecord8(output) && typeof output.effort === "string") return output.effort;
|
|
3109
|
+
return void 0;
|
|
3110
|
+
}
|
|
3111
|
+
if (isRecord8(request.reasoning) && typeof request.reasoning.effort === "string") return request.reasoning.effort;
|
|
3112
|
+
return void 0;
|
|
3113
|
+
}
|
|
2820
3114
|
function buildResolution(params) {
|
|
2821
3115
|
return {
|
|
2822
3116
|
target: params.target,
|
|
@@ -2824,19 +3118,20 @@ function buildResolution(params) {
|
|
|
2824
3118
|
effectiveModel: params.effectiveModel,
|
|
2825
3119
|
bypassed: params.bypassed,
|
|
2826
3120
|
...params.requestedEffort ? { requestedEffort: params.requestedEffort } : {},
|
|
3121
|
+
...params.sentEffort ? { sentEffort: params.sentEffort } : {},
|
|
2827
3122
|
...params.outcome ? { outcome: params.outcome } : {}
|
|
2828
3123
|
};
|
|
2829
3124
|
}
|
|
2830
|
-
function applyNestedReasoning(request, parentEffort) {
|
|
3125
|
+
function applyNestedReasoning(request, parentEffort, degrade) {
|
|
2831
3126
|
const serverTools = request.serverTools;
|
|
2832
3127
|
if (!serverTools) return;
|
|
2833
|
-
if (serverTools.fusion) serverTools.fusion = settleNested(serverTools.fusion, "fusion", parentEffort);
|
|
3128
|
+
if (serverTools.fusion) serverTools.fusion = settleNested(serverTools.fusion, "fusion", parentEffort, degrade);
|
|
2834
3129
|
if (serverTools.advisor) {
|
|
2835
|
-
serverTools.advisor = Array.isArray(serverTools.advisor) ? serverTools.advisor.map((advisor) => settleNested(advisor, "advisor", parentEffort)) : settleNested(serverTools.advisor, "advisor", parentEffort);
|
|
3130
|
+
serverTools.advisor = Array.isArray(serverTools.advisor) ? serverTools.advisor.map((advisor) => settleNested(advisor, "advisor", parentEffort, degrade)) : settleNested(serverTools.advisor, "advisor", parentEffort, degrade);
|
|
2836
3131
|
}
|
|
2837
|
-
if (serverTools.subagent) serverTools.subagent = settleNested(serverTools.subagent, "subagent", parentEffort);
|
|
3132
|
+
if (serverTools.subagent) serverTools.subagent = settleNested(serverTools.subagent, "subagent", parentEffort, degrade);
|
|
2838
3133
|
}
|
|
2839
|
-
function settleNested(policy, kind, parentEffort) {
|
|
3134
|
+
function settleNested(policy, kind, parentEffort, degrade) {
|
|
2840
3135
|
const current = policy;
|
|
2841
3136
|
const childEffort = current.reasoningEffort;
|
|
2842
3137
|
const next = { ...current };
|
|
@@ -2846,12 +3141,18 @@ function settleNested(policy, kind, parentEffort) {
|
|
|
2846
3141
|
if (!effort) return next;
|
|
2847
3142
|
const model = kind === "fusion" ? next.judgeModel : next.model;
|
|
2848
3143
|
if (!model) return next;
|
|
2849
|
-
const directive =
|
|
3144
|
+
const directive = resolveEffortDirective({
|
|
3145
|
+
target: "openrouter",
|
|
3146
|
+
model,
|
|
3147
|
+
effort,
|
|
3148
|
+
ignoreUnknown: false,
|
|
3149
|
+
degrade
|
|
3150
|
+
}).directive;
|
|
2850
3151
|
if (directive.model) {
|
|
2851
3152
|
if (kind === "fusion") next.judgeModel = directive.model;
|
|
2852
3153
|
else next.model = directive.model;
|
|
2853
3154
|
}
|
|
2854
|
-
if (
|
|
3155
|
+
if (isRecord8(directive.body.reasoning)) next.reasoning = directive.body.reasoning;
|
|
2855
3156
|
return next;
|
|
2856
3157
|
}
|
|
2857
3158
|
function applyPromptPrefix(request, prefix) {
|
|
@@ -2888,10 +3189,10 @@ function prefixMessages(messages, prefix) {
|
|
|
2888
3189
|
return false;
|
|
2889
3190
|
}
|
|
2890
3191
|
function prefixInputItems(items, prefix) {
|
|
2891
|
-
for (let
|
|
2892
|
-
const item = items[
|
|
3192
|
+
for (let index2 = 0; index2 < items.length; index2 += 1) {
|
|
3193
|
+
const item = items[index2];
|
|
2893
3194
|
if (typeof item === "string") {
|
|
2894
|
-
items[
|
|
3195
|
+
items[index2] = prefix + item;
|
|
2895
3196
|
return true;
|
|
2896
3197
|
}
|
|
2897
3198
|
if (!item || item.role === "system") continue;
|
|
@@ -2901,7 +3202,7 @@ function prefixInputItems(items, prefix) {
|
|
|
2901
3202
|
}
|
|
2902
3203
|
if (!Array.isArray(item.content)) continue;
|
|
2903
3204
|
for (const part of item.content) {
|
|
2904
|
-
if (!
|
|
3205
|
+
if (!isRecord8(part) || typeof part.text !== "string") continue;
|
|
2905
3206
|
if (part.type === "text" || part.type === "input_text") {
|
|
2906
3207
|
part.text = prefix + part.text;
|
|
2907
3208
|
return true;
|
|
@@ -2962,7 +3263,7 @@ var ROLE_STAMP_FIELDS = ["role", "roleLayer", "roleDigest", "profileChoice"];
|
|
|
2962
3263
|
function applyRoleStamp(request) {
|
|
2963
3264
|
const stamp = request.role;
|
|
2964
3265
|
delete request.role;
|
|
2965
|
-
if (!
|
|
3266
|
+
if (!isRecord8(stamp)) return;
|
|
2966
3267
|
const identity = {};
|
|
2967
3268
|
for (const field of ROLE_STAMP_FIELDS) {
|
|
2968
3269
|
const value = stamp[field];
|
|
@@ -2977,8 +3278,8 @@ function applyRoleStamp(request) {
|
|
|
2977
3278
|
}
|
|
2978
3279
|
function absorbOverrideMetadata(request) {
|
|
2979
3280
|
const overrides = request.rawOpenRouterOverrides;
|
|
2980
|
-
if (!
|
|
2981
|
-
if (
|
|
3281
|
+
if (!isRecord8(overrides) || !Object.prototype.hasOwnProperty.call(overrides, "metadata")) return;
|
|
3282
|
+
if (isRecord8(overrides.metadata)) {
|
|
2982
3283
|
const current = { ...request.metadata ?? {} };
|
|
2983
3284
|
const extra = {};
|
|
2984
3285
|
for (const [key, value] of Object.entries(overrides.metadata)) {
|
|
@@ -3023,7 +3324,7 @@ function hasOwnKeys(value) {
|
|
|
3023
3324
|
function hasStreamMetadata(directive) {
|
|
3024
3325
|
return directive.response.streamReasoningKeys.length > 0 || directive.response.streamReasoningPaths.length > 0;
|
|
3025
3326
|
}
|
|
3026
|
-
function
|
|
3327
|
+
function isRecord8(value) {
|
|
3027
3328
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3028
3329
|
}
|
|
3029
3330
|
function readEnv2(name) {
|
|
@@ -3170,22 +3471,22 @@ var import_openrouter_runtime2 = require("@x12i/openrouter-runtime");
|
|
|
3170
3471
|
var DEFAULT_BASE_URL2 = "https://api.openai.com/v1";
|
|
3171
3472
|
var DEFAULT_TIMEOUT_MS2 = 12e4;
|
|
3172
3473
|
function createOpenAiProviderAdapter(options = {}, packer) {
|
|
3173
|
-
const
|
|
3474
|
+
const resolved2 = resolveOpenAiOptions(options, packer);
|
|
3174
3475
|
return {
|
|
3175
3476
|
compile(request, call) {
|
|
3176
|
-
return compileOpenAiRequest(request,
|
|
3477
|
+
return compileOpenAiRequest(request, resolved2, call, false);
|
|
3177
3478
|
},
|
|
3178
3479
|
async run(request, call) {
|
|
3179
3480
|
const requestId = request.id ?? "openai";
|
|
3180
3481
|
try {
|
|
3181
|
-
return await runOpenAi(request,
|
|
3482
|
+
return await runOpenAi(request, resolved2, call, requestId);
|
|
3182
3483
|
} catch (error) {
|
|
3183
3484
|
if (error instanceof AiDispatcherError && isConfigError2(error.code)) throw error;
|
|
3184
3485
|
return failedResponse2(request, requestId, error);
|
|
3185
3486
|
}
|
|
3186
3487
|
},
|
|
3187
3488
|
executeStreamingChat(request, call) {
|
|
3188
|
-
return streamOpenAi(request,
|
|
3489
|
+
return streamOpenAi(request, resolved2, call);
|
|
3189
3490
|
}
|
|
3190
3491
|
};
|
|
3191
3492
|
}
|
|
@@ -3342,7 +3643,7 @@ async function runOpenAi(request, options, call, requestId) {
|
|
|
3342
3643
|
let response;
|
|
3343
3644
|
for (let iteration = 0; iteration <= maxIterations; iteration += 1) {
|
|
3344
3645
|
response = await sendWithRetries2(active, options, timeoutFor2(request, options));
|
|
3345
|
-
const calls = functionCalls(
|
|
3646
|
+
const calls = functionCalls(isRecord9(response) ? response : {});
|
|
3346
3647
|
if (!calls.length) break;
|
|
3347
3648
|
if (!calls.every((item) => resolveExecutor2(item.name, request, options))) {
|
|
3348
3649
|
return normalizeOpenAiResponse({
|
|
@@ -3362,7 +3663,7 @@ async function runOpenAi(request, options, call, requestId) {
|
|
|
3362
3663
|
results.push(await executeOpenAiTool(item, request, options));
|
|
3363
3664
|
}
|
|
3364
3665
|
functionUsage.push(...results);
|
|
3365
|
-
const record2 =
|
|
3666
|
+
const record2 = isRecord9(response) ? response : {};
|
|
3366
3667
|
active = {
|
|
3367
3668
|
...active,
|
|
3368
3669
|
body: clean2({
|
|
@@ -3477,7 +3778,7 @@ async function* streamOpenAi(request, options, call) {
|
|
|
3477
3778
|
throw failure;
|
|
3478
3779
|
}
|
|
3479
3780
|
for await (const event of parseSse2(response)) {
|
|
3480
|
-
if (!
|
|
3781
|
+
if (!isRecord9(event)) continue;
|
|
3481
3782
|
if (event.type === "response.output_text.delta" && typeof event.delta === "string" && event.delta) {
|
|
3482
3783
|
text += event.delta;
|
|
3483
3784
|
yield { type: "stream.text.delta", requestId, data: { text: event.delta } };
|
|
@@ -3496,7 +3797,7 @@ async function* streamOpenAi(request, options, call) {
|
|
|
3496
3797
|
argumentsDelta: event.delta
|
|
3497
3798
|
}
|
|
3498
3799
|
};
|
|
3499
|
-
} else if (event.type === "response.completed" &&
|
|
3800
|
+
} else if (event.type === "response.completed" && isRecord9(event.response)) {
|
|
3500
3801
|
const usage = normalizeUsage2(event.response.usage);
|
|
3501
3802
|
if (usage) yield { type: "stream.usage", requestId, data: { usage } };
|
|
3502
3803
|
} else if (event.type === "error") {
|
|
@@ -3590,7 +3891,7 @@ function isConfigError2(code) {
|
|
|
3590
3891
|
}
|
|
3591
3892
|
function asTerminalError2(error) {
|
|
3592
3893
|
if (error instanceof AiDispatcherError && error.code === "PROVIDER_RETRYABLE") {
|
|
3593
|
-
const status =
|
|
3894
|
+
const status = isRecord9(error.details) ? error.details.status : void 0;
|
|
3594
3895
|
if (status === 429) return new AiDispatcherError("PROVIDER_RATE_LIMITED", error.message, error.details);
|
|
3595
3896
|
return new AiDispatcherError("PROVIDER_GATEWAY_UNREACHABLE", error.message, error.details);
|
|
3596
3897
|
}
|
|
@@ -3598,7 +3899,7 @@ function asTerminalError2(error) {
|
|
|
3598
3899
|
return new AiDispatcherError("PROVIDER_REQUEST_FAILED", error instanceof Error ? error.message : String(error));
|
|
3599
3900
|
}
|
|
3600
3901
|
function normalizeOpenAiResponse(params) {
|
|
3601
|
-
const record2 =
|
|
3902
|
+
const record2 = isRecord9(params.response) ? params.response : {};
|
|
3602
3903
|
const text = answerText2(record2);
|
|
3603
3904
|
const calls = params.functionTools ?? functionCalls(record2);
|
|
3604
3905
|
const usage = normalizeUsage2(record2.usage);
|
|
@@ -3625,9 +3926,9 @@ function answerText2(response) {
|
|
|
3625
3926
|
if (Array.isArray(output)) {
|
|
3626
3927
|
const parts = [];
|
|
3627
3928
|
for (const item of output) {
|
|
3628
|
-
if (!
|
|
3929
|
+
if (!isRecord9(item) || item.type === "reasoning" || item.type !== "message" || !Array.isArray(item.content)) continue;
|
|
3629
3930
|
for (const part of item.content) {
|
|
3630
|
-
if (
|
|
3931
|
+
if (isRecord9(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
|
|
3631
3932
|
}
|
|
3632
3933
|
}
|
|
3633
3934
|
if (parts.length > 0) return parts.join("");
|
|
@@ -3638,7 +3939,7 @@ function functionCalls(response) {
|
|
|
3638
3939
|
if (!Array.isArray(response.output)) return [];
|
|
3639
3940
|
const calls = [];
|
|
3640
3941
|
for (const item of response.output) {
|
|
3641
|
-
if (!
|
|
3942
|
+
if (!isRecord9(item) || item.type !== "function_call") continue;
|
|
3642
3943
|
const name = typeof item.name === "string" ? item.name : "function";
|
|
3643
3944
|
const callId = typeof item.call_id === "string" ? item.call_id : name;
|
|
3644
3945
|
let args = item.arguments;
|
|
@@ -3670,7 +3971,7 @@ function toolUsage(calls) {
|
|
|
3670
3971
|
};
|
|
3671
3972
|
}
|
|
3672
3973
|
function normalizeUsage2(usage) {
|
|
3673
|
-
if (!
|
|
3974
|
+
if (!isRecord9(usage)) return void 0;
|
|
3674
3975
|
const inputTokens = numberValue2(usage.input_tokens);
|
|
3675
3976
|
const outputTokens = numberValue2(usage.output_tokens);
|
|
3676
3977
|
const totalTokens = numberValue2(usage.total_tokens) ?? (inputTokens !== void 0 || outputTokens !== void 0 ? (inputTokens ?? 0) + (outputTokens ?? 0) : void 0);
|
|
@@ -3722,16 +4023,16 @@ function modelOf2(compiled) {
|
|
|
3722
4023
|
return typeof compiled.body.model === "string" ? compiled.body.model : "";
|
|
3723
4024
|
}
|
|
3724
4025
|
function messageFrom2(body) {
|
|
3725
|
-
if (!
|
|
4026
|
+
if (!isRecord9(body)) return void 0;
|
|
3726
4027
|
if (typeof body.message === "string") return body.message;
|
|
3727
|
-
if (
|
|
4028
|
+
if (isRecord9(body.error) && typeof body.error.message === "string") return body.error.message;
|
|
3728
4029
|
return void 0;
|
|
3729
4030
|
}
|
|
3730
4031
|
function numberValue2(value) {
|
|
3731
4032
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3732
4033
|
}
|
|
3733
4034
|
function attachProviderMetadata(body, request, packer) {
|
|
3734
|
-
const fromBody =
|
|
4035
|
+
const fromBody = isRecord9(body.metadata) ? body.metadata : void 0;
|
|
3735
4036
|
const packed = (0, import_openrouter_runtime2.packProviderRecord)(request.metadata, request.agentId, fromBody, packer);
|
|
3736
4037
|
if (packed.wire) return { body: { ...body, metadata: packed.wire }, ...packed.warning ? { warning: packed.warning } : {} };
|
|
3737
4038
|
if (body.metadata === void 0) return { body, ...packed.warning ? { warning: packed.warning } : {} };
|
|
@@ -3805,7 +4106,7 @@ function readEnv3(name) {
|
|
|
3805
4106
|
if (typeof process === "undefined") return void 0;
|
|
3806
4107
|
return process.env[name];
|
|
3807
4108
|
}
|
|
3808
|
-
function
|
|
4109
|
+
function isRecord9(value) {
|
|
3809
4110
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3810
4111
|
}
|
|
3811
4112
|
|
|
@@ -3987,7 +4288,7 @@ function callOf(call) {
|
|
|
3987
4288
|
}
|
|
3988
4289
|
function attachCompileMeta(prepared, compiled) {
|
|
3989
4290
|
const record2 = compiled;
|
|
3990
|
-
const headers =
|
|
4291
|
+
const headers = isRecord10(record2.headers) ? redactHeaders(record2.headers) : void 0;
|
|
3991
4292
|
const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
|
|
3992
4293
|
return {
|
|
3993
4294
|
...record2,
|
|
@@ -4023,7 +4324,7 @@ function log(options, event, prepared, entrypoint, streaming) {
|
|
|
4023
4324
|
if (event.endsWith("compiled")) options.logger?.debug?.(event, payload);
|
|
4024
4325
|
else options.logger?.info?.(event, payload);
|
|
4025
4326
|
}
|
|
4026
|
-
function
|
|
4327
|
+
function isRecord10(value) {
|
|
4027
4328
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4028
4329
|
}
|
|
4029
4330
|
|