@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.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, context);
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, context) {
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, context);
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, context);
1292
+ processToolOutput(item, messages);
1349
1293
  return;
1350
1294
  }
1351
1295
  }
1352
- function processToolCall(item, messages, getLastAssistant, fallbackThoughtSignature, context) {
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, context) {
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 rawParams = fn?.parameters ?? tool.parameters ?? { type: "object" };
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(name)) {
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 idx = tc.index ?? 0;
1727
- let state = this.toolCalls.get(idx);
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(idx, state);
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 body = await upstream.json();
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(body, { model: request.model })
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(body, { model: request.model })
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 events = format === "anthropic" ? translateStream(upstream.body, { model: request.model, requestMetadata }) : translateStream2(upstream.body, { model: request.model, requestMetadata });
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
  {