@galaxy-yearn/codex-deepseek-gateway 0.1.5 → 0.1.6

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/src/protocol.js CHANGED
@@ -1,5 +1,10 @@
1
1
  import { generateId, isObject, normalizeRole, toText } from './common.js';
2
- import { deepseekReasoningPayload, resolveModelAlias } from './model-map.js';
2
+ import {
3
+ DEFAULT_MODEL_ALIASES,
4
+ deepseekReasoningPayload,
5
+ isDeprecatedModel,
6
+ resolveModelAlias,
7
+ } from './model-map.js';
3
8
 
4
9
  const TEXT_PART_TYPES = new Set(['input_text', 'output_text', 'text']);
5
10
  const INPUT_CONTENT_PART_TYPES = new Set(['input_text', 'input_image', 'input_file', 'input_audio']);
@@ -10,6 +15,7 @@ const TOOL_CALL_TYPES = new Set([
10
15
  'computer_call',
11
16
  'mcp_call',
12
17
  'web_search_call',
18
+ 'tool_search_call',
13
19
  'file_search_call',
14
20
  'code_interpreter_call',
15
21
  'image_generation_call',
@@ -21,11 +27,17 @@ const TOOL_OUTPUT_TYPES = new Set([
21
27
  'computer_call_output',
22
28
  'mcp_call_output',
23
29
  'web_search_call_output',
30
+ 'tool_search_output',
24
31
  'file_search_call_output',
25
32
  'code_interpreter_call_output',
26
33
  'image_generation_call_output',
27
34
  ]);
28
- const CHAT_HISTORY_IGNORED_TOOL_ITEM_TYPES = new Set(['web_search_call', 'web_search_call_output']);
35
+ const CHAT_HISTORY_IGNORED_TOOL_ITEM_TYPES = new Set([
36
+ 'web_search_call',
37
+ 'web_search_call_output',
38
+ 'tool_search_call',
39
+ 'tool_search_output',
40
+ ]);
29
41
  const EMULATED_HOSTED_TOOL_TYPES = new Set(['web_search', 'web_search_preview']);
30
42
  const DEEPSEEK_TOOL_INSTRUCTIONS_MARKER = 'The tools in this request are real callable functions available now.';
31
43
  const DEEPSEEK_TOOL_INSTRUCTIONS = [
@@ -36,12 +48,26 @@ const DEEPSEEK_TOOL_INSTRUCTIONS = [
36
48
  ].join(' ');
37
49
  const DEEPSEEK_TOOL_DESCRIPTION_CHARS = 220;
38
50
  const DEEPSEEK_SCHEMA_DESCRIPTION_CHARS = 160;
51
+ const CODEX_REASONING_EFFORTS = ['low', 'medium', 'high', 'xhigh'];
52
+ const CODEX_SPAWN_AGENT_TOOL_NAME = 'multi_agent_v1__spawn_agent';
53
+ const CODEX_TOOL_SEARCH_TOOL_NAME = 'tool_search';
39
54
 
40
55
  function jsonString(value) {
41
56
  if (typeof value === 'string') return value;
42
57
  return JSON.stringify(value ?? {});
43
58
  }
44
59
 
60
+ function parseJsonObject(value) {
61
+ if (isObject(value)) return value;
62
+ if (typeof value !== 'string') return {};
63
+ try {
64
+ const parsed = JSON.parse(value);
65
+ return isObject(parsed) ? parsed : {};
66
+ } catch {
67
+ return {};
68
+ }
69
+ }
70
+
45
71
  function sanitizeFunctionName(name, fallback = 'tool_call') {
46
72
  const candidate = String(name || fallback)
47
73
  .replace(/[^a-zA-Z0-9_-]/g, '_')
@@ -74,6 +100,10 @@ function decodedToolName(name, toolNames) {
74
100
  return known ? { ...known } : { name: value };
75
101
  }
76
102
 
103
+ function isCodexToolSearchTool(name) {
104
+ return String(name || '') === CODEX_TOOL_SEARCH_TOOL_NAME;
105
+ }
106
+
77
107
  function omitUndefined(value) {
78
108
  if (!isObject(value)) return value;
79
109
  const result = {};
@@ -195,6 +225,7 @@ function toolName(item) {
195
225
 
196
226
  function toolArguments(item) {
197
227
  if (item.type === 'function_call') return jsonString(item.arguments ?? {});
228
+ if (item.type === 'tool_search_call') return jsonString(item.arguments ?? {});
198
229
  if (item.arguments !== undefined) return jsonString(item.arguments);
199
230
  if (item.input !== undefined) return jsonString({ input: item.input });
200
231
  if (item.action !== undefined) return jsonString({ action: item.action });
@@ -474,10 +505,45 @@ function expandTools(tools) {
474
505
  }
475
506
 
476
507
  function normalizeTools(tools) {
477
- const normalized = expandTools(tools).map(normalizeTool).filter(Boolean);
508
+ const seen = new Set();
509
+ const normalized = [];
510
+ for (const tool of expandTools(tools).map(normalizeTool).filter(Boolean)) {
511
+ const name = tool?.type === 'function' ? tool.function?.name : '';
512
+ if (name) {
513
+ if (seen.has(name)) continue;
514
+ seen.add(name);
515
+ }
516
+ normalized.push(tool);
517
+ }
478
518
  return normalized.length ? normalized : undefined;
479
519
  }
480
520
 
521
+ function collectToolSearchOutputTools(input) {
522
+ const discovered = [];
523
+ const scan = (value) => {
524
+ if (Array.isArray(value)) {
525
+ for (const item of value) scan(item);
526
+ return;
527
+ }
528
+ if (!isObject(value)) return;
529
+ if (value.type === 'tool_search_output' && Array.isArray(value.tools)) {
530
+ discovered.push(...value.tools.filter(isObject));
531
+ return;
532
+ }
533
+ if (Array.isArray(value.input)) scan(value.input);
534
+ if (Array.isArray(value.content)) scan(value.content);
535
+ };
536
+ scan(input);
537
+ return discovered;
538
+ }
539
+
540
+ function mergeToolsWithToolSearchOutput(requestTools, input) {
541
+ const discovered = collectToolSearchOutputTools(input);
542
+ if (!discovered.length) return requestTools;
543
+ const base = Array.isArray(requestTools) ? requestTools : [];
544
+ return base.concat(discovered);
545
+ }
546
+
481
547
  function normalizeJsonSchemaObject(schema) {
482
548
  if (!isObject(schema)) {
483
549
  return { type: 'object', properties: {}, additionalProperties: true };
@@ -614,6 +680,60 @@ function coerceValueForSchema(value, schema) {
614
680
  return value;
615
681
  }
616
682
 
683
+ function toolSearchArgumentsFromText(argumentsText) {
684
+ const parsed = parseJsonObject(argumentsText);
685
+ const args = {};
686
+ if (parsed.limit !== undefined) {
687
+ const limit = Number(parsed.limit);
688
+ if (Number.isFinite(limit)) args.limit = limit;
689
+ }
690
+ if (parsed.query !== undefined) args.query = String(parsed.query);
691
+ return args;
692
+ }
693
+
694
+ function finalizeToolSearchCallItemArguments(item) {
695
+ if (!item || item.type !== 'tool_search_call') return;
696
+ if (typeof item.arguments === 'string') {
697
+ item.arguments = toolSearchArgumentsFromText(item.arguments);
698
+ } else if (!isObject(item.arguments)) {
699
+ item.arguments = {};
700
+ }
701
+ }
702
+
703
+ function convertItemToToolSearchCall(item) {
704
+ if (!item || item.type === 'tool_search_call') return item;
705
+ item.type = 'tool_search_call';
706
+ item.id = generateId('tsc');
707
+ item.execution = 'client';
708
+ delete item.name;
709
+ delete item.namespace;
710
+ return item;
711
+ }
712
+
713
+ function responseItemFromChatToolCall(toolCall, toolNames) {
714
+ const callId = toolCall.id || generateId('call');
715
+ if (isCodexToolSearchTool(toolCall.function?.name)) {
716
+ return {
717
+ type: 'tool_search_call',
718
+ id: generateId('tsc'),
719
+ call_id: callId,
720
+ status: 'completed',
721
+ execution: 'client',
722
+ arguments: toolSearchArgumentsFromText(toolCall.function?.arguments || ''),
723
+ };
724
+ }
725
+ const decoded = decodedToolName(toolCall.function?.name, toolNames);
726
+ return omitUndefined({
727
+ type: 'function_call',
728
+ id: callId,
729
+ call_id: callId,
730
+ name: decoded.name,
731
+ namespace: decoded.namespace,
732
+ arguments: toolCall.function?.arguments || '',
733
+ status: 'completed',
734
+ });
735
+ }
736
+
617
737
  function buildToolSchemas(tools) {
618
738
  const schemas = new Map();
619
739
  for (const tool of expandTools(tools)) {
@@ -670,13 +790,81 @@ function defaultDeepSeekToolDescription(name) {
670
790
  return compactText(`Call ${readable || name || 'this function'} when needed.`);
671
791
  }
672
792
 
673
- function simplifyToolForDeepSeek(tool) {
793
+ function deepSeekGatewayModelAliases(config = {}) {
794
+ const aliases = isObject(config.modelAliases) && Object.keys(config.modelAliases).length
795
+ ? config.modelAliases
796
+ : DEFAULT_MODEL_ALIASES;
797
+ const spawnConfig = { ...config, upstreamProvider: 'deepseek', modelAliases: aliases };
798
+ const names = [];
799
+ for (const name of Object.keys(aliases)) {
800
+ if (!name || isDeprecatedModel(name)) continue;
801
+ const alias = resolveModelAlias(name, spawnConfig);
802
+ if (isDeprecatedModel(alias.upstreamModel)) continue;
803
+ names.push(name);
804
+ }
805
+ return [...new Set(names)];
806
+ }
807
+
808
+ function enumStringProperty(property, values, description) {
809
+ const source = isObject(property) ? property : {};
810
+ const next = { ...source };
811
+ delete next.const;
812
+ delete next.oneOf;
813
+ delete next.anyOf;
814
+ delete next.allOf;
815
+ delete next.examples;
816
+ if (next.default !== undefined && !values.includes(next.default)) delete next.default;
817
+ next.type = 'string';
818
+ next.enum = values;
819
+ next.description = description;
820
+ return next;
821
+ }
822
+
823
+ function deepSeekSpawnAgentParameters(parameters, config = {}) {
824
+ const next = normalizeJsonSchemaObject(parameters);
825
+ const properties = isObject(next.properties) ? { ...next.properties } : {};
826
+ const modelAliases = deepSeekGatewayModelAliases(config);
827
+ properties.model = enumStringProperty(
828
+ properties.model,
829
+ modelAliases,
830
+ 'Model for the sub-agent. Omit to inherit.',
831
+ );
832
+ properties.reasoning_effort = enumStringProperty(
833
+ properties.reasoning_effort,
834
+ CODEX_REASONING_EFFORTS,
835
+ 'Codex reasoning effort for the sub-agent. Omit to inherit.',
836
+ );
837
+ return {
838
+ ...next,
839
+ properties,
840
+ };
841
+ }
842
+
843
+ function deepSeekSpawnAgentDescription() {
844
+ const description = [
845
+ 'Spawn a Codex-native sub-agent.',
846
+ 'Omit model/reasoning_effort to inherit.',
847
+ 'Valid values are enforced by the schema.',
848
+ ].filter(Boolean).join(' ');
849
+ return shortenText(description, DEEPSEEK_TOOL_DESCRIPTION_CHARS);
850
+ }
851
+
852
+ function isCodexSpawnAgentTool(name) {
853
+ return name === CODEX_SPAWN_AGENT_TOOL_NAME || name === 'spawn_agent';
854
+ }
855
+
856
+ function simplifyToolForDeepSeek(tool, config = {}) {
674
857
  if (tool?.type !== 'function' || !isObject(tool.function)) return tool;
675
858
  const fn = tool.function;
676
- const parameters = simplifyJsonSchemaDescriptions(fn.parameters);
859
+ let parameters = simplifyJsonSchemaDescriptions(fn.parameters);
860
+ if (isCodexSpawnAgentTool(fn.name)) {
861
+ parameters = deepSeekSpawnAgentParameters(parameters, config);
862
+ }
677
863
  const requiredText = requiredParametersText(parameters);
678
864
  const descriptionBudget = Math.max(32, DEEPSEEK_TOOL_DESCRIPTION_CHARS - requiredText.length);
679
- const baseDescription = shortenText(fn.description, descriptionBudget) || defaultDeepSeekToolDescription(fn.name);
865
+ const baseDescription = isCodexSpawnAgentTool(fn.name)
866
+ ? deepSeekSpawnAgentDescription()
867
+ : shortenText(fn.description, descriptionBudget) || defaultDeepSeekToolDescription(fn.name);
680
868
  const description = shortenText(`${baseDescription}${requiredText}`, DEEPSEEK_TOOL_DESCRIPTION_CHARS);
681
869
  return {
682
870
  ...tool,
@@ -706,9 +894,9 @@ function addDeepSeekToolInstructions(messages, tools) {
706
894
  ];
707
895
  }
708
896
 
709
- function adaptToolsForProvider(tools, provider) {
897
+ function adaptToolsForProvider(tools, provider, config = {}) {
710
898
  if (provider !== 'deepseek' || !Array.isArray(tools)) return tools;
711
- return tools.map(simplifyToolForDeepSeek);
899
+ return tools.map((tool) => simplifyToolForDeepSeek(tool, config));
712
900
  }
713
901
 
714
902
  function normalizeToolCallArguments(name, argumentsText, toolSchema) {
@@ -733,10 +921,48 @@ function normalizeToolCallArguments(name, argumentsText, toolSchema) {
733
921
  }
734
922
  }
735
923
 
736
- function normalizeFunctionCallItemArguments(item, toolSchemas) {
924
+ function normalizeReasoningEffortName(value) {
925
+ return value == null ? '' : String(value).toLowerCase().replaceAll('_', '-');
926
+ }
927
+
928
+ function normalizeCodexSpawnAgentArguments(encodedName, argumentsText, config = {}) {
929
+ if (!isCodexSpawnAgentTool(encodedName) || !argumentsText) return argumentsText;
930
+ let parsed;
931
+ try {
932
+ parsed = JSON.parse(argumentsText);
933
+ } catch {
934
+ return argumentsText;
935
+ }
936
+ if (!isObject(parsed)) return argumentsText;
937
+ const next = { ...parsed };
938
+ let changed = false;
939
+ const allowedModels = deepSeekGatewayModelAliases(config);
940
+
941
+ if (typeof next.model === 'string') {
942
+ const requestedModel = next.model;
943
+ if (allowedModels.length && !allowedModels.includes(requestedModel)) {
944
+ delete next.model;
945
+ changed = true;
946
+ }
947
+ }
948
+
949
+ if (typeof next.reasoning_effort === 'string') {
950
+ const requestedEffort = normalizeReasoningEffortName(next.reasoning_effort);
951
+ if (!CODEX_REASONING_EFFORTS.includes(requestedEffort)) {
952
+ delete next.reasoning_effort;
953
+ changed = true;
954
+ return JSON.stringify(next);
955
+ }
956
+ }
957
+
958
+ return changed ? JSON.stringify(next) : argumentsText;
959
+ }
960
+
961
+ function normalizeFunctionCallItemArguments(item, toolSchemas, config = {}) {
737
962
  if (!item || item.type !== 'function_call') return;
738
963
  const encodedName = encodeToolName(item.namespace, item.name);
739
964
  item.arguments = normalizeToolCallArguments(encodedName, item.arguments, toolSchemas?.get(encodedName));
965
+ item.arguments = normalizeCodexSpawnAgentArguments(encodedName, item.arguments, config);
740
966
  }
741
967
 
742
968
  function sanitizeToolCallsForChatCompletion(toolCalls) {
@@ -764,7 +990,9 @@ function sanitizeMessageForChatCompletion(message, provider = 'generic') {
764
990
  content: contentToChatContent(message.content),
765
991
  };
766
992
  if (message.name !== undefined) sanitized.name = message.name;
767
- if (Array.isArray(message.tool_calls)) sanitized.tool_calls = sanitizeToolCallsForChatCompletion(message.tool_calls);
993
+ if (Array.isArray(message.tool_calls)) {
994
+ sanitized.tool_calls = sanitizeToolCallsForChatCompletion(message.tool_calls);
995
+ }
768
996
  if (message.tool_call_id !== undefined) sanitized.tool_call_id = message.tool_call_id;
769
997
  if (provider === 'deepseek' && message.role === 'assistant' && typeof message.reasoning_content === 'string') {
770
998
  sanitized.reasoning_content = message.reasoning_content;
@@ -836,6 +1064,16 @@ function snapshotResponsePart(part) {
836
1064
 
837
1065
  function snapshotResponseItem(item) {
838
1066
  if (!isObject(item)) return item;
1067
+ if (item.type === 'tool_search_call') {
1068
+ return omitUndefined({
1069
+ type: item.type,
1070
+ id: item.id,
1071
+ call_id: item.call_id,
1072
+ status: item.status,
1073
+ execution: item.execution,
1074
+ arguments: isObject(item.arguments) ? { ...item.arguments } : toolSearchArgumentsFromText(item.arguments),
1075
+ });
1076
+ }
839
1077
  return {
840
1078
  ...item,
841
1079
  content: Array.isArray(item.content) ? item.content.map(snapshotResponsePart) : item.content,
@@ -901,6 +1139,7 @@ export function normalizeResponsesRequest(request) {
901
1139
  const model = request.model || request.model_id || request.upstream_model || '';
902
1140
  const instructions = normalizeInstructions(request.instructions);
903
1141
  const responseFormat = request.response_format || request.text?.format;
1142
+ const tools = mergeToolsWithToolSearchOutput(request.tools, request.input ?? request);
904
1143
  return {
905
1144
  model,
906
1145
  messages,
@@ -910,7 +1149,7 @@ export function normalizeResponsesRequest(request) {
910
1149
  max_tokens: request.max_output_tokens ?? request.max_tokens,
911
1150
  stop: request.stop,
912
1151
  stream: Boolean(request.stream),
913
- tools: request.tools,
1152
+ tools,
914
1153
  tool_choice: request.tool_choice,
915
1154
  parallel_tool_calls: request.parallel_tool_calls,
916
1155
  presence_penalty: request.presence_penalty,
@@ -1043,7 +1282,7 @@ export function toProviderChatCompletionsRequest(chatRequest, config = {}) {
1043
1282
  if (provider === 'deepseek') {
1044
1283
  delete request.reasoning_effort;
1045
1284
  delete request.parallel_tool_calls;
1046
- request.tools = adaptToolsForProvider(request.tools, provider);
1285
+ request.tools = adaptToolsForProvider(request.tools, provider, config);
1047
1286
  request.messages = addDeepSeekToolInstructions(request.messages, request.tools);
1048
1287
  if (request.user !== undefined) {
1049
1288
  request.user_id = request.user;
@@ -1174,7 +1413,7 @@ export function createResponseEnvelope({
1174
1413
  });
1175
1414
  }
1176
1415
 
1177
- export function convertChatCompletionToResponses({ completion, model, previousResponseId, normalized, responseId = generateId('resp') }) {
1416
+ export function convertChatCompletionToResponses({ completion, model, previousResponseId, normalized, responseId = generateId('resp'), config = {} }) {
1178
1417
  const createdAt = completion.created || Date.now() / 1000;
1179
1418
  const choice = Array.isArray(completion.choices) ? completion.choices[0] : null;
1180
1419
  const message = choice?.message || {};
@@ -1196,18 +1435,8 @@ export function convertChatCompletionToResponses({ completion, model, previousRe
1196
1435
 
1197
1436
  if (Array.isArray(message.tool_calls)) {
1198
1437
  for (const toolCall of message.tool_calls) {
1199
- const callId = toolCall.id || generateId('call');
1200
- const decoded = decodedToolName(toolCall.function?.name, toolNames);
1201
- const item = omitUndefined({
1202
- type: 'function_call',
1203
- id: callId,
1204
- call_id: callId,
1205
- name: decoded.name,
1206
- namespace: decoded.namespace,
1207
- arguments: toolCall.function?.arguments || '',
1208
- status: 'completed',
1209
- });
1210
- normalizeFunctionCallItemArguments(item, toolSchemas);
1438
+ const item = responseItemFromChatToolCall(toolCall, toolNames);
1439
+ normalizeFunctionCallItemArguments(item, toolSchemas, config);
1211
1440
  output.push(item);
1212
1441
  }
1213
1442
  }
@@ -1249,6 +1478,7 @@ export class ResponsesStreamMapper {
1249
1478
  bufferOutputUntilDone = false,
1250
1479
  emitReasoningSummary = true,
1251
1480
  emitReasoningText = false,
1481
+ config = {},
1252
1482
  } = {}) {
1253
1483
  this.responseId = responseId;
1254
1484
  this.model = model;
@@ -1278,6 +1508,7 @@ export class ResponsesStreamMapper {
1278
1508
  this.streamedReasoningSummaryText = '';
1279
1509
  this.toolSchemas = buildToolSchemas(normalized?.tools);
1280
1510
  this.toolNames = buildToolNames(normalized?.tools);
1511
+ this.config = config;
1281
1512
  }
1282
1513
 
1283
1514
  nextSequence() {
@@ -1523,18 +1754,31 @@ export class ResponsesStreamMapper {
1523
1754
  let item = this.toolItems.get(index);
1524
1755
  if (!item) {
1525
1756
  const callId = toolCall.id || generateId('call');
1526
- item = {
1527
- id: callId,
1528
- type: 'function_call',
1529
- status: 'in_progress',
1530
- call_id: callId,
1531
- ...decodedToolName(toolCall.function?.name, this.toolNames),
1532
- arguments: '',
1533
- };
1757
+ item = isCodexToolSearchTool(toolCall.function?.name)
1758
+ ? {
1759
+ id: generateId('tsc'),
1760
+ type: 'tool_search_call',
1761
+ status: 'in_progress',
1762
+ call_id: callId,
1763
+ execution: 'client',
1764
+ arguments: '',
1765
+ }
1766
+ : {
1767
+ id: callId,
1768
+ type: 'function_call',
1769
+ status: 'in_progress',
1770
+ call_id: callId,
1771
+ ...decodedToolName(toolCall.function?.name, this.toolNames),
1772
+ arguments: '',
1773
+ };
1534
1774
  this.toolItems.set(index, item);
1535
1775
  this.output.push(item);
1536
1776
  }
1537
- if (toolCall.function?.name) Object.assign(item, decodedToolName(toolCall.function.name, this.toolNames));
1777
+ if (isCodexToolSearchTool(toolCall.function?.name)) {
1778
+ item = convertItemToToolSearchCall(item);
1779
+ } else if (toolCall.function?.name && item.type !== 'tool_search_call') {
1780
+ Object.assign(item, decodedToolName(toolCall.function.name, this.toolNames));
1781
+ }
1538
1782
  item.arguments += toolCall.function?.arguments || '';
1539
1783
  return [];
1540
1784
  }
@@ -1547,14 +1791,23 @@ export class ResponsesStreamMapper {
1547
1791
  let item = this.toolItems.get(index);
1548
1792
  if (!item) {
1549
1793
  const callId = toolCall.id || generateId('call');
1550
- item = {
1551
- id: callId,
1552
- type: 'function_call',
1553
- status: 'in_progress',
1554
- call_id: callId,
1555
- ...decodedToolName(toolCall.function?.name, this.toolNames),
1556
- arguments: '',
1557
- };
1794
+ item = isCodexToolSearchTool(toolCall.function?.name)
1795
+ ? {
1796
+ id: generateId('tsc'),
1797
+ type: 'tool_search_call',
1798
+ status: 'in_progress',
1799
+ call_id: callId,
1800
+ execution: 'client',
1801
+ arguments: '',
1802
+ }
1803
+ : {
1804
+ id: callId,
1805
+ type: 'function_call',
1806
+ status: 'in_progress',
1807
+ call_id: callId,
1808
+ ...decodedToolName(toolCall.function?.name, this.toolNames),
1809
+ arguments: '',
1810
+ };
1558
1811
  this.toolItems.set(index, item);
1559
1812
  this.output.push(item);
1560
1813
  events.push({
@@ -1564,10 +1817,14 @@ export class ResponsesStreamMapper {
1564
1817
  item: snapshotResponseItem(item),
1565
1818
  });
1566
1819
  }
1567
- if (toolCall.function?.name) Object.assign(item, decodedToolName(toolCall.function.name, this.toolNames));
1820
+ if (isCodexToolSearchTool(toolCall.function?.name)) {
1821
+ item = convertItemToToolSearchCall(item);
1822
+ } else if (toolCall.function?.name && item.type !== 'tool_search_call') {
1823
+ Object.assign(item, decodedToolName(toolCall.function.name, this.toolNames));
1824
+ }
1568
1825
  const delta = toolCall.function?.arguments || '';
1569
1826
  item.arguments += delta;
1570
- if (delta) {
1827
+ if (delta && item.type === 'function_call') {
1571
1828
  events.push({
1572
1829
  type: 'response.function_call_arguments.delta',
1573
1830
  sequence_number: this.nextSequence(),
@@ -1665,20 +1922,23 @@ export class ResponsesStreamMapper {
1665
1922
 
1666
1923
  for (const item of this.toolItems.values()) {
1667
1924
  item.status = status;
1668
- const encodedName = encodeToolName(item.namespace, item.name);
1669
- item.arguments = normalizeToolCallArguments(encodedName, item.arguments, this.toolSchemas.get(encodedName));
1925
+ if (item.type === 'tool_search_call') finalizeToolSearchCallItemArguments(item);
1926
+ else normalizeFunctionCallItemArguments(item, this.toolSchemas, this.config);
1670
1927
  const outputIndex = this.output.indexOf(item);
1671
1928
  events.push({
1672
1929
  type: 'response.output_item.added',
1673
1930
  sequence_number: this.nextSequence(),
1674
1931
  output_index: outputIndex,
1675
- item: snapshotResponseItem({
1932
+ item: snapshotResponseItem(item.type === 'tool_search_call' ? {
1933
+ ...item,
1934
+ status: 'in_progress',
1935
+ } : {
1676
1936
  ...item,
1677
1937
  status: 'in_progress',
1678
1938
  arguments: '',
1679
1939
  }),
1680
1940
  });
1681
- if (item.arguments) {
1941
+ if (item.type === 'function_call' && item.arguments) {
1682
1942
  events.push({
1683
1943
  type: 'response.function_call_arguments.delta',
1684
1944
  sequence_number: this.nextSequence(),
@@ -1687,13 +1947,15 @@ export class ResponsesStreamMapper {
1687
1947
  delta: item.arguments,
1688
1948
  });
1689
1949
  }
1690
- events.push({
1691
- type: 'response.function_call_arguments.done',
1692
- sequence_number: this.nextSequence(),
1693
- output_index: outputIndex,
1694
- item_id: item.id,
1695
- arguments: item.arguments,
1696
- });
1950
+ if (item.type === 'function_call') {
1951
+ events.push({
1952
+ type: 'response.function_call_arguments.done',
1953
+ sequence_number: this.nextSequence(),
1954
+ output_index: outputIndex,
1955
+ item_id: item.id,
1956
+ arguments: item.arguments,
1957
+ });
1958
+ }
1697
1959
  events.push({
1698
1960
  type: 'response.output_item.done',
1699
1961
  sequence_number: this.nextSequence(),
@@ -1778,14 +2040,17 @@ export class ResponsesStreamMapper {
1778
2040
  events.push(...this.closeReasoningItem(finishReason === 'length' ? 'incomplete' : 'completed'));
1779
2041
  for (const item of this.toolItems.values()) {
1780
2042
  item.status = finishReason === 'length' ? 'incomplete' : 'completed';
1781
- normalizeFunctionCallItemArguments(item, this.toolSchemas);
1782
- events.push({
1783
- type: 'response.function_call_arguments.done',
1784
- sequence_number: this.nextSequence(),
1785
- output_index: this.output.indexOf(item),
1786
- item_id: item.id,
1787
- arguments: item.arguments,
1788
- });
2043
+ if (item.type === 'tool_search_call') finalizeToolSearchCallItemArguments(item);
2044
+ else normalizeFunctionCallItemArguments(item, this.toolSchemas, this.config);
2045
+ if (item.type === 'function_call') {
2046
+ events.push({
2047
+ type: 'response.function_call_arguments.done',
2048
+ sequence_number: this.nextSequence(),
2049
+ output_index: this.output.indexOf(item),
2050
+ item_id: item.id,
2051
+ arguments: item.arguments,
2052
+ });
2053
+ }
1789
2054
  events.push({
1790
2055
  type: 'response.output_item.done',
1791
2056
  sequence_number: this.nextSequence(),
package/src/server.js CHANGED
@@ -747,6 +747,7 @@ export function createProxyServer({ config = loadConfig(), sessions = new Sessio
747
747
  previousResponseId,
748
748
  normalized,
749
749
  responseId,
750
+ config,
750
751
  }), loop.searches, normalized, loop.openedPages);
751
752
  if (loop.incompleteReason) markPayloadIncomplete(payload, loop.incompleteReason);
752
753
  const assistantMessage = assistantMessageFromResponseOutput(payload.output);
@@ -802,6 +803,7 @@ export function createProxyServer({ config = loadConfig(), sessions = new Sessio
802
803
  previousResponseId,
803
804
  normalized,
804
805
  responseId,
806
+ config,
805
807
  });
806
808
  nextSession.history.push({
807
809
  request: normalized,
@@ -830,6 +832,7 @@ export function createProxyServer({ config = loadConfig(), sessions = new Sessio
830
832
  createdAt: Math.floor(Date.now() / 1000),
831
833
  previousResponseId,
832
834
  normalized,
835
+ config,
833
836
  ...(() => {
834
837
  const reasoningMode = resolveReasoningStreamMode(config, upstreamRequest);
835
838
  return {