@galaxy-yearn/codex-deepseek-gateway 0.1.3 → 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/README.md +86 -157
- package/bin/codex-deepseek-gateway.js +20 -9
- package/config/gateway.example.json +1 -17
- package/package.json +2 -2
- package/src/codex-launch.js +241 -0
- package/src/codex-sessions.js +93 -189
- package/src/config.js +1 -1
- package/src/firecrawl.js +2 -2
- package/src/protocol.js +331 -86
- package/src/server.js +125 -15
- package/src/tavily.js +3 -3
- package/src/web-search-emulator.js +104 -23
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
|
|
141
|
-
item
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
if (typeof item.text === 'string')
|
|
176
|
-
if (typeof item.content === 'string')
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
355
|
-
function: {
|
|
356
|
-
...
|
|
357
|
-
name:
|
|
358
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
767
|
-
.
|
|
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
|
|
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:
|
|
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 =
|
|
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: [
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
1896
|
+
this.syncReasoningItemContent();
|
|
1652
1897
|
const summaryText = reasoningSummaryText(this.reasoningText);
|
|
1653
1898
|
if (this.emitReasoningSummary && this.reasoningText && !this.reasoningSummaryAdded) {
|
|
1654
1899
|
this.reasoningSummaryAdded = true;
|