@codeproxy/core 0.1.8 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +267 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -48
- package/dist/index.d.ts +56 -48
- package/dist/index.js +267 -94
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1071,66 +1071,9 @@ __export(openai_exports, {
|
|
|
1071
1071
|
translateStream: () => translateStream2
|
|
1072
1072
|
});
|
|
1073
1073
|
|
|
1074
|
-
// src/translate/openai/toolSchema.ts
|
|
1075
|
-
function sanitizeJsonSchema(schema, depth = 0) {
|
|
1076
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema) || depth > 20) {
|
|
1077
|
-
return schema;
|
|
1078
|
-
}
|
|
1079
|
-
const src = schema;
|
|
1080
|
-
if ("$ref" in src) {
|
|
1081
|
-
return src.description ? { description: src.description } : {};
|
|
1082
|
-
}
|
|
1083
|
-
const out = {};
|
|
1084
|
-
for (const [key, val] of Object.entries(src)) {
|
|
1085
|
-
if (isDroppedSchemaKeyword(key)) {
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
if (key === "properties" && val && typeof val === "object" && !Array.isArray(val)) {
|
|
1089
|
-
const props = {};
|
|
1090
|
-
for (const [propName, propSchema] of Object.entries(val)) {
|
|
1091
|
-
props[propName] = sanitizeJsonSchema(propSchema, depth + 1);
|
|
1092
|
-
}
|
|
1093
|
-
out[key] = props;
|
|
1094
|
-
} else if (key === "additionalProperties") {
|
|
1095
|
-
if (typeof val !== "boolean") {
|
|
1096
|
-
out[key] = sanitizeJsonSchema(val, depth + 1);
|
|
1097
|
-
}
|
|
1098
|
-
} else if (key === "items") {
|
|
1099
|
-
out[key] = sanitizeJsonSchema(val, depth + 1);
|
|
1100
|
-
} else if (isSchemaCompositionKeyword(key) && Array.isArray(val)) {
|
|
1101
|
-
out[key] = val.map((schemaItem) => sanitizeJsonSchema(schemaItem, depth + 1));
|
|
1102
|
-
} else {
|
|
1103
|
-
out[key] = val;
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
return out;
|
|
1107
|
-
}
|
|
1108
|
-
function getValidFunctionNames(tools) {
|
|
1109
|
-
const names = /* @__PURE__ */ new Set();
|
|
1110
|
-
for (const tool of tools) {
|
|
1111
|
-
const maybeTool = tool;
|
|
1112
|
-
if (maybeTool.type === "function" && typeof maybeTool.function?.name === "string") {
|
|
1113
|
-
names.add(maybeTool.function.name);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
return names.size ? names : void 0;
|
|
1117
|
-
}
|
|
1118
|
-
function isDroppedSchemaKeyword(key) {
|
|
1119
|
-
return key === "$schema" || key === "$defs" || key === "definitions" || key === "$id" || key === "$anchor" || key === "$comment";
|
|
1120
|
-
}
|
|
1121
|
-
function isSchemaCompositionKeyword(key) {
|
|
1122
|
-
return key === "anyOf" || key === "oneOf" || key === "allOf" || key === "not";
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
1074
|
// src/translate/openai/translateRequest.ts
|
|
1126
1075
|
function translateRequest2(data, options = {}) {
|
|
1127
1076
|
const messages = [];
|
|
1128
|
-
const tools = mapTools2(data.tools ?? []);
|
|
1129
|
-
const validFunctionNames = getValidFunctionNames(tools);
|
|
1130
|
-
const context = {
|
|
1131
|
-
validFunctionNames,
|
|
1132
|
-
ignoredToolCallIds: /* @__PURE__ */ new Set()
|
|
1133
|
-
};
|
|
1134
1077
|
const systemContent = buildSystemContent(data.instructions);
|
|
1135
1078
|
if (systemContent) {
|
|
1136
1079
|
messages.push({ role: "system", content: systemContent });
|
|
@@ -1145,7 +1088,7 @@ function translateRequest2(data, options = {}) {
|
|
|
1145
1088
|
continue;
|
|
1146
1089
|
}
|
|
1147
1090
|
const rawItem = raw;
|
|
1148
|
-
processInputItem(rawItem, messages, options
|
|
1091
|
+
processInputItem(rawItem, messages, options);
|
|
1149
1092
|
}
|
|
1150
1093
|
const request = {
|
|
1151
1094
|
model: data.model,
|
|
@@ -1166,6 +1109,7 @@ function translateRequest2(data, options = {}) {
|
|
|
1166
1109
|
if (typeof maxTokens === "number") {
|
|
1167
1110
|
request.max_tokens = maxTokens;
|
|
1168
1111
|
}
|
|
1112
|
+
const tools = mapTools2(data.tools ?? []);
|
|
1169
1113
|
if (tools.length) {
|
|
1170
1114
|
request.tools = tools;
|
|
1171
1115
|
const toolChoice = mapToolChoice2(data.tool_choice);
|
|
@@ -1204,7 +1148,7 @@ function buildSystemContent(instructions) {
|
|
|
1204
1148
|
}
|
|
1205
1149
|
return out;
|
|
1206
1150
|
}
|
|
1207
|
-
function processInputItem(item, messages, options
|
|
1151
|
+
function processInputItem(item, messages, options) {
|
|
1208
1152
|
const itemType = String(item.type) || "message";
|
|
1209
1153
|
const getLastAssistant = () => {
|
|
1210
1154
|
const last = messages[messages.length - 1];
|
|
@@ -1341,15 +1285,15 @@ function processInputItem(item, messages, options, context) {
|
|
|
1341
1285
|
return;
|
|
1342
1286
|
}
|
|
1343
1287
|
if (itemType === "function_call" || itemType === "commandExecution" || itemType === "local_shell_call" || itemType === "fileChange" || itemType === "custom_tool_call" || itemType === "web_search_call") {
|
|
1344
|
-
processToolCall(item, messages, getLastAssistant, options.fallbackThoughtSignature
|
|
1288
|
+
processToolCall(item, messages, getLastAssistant, options.fallbackThoughtSignature);
|
|
1345
1289
|
return;
|
|
1346
1290
|
}
|
|
1347
1291
|
if (itemType === "function_call_output" || itemType === "commandExecutionOutput" || itemType === "fileChangeOutput" || itemType === "custom_tool_call_output") {
|
|
1348
|
-
processToolOutput(item, messages
|
|
1292
|
+
processToolOutput(item, messages);
|
|
1349
1293
|
return;
|
|
1350
1294
|
}
|
|
1351
1295
|
}
|
|
1352
|
-
function processToolCall(item, messages, getLastAssistant, fallbackThoughtSignature
|
|
1296
|
+
function processToolCall(item, messages, getLastAssistant, fallbackThoughtSignature) {
|
|
1353
1297
|
const callId = String(item.call_id ?? "") || String(item.id ?? "") || makeId("call");
|
|
1354
1298
|
let name = item.name === void 0 ? void 0 : String(item.name);
|
|
1355
1299
|
const itemType = item.type === void 0 ? void 0 : String(item.type);
|
|
@@ -1391,14 +1335,6 @@ function processToolCall(item, messages, getLastAssistant, fallbackThoughtSignat
|
|
|
1391
1335
|
if (!name) {
|
|
1392
1336
|
return;
|
|
1393
1337
|
}
|
|
1394
|
-
if (context?.validFunctionNames?.size && !context.validFunctionNames.has(name)) {
|
|
1395
|
-
context.ignoredToolCallIds.add(callId);
|
|
1396
|
-
const amsg2 = getLastAssistant();
|
|
1397
|
-
const note = `Unsupported tool call omitted: ${name}`;
|
|
1398
|
-
amsg2.content = typeof amsg2.content === "string" && amsg2.content ? `${amsg2.content}
|
|
1399
|
-
${note}` : note;
|
|
1400
|
-
return;
|
|
1401
|
-
}
|
|
1402
1338
|
const amsg = getLastAssistant();
|
|
1403
1339
|
if (!amsg.tool_calls) {
|
|
1404
1340
|
amsg.tool_calls = [];
|
|
@@ -1419,7 +1355,7 @@ ${note}` : note;
|
|
|
1419
1355
|
amsg.reasoning_content = (amsg.reasoning_content ?? "") + thought;
|
|
1420
1356
|
}
|
|
1421
1357
|
}
|
|
1422
|
-
function processToolOutput(item, messages
|
|
1358
|
+
function processToolOutput(item, messages) {
|
|
1423
1359
|
const callId = item.call_id === void 0 ? void 0 : String(item.call_id);
|
|
1424
1360
|
const outputRaw = item.output ?? item.content ?? item.stdout ?? "";
|
|
1425
1361
|
let content = "";
|
|
@@ -1446,15 +1382,6 @@ function processToolOutput(item, messages, context) {
|
|
|
1446
1382
|
if (!content && typeof item.stderr === "string" && item.stderr) {
|
|
1447
1383
|
content = `Error: ${item.stderr}`;
|
|
1448
1384
|
}
|
|
1449
|
-
if (callId && context?.ignoredToolCallIds.has(callId)) {
|
|
1450
|
-
if (content) {
|
|
1451
|
-
messages.push({
|
|
1452
|
-
role: "user",
|
|
1453
|
-
content: `Output for omitted unsupported tool call: ${content}`
|
|
1454
|
-
});
|
|
1455
|
-
}
|
|
1456
|
-
return;
|
|
1457
|
-
}
|
|
1458
1385
|
messages.push({
|
|
1459
1386
|
role: "tool",
|
|
1460
1387
|
tool_call_id: callId,
|
|
@@ -1474,8 +1401,7 @@ function mapTools2(tools) {
|
|
|
1474
1401
|
if (!name) {
|
|
1475
1402
|
continue;
|
|
1476
1403
|
}
|
|
1477
|
-
const
|
|
1478
|
-
const params = sanitizeJsonSchema(rawParams);
|
|
1404
|
+
const params = fn?.parameters ?? tool.parameters ?? { type: "object" };
|
|
1479
1405
|
out.push({
|
|
1480
1406
|
type: "function",
|
|
1481
1407
|
function: {
|
|
@@ -1486,6 +1412,32 @@ function mapTools2(tools) {
|
|
|
1486
1412
|
});
|
|
1487
1413
|
continue;
|
|
1488
1414
|
}
|
|
1415
|
+
if (tt === "namespace") {
|
|
1416
|
+
const ns = tool.name;
|
|
1417
|
+
const nested = tool.tools;
|
|
1418
|
+
if (ns && Array.isArray(nested)) {
|
|
1419
|
+
for (const sub of nested) {
|
|
1420
|
+
if (!sub || typeof sub !== "object" || sub.type !== "function") {
|
|
1421
|
+
continue;
|
|
1422
|
+
}
|
|
1423
|
+
const subName = sub.name;
|
|
1424
|
+
if (!subName) {
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
const params = sub.parameters ?? { type: "object" };
|
|
1428
|
+
out.push({
|
|
1429
|
+
type: "function",
|
|
1430
|
+
function: {
|
|
1431
|
+
name: `${ns}.${subName}`,
|
|
1432
|
+
description: sub.description ?? "",
|
|
1433
|
+
// eslint-disable-next-line no-restricted-syntax -- schema is Record<string,unknown> by OpenAPI convention
|
|
1434
|
+
parameters: params
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
continue;
|
|
1440
|
+
}
|
|
1489
1441
|
}
|
|
1490
1442
|
return out;
|
|
1491
1443
|
}
|
|
@@ -1564,6 +1516,36 @@ function repairToolMessageOrder(messages) {
|
|
|
1564
1516
|
|
|
1565
1517
|
// src/translate/openai/translateResponse.ts
|
|
1566
1518
|
var SHELL_TOOL_NAMES3 = /* @__PURE__ */ new Set(["shell", "container.exec", "shell_command"]);
|
|
1519
|
+
function buildShortNameToNamespace(tools) {
|
|
1520
|
+
const map = /* @__PURE__ */ new Map();
|
|
1521
|
+
for (const tool of tools) {
|
|
1522
|
+
if (!tool || typeof tool !== "object") {
|
|
1523
|
+
continue;
|
|
1524
|
+
}
|
|
1525
|
+
const entry = tool;
|
|
1526
|
+
const fn = entry.function;
|
|
1527
|
+
const flatName = typeof fn?.name === "string" ? fn.name : typeof entry.name === "string" ? entry.name : "";
|
|
1528
|
+
const dotIdx = flatName.indexOf(".");
|
|
1529
|
+
if (dotIdx !== -1) {
|
|
1530
|
+
map.set(flatName.slice(dotIdx + 1), flatName.slice(0, dotIdx));
|
|
1531
|
+
continue;
|
|
1532
|
+
}
|
|
1533
|
+
if (entry.type === "namespace" && typeof entry.name === "string" && Array.isArray(entry.tools)) {
|
|
1534
|
+
const ns = entry.name;
|
|
1535
|
+
for (const sub of entry.tools) {
|
|
1536
|
+
if (!sub || typeof sub !== "object") {
|
|
1537
|
+
continue;
|
|
1538
|
+
}
|
|
1539
|
+
const subEntry = sub;
|
|
1540
|
+
const subName = typeof subEntry.name === "string" ? subEntry.name : "";
|
|
1541
|
+
if (subName) {
|
|
1542
|
+
map.set(subName, ns);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return map;
|
|
1548
|
+
}
|
|
1567
1549
|
function translateResponse2(body, options = {}) {
|
|
1568
1550
|
const createdAt = options.createdAt ?? body.created ?? Math.floor(Date.now() / 1e3);
|
|
1569
1551
|
const id = options.responseId ?? body.id ?? makeId("resp");
|
|
@@ -1571,9 +1553,10 @@ function translateResponse2(body, options = {}) {
|
|
|
1571
1553
|
const choice = body.choices?.[0];
|
|
1572
1554
|
const message = choice?.message;
|
|
1573
1555
|
const output = [];
|
|
1556
|
+
const shortNameToNs = buildShortNameToNamespace(options.requestTools ?? []);
|
|
1574
1557
|
if (message?.tool_calls?.length) {
|
|
1575
1558
|
for (const tc of message.tool_calls) {
|
|
1576
|
-
const item = mapToolCallToOutput(tc);
|
|
1559
|
+
const item = mapToolCallToOutput(tc, shortNameToNs);
|
|
1577
1560
|
if (item) {
|
|
1578
1561
|
output.push(item);
|
|
1579
1562
|
}
|
|
@@ -1610,7 +1593,7 @@ function translateResponse2(body, options = {}) {
|
|
|
1610
1593
|
}
|
|
1611
1594
|
};
|
|
1612
1595
|
}
|
|
1613
|
-
function mapToolCallToOutput(tc) {
|
|
1596
|
+
function mapToolCallToOutput(tc, shortNameToNs) {
|
|
1614
1597
|
const name = tc.function?.name;
|
|
1615
1598
|
if (!name) {
|
|
1616
1599
|
return void 0;
|
|
@@ -1620,11 +1603,23 @@ function mapToolCallToOutput(tc) {
|
|
|
1620
1603
|
if (typeof args !== "string") {
|
|
1621
1604
|
args = jsonStringifySafe(args ?? {});
|
|
1622
1605
|
}
|
|
1606
|
+
let resolvedName = name;
|
|
1607
|
+
let resolvedNamespace;
|
|
1608
|
+
if (!SHELL_TOOL_NAMES3.has(name)) {
|
|
1609
|
+
const dotIdx = name.indexOf(".");
|
|
1610
|
+
if (dotIdx !== -1) {
|
|
1611
|
+
resolvedNamespace = name.slice(0, dotIdx);
|
|
1612
|
+
resolvedName = name.slice(dotIdx + 1);
|
|
1613
|
+
} else {
|
|
1614
|
+
resolvedNamespace = shortNameToNs?.get(name);
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1623
1617
|
const item = {
|
|
1624
1618
|
id: callId,
|
|
1625
1619
|
type: "function_call",
|
|
1626
1620
|
status: "completed",
|
|
1627
|
-
name,
|
|
1621
|
+
name: resolvedName,
|
|
1622
|
+
...resolvedNamespace ? { namespace: resolvedNamespace } : {},
|
|
1628
1623
|
arguments: args,
|
|
1629
1624
|
call_id: callId
|
|
1630
1625
|
};
|
|
@@ -1632,7 +1627,7 @@ function mapToolCallToOutput(tc) {
|
|
|
1632
1627
|
if (thoughtSignature) {
|
|
1633
1628
|
item.thought_signature = thoughtSignature;
|
|
1634
1629
|
}
|
|
1635
|
-
if (SHELL_TOOL_NAMES3.has(
|
|
1630
|
+
if (SHELL_TOOL_NAMES3.has(resolvedName)) {
|
|
1636
1631
|
item.type = "local_shell_call";
|
|
1637
1632
|
const parsed = safeJsonParse(args);
|
|
1638
1633
|
item.action = { type: "exec", command: parsed?.command ?? [] };
|
|
@@ -1646,6 +1641,36 @@ function getThoughtSignature(tc) {
|
|
|
1646
1641
|
|
|
1647
1642
|
// src/translate/openai/translateStream.ts
|
|
1648
1643
|
var SHELL_TOOL_NAMES4 = /* @__PURE__ */ new Set(["shell", "container.exec", "shell_command"]);
|
|
1644
|
+
function buildShortNameToNamespace2(tools) {
|
|
1645
|
+
const map = /* @__PURE__ */ new Map();
|
|
1646
|
+
for (const tool of tools) {
|
|
1647
|
+
if (!tool || typeof tool !== "object") {
|
|
1648
|
+
continue;
|
|
1649
|
+
}
|
|
1650
|
+
const entry = tool;
|
|
1651
|
+
const fn = entry.function;
|
|
1652
|
+
const flatName = typeof fn?.name === "string" ? fn.name : typeof entry.name === "string" ? entry.name : "";
|
|
1653
|
+
const dotIdx = flatName.indexOf(".");
|
|
1654
|
+
if (dotIdx !== -1) {
|
|
1655
|
+
map.set(flatName.slice(dotIdx + 1), flatName.slice(0, dotIdx));
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
if (entry.type === "namespace" && typeof entry.name === "string" && Array.isArray(entry.tools)) {
|
|
1659
|
+
const ns = entry.name;
|
|
1660
|
+
for (const sub of entry.tools) {
|
|
1661
|
+
if (!sub || typeof sub !== "object") {
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
const subEntry = sub;
|
|
1665
|
+
const subName = typeof subEntry.name === "string" ? subEntry.name : "";
|
|
1666
|
+
if (subName) {
|
|
1667
|
+
map.set(subName, ns);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
return map;
|
|
1673
|
+
}
|
|
1649
1674
|
async function* translateStream2(stream, options = {}) {
|
|
1650
1675
|
const translator = new StreamTranslator2(options);
|
|
1651
1676
|
yield translator.createInitialEvent();
|
|
@@ -1664,6 +1689,15 @@ async function* translateStream2(stream, options = {}) {
|
|
|
1664
1689
|
function isDoneMessage(msg) {
|
|
1665
1690
|
return msg.data.trim() === "[DONE]";
|
|
1666
1691
|
}
|
|
1692
|
+
function getToolCallKey(tc, ordinal) {
|
|
1693
|
+
if (typeof tc.index === "number") {
|
|
1694
|
+
return `index:${tc.index}`;
|
|
1695
|
+
}
|
|
1696
|
+
if (tc.id) {
|
|
1697
|
+
return `id:${tc.id}`;
|
|
1698
|
+
}
|
|
1699
|
+
return `ordinal:${ordinal}`;
|
|
1700
|
+
}
|
|
1667
1701
|
var StreamTranslator2 = class {
|
|
1668
1702
|
constructor(options) {
|
|
1669
1703
|
__publicField(this, "model");
|
|
@@ -1676,6 +1710,10 @@ var StreamTranslator2 = class {
|
|
|
1676
1710
|
__publicField(this, "textItemIndex", -1);
|
|
1677
1711
|
__publicField(this, "textBuffer", "");
|
|
1678
1712
|
__publicField(this, "toolCalls", /* @__PURE__ */ new Map());
|
|
1713
|
+
// shortName → namespace reverse map built from flattened namespace tools in
|
|
1714
|
+
// the translated request. Used to restore the namespace when an upstream
|
|
1715
|
+
// (e.g. DeepSeek) omits the "namespace." prefix in its tool-call response.
|
|
1716
|
+
__publicField(this, "shortNameToNamespace");
|
|
1679
1717
|
__publicField(this, "inputTokens", 0);
|
|
1680
1718
|
__publicField(this, "outputTokens", 0);
|
|
1681
1719
|
__publicField(this, "cachedTokens", 0);
|
|
@@ -1683,6 +1721,7 @@ var StreamTranslator2 = class {
|
|
|
1683
1721
|
this.responseId = options.responseId ?? makeId("resp");
|
|
1684
1722
|
this.createdAt = options.createdAt ?? Math.floor(Date.now() / 1e3);
|
|
1685
1723
|
this.metadata = options.requestMetadata ?? {};
|
|
1724
|
+
this.shortNameToNamespace = buildShortNameToNamespace2(this.metadata.tools ?? []);
|
|
1686
1725
|
}
|
|
1687
1726
|
createInitialEvent() {
|
|
1688
1727
|
const toolsArr = this.metadata.tools ?? [];
|
|
@@ -1722,9 +1761,9 @@ var StreamTranslator2 = class {
|
|
|
1722
1761
|
return;
|
|
1723
1762
|
}
|
|
1724
1763
|
if (delta.tool_calls?.length) {
|
|
1725
|
-
for (const tc of delta.tool_calls) {
|
|
1726
|
-
const
|
|
1727
|
-
let state = this.toolCalls.get(
|
|
1764
|
+
for (const [ordinal, tc] of delta.tool_calls.entries()) {
|
|
1765
|
+
const key = getToolCallKey(tc, ordinal);
|
|
1766
|
+
let state = this.toolCalls.get(key);
|
|
1728
1767
|
if (!state) {
|
|
1729
1768
|
const outputIndex = this.outputCounter++;
|
|
1730
1769
|
const callId = tc.id ?? makeId("call");
|
|
@@ -1737,7 +1776,7 @@ var StreamTranslator2 = class {
|
|
|
1737
1776
|
call_id: callId
|
|
1738
1777
|
};
|
|
1739
1778
|
state = { outputIndex, item };
|
|
1740
|
-
this.toolCalls.set(
|
|
1779
|
+
this.toolCalls.set(key, state);
|
|
1741
1780
|
yield this.makeEvent("response.output_item.added", {
|
|
1742
1781
|
response_id: this.responseId,
|
|
1743
1782
|
output_index: outputIndex,
|
|
@@ -1804,6 +1843,18 @@ var StreamTranslator2 = class {
|
|
|
1804
1843
|
for (const state of this.toolCalls.values()) {
|
|
1805
1844
|
const item = state.item;
|
|
1806
1845
|
item.status = "completed";
|
|
1846
|
+
if (item.name && !SHELL_TOOL_NAMES4.has(item.name)) {
|
|
1847
|
+
const dotIdx = item.name.indexOf(".");
|
|
1848
|
+
if (dotIdx !== -1) {
|
|
1849
|
+
item.namespace = item.name.slice(0, dotIdx);
|
|
1850
|
+
item.name = item.name.slice(dotIdx + 1);
|
|
1851
|
+
} else {
|
|
1852
|
+
const ns = this.shortNameToNamespace.get(item.name);
|
|
1853
|
+
if (ns) {
|
|
1854
|
+
item.namespace = ns;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1807
1858
|
if (item.name && SHELL_TOOL_NAMES4.has(item.name)) {
|
|
1808
1859
|
item.type = "local_shell_call";
|
|
1809
1860
|
const parsed = safeJsonParse(item.arguments ?? "");
|
|
@@ -1865,6 +1916,109 @@ function getThoughtSignature2(tc) {
|
|
|
1865
1916
|
return typeof sig === "string" && sig ? sig : void 0;
|
|
1866
1917
|
}
|
|
1867
1918
|
|
|
1919
|
+
// src/tool-name-sanitizer.ts
|
|
1920
|
+
function sanitizeUpstreamToolNames(body) {
|
|
1921
|
+
const map = /* @__PURE__ */ new Map();
|
|
1922
|
+
const tools = body.tools;
|
|
1923
|
+
if (!Array.isArray(tools)) {
|
|
1924
|
+
return map;
|
|
1925
|
+
}
|
|
1926
|
+
for (const tool of tools) {
|
|
1927
|
+
if (!tool || typeof tool !== "object") {
|
|
1928
|
+
continue;
|
|
1929
|
+
}
|
|
1930
|
+
const toolRecord = tool;
|
|
1931
|
+
const fn = toolRecord.function;
|
|
1932
|
+
if (!fn || typeof fn !== "object") {
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
const fnRecord = fn;
|
|
1936
|
+
const original = fnRecord.name;
|
|
1937
|
+
if (typeof original !== "string") {
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1940
|
+
const sanitized = original.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1941
|
+
if (sanitized !== original) {
|
|
1942
|
+
map.set(sanitized, original);
|
|
1943
|
+
fnRecord.name = sanitized;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
return map;
|
|
1947
|
+
}
|
|
1948
|
+
function restoreToolNamesInChatResponse(body, map) {
|
|
1949
|
+
if (map.size === 0) {
|
|
1950
|
+
return body;
|
|
1951
|
+
}
|
|
1952
|
+
const choices = body.choices;
|
|
1953
|
+
if (!Array.isArray(choices)) {
|
|
1954
|
+
return body;
|
|
1955
|
+
}
|
|
1956
|
+
for (const choice of choices) {
|
|
1957
|
+
if (!choice || typeof choice !== "object") {
|
|
1958
|
+
continue;
|
|
1959
|
+
}
|
|
1960
|
+
const choiceRecord = choice;
|
|
1961
|
+
const message = choiceRecord.message;
|
|
1962
|
+
if (!message || typeof message !== "object") {
|
|
1963
|
+
continue;
|
|
1964
|
+
}
|
|
1965
|
+
const msg = message;
|
|
1966
|
+
const toolCalls = msg.tool_calls;
|
|
1967
|
+
if (!Array.isArray(toolCalls)) {
|
|
1968
|
+
continue;
|
|
1969
|
+
}
|
|
1970
|
+
for (const tc of toolCalls) {
|
|
1971
|
+
if (!tc || typeof tc !== "object") {
|
|
1972
|
+
continue;
|
|
1973
|
+
}
|
|
1974
|
+
const callRecord = tc;
|
|
1975
|
+
const fn = callRecord.function;
|
|
1976
|
+
if (!fn || typeof fn !== "object") {
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1979
|
+
const fnRecord = fn;
|
|
1980
|
+
const name = fnRecord.name;
|
|
1981
|
+
if (typeof name === "string" && map.has(name)) {
|
|
1982
|
+
fnRecord.name = map.get(name);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
return body;
|
|
1987
|
+
}
|
|
1988
|
+
function createToolNameRestoreStream(body, map) {
|
|
1989
|
+
if (map.size === 0) {
|
|
1990
|
+
return body;
|
|
1991
|
+
}
|
|
1992
|
+
const entries = Array.from(map.entries());
|
|
1993
|
+
const decoder = new TextDecoder();
|
|
1994
|
+
const encoder = new TextEncoder();
|
|
1995
|
+
const reader = body.getReader();
|
|
1996
|
+
return new ReadableStream({
|
|
1997
|
+
async pull(controller) {
|
|
1998
|
+
try {
|
|
1999
|
+
const { value, done } = await reader.read();
|
|
2000
|
+
if (done) {
|
|
2001
|
+
controller.close();
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
let text = decoder.decode(value, { stream: true });
|
|
2005
|
+
for (const [sanitized, original] of entries) {
|
|
2006
|
+
const escapedSanitized = sanitized.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2007
|
+
const re = new RegExp(`("name"\\s*:\\s*")${escapedSanitized}(")`, "g");
|
|
2008
|
+
text = text.replace(re, `$1${original}$2`);
|
|
2009
|
+
}
|
|
2010
|
+
controller.enqueue(encoder.encode(text));
|
|
2011
|
+
} catch (err) {
|
|
2012
|
+
controller.error(err);
|
|
2013
|
+
}
|
|
2014
|
+
},
|
|
2015
|
+
cancel() {
|
|
2016
|
+
reader.cancel().catch(() => {
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
|
|
1868
2022
|
// src/fetch.ts
|
|
1869
2023
|
function createResponsesFetch(options) {
|
|
1870
2024
|
if (!options.baseUrl) {
|
|
@@ -2033,6 +2187,10 @@ async function handleResponses(request, format, options, baseFetch, incomingHead
|
|
|
2033
2187
|
const fbModel = fb.model ? `, model: ${fb.model}` : "";
|
|
2034
2188
|
console.warn(`[fallback] last user message has image, routing to ${fb.baseUrl}${fbModel}`);
|
|
2035
2189
|
}
|
|
2190
|
+
if (options.dropTools && request.tools) {
|
|
2191
|
+
const { dropTools } = options;
|
|
2192
|
+
request = { ...request, tools: request.tools.filter((tool) => !dropTools(tool)) };
|
|
2193
|
+
}
|
|
2036
2194
|
const streaming = request.stream ?? false;
|
|
2037
2195
|
const resolvedUrl = normalizeBaseUrl(options.baseUrl, format);
|
|
2038
2196
|
const { upstreamBody, requestMetadata } = buildUpstreamBody(
|
|
@@ -2046,6 +2204,10 @@ async function handleResponses(request, format, options, baseFetch, incomingHead
|
|
|
2046
2204
|
options.fallbackThoughtSignature
|
|
2047
2205
|
);
|
|
2048
2206
|
const upstreamHeaders = buildUpstreamHeaders(format, options, incomingHeaders);
|
|
2207
|
+
const toolNameMap = format === "openai-chat" ? (
|
|
2208
|
+
// eslint-disable-next-line no-restricted-syntax -- upstreamBody is unknown; cast to Record for tool mutation
|
|
2209
|
+
sanitizeUpstreamToolNames(upstreamBody)
|
|
2210
|
+
) : /* @__PURE__ */ new Map();
|
|
2049
2211
|
const upstream = await baseFetch(resolvedUrl, {
|
|
2050
2212
|
method: "POST",
|
|
2051
2213
|
headers: upstreamHeaders,
|
|
@@ -2059,13 +2221,23 @@ async function handleResponses(request, format, options, baseFetch, incomingHead
|
|
|
2059
2221
|
});
|
|
2060
2222
|
}
|
|
2061
2223
|
if (!streaming) {
|
|
2062
|
-
const
|
|
2224
|
+
const rawBody = await upstream.json();
|
|
2225
|
+
const restoredBody = restoreToolNamesInChatResponse(
|
|
2226
|
+
// eslint-disable-next-line no-restricted-syntax -- upstream json() returns unknown; cast to Record for tool name restoration
|
|
2227
|
+
rawBody,
|
|
2228
|
+
toolNameMap
|
|
2229
|
+
);
|
|
2063
2230
|
const translated = format === "anthropic" ? (
|
|
2064
2231
|
// eslint-disable-next-line no-restricted-syntax -- union type narrowing requires type assertion
|
|
2065
|
-
translateResponse(
|
|
2232
|
+
translateResponse(restoredBody, {
|
|
2233
|
+
model: request.model
|
|
2234
|
+
})
|
|
2066
2235
|
) : (
|
|
2067
2236
|
// eslint-disable-next-line no-restricted-syntax -- union type narrowing requires type assertion
|
|
2068
|
-
translateResponse2(
|
|
2237
|
+
translateResponse2(restoredBody, {
|
|
2238
|
+
model: request.model,
|
|
2239
|
+
requestTools: request.tools ?? []
|
|
2240
|
+
})
|
|
2069
2241
|
);
|
|
2070
2242
|
options.onCacheStats?.(extractCacheStatsFromResponse(translated));
|
|
2071
2243
|
return new Response(JSON.stringify(translated), {
|
|
@@ -2076,7 +2248,8 @@ async function handleResponses(request, format, options, baseFetch, incomingHead
|
|
|
2076
2248
|
if (!upstream.body) {
|
|
2077
2249
|
return jsonErrorResponse(502, "Upstream streaming response has no body");
|
|
2078
2250
|
}
|
|
2079
|
-
const
|
|
2251
|
+
const upstreamBodyStream = createToolNameRestoreStream(upstream.body, toolNameMap);
|
|
2252
|
+
const events = format === "anthropic" ? translateStream(upstreamBodyStream, { model: request.model, requestMetadata }) : translateStream2(upstreamBodyStream, { model: request.model, requestMetadata });
|
|
2080
2253
|
return new Response(
|
|
2081
2254
|
responsesEventsToSseStream(collectCacheStatsFromStream(events, options.onCacheStats)),
|
|
2082
2255
|
{
|