@x12i/ai-dispatcher 3.1.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 +36 -17
- package/dist/index.cjs +408 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -4
- package/dist/index.d.ts +21 -4
- package/dist/index.js +407 -105
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -41,12 +41,13 @@ __export(index_exports, {
|
|
|
41
41
|
isImplementedAiProvider: () => isImplementedAiProvider,
|
|
42
42
|
normalizeMetadata: () => import_openrouter_runtime4.normalizeMetadata,
|
|
43
43
|
providerNotImplemented: () => providerNotImplemented,
|
|
44
|
-
registerHostIntents: () =>
|
|
44
|
+
registerHostIntents: () => import_ai_profiles4.registerHostIntents,
|
|
45
|
+
resolveAIProfile: () => import_ai_profiles4.resolveAIProfile,
|
|
45
46
|
resolveProvider: () => resolveProvider,
|
|
46
47
|
stripReasoningHistoryFields: () => stripReasoningHistoryFields
|
|
47
48
|
});
|
|
48
49
|
module.exports = __toCommonJS(index_exports);
|
|
49
|
-
var
|
|
50
|
+
var import_ai_profiles4 = require("@x12i/ai-profiles");
|
|
50
51
|
var import_openrouter_runtime4 = require("@x12i/openrouter-runtime");
|
|
51
52
|
|
|
52
53
|
// src/create-dispatcher.ts
|
|
@@ -161,7 +162,7 @@ async function openTrack(settings, model) {
|
|
|
161
162
|
try {
|
|
162
163
|
tokenCounter = await loadTokenizer(tokenizer);
|
|
163
164
|
const framing = framingFor(settings);
|
|
164
|
-
const
|
|
165
|
+
const resolved2 = (0, import_core.resolveSettings)({
|
|
165
166
|
files: [],
|
|
166
167
|
env: {},
|
|
167
168
|
factory: {
|
|
@@ -176,8 +177,8 @@ async function openTrack(settings, model) {
|
|
|
176
177
|
});
|
|
177
178
|
const approvals = settings.approvals;
|
|
178
179
|
const client = (0, import_core.createCoreClient)({
|
|
179
|
-
config:
|
|
180
|
-
explanation:
|
|
180
|
+
config: resolved2.config,
|
|
181
|
+
explanation: resolved2.explanation,
|
|
181
182
|
...approvals && approvals.length > 0 ? { policy: { approvals: [...approvals] } } : {},
|
|
182
183
|
...tokenCounter ? { tokenCounter } : {},
|
|
183
184
|
warn: () => void 0
|
|
@@ -231,10 +232,10 @@ async function encodeRequestText(request, track) {
|
|
|
231
232
|
if (typeof request.input === "string") {
|
|
232
233
|
request.input = await encodeString(track, request.input);
|
|
233
234
|
} else if (Array.isArray(request.input)) {
|
|
234
|
-
for (let
|
|
235
|
-
const item = request.input[
|
|
235
|
+
for (let index2 = 0; index2 < request.input.length; index2 += 1) {
|
|
236
|
+
const item = request.input[index2];
|
|
236
237
|
if (typeof item === "string") {
|
|
237
|
-
request.input[
|
|
238
|
+
request.input[index2] = await encodeString(track, item);
|
|
238
239
|
} else if (item) {
|
|
239
240
|
await encodeContentRecord(item, track);
|
|
240
241
|
}
|
|
@@ -431,9 +432,9 @@ function walk(current, tokens) {
|
|
|
431
432
|
}
|
|
432
433
|
if (Array.isArray(current)) {
|
|
433
434
|
if (!/^\d+$/.test(head)) return [];
|
|
434
|
-
const
|
|
435
|
-
if (
|
|
436
|
-
return walk(current[
|
|
435
|
+
const index2 = Number(head);
|
|
436
|
+
if (index2 >= current.length) return [];
|
|
437
|
+
return walk(current[index2], rest);
|
|
437
438
|
}
|
|
438
439
|
if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
|
|
439
440
|
return walk(current[head], rest);
|
|
@@ -468,9 +469,9 @@ function collectParents(current, tokens) {
|
|
|
468
469
|
}
|
|
469
470
|
if (Array.isArray(current)) {
|
|
470
471
|
if (!/^\d+$/.test(head)) return [];
|
|
471
|
-
const
|
|
472
|
-
if (
|
|
473
|
-
return collectParents(current[
|
|
472
|
+
const index2 = Number(head);
|
|
473
|
+
if (index2 >= current.length) return [];
|
|
474
|
+
return collectParents(current[index2], rest);
|
|
474
475
|
}
|
|
475
476
|
if (!isRecord2(current) || !Object.prototype.hasOwnProperty.call(current, head)) return [];
|
|
476
477
|
return collectParents(current[head], rest);
|
|
@@ -484,8 +485,8 @@ function deletePointer(root, pointer) {
|
|
|
484
485
|
for (const parent of parents) {
|
|
485
486
|
if (Array.isArray(parent)) {
|
|
486
487
|
if (!/^\d+$/.test(last)) continue;
|
|
487
|
-
const
|
|
488
|
-
if (
|
|
488
|
+
const index2 = Number(last);
|
|
489
|
+
if (index2 < parent.length) parent.splice(index2, 1);
|
|
489
490
|
continue;
|
|
490
491
|
}
|
|
491
492
|
if (isRecord2(parent) && Object.prototype.hasOwnProperty.call(parent, last)) {
|
|
@@ -517,6 +518,38 @@ function extractStreamReasoningText(event, response) {
|
|
|
517
518
|
}
|
|
518
519
|
return firstConcatenatedText(event, response.streamReasoningPaths);
|
|
519
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
|
+
}
|
|
520
553
|
function readReasoningTokens(root, paths) {
|
|
521
554
|
for (const path of paths) {
|
|
522
555
|
const absolute = firstNumber(root, [path]);
|
|
@@ -601,7 +634,10 @@ function splitThinkTags(text) {
|
|
|
601
634
|
// src/apply-resolution.ts
|
|
602
635
|
function applyResolution(response, prepared) {
|
|
603
636
|
const result = response;
|
|
604
|
-
if (prepared.resolution)
|
|
637
|
+
if (prepared.resolution) {
|
|
638
|
+
const reportedEffort = readReportedEffort(response.raw?.response);
|
|
639
|
+
result.reasoningResolution = reportedEffort ? { ...prepared.resolution, reportedEffort } : prepared.resolution;
|
|
640
|
+
}
|
|
605
641
|
if (prepared.cacheResolution) result.cacheResolution = prepared.cacheResolution;
|
|
606
642
|
if (prepared.cacheWarnings?.length) {
|
|
607
643
|
result.warnings = [...result.warnings, ...prepared.cacheWarnings];
|
|
@@ -983,7 +1019,7 @@ function isRecord5(value) {
|
|
|
983
1019
|
}
|
|
984
1020
|
|
|
985
1021
|
// src/prepare-request.ts
|
|
986
|
-
var
|
|
1022
|
+
var import_ai_profiles3 = require("@x12i/ai-profiles");
|
|
987
1023
|
|
|
988
1024
|
// src/cache-apply.ts
|
|
989
1025
|
var BREAKPOINT = { mode: "explicit" };
|
|
@@ -1066,38 +1102,38 @@ function placeBedrockBreakpoint(body, ttl) {
|
|
|
1066
1102
|
function markMessages(body, field, markerKey, markerValue, textType) {
|
|
1067
1103
|
const messages = body[field];
|
|
1068
1104
|
if (!Array.isArray(messages)) return { body, placed: false };
|
|
1069
|
-
const
|
|
1070
|
-
if (
|
|
1071
|
-
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);
|
|
1072
1108
|
if (!marked) return { body, placed: false };
|
|
1073
1109
|
const next = messages.slice();
|
|
1074
|
-
next[
|
|
1110
|
+
next[index2] = marked;
|
|
1075
1111
|
return { placed: true, body: { ...body, [field]: next } };
|
|
1076
1112
|
}
|
|
1077
1113
|
function markInput(body, markerKey, markerValue, textType) {
|
|
1078
1114
|
if (!Array.isArray(body.input)) return { body, placed: false };
|
|
1079
|
-
const
|
|
1080
|
-
if (
|
|
1081
|
-
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);
|
|
1082
1118
|
if (!marked) return { body, placed: false };
|
|
1083
1119
|
const next = body.input.slice();
|
|
1084
|
-
next[
|
|
1120
|
+
next[index2] = marked;
|
|
1085
1121
|
return { placed: true, body: { ...body, input: next } };
|
|
1086
1122
|
}
|
|
1087
1123
|
function stableMessageIndex(messages) {
|
|
1088
1124
|
let lastSystem = -1;
|
|
1089
|
-
for (let
|
|
1090
|
-
const message = messages[
|
|
1091
|
-
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;
|
|
1092
1128
|
}
|
|
1093
1129
|
return lastSystem;
|
|
1094
1130
|
}
|
|
1095
1131
|
function stableInputIndex(items) {
|
|
1096
1132
|
let lastStable = -1;
|
|
1097
|
-
for (let
|
|
1098
|
-
const item = items[
|
|
1133
|
+
for (let index2 = 0; index2 < items.length; index2 += 1) {
|
|
1134
|
+
const item = items[index2];
|
|
1099
1135
|
if (!isPlainRecord(item) || !hasText(item.content)) continue;
|
|
1100
|
-
if (item.role === "system" || item.role === "developer") lastStable =
|
|
1136
|
+
if (item.role === "system" || item.role === "developer") lastStable = index2;
|
|
1101
1137
|
}
|
|
1102
1138
|
return lastStable;
|
|
1103
1139
|
}
|
|
@@ -1114,10 +1150,10 @@ function markContent(content, markerKey, markerValue, textType) {
|
|
|
1114
1150
|
}
|
|
1115
1151
|
if (!Array.isArray(content)) return void 0;
|
|
1116
1152
|
const parts = content.map((part) => isPlainRecord(part) ? { ...part } : part);
|
|
1117
|
-
for (let
|
|
1118
|
-
const part = parts[
|
|
1153
|
+
for (let index2 = parts.length - 1; index2 >= 0; index2 -= 1) {
|
|
1154
|
+
const part = parts[index2];
|
|
1119
1155
|
if (!isPlainRecord(part) || typeof part.text !== "string" || !part.text.trim()) continue;
|
|
1120
|
-
parts[
|
|
1156
|
+
parts[index2] = { ...part, [markerKey]: markerValue };
|
|
1121
1157
|
return parts;
|
|
1122
1158
|
}
|
|
1123
1159
|
return void 0;
|
|
@@ -1273,11 +1309,11 @@ function resolveCloudflarePromptCache(args) {
|
|
|
1273
1309
|
warnings: []
|
|
1274
1310
|
};
|
|
1275
1311
|
}
|
|
1276
|
-
const
|
|
1277
|
-
const ttl =
|
|
1312
|
+
const resolved2 = applyProfile({ input, mode, key, requestedTtl, resolutionBase, model, profile });
|
|
1313
|
+
const ttl = resolved2.plan.ttl ?? requestedTtl;
|
|
1278
1314
|
return {
|
|
1279
|
-
...
|
|
1280
|
-
plan: { ...
|
|
1315
|
+
...resolved2,
|
|
1316
|
+
plan: { ...resolved2.plan, gateway: gatewayDirective(false, ttl, key) }
|
|
1281
1317
|
};
|
|
1282
1318
|
}
|
|
1283
1319
|
function applyProfile(args) {
|
|
@@ -1482,22 +1518,22 @@ function restoreCloudflareModel(model, prefix) {
|
|
|
1482
1518
|
return `${prefix}${model}`;
|
|
1483
1519
|
}
|
|
1484
1520
|
function createCloudflareProviderAdapter(options = {}, packer) {
|
|
1485
|
-
const
|
|
1521
|
+
const resolved2 = resolveCloudflareOptions(options, packer);
|
|
1486
1522
|
return {
|
|
1487
1523
|
compile(request, call) {
|
|
1488
|
-
return compileCloudflareRequest(request,
|
|
1524
|
+
return compileCloudflareRequest(request, resolved2, call, false);
|
|
1489
1525
|
},
|
|
1490
1526
|
async run(request, call) {
|
|
1491
1527
|
const requestId = request.id ?? "cloudflare";
|
|
1492
1528
|
try {
|
|
1493
|
-
return await runCloudflare(request,
|
|
1529
|
+
return await runCloudflare(request, resolved2, call, requestId);
|
|
1494
1530
|
} catch (error) {
|
|
1495
1531
|
if (error instanceof AiDispatcherError && isConfigError(error.code)) throw error;
|
|
1496
1532
|
return failedResponse(request, requestId, error, "chat");
|
|
1497
1533
|
}
|
|
1498
1534
|
},
|
|
1499
1535
|
executeStreamingChat(request, call) {
|
|
1500
|
-
return streamCloudflare(request,
|
|
1536
|
+
return streamCloudflare(request, resolved2, call);
|
|
1501
1537
|
}
|
|
1502
1538
|
};
|
|
1503
1539
|
}
|
|
@@ -2645,6 +2681,259 @@ function isRecord6(value) {
|
|
|
2645
2681
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2646
2682
|
}
|
|
2647
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
|
+
|
|
2648
2937
|
// src/prepare-request.ts
|
|
2649
2938
|
function prepareDispatchRequest(params) {
|
|
2650
2939
|
const cloned = cloneRequest(params.request);
|
|
@@ -2654,11 +2943,13 @@ function prepareDispatchRequest(params) {
|
|
|
2654
2943
|
applyDispatchGate(cloned);
|
|
2655
2944
|
const provider = params.provider;
|
|
2656
2945
|
const reasoningEffort = cloned.reasoningEffort;
|
|
2946
|
+
const degradeReasoningEffort = cloned.degradeReasoningEffort === true;
|
|
2657
2947
|
const bedrockControls = cloned.bedrockControls;
|
|
2658
2948
|
const cachePolicy = cloned.cache;
|
|
2659
2949
|
const cloudflareRequest = cloned.cloudflare;
|
|
2660
2950
|
delete cloned.provider;
|
|
2661
2951
|
delete cloned.reasoningEffort;
|
|
2952
|
+
delete cloned.degradeReasoningEffort;
|
|
2662
2953
|
delete cloned.bedrockControls;
|
|
2663
2954
|
delete cloned.cache;
|
|
2664
2955
|
delete cloned.cloudflare;
|
|
@@ -2676,6 +2967,7 @@ function prepareDispatchRequest(params) {
|
|
|
2676
2967
|
const requestedModel = cloned.model ?? defaultModelFor(provider, params.options) ?? "";
|
|
2677
2968
|
const explicit = hasExplicitControl(provider, cloned, bedrockControls);
|
|
2678
2969
|
let directive;
|
|
2970
|
+
let sentEffort;
|
|
2679
2971
|
let catalogPrefix;
|
|
2680
2972
|
if (!explicit && reasoningEffort !== void 0) {
|
|
2681
2973
|
if (!requestedModel) {
|
|
@@ -2687,13 +2979,29 @@ function prepareDispatchRequest(params) {
|
|
|
2687
2979
|
if (provider === "cloudflare") {
|
|
2688
2980
|
const query = cloudflareCatalogQuery(requestedModel);
|
|
2689
2981
|
catalogPrefix = query.prefix;
|
|
2690
|
-
|
|
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;
|
|
2691
2991
|
} else if (isReasoningTarget(provider)) {
|
|
2692
|
-
|
|
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;
|
|
2693
3001
|
}
|
|
2694
3002
|
}
|
|
2695
3003
|
if (provider === "openrouter") {
|
|
2696
|
-
applyNestedReasoning(cloned, reasoningEffort);
|
|
3004
|
+
applyNestedReasoning(cloned, reasoningEffort, degradeReasoningEffort);
|
|
2697
3005
|
}
|
|
2698
3006
|
if (directive?.model) {
|
|
2699
3007
|
cloned.model = provider === "cloudflare" ? restoreCloudflareModel(directive.model, catalogPrefix) : directive.model;
|
|
@@ -2727,7 +3035,7 @@ function prepareDispatchRequest(params) {
|
|
|
2727
3035
|
if (overlay || cacheTouchesBody) {
|
|
2728
3036
|
const bodyOverlay = overlay;
|
|
2729
3037
|
call.finalizeBody = (body) => {
|
|
2730
|
-
const merged = bodyOverlay ? (0,
|
|
3038
|
+
const merged = bodyOverlay ? (0, import_ai_profiles3.mergeReasoningBody)(body, bodyOverlay) : body;
|
|
2731
3039
|
if (!cacheTouchesBody || !cachePlan) return merged;
|
|
2732
3040
|
const applied = applyPromptCache(merged, cachePlan);
|
|
2733
3041
|
if (cachePlan.placeBreakpoint && !applied.placed) {
|
|
@@ -2754,6 +3062,7 @@ function prepareDispatchRequest(params) {
|
|
|
2754
3062
|
}
|
|
2755
3063
|
const resolution = reasoningEffort !== void 0 || explicit ? buildResolution({
|
|
2756
3064
|
requestedEffort: reasoningEffort,
|
|
3065
|
+
sentEffort: explicit ? explicitSentEffort(provider, cloned, bedrockControls) : sentEffort,
|
|
2757
3066
|
target: provider,
|
|
2758
3067
|
requestedModel,
|
|
2759
3068
|
effectiveModel,
|
|
@@ -2786,29 +3095,6 @@ function noteUnplacedCache(resolution, warnings, target, model) {
|
|
|
2786
3095
|
details: { target, model }
|
|
2787
3096
|
});
|
|
2788
3097
|
}
|
|
2789
|
-
function resolveCatalog(input, ignoreUnknown) {
|
|
2790
|
-
try {
|
|
2791
|
-
return (0, import_ai_profiles.resolveReasoning)(input);
|
|
2792
|
-
} catch (error) {
|
|
2793
|
-
if (error instanceof import_ai_profiles.AIProfilesError) {
|
|
2794
|
-
if (ignoreUnknown && (error.code === "UNKNOWN_MODEL" || error.code === "REASONING_MAPPING_MISSING")) {
|
|
2795
|
-
return {
|
|
2796
|
-
outcome: "ignored",
|
|
2797
|
-
body: {},
|
|
2798
|
-
response: {
|
|
2799
|
-
reasoningTextPaths: [],
|
|
2800
|
-
streamReasoningKeys: [],
|
|
2801
|
-
streamReasoningPaths: [],
|
|
2802
|
-
stripFromHistoryPaths: [],
|
|
2803
|
-
stripThinkTags: false
|
|
2804
|
-
}
|
|
2805
|
-
};
|
|
2806
|
-
}
|
|
2807
|
-
throw new AiDispatcherError(error.code, error.message, error.details);
|
|
2808
|
-
}
|
|
2809
|
-
throw error;
|
|
2810
|
-
}
|
|
2811
|
-
}
|
|
2812
3098
|
function isReasoningTarget(provider) {
|
|
2813
3099
|
return provider === "openrouter" || provider === "bedrock" || provider === "openai";
|
|
2814
3100
|
}
|
|
@@ -2816,6 +3102,15 @@ function hasExplicitControl(provider, request, bedrockControls) {
|
|
|
2816
3102
|
if (provider === "bedrock") return bedrockControls?.additionalModelRequestFields !== void 0;
|
|
2817
3103
|
return request.reasoning !== void 0;
|
|
2818
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
|
+
}
|
|
2819
3114
|
function buildResolution(params) {
|
|
2820
3115
|
return {
|
|
2821
3116
|
target: params.target,
|
|
@@ -2823,19 +3118,20 @@ function buildResolution(params) {
|
|
|
2823
3118
|
effectiveModel: params.effectiveModel,
|
|
2824
3119
|
bypassed: params.bypassed,
|
|
2825
3120
|
...params.requestedEffort ? { requestedEffort: params.requestedEffort } : {},
|
|
3121
|
+
...params.sentEffort ? { sentEffort: params.sentEffort } : {},
|
|
2826
3122
|
...params.outcome ? { outcome: params.outcome } : {}
|
|
2827
3123
|
};
|
|
2828
3124
|
}
|
|
2829
|
-
function applyNestedReasoning(request, parentEffort) {
|
|
3125
|
+
function applyNestedReasoning(request, parentEffort, degrade) {
|
|
2830
3126
|
const serverTools = request.serverTools;
|
|
2831
3127
|
if (!serverTools) return;
|
|
2832
|
-
if (serverTools.fusion) serverTools.fusion = settleNested(serverTools.fusion, "fusion", parentEffort);
|
|
3128
|
+
if (serverTools.fusion) serverTools.fusion = settleNested(serverTools.fusion, "fusion", parentEffort, degrade);
|
|
2833
3129
|
if (serverTools.advisor) {
|
|
2834
|
-
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);
|
|
2835
3131
|
}
|
|
2836
|
-
if (serverTools.subagent) serverTools.subagent = settleNested(serverTools.subagent, "subagent", parentEffort);
|
|
3132
|
+
if (serverTools.subagent) serverTools.subagent = settleNested(serverTools.subagent, "subagent", parentEffort, degrade);
|
|
2837
3133
|
}
|
|
2838
|
-
function settleNested(policy, kind, parentEffort) {
|
|
3134
|
+
function settleNested(policy, kind, parentEffort, degrade) {
|
|
2839
3135
|
const current = policy;
|
|
2840
3136
|
const childEffort = current.reasoningEffort;
|
|
2841
3137
|
const next = { ...current };
|
|
@@ -2845,12 +3141,18 @@ function settleNested(policy, kind, parentEffort) {
|
|
|
2845
3141
|
if (!effort) return next;
|
|
2846
3142
|
const model = kind === "fusion" ? next.judgeModel : next.model;
|
|
2847
3143
|
if (!model) return next;
|
|
2848
|
-
const directive =
|
|
3144
|
+
const directive = resolveEffortDirective({
|
|
3145
|
+
target: "openrouter",
|
|
3146
|
+
model,
|
|
3147
|
+
effort,
|
|
3148
|
+
ignoreUnknown: false,
|
|
3149
|
+
degrade
|
|
3150
|
+
}).directive;
|
|
2849
3151
|
if (directive.model) {
|
|
2850
3152
|
if (kind === "fusion") next.judgeModel = directive.model;
|
|
2851
3153
|
else next.model = directive.model;
|
|
2852
3154
|
}
|
|
2853
|
-
if (
|
|
3155
|
+
if (isRecord8(directive.body.reasoning)) next.reasoning = directive.body.reasoning;
|
|
2854
3156
|
return next;
|
|
2855
3157
|
}
|
|
2856
3158
|
function applyPromptPrefix(request, prefix) {
|
|
@@ -2887,10 +3189,10 @@ function prefixMessages(messages, prefix) {
|
|
|
2887
3189
|
return false;
|
|
2888
3190
|
}
|
|
2889
3191
|
function prefixInputItems(items, prefix) {
|
|
2890
|
-
for (let
|
|
2891
|
-
const item = items[
|
|
3192
|
+
for (let index2 = 0; index2 < items.length; index2 += 1) {
|
|
3193
|
+
const item = items[index2];
|
|
2892
3194
|
if (typeof item === "string") {
|
|
2893
|
-
items[
|
|
3195
|
+
items[index2] = prefix + item;
|
|
2894
3196
|
return true;
|
|
2895
3197
|
}
|
|
2896
3198
|
if (!item || item.role === "system") continue;
|
|
@@ -2900,7 +3202,7 @@ function prefixInputItems(items, prefix) {
|
|
|
2900
3202
|
}
|
|
2901
3203
|
if (!Array.isArray(item.content)) continue;
|
|
2902
3204
|
for (const part of item.content) {
|
|
2903
|
-
if (!
|
|
3205
|
+
if (!isRecord8(part) || typeof part.text !== "string") continue;
|
|
2904
3206
|
if (part.type === "text" || part.type === "input_text") {
|
|
2905
3207
|
part.text = prefix + part.text;
|
|
2906
3208
|
return true;
|
|
@@ -2961,7 +3263,7 @@ var ROLE_STAMP_FIELDS = ["role", "roleLayer", "roleDigest", "profileChoice"];
|
|
|
2961
3263
|
function applyRoleStamp(request) {
|
|
2962
3264
|
const stamp = request.role;
|
|
2963
3265
|
delete request.role;
|
|
2964
|
-
if (!
|
|
3266
|
+
if (!isRecord8(stamp)) return;
|
|
2965
3267
|
const identity = {};
|
|
2966
3268
|
for (const field of ROLE_STAMP_FIELDS) {
|
|
2967
3269
|
const value = stamp[field];
|
|
@@ -2976,8 +3278,8 @@ function applyRoleStamp(request) {
|
|
|
2976
3278
|
}
|
|
2977
3279
|
function absorbOverrideMetadata(request) {
|
|
2978
3280
|
const overrides = request.rawOpenRouterOverrides;
|
|
2979
|
-
if (!
|
|
2980
|
-
if (
|
|
3281
|
+
if (!isRecord8(overrides) || !Object.prototype.hasOwnProperty.call(overrides, "metadata")) return;
|
|
3282
|
+
if (isRecord8(overrides.metadata)) {
|
|
2981
3283
|
const current = { ...request.metadata ?? {} };
|
|
2982
3284
|
const extra = {};
|
|
2983
3285
|
for (const [key, value] of Object.entries(overrides.metadata)) {
|
|
@@ -3022,7 +3324,7 @@ function hasOwnKeys(value) {
|
|
|
3022
3324
|
function hasStreamMetadata(directive) {
|
|
3023
3325
|
return directive.response.streamReasoningKeys.length > 0 || directive.response.streamReasoningPaths.length > 0;
|
|
3024
3326
|
}
|
|
3025
|
-
function
|
|
3327
|
+
function isRecord8(value) {
|
|
3026
3328
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3027
3329
|
}
|
|
3028
3330
|
function readEnv2(name) {
|
|
@@ -3169,22 +3471,22 @@ var import_openrouter_runtime2 = require("@x12i/openrouter-runtime");
|
|
|
3169
3471
|
var DEFAULT_BASE_URL2 = "https://api.openai.com/v1";
|
|
3170
3472
|
var DEFAULT_TIMEOUT_MS2 = 12e4;
|
|
3171
3473
|
function createOpenAiProviderAdapter(options = {}, packer) {
|
|
3172
|
-
const
|
|
3474
|
+
const resolved2 = resolveOpenAiOptions(options, packer);
|
|
3173
3475
|
return {
|
|
3174
3476
|
compile(request, call) {
|
|
3175
|
-
return compileOpenAiRequest(request,
|
|
3477
|
+
return compileOpenAiRequest(request, resolved2, call, false);
|
|
3176
3478
|
},
|
|
3177
3479
|
async run(request, call) {
|
|
3178
3480
|
const requestId = request.id ?? "openai";
|
|
3179
3481
|
try {
|
|
3180
|
-
return await runOpenAi(request,
|
|
3482
|
+
return await runOpenAi(request, resolved2, call, requestId);
|
|
3181
3483
|
} catch (error) {
|
|
3182
3484
|
if (error instanceof AiDispatcherError && isConfigError2(error.code)) throw error;
|
|
3183
3485
|
return failedResponse2(request, requestId, error);
|
|
3184
3486
|
}
|
|
3185
3487
|
},
|
|
3186
3488
|
executeStreamingChat(request, call) {
|
|
3187
|
-
return streamOpenAi(request,
|
|
3489
|
+
return streamOpenAi(request, resolved2, call);
|
|
3188
3490
|
}
|
|
3189
3491
|
};
|
|
3190
3492
|
}
|
|
@@ -3341,7 +3643,7 @@ async function runOpenAi(request, options, call, requestId) {
|
|
|
3341
3643
|
let response;
|
|
3342
3644
|
for (let iteration = 0; iteration <= maxIterations; iteration += 1) {
|
|
3343
3645
|
response = await sendWithRetries2(active, options, timeoutFor2(request, options));
|
|
3344
|
-
const calls = functionCalls(
|
|
3646
|
+
const calls = functionCalls(isRecord9(response) ? response : {});
|
|
3345
3647
|
if (!calls.length) break;
|
|
3346
3648
|
if (!calls.every((item) => resolveExecutor2(item.name, request, options))) {
|
|
3347
3649
|
return normalizeOpenAiResponse({
|
|
@@ -3361,7 +3663,7 @@ async function runOpenAi(request, options, call, requestId) {
|
|
|
3361
3663
|
results.push(await executeOpenAiTool(item, request, options));
|
|
3362
3664
|
}
|
|
3363
3665
|
functionUsage.push(...results);
|
|
3364
|
-
const record2 =
|
|
3666
|
+
const record2 = isRecord9(response) ? response : {};
|
|
3365
3667
|
active = {
|
|
3366
3668
|
...active,
|
|
3367
3669
|
body: clean2({
|
|
@@ -3476,7 +3778,7 @@ async function* streamOpenAi(request, options, call) {
|
|
|
3476
3778
|
throw failure;
|
|
3477
3779
|
}
|
|
3478
3780
|
for await (const event of parseSse2(response)) {
|
|
3479
|
-
if (!
|
|
3781
|
+
if (!isRecord9(event)) continue;
|
|
3480
3782
|
if (event.type === "response.output_text.delta" && typeof event.delta === "string" && event.delta) {
|
|
3481
3783
|
text += event.delta;
|
|
3482
3784
|
yield { type: "stream.text.delta", requestId, data: { text: event.delta } };
|
|
@@ -3495,7 +3797,7 @@ async function* streamOpenAi(request, options, call) {
|
|
|
3495
3797
|
argumentsDelta: event.delta
|
|
3496
3798
|
}
|
|
3497
3799
|
};
|
|
3498
|
-
} else if (event.type === "response.completed" &&
|
|
3800
|
+
} else if (event.type === "response.completed" && isRecord9(event.response)) {
|
|
3499
3801
|
const usage = normalizeUsage2(event.response.usage);
|
|
3500
3802
|
if (usage) yield { type: "stream.usage", requestId, data: { usage } };
|
|
3501
3803
|
} else if (event.type === "error") {
|
|
@@ -3589,7 +3891,7 @@ function isConfigError2(code) {
|
|
|
3589
3891
|
}
|
|
3590
3892
|
function asTerminalError2(error) {
|
|
3591
3893
|
if (error instanceof AiDispatcherError && error.code === "PROVIDER_RETRYABLE") {
|
|
3592
|
-
const status =
|
|
3894
|
+
const status = isRecord9(error.details) ? error.details.status : void 0;
|
|
3593
3895
|
if (status === 429) return new AiDispatcherError("PROVIDER_RATE_LIMITED", error.message, error.details);
|
|
3594
3896
|
return new AiDispatcherError("PROVIDER_GATEWAY_UNREACHABLE", error.message, error.details);
|
|
3595
3897
|
}
|
|
@@ -3597,7 +3899,7 @@ function asTerminalError2(error) {
|
|
|
3597
3899
|
return new AiDispatcherError("PROVIDER_REQUEST_FAILED", error instanceof Error ? error.message : String(error));
|
|
3598
3900
|
}
|
|
3599
3901
|
function normalizeOpenAiResponse(params) {
|
|
3600
|
-
const record2 =
|
|
3902
|
+
const record2 = isRecord9(params.response) ? params.response : {};
|
|
3601
3903
|
const text = answerText2(record2);
|
|
3602
3904
|
const calls = params.functionTools ?? functionCalls(record2);
|
|
3603
3905
|
const usage = normalizeUsage2(record2.usage);
|
|
@@ -3624,9 +3926,9 @@ function answerText2(response) {
|
|
|
3624
3926
|
if (Array.isArray(output)) {
|
|
3625
3927
|
const parts = [];
|
|
3626
3928
|
for (const item of output) {
|
|
3627
|
-
if (!
|
|
3929
|
+
if (!isRecord9(item) || item.type === "reasoning" || item.type !== "message" || !Array.isArray(item.content)) continue;
|
|
3628
3930
|
for (const part of item.content) {
|
|
3629
|
-
if (
|
|
3931
|
+
if (isRecord9(part) && part.type === "output_text" && typeof part.text === "string") parts.push(part.text);
|
|
3630
3932
|
}
|
|
3631
3933
|
}
|
|
3632
3934
|
if (parts.length > 0) return parts.join("");
|
|
@@ -3637,7 +3939,7 @@ function functionCalls(response) {
|
|
|
3637
3939
|
if (!Array.isArray(response.output)) return [];
|
|
3638
3940
|
const calls = [];
|
|
3639
3941
|
for (const item of response.output) {
|
|
3640
|
-
if (!
|
|
3942
|
+
if (!isRecord9(item) || item.type !== "function_call") continue;
|
|
3641
3943
|
const name = typeof item.name === "string" ? item.name : "function";
|
|
3642
3944
|
const callId = typeof item.call_id === "string" ? item.call_id : name;
|
|
3643
3945
|
let args = item.arguments;
|
|
@@ -3669,7 +3971,7 @@ function toolUsage(calls) {
|
|
|
3669
3971
|
};
|
|
3670
3972
|
}
|
|
3671
3973
|
function normalizeUsage2(usage) {
|
|
3672
|
-
if (!
|
|
3974
|
+
if (!isRecord9(usage)) return void 0;
|
|
3673
3975
|
const inputTokens = numberValue2(usage.input_tokens);
|
|
3674
3976
|
const outputTokens = numberValue2(usage.output_tokens);
|
|
3675
3977
|
const totalTokens = numberValue2(usage.total_tokens) ?? (inputTokens !== void 0 || outputTokens !== void 0 ? (inputTokens ?? 0) + (outputTokens ?? 0) : void 0);
|
|
@@ -3721,16 +4023,16 @@ function modelOf2(compiled) {
|
|
|
3721
4023
|
return typeof compiled.body.model === "string" ? compiled.body.model : "";
|
|
3722
4024
|
}
|
|
3723
4025
|
function messageFrom2(body) {
|
|
3724
|
-
if (!
|
|
4026
|
+
if (!isRecord9(body)) return void 0;
|
|
3725
4027
|
if (typeof body.message === "string") return body.message;
|
|
3726
|
-
if (
|
|
4028
|
+
if (isRecord9(body.error) && typeof body.error.message === "string") return body.error.message;
|
|
3727
4029
|
return void 0;
|
|
3728
4030
|
}
|
|
3729
4031
|
function numberValue2(value) {
|
|
3730
4032
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3731
4033
|
}
|
|
3732
4034
|
function attachProviderMetadata(body, request, packer) {
|
|
3733
|
-
const fromBody =
|
|
4035
|
+
const fromBody = isRecord9(body.metadata) ? body.metadata : void 0;
|
|
3734
4036
|
const packed = (0, import_openrouter_runtime2.packProviderRecord)(request.metadata, request.agentId, fromBody, packer);
|
|
3735
4037
|
if (packed.wire) return { body: { ...body, metadata: packed.wire }, ...packed.warning ? { warning: packed.warning } : {} };
|
|
3736
4038
|
if (body.metadata === void 0) return { body, ...packed.warning ? { warning: packed.warning } : {} };
|
|
@@ -3804,7 +4106,7 @@ function readEnv3(name) {
|
|
|
3804
4106
|
if (typeof process === "undefined") return void 0;
|
|
3805
4107
|
return process.env[name];
|
|
3806
4108
|
}
|
|
3807
|
-
function
|
|
4109
|
+
function isRecord9(value) {
|
|
3808
4110
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3809
4111
|
}
|
|
3810
4112
|
|
|
@@ -3986,7 +4288,7 @@ function callOf(call) {
|
|
|
3986
4288
|
}
|
|
3987
4289
|
function attachCompileMeta(prepared, compiled) {
|
|
3988
4290
|
const record2 = compiled;
|
|
3989
|
-
const headers =
|
|
4291
|
+
const headers = isRecord10(record2.headers) ? redactHeaders(record2.headers) : void 0;
|
|
3990
4292
|
const inputResolution = prepared.inputTrack ? visibleInputResolution(prepared.inputTrack) : void 0;
|
|
3991
4293
|
return {
|
|
3992
4294
|
...record2,
|
|
@@ -4022,7 +4324,7 @@ function log(options, event, prepared, entrypoint, streaming) {
|
|
|
4022
4324
|
if (event.endsWith("compiled")) options.logger?.debug?.(event, payload);
|
|
4023
4325
|
else options.logger?.info?.(event, payload);
|
|
4024
4326
|
}
|
|
4025
|
-
function
|
|
4327
|
+
function isRecord10(value) {
|
|
4026
4328
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4027
4329
|
}
|
|
4028
4330
|
|
|
@@ -4046,6 +4348,7 @@ function stripReasoningHistoryFields(message, paths) {
|
|
|
4046
4348
|
normalizeMetadata,
|
|
4047
4349
|
providerNotImplemented,
|
|
4048
4350
|
registerHostIntents,
|
|
4351
|
+
resolveAIProfile,
|
|
4049
4352
|
resolveProvider,
|
|
4050
4353
|
stripReasoningHistoryFields
|
|
4051
4354
|
});
|