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

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
@@ -27,6 +27,15 @@ const TOOL_OUTPUT_TYPES = new Set([
27
27
  ]);
28
28
  const CHAT_HISTORY_IGNORED_TOOL_ITEM_TYPES = new Set(['web_search_call', 'web_search_call_output']);
29
29
  const EMULATED_HOSTED_TOOL_TYPES = new Set(['web_search', 'web_search_preview']);
30
+ const DEEPSEEK_TOOL_INSTRUCTIONS_MARKER = 'The tools in this request are real callable functions available now.';
31
+ const DEEPSEEK_TOOL_INSTRUCTIONS = [
32
+ DEEPSEEK_TOOL_INSTRUCTIONS_MARKER,
33
+ 'When a tool is needed, respond with Chat Completions tool_calls and JSON arguments matching the schema.',
34
+ 'Do not write pseudo XML, DSML, or JSON tool calls in assistant text.',
35
+ 'Do not claim a listed function is unavailable because its name is unfamiliar.',
36
+ ].join(' ');
37
+ const DEEPSEEK_TOOL_DESCRIPTION_CHARS = 220;
38
+ const DEEPSEEK_SCHEMA_DESCRIPTION_CHARS = 160;
30
39
 
31
40
  function jsonString(value) {
32
41
  if (typeof value === 'string') return value;
@@ -41,6 +50,30 @@ function sanitizeFunctionName(name, fallback = 'tool_call') {
41
50
  return candidate || fallback;
42
51
  }
43
52
 
53
+ function toolNamespace(tool) {
54
+ if (!isObject(tool)) return '';
55
+ return String(tool.namespace || tool.function?.namespace || '').trim();
56
+ }
57
+
58
+ function toolBaseName(tool, fallback = 'tool_call') {
59
+ if (!isObject(tool)) return fallback;
60
+ if (isObject(tool.function) && tool.function.name) return tool.function.name;
61
+ return tool.name || tool.tool_name || tool.toolName || tool.server_label || fallback;
62
+ }
63
+
64
+ function encodeToolName(namespace, name, fallback = 'tool_call') {
65
+ const baseName = sanitizeFunctionName(name, fallback);
66
+ if (!namespace) return baseName;
67
+ const encodedNamespace = sanitizeFunctionName(namespace, 'namespace');
68
+ return sanitizeFunctionName(`${encodedNamespace}__${baseName}`, fallback);
69
+ }
70
+
71
+ function decodedToolName(name, toolNames) {
72
+ const value = String(name || '');
73
+ const known = toolNames?.get(value);
74
+ return known ? { ...known } : { name: value };
75
+ }
76
+
44
77
  function omitUndefined(value) {
45
78
  if (!isObject(value)) return value;
46
79
  const result = {};
@@ -50,6 +83,19 @@ function omitUndefined(value) {
50
83
  return result;
51
84
  }
52
85
 
86
+ function compactText(value) {
87
+ return String(value ?? '').replace(/\s+/g, ' ').trim();
88
+ }
89
+
90
+ function shortenText(value, maxChars) {
91
+ const text = compactText(value);
92
+ if (!text || text.length <= maxChars) return text;
93
+ const softLimit = Math.max(24, Math.floor(maxChars * 0.65));
94
+ const slice = text.slice(0, maxChars - 3);
95
+ const breakAt = Math.max(slice.lastIndexOf('. '), slice.lastIndexOf('; '), slice.lastIndexOf(', '), slice.lastIndexOf(' '));
96
+ return `${slice.slice(0, breakAt >= softLimit ? breakAt : slice.length).trimEnd()}...`;
97
+ }
98
+
53
99
  function textPart(text) {
54
100
  return { type: 'text', text: String(text ?? '') };
55
101
  }
@@ -137,8 +183,9 @@ function toolCallId(item) {
137
183
  }
138
184
 
139
185
  function toolName(item) {
140
- return sanitizeFunctionName(
141
- item.name ||
186
+ return encodeToolName(
187
+ toolNamespace(item),
188
+ item.name ||
142
189
  item.tool_name ||
143
190
  item.toolName ||
144
191
  item.server_label ||
@@ -170,35 +217,55 @@ function chatToolCallFromResponseItem(item) {
170
217
 
171
218
  function reasoningTextFromItem(item) {
172
219
  if (!isObject(item)) return '';
173
- const parts = [];
174
- if (typeof item.reasoning_content === 'string') parts.push(item.reasoning_content);
175
- if (typeof item.text === 'string') parts.push(item.text);
176
- if (typeof item.content === 'string') parts.push(item.content);
220
+ if (typeof item.reasoning_content === 'string') return normalizeReasoningContent(item.reasoning_content);
221
+ const rawParts = [];
222
+ if (typeof item.text === 'string') rawParts.push(item.text);
223
+ if (typeof item.content === 'string') rawParts.push(item.content);
177
224
  if (Array.isArray(item.content)) {
178
225
  for (const part of item.content) {
179
226
  if (typeof part === 'string') {
180
- parts.push(part);
227
+ rawParts.push(part);
181
228
  continue;
182
229
  }
183
230
  if (!isObject(part)) continue;
184
231
  if (part.type === 'reasoning_text' || part.type === 'text' || part.type === 'output_text') {
185
- parts.push(String(part.text ?? part.content ?? ''));
186
- }
187
- }
188
- }
189
- if (Array.isArray(item.summary)) {
190
- for (const part of item.summary) {
191
- if (typeof part === 'string') {
192
- parts.push(part);
193
- continue;
194
- }
195
- if (!isObject(part)) continue;
196
- if (part.type === 'summary_text' || part.type === 'text') {
197
- parts.push(String(part.text ?? part.content ?? ''));
232
+ rawParts.push(String(part.text ?? part.content ?? ''));
198
233
  }
199
234
  }
200
235
  }
201
- return parts.filter(Boolean).join('');
236
+ const rawText = rawParts.filter(Boolean).join('');
237
+ return normalizeReasoningContent(rawText);
238
+ }
239
+
240
+ function normalizeReasoningContent(text) {
241
+ return String(text ?? '').replace(/\r\n?/g, '\n').trimEnd();
242
+ }
243
+
244
+ function normalizeReasoningDisplayText(text) {
245
+ const value = normalizeReasoningContent(text);
246
+ if (!value) return '';
247
+ const plain = value
248
+ .split('\n')
249
+ .map((line) => line
250
+ .replace(/^[ \t]{0,3}(?:`{3,}|~{3,}).*$/, '')
251
+ .replace(/^[ \t]{0,3}#{1,6}[ \t]+/, '')
252
+ .replace(/^[ \t]{0,3}>[ \t]?/, '')
253
+ .replace(/^[ \t]*[-*+][ \t]+(?:\[[ xX]\][ \t]+)?/, '\u2022 ')
254
+ .replace(/^[ \t]*(\d+)\.[ \t]+/, '$1) ')
255
+ .replace(/!\[([^\]]*)\]\([^)]+\)/g, '$1')
256
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
257
+ .replace(/`([^`]*)`/g, '$1')
258
+ .replace(/(\*\*|__)([^*_]+)\1/g, '$2')
259
+ .replace(/(\*|_)([^*_]+)\1/g, '$2')
260
+ .replace(/[*_`~]/g, '')
261
+ .replace(/\\([\\`*_{}[\]()#+\-.!>])/g, '$1')
262
+ .trimEnd())
263
+ .join('\n');
264
+ return plain.replace(/^\n+/, '').trimEnd();
265
+ }
266
+
267
+ function reasoningDisplayText(text) {
268
+ return normalizeReasoningDisplayText(text);
202
269
  }
203
270
 
204
271
  function toolOutputContent(item) {
@@ -346,24 +413,28 @@ function extractMessagesFromResponsesInput(input) {
346
413
 
347
414
  function normalizeTool(tool) {
348
415
  if (!isObject(tool)) return tool;
416
+ if (tool.type === 'namespace') return null;
349
417
  if (typeof tool.type === 'string' && EMULATED_HOSTED_TOOL_TYPES.has(tool.type)) {
350
418
  return null;
351
419
  }
352
420
  if (tool.type === 'function' && isObject(tool.function)) {
421
+ const { namespace, ...fn } = tool.function;
353
422
  return {
354
- ...tool,
355
- function: {
356
- ...tool.function,
357
- name: sanitizeFunctionName(tool.function.name),
358
- parameters: normalizeJsonSchemaObject(tool.function.parameters),
359
- },
423
+ type: 'function',
424
+ function: omitUndefined({
425
+ ...fn,
426
+ name: encodeToolName(toolNamespace(tool), fn.name),
427
+ description: fn.description ?? tool.description,
428
+ parameters: normalizeJsonSchemaObject(fn.parameters ?? tool.parameters ?? tool.input_schema),
429
+ strict: fn.strict ?? tool.strict,
430
+ }),
360
431
  };
361
432
  }
362
433
  if (tool.type === 'function' || tool.type === 'custom' || tool.name || tool.parameters || tool.input_schema) {
363
434
  return {
364
435
  type: 'function',
365
436
  function: omitUndefined({
366
- name: sanitizeFunctionName(tool.name || tool.type),
437
+ name: encodeToolName(toolNamespace(tool), toolBaseName(tool, tool.type)),
367
438
  description: tool.description,
368
439
  parameters: normalizeJsonSchemaObject(tool.parameters || tool.input_schema),
369
440
  strict: tool.strict,
@@ -373,6 +444,40 @@ function normalizeTool(tool) {
373
444
  return null;
374
445
  }
375
446
 
447
+ function expandNamespaceTool(tool) {
448
+ if (!isObject(tool) || tool.type !== 'namespace') return [tool];
449
+ const namespace = tool.name || tool.namespace || tool.server_label;
450
+ const children = Array.isArray(tool.tools) ? tool.tools : [];
451
+ return children
452
+ .filter(isObject)
453
+ .map((child) => {
454
+ if (child.type === 'function' && isObject(child.function)) {
455
+ return {
456
+ ...child,
457
+ namespace: child.namespace || namespace,
458
+ function: {
459
+ ...child.function,
460
+ namespace: child.function.namespace || child.namespace || namespace,
461
+ },
462
+ };
463
+ }
464
+ return {
465
+ ...child,
466
+ namespace: child.namespace || namespace,
467
+ };
468
+ });
469
+ }
470
+
471
+ function expandTools(tools) {
472
+ if (!Array.isArray(tools)) return [];
473
+ return tools.flatMap(expandNamespaceTool);
474
+ }
475
+
476
+ function normalizeTools(tools) {
477
+ const normalized = expandTools(tools).map(normalizeTool).filter(Boolean);
478
+ return normalized.length ? normalized : undefined;
479
+ }
480
+
376
481
  function normalizeJsonSchemaObject(schema) {
377
482
  if (!isObject(schema)) {
378
483
  return { type: 'object', properties: {}, additionalProperties: true };
@@ -405,7 +510,7 @@ function normalizeToolChoice(toolChoice) {
405
510
  if (toolChoice.type === 'function' && toolChoice.name) {
406
511
  return {
407
512
  type: 'function',
408
- function: { name: sanitizeFunctionName(toolChoice.name) },
513
+ function: { name: encodeToolName(toolNamespace(toolChoice), toolChoice.name) },
409
514
  };
410
515
  }
411
516
  if (toolChoice.type === 'function' && isObject(toolChoice.function)) {
@@ -413,7 +518,7 @@ function normalizeToolChoice(toolChoice) {
413
518
  ...toolChoice,
414
519
  function: {
415
520
  ...toolChoice.function,
416
- name: sanitizeFunctionName(toolChoice.function.name),
521
+ name: encodeToolName(toolNamespace(toolChoice), toolChoice.function.name),
417
522
  },
418
523
  };
419
524
  }
@@ -424,7 +529,8 @@ function normalizeToolChoice(toolChoice) {
424
529
  return {
425
530
  type: 'function',
426
531
  function: {
427
- name: sanitizeFunctionName(
532
+ name: encodeToolName(
533
+ toolNamespace(toolChoice),
428
534
  toolChoice.name ||
429
535
  toolChoice.tool_name ||
430
536
  toolChoice.toolName ||
@@ -437,6 +543,45 @@ function normalizeToolChoice(toolChoice) {
437
543
  return toolChoice;
438
544
  }
439
545
 
546
+ function toolChoiceEntryName(entry) {
547
+ if (!isObject(entry)) return '';
548
+ if (entry.type === 'function' && entry.name) return encodeToolName(toolNamespace(entry), entry.name);
549
+ if (entry.type === 'function' && isObject(entry.function)) {
550
+ return encodeToolName(toolNamespace(entry), entry.function.name);
551
+ }
552
+ return encodeToolName(
553
+ toolNamespace(entry),
554
+ entry.name ||
555
+ entry.tool_name ||
556
+ entry.toolName ||
557
+ entry.server_label ||
558
+ entry.type,
559
+ );
560
+ }
561
+
562
+ function allowedToolNames(toolChoice) {
563
+ if (!isObject(toolChoice) || toolChoice.type !== 'allowed_tools') return null;
564
+ const entries = Array.isArray(toolChoice.tools)
565
+ ? toolChoice.tools
566
+ : Array.isArray(toolChoice.allowed_tools)
567
+ ? toolChoice.allowed_tools
568
+ : Array.isArray(toolChoice.names)
569
+ ? toolChoice.names.map((name) => ({ type: 'function', name }))
570
+ : [];
571
+ const names = entries.map(toolChoiceEntryName).filter(Boolean);
572
+ return names.length ? new Set(names) : null;
573
+ }
574
+
575
+ function applyAllowedTools(tools, toolChoice) {
576
+ const allowed = allowedToolNames(toolChoice);
577
+ if (!allowed || !Array.isArray(tools)) return tools;
578
+ const filtered = tools.filter((tool) => {
579
+ const name = tool?.type === 'function' ? tool.function?.name : '';
580
+ return !name || allowed.has(name);
581
+ });
582
+ return filtered.length ? filtered : undefined;
583
+ }
584
+
440
585
  function unwrapJsonString(value) {
441
586
  if (typeof value !== 'string') return value;
442
587
  const trimmed = value.trim();
@@ -471,8 +616,7 @@ function coerceValueForSchema(value, schema) {
471
616
 
472
617
  function buildToolSchemas(tools) {
473
618
  const schemas = new Map();
474
- if (!Array.isArray(tools)) return schemas;
475
- for (const tool of tools) {
619
+ for (const tool of expandTools(tools)) {
476
620
  const normalizedTool = normalizeTool(tool);
477
621
  const fn = normalizedTool?.type === 'function' ? normalizedTool.function : null;
478
622
  if (!fn?.name) continue;
@@ -481,6 +625,92 @@ function buildToolSchemas(tools) {
481
625
  return schemas;
482
626
  }
483
627
 
628
+ function buildToolNames(tools) {
629
+ const names = new Map();
630
+ for (const tool of expandTools(tools)) {
631
+ const namespace = toolNamespace(tool);
632
+ if (!namespace) continue;
633
+ const normalizedTool = normalizeTool(tool);
634
+ const fn = normalizedTool?.type === 'function' ? normalizedTool.function : null;
635
+ if (!fn?.name) continue;
636
+ names.set(fn.name, {
637
+ namespace: sanitizeFunctionName(namespace, 'namespace'),
638
+ name: sanitizeFunctionName(toolBaseName(tool, tool.type)),
639
+ });
640
+ }
641
+ return names;
642
+ }
643
+
644
+ function simplifyJsonSchemaDescriptions(schema) {
645
+ if (Array.isArray(schema)) return schema.map(simplifyJsonSchemaDescriptions);
646
+ if (!isObject(schema)) return schema;
647
+ const next = {};
648
+ for (const [key, value] of Object.entries(schema)) {
649
+ if (key === 'description' && typeof value === 'string') {
650
+ const description = shortenText(value, DEEPSEEK_SCHEMA_DESCRIPTION_CHARS);
651
+ if (description) next.description = description;
652
+ continue;
653
+ }
654
+ next[key] = isObject(value) || Array.isArray(value) ? simplifyJsonSchemaDescriptions(value) : value;
655
+ }
656
+ return next;
657
+ }
658
+
659
+ function readableToolName(name) {
660
+ return compactText(String(name || '').replace(/[_-]+/g, ' '));
661
+ }
662
+
663
+ function requiredParametersText(parameters) {
664
+ const required = Array.isArray(parameters?.required) ? parameters.required.filter((name) => typeof name === 'string') : [];
665
+ return required.length ? ` Required: ${required.join(', ')}.` : '';
666
+ }
667
+
668
+ function defaultDeepSeekToolDescription(name) {
669
+ const readable = readableToolName(name);
670
+ return compactText(`Call ${readable || name || 'this function'} when needed.`);
671
+ }
672
+
673
+ function simplifyToolForDeepSeek(tool) {
674
+ if (tool?.type !== 'function' || !isObject(tool.function)) return tool;
675
+ const fn = tool.function;
676
+ const parameters = simplifyJsonSchemaDescriptions(fn.parameters);
677
+ const requiredText = requiredParametersText(parameters);
678
+ const descriptionBudget = Math.max(32, DEEPSEEK_TOOL_DESCRIPTION_CHARS - requiredText.length);
679
+ const baseDescription = shortenText(fn.description, descriptionBudget) || defaultDeepSeekToolDescription(fn.name);
680
+ const description = shortenText(`${baseDescription}${requiredText}`, DEEPSEEK_TOOL_DESCRIPTION_CHARS);
681
+ return {
682
+ ...tool,
683
+ function: omitUndefined({
684
+ ...fn,
685
+ description,
686
+ parameters,
687
+ }),
688
+ };
689
+ }
690
+
691
+ function hasDeepSeekToolInstructions(messages) {
692
+ return messages.some((message) => message?.role === 'system' && toText(message.content).includes(DEEPSEEK_TOOL_INSTRUCTIONS_MARKER));
693
+ }
694
+
695
+ function addDeepSeekToolInstructions(messages, tools) {
696
+ if (!Array.isArray(tools) || !tools.length || hasDeepSeekToolInstructions(messages)) return messages;
697
+ if (!messages.length || messages[0]?.role !== 'system') {
698
+ return [{ role: 'system', content: DEEPSEEK_TOOL_INSTRUCTIONS }, ...messages];
699
+ }
700
+ return [
701
+ {
702
+ ...messages[0],
703
+ content: `${toText(messages[0].content)}\n\n${DEEPSEEK_TOOL_INSTRUCTIONS}`,
704
+ },
705
+ ...messages.slice(1),
706
+ ];
707
+ }
708
+
709
+ function adaptToolsForProvider(tools, provider) {
710
+ if (provider !== 'deepseek' || !Array.isArray(tools)) return tools;
711
+ return tools.map(simplifyToolForDeepSeek);
712
+ }
713
+
484
714
  function normalizeToolCallArguments(name, argumentsText, toolSchema) {
485
715
  if (!argumentsText) return '';
486
716
  if (!isObject(toolSchema) || !isObject(toolSchema.properties)) return argumentsText;
@@ -505,7 +735,26 @@ function normalizeToolCallArguments(name, argumentsText, toolSchema) {
505
735
 
506
736
  function normalizeFunctionCallItemArguments(item, toolSchemas) {
507
737
  if (!item || item.type !== 'function_call') return;
508
- item.arguments = normalizeToolCallArguments(item.name, item.arguments, toolSchemas?.get(item.name));
738
+ const encodedName = encodeToolName(item.namespace, item.name);
739
+ item.arguments = normalizeToolCallArguments(encodedName, item.arguments, toolSchemas?.get(encodedName));
740
+ }
741
+
742
+ function sanitizeToolCallsForChatCompletion(toolCalls) {
743
+ return toolCalls.map((toolCall) => {
744
+ if (!isObject(toolCall)) return toolCall;
745
+ const fn = isObject(toolCall.function) ? toolCall.function : {};
746
+ const { namespace, ...functionFields } = fn;
747
+ const name = fn.name || toolCall.name || 'tool_call';
748
+ const toolCallNamespace = toolCall.namespace || namespace || '';
749
+ return {
750
+ id: toolCall.id,
751
+ type: toolCall.type || 'function',
752
+ function: {
753
+ ...functionFields,
754
+ name: encodeToolName(toolCallNamespace, name),
755
+ },
756
+ };
757
+ });
509
758
  }
510
759
 
511
760
  function sanitizeMessageForChatCompletion(message, provider = 'generic') {
@@ -515,7 +764,7 @@ function sanitizeMessageForChatCompletion(message, provider = 'generic') {
515
764
  content: contentToChatContent(message.content),
516
765
  };
517
766
  if (message.name !== undefined) sanitized.name = message.name;
518
- if (Array.isArray(message.tool_calls)) sanitized.tool_calls = message.tool_calls;
767
+ if (Array.isArray(message.tool_calls)) sanitized.tool_calls = sanitizeToolCallsForChatCompletion(message.tool_calls);
519
768
  if (message.tool_call_id !== undefined) sanitized.tool_call_id = message.tool_call_id;
520
769
  if (provider === 'deepseek' && message.role === 'assistant' && typeof message.reasoning_content === 'string') {
521
770
  sanitized.reasoning_content = message.reasoning_content;
@@ -543,32 +792,8 @@ function normalizeOutputTextPart(text, annotations = []) {
543
792
  };
544
793
  }
545
794
 
546
- function normalizeReasoningSummaryText(text) {
547
- const value = String(text ?? '').replace(/\r\n?/g, '\n');
548
- if (!value) return '';
549
- const plain = value
550
- .split('\n')
551
- .map((line) => line
552
- .replace(/^[ \t]{0,3}(?:`{3,}|~{3,}).*$/, '')
553
- .replace(/^[ \t]{0,3}#{1,6}[ \t]+/, '')
554
- .replace(/^[ \t]{0,3}>[ \t]?/, '')
555
- .replace(/^[ \t]*[-*+][ \t]+(?:\[[ xX]\][ \t]+)?/, '\u2022 ')
556
- .replace(/^[ \t]*(\d+)\.[ \t]+/, '$1) ')
557
- .replace(/!\[([^\]]*)\]\([^)]+\)/g, '$1')
558
- .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
559
- .replace(/`([^`]*)`/g, '$1')
560
- .replace(/(\*\*|__)([^*_]+)\1/g, '$2')
561
- .replace(/(\*|_)([^*_]+)\1/g, '$2')
562
- .replace(/[*_`~]/g, '')
563
- .replace(/\\([\\`*_{}[\]()#+\-.!>])/g, '$1')
564
- .trimEnd())
565
- .join('\n');
566
- return plain.replace(/^\n+/, '').trimEnd();
567
- }
568
-
569
795
  function reasoningSummaryText(text) {
570
- const summary = normalizeReasoningSummaryText(text);
571
- return summary ? `**Reasoning**\n\n${summary}` : '';
796
+ return reasoningDisplayText(text);
572
797
  }
573
798
 
574
799
  function normalizeSummaryTextPart(text) {
@@ -710,7 +935,7 @@ export function toChatCompletionsRequest(normalized, overrides = {}) {
710
935
  messages.push({ role: 'system', content: normalized.instructions });
711
936
  }
712
937
  messages.push(...normalized.messages);
713
- const tools = Array.isArray(normalized.tools) ? normalized.tools.map(normalizeTool).filter(Boolean) : undefined;
938
+ const tools = applyAllowedTools(normalizeTools(normalized.tools), normalized.tool_choice);
714
939
  const request = {
715
940
  model: overrides.model || normalized.model,
716
941
  messages,
@@ -757,16 +982,14 @@ export function assistantMessageFromResponseOutput(output) {
757
982
  id: item.call_id || item.id,
758
983
  type: 'function',
759
984
  function: {
760
- name: item.name,
985
+ name: encodeToolName(item.namespace, item.name),
761
986
  arguments: item.arguments || '',
762
987
  },
763
988
  }));
764
989
  if (toolCalls.length) assistant.tool_calls = toolCalls;
765
990
  const reasoningContent = reasoningItems
766
- .map((item) => item.content || [])
767
- .flat()
768
- .filter((part) => part.type === 'reasoning_text')
769
- .map((part) => part.text)
991
+ .map((item) => reasoningTextFromItem(item))
992
+ .filter(Boolean)
770
993
  .join('');
771
994
  if (reasoningContent) assistant.reasoning_content = reasoningContent;
772
995
  return assistant;
@@ -820,6 +1043,8 @@ export function toProviderChatCompletionsRequest(chatRequest, config = {}) {
820
1043
  if (provider === 'deepseek') {
821
1044
  delete request.reasoning_effort;
822
1045
  delete request.parallel_tool_calls;
1046
+ request.tools = adaptToolsForProvider(request.tools, provider);
1047
+ request.messages = addDeepSeekToolInstructions(request.messages, request.tools);
823
1048
  if (request.user !== undefined) {
824
1049
  request.user_id = request.user;
825
1050
  delete request.user;
@@ -955,6 +1180,7 @@ export function convertChatCompletionToResponses({ completion, model, previousRe
955
1180
  const message = choice?.message || {};
956
1181
  const content = chatContentToResponseOutputParts(message.content);
957
1182
  const toolSchemas = buildToolSchemas(normalized?.tools);
1183
+ const toolNames = buildToolNames(normalized?.tools);
958
1184
  const output = [];
959
1185
 
960
1186
  if (content.length || message.tool_calls?.length) {
@@ -971,26 +1197,29 @@ export function convertChatCompletionToResponses({ completion, model, previousRe
971
1197
  if (Array.isArray(message.tool_calls)) {
972
1198
  for (const toolCall of message.tool_calls) {
973
1199
  const callId = toolCall.id || generateId('call');
974
- const item = {
1200
+ const decoded = decodedToolName(toolCall.function?.name, toolNames);
1201
+ const item = omitUndefined({
975
1202
  type: 'function_call',
976
1203
  id: callId,
977
1204
  call_id: callId,
978
- name: toolCall.function?.name,
1205
+ name: decoded.name,
1206
+ namespace: decoded.namespace,
979
1207
  arguments: toolCall.function?.arguments || '',
980
1208
  status: 'completed',
981
- };
1209
+ });
982
1210
  normalizeFunctionCallItemArguments(item, toolSchemas);
983
1211
  output.push(item);
984
1212
  }
985
1213
  }
986
1214
 
987
1215
  if (message.reasoning_content) {
988
- const reasoningText = String(message.reasoning_content);
1216
+ const reasoningText = normalizeReasoningContent(message.reasoning_content);
989
1217
  output.unshift({
990
1218
  type: 'reasoning',
991
1219
  id: generateId('rs'),
992
1220
  summary: [normalizeSummaryTextPart(reasoningSummaryText(reasoningText))],
993
- content: [normalizeReasoningTextPart(reasoningText)],
1221
+ content: [],
1222
+ reasoning_content: reasoningText,
994
1223
  encrypted_content: null,
995
1224
  status: 'completed',
996
1225
  });
@@ -1048,6 +1277,7 @@ export class ResponsesStreamMapper {
1048
1277
  this.reasoningItemAdded = false;
1049
1278
  this.streamedReasoningSummaryText = '';
1050
1279
  this.toolSchemas = buildToolSchemas(normalized?.tools);
1280
+ this.toolNames = buildToolNames(normalized?.tools);
1051
1281
  }
1052
1282
 
1053
1283
  nextSequence() {
@@ -1114,7 +1344,7 @@ export class ResponsesStreamMapper {
1114
1344
  type: 'reasoning',
1115
1345
  status: 'in_progress',
1116
1346
  summary: [],
1117
- content: [normalizeReasoningTextPart('')],
1347
+ content: this.emitReasoningText ? [normalizeReasoningTextPart('')] : [],
1118
1348
  encrypted_content: null,
1119
1349
  };
1120
1350
  this.output.push(this.reasoningItem);
@@ -1133,6 +1363,7 @@ export class ResponsesStreamMapper {
1133
1363
 
1134
1364
  ensureReasoningContentPart(events) {
1135
1365
  if (!this.emitReasoningText || this.reasoningContentAdded || !this.reasoningItem) return;
1366
+ if (!this.reasoningItem.content[0]) this.reasoningItem.content[0] = normalizeReasoningTextPart('');
1136
1367
  this.reasoningContentAdded = true;
1137
1368
  events.push({
1138
1369
  type: 'response.content_part.added',
@@ -1144,6 +1375,19 @@ export class ResponsesStreamMapper {
1144
1375
  });
1145
1376
  }
1146
1377
 
1378
+ syncReasoningItemContent() {
1379
+ if (!this.reasoningItem) return;
1380
+ const reasoningText = normalizeReasoningContent(this.reasoningText);
1381
+ if (this.emitReasoningText) {
1382
+ if (!this.reasoningItem.content[0]) this.reasoningItem.content[0] = normalizeReasoningTextPart('');
1383
+ this.reasoningItem.content[0].text = reasoningText;
1384
+ } else {
1385
+ this.reasoningItem.content = [];
1386
+ }
1387
+ if (reasoningText) this.reasoningItem.reasoning_content = reasoningText;
1388
+ else delete this.reasoningItem.reasoning_content;
1389
+ }
1390
+
1147
1391
  appendReasoningSummaryDelta(events) {
1148
1392
  if (!this.emitReasoningSummary || !this.reasoningItem) return;
1149
1393
  if (!this.reasoningSummaryAdded) {
@@ -1234,7 +1478,7 @@ export class ResponsesStreamMapper {
1234
1478
  const events = [];
1235
1479
  const added = this.ensureReasoningItem();
1236
1480
  if (added) events.push(added);
1237
- this.reasoningItem.content[0].text = this.reasoningText;
1481
+ this.syncReasoningItemContent();
1238
1482
  this.appendReasoningSummaryDelta(events);
1239
1483
  return events;
1240
1484
  }
@@ -1245,12 +1489,12 @@ export class ResponsesStreamMapper {
1245
1489
  type: 'reasoning',
1246
1490
  status: 'in_progress',
1247
1491
  summary: [],
1248
- content: [normalizeReasoningTextPart('')],
1492
+ content: this.emitReasoningText ? [normalizeReasoningTextPart('')] : [],
1249
1493
  encrypted_content: null,
1250
1494
  };
1251
1495
  this.output.push(this.reasoningItem);
1252
1496
  }
1253
- this.reasoningItem.content[0].text = this.reasoningText;
1497
+ this.syncReasoningItemContent();
1254
1498
  return [];
1255
1499
  }
1256
1500
 
@@ -1258,7 +1502,7 @@ export class ResponsesStreamMapper {
1258
1502
  const added = this.ensureReasoningItem();
1259
1503
  if (added) events.push(added);
1260
1504
  this.ensureReasoningContentPart(events);
1261
- this.reasoningItem.content[0].text = this.reasoningText;
1505
+ this.syncReasoningItemContent();
1262
1506
  this.appendReasoningSummaryDelta(events);
1263
1507
  if (this.emitReasoningText) {
1264
1508
  events.push({
@@ -1284,13 +1528,13 @@ export class ResponsesStreamMapper {
1284
1528
  type: 'function_call',
1285
1529
  status: 'in_progress',
1286
1530
  call_id: callId,
1287
- name: toolCall.function?.name || '',
1531
+ ...decodedToolName(toolCall.function?.name, this.toolNames),
1288
1532
  arguments: '',
1289
1533
  };
1290
1534
  this.toolItems.set(index, item);
1291
1535
  this.output.push(item);
1292
1536
  }
1293
- if (toolCall.function?.name) item.name = toolCall.function.name;
1537
+ if (toolCall.function?.name) Object.assign(item, decodedToolName(toolCall.function.name, this.toolNames));
1294
1538
  item.arguments += toolCall.function?.arguments || '';
1295
1539
  return [];
1296
1540
  }
@@ -1308,7 +1552,7 @@ export class ResponsesStreamMapper {
1308
1552
  type: 'function_call',
1309
1553
  status: 'in_progress',
1310
1554
  call_id: callId,
1311
- name: toolCall.function?.name || '',
1555
+ ...decodedToolName(toolCall.function?.name, this.toolNames),
1312
1556
  arguments: '',
1313
1557
  };
1314
1558
  this.toolItems.set(index, item);
@@ -1320,7 +1564,7 @@ export class ResponsesStreamMapper {
1320
1564
  item: snapshotResponseItem(item),
1321
1565
  });
1322
1566
  }
1323
- if (toolCall.function?.name) item.name = toolCall.function.name;
1567
+ if (toolCall.function?.name) Object.assign(item, decodedToolName(toolCall.function.name, this.toolNames));
1324
1568
  const delta = toolCall.function?.arguments || '';
1325
1569
  item.arguments += delta;
1326
1570
  if (delta) {
@@ -1347,7 +1591,7 @@ export class ResponsesStreamMapper {
1347
1591
 
1348
1592
  if (this.reasoningItem) {
1349
1593
  this.reasoningItem.status = status;
1350
- this.reasoningItem.content[0].text = this.reasoningText;
1594
+ this.syncReasoningItemContent();
1351
1595
  }
1352
1596
  if (this.messageItem) {
1353
1597
  this.messageItem.status = status;
@@ -1421,7 +1665,8 @@ export class ResponsesStreamMapper {
1421
1665
 
1422
1666
  for (const item of this.toolItems.values()) {
1423
1667
  item.status = status;
1424
- item.arguments = normalizeToolCallArguments(item.name, item.arguments, this.toolSchemas.get(item.name));
1668
+ const encodedName = encodeToolName(item.namespace, item.name);
1669
+ item.arguments = normalizeToolCallArguments(encodedName, item.arguments, this.toolSchemas.get(encodedName));
1425
1670
  const outputIndex = this.output.indexOf(item);
1426
1671
  events.push({
1427
1672
  type: 'response.output_item.added',
@@ -1487,7 +1732,7 @@ export class ResponsesStreamMapper {
1487
1732
  this.reasoningSummaryAdded = true;
1488
1733
  this.reasoningItem.summary.push(normalizeSummaryTextPart(reasoningSummaryText(this.reasoningText)));
1489
1734
  }
1490
- this.reasoningItem.content[0].text = this.reasoningText;
1735
+ this.syncReasoningItemContent();
1491
1736
  if (this.reasoningItem.summary[0]) {
1492
1737
  this.reasoningItem.summary[0].text = reasoningSummaryText(this.reasoningText);
1493
1738
  }
@@ -1587,7 +1832,7 @@ export class ResponsesStreamMapper {
1587
1832
  ...this.reasoningItem,
1588
1833
  status: 'in_progress',
1589
1834
  summary: [],
1590
- content: [normalizeReasoningTextPart('')],
1835
+ content: this.emitReasoningText ? [normalizeReasoningTextPart('')] : [],
1591
1836
  }),
1592
1837
  });
1593
1838
  }
@@ -1640,7 +1885,7 @@ export class ResponsesStreamMapper {
1640
1885
  this.reasoningItem.summary[0].text = summaryText;
1641
1886
  }
1642
1887
  this.reasoningItem.status = status;
1643
- this.reasoningItem.content[0].text = this.reasoningText;
1888
+ this.syncReasoningItemContent();
1644
1889
  return events;
1645
1890
  }
1646
1891
 
@@ -1648,7 +1893,7 @@ export class ResponsesStreamMapper {
1648
1893
  if (!this.reasoningItem || this.reasoningItemDone) return [];
1649
1894
  this.reasoningItemDone = true;
1650
1895
  this.reasoningItem.status = status;
1651
- this.reasoningItem.content[0].text = this.reasoningText;
1896
+ this.syncReasoningItemContent();
1652
1897
  const summaryText = reasoningSummaryText(this.reasoningText);
1653
1898
  if (this.emitReasoningSummary && this.reasoningText && !this.reasoningSummaryAdded) {
1654
1899
  this.reasoningSummaryAdded = true;