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