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