aicodeswitch 4.0.4 → 5.0.0
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 +6 -5
- package/UPGRADE.md +5 -6
- package/dist/server/coding-plan.js +94 -0
- package/dist/server/config-managed-fields.js +1 -0
- package/dist/server/conversions/compact.js +613 -0
- package/dist/server/conversions/detector.js +70 -0
- package/dist/server/conversions/index.js +285 -0
- package/dist/server/conversions/pairs/claude-completions/request.js +167 -0
- package/dist/server/conversions/pairs/claude-completions/response.js +56 -0
- package/dist/server/conversions/pairs/claude-completions/streaming.js +259 -0
- package/dist/server/conversions/pairs/claude-gemini/request.js +130 -0
- package/dist/server/conversions/pairs/claude-gemini/response.js +65 -0
- package/dist/server/conversions/pairs/claude-gemini/streaming.js +199 -0
- package/dist/server/conversions/pairs/claude-responses/request.js +190 -0
- package/dist/server/conversions/pairs/claude-responses/response.js +89 -0
- package/dist/server/conversions/pairs/claude-responses/streaming.js +266 -0
- package/dist/server/conversions/pairs/completions-claude/request.js +111 -0
- package/dist/server/conversions/pairs/completions-claude/response.js +67 -0
- package/dist/server/conversions/pairs/completions-claude/streaming.js +165 -0
- package/dist/server/conversions/pairs/completions-gemini/request.js +169 -0
- package/dist/server/conversions/pairs/completions-gemini/response.js +70 -0
- package/dist/server/conversions/pairs/completions-gemini/streaming.js +132 -0
- package/dist/server/conversions/pairs/completions-responses/request.js +149 -0
- package/dist/server/conversions/pairs/completions-responses/response.js +74 -0
- package/dist/server/conversions/pairs/completions-responses/streaming.js +189 -0
- package/dist/server/conversions/pairs/gemini-claude/request.js +118 -0
- package/dist/server/conversions/pairs/gemini-claude/response.js +45 -0
- package/dist/server/conversions/pairs/gemini-claude/streaming.js +146 -0
- package/dist/server/conversions/pairs/gemini-completions/request.js +151 -0
- package/dist/server/conversions/pairs/gemini-completions/response.js +54 -0
- package/dist/server/conversions/pairs/gemini-completions/streaming.js +108 -0
- package/dist/server/conversions/pairs/gemini-responses/request.js +18 -0
- package/dist/server/conversions/pairs/gemini-responses/response.js +18 -0
- package/dist/server/conversions/pairs/gemini-responses/streaming.js +43 -0
- package/dist/server/conversions/pairs/responses-claude/request.js +155 -0
- package/dist/server/conversions/pairs/responses-claude/response.js +70 -0
- package/dist/server/conversions/pairs/responses-claude/streaming.js +345 -0
- package/dist/server/conversions/pairs/responses-completions/request.js +207 -0
- package/dist/server/conversions/pairs/responses-completions/response.js +96 -0
- package/dist/server/conversions/pairs/responses-completions/streaming.js +344 -0
- package/dist/server/conversions/pairs/responses-gemini/request.js +18 -0
- package/dist/server/conversions/pairs/responses-gemini/response.js +18 -0
- package/dist/server/conversions/pairs/responses-gemini/streaming.js +43 -0
- package/dist/server/conversions/pairs/responses-responses/request.js +115 -0
- package/dist/server/conversions/pipeline.js +296 -0
- package/dist/server/conversions/stream-converter-adapter.js +49 -0
- package/dist/server/conversions/thinking/effort.js +61 -0
- package/dist/server/conversions/thinking/mapper.js +59 -0
- package/dist/server/conversions/thinking/providers.js +76 -0
- package/dist/server/conversions/types.js +5 -0
- package/dist/server/conversions/url-normalizer.js +58 -0
- package/dist/server/conversions/utils/format-mappers.js +57 -0
- package/dist/server/conversions/utils/id.js +33 -0
- package/dist/server/conversions/utils/stop-reasons.js +95 -0
- package/dist/server/conversions/utils/streaming-helpers.js +59 -0
- package/dist/server/conversions/utils/tool-schema.js +169 -0
- package/dist/server/conversions/utils/usage.js +82 -0
- package/dist/server/fs-database.js +465 -135
- package/dist/server/main.js +93 -33
- package/dist/server/original-config-reader.js +1 -1
- package/dist/server/proxy-server.js +887 -633
- package/dist/server/transformers/chunk-collector.js +5 -1
- package/dist/server/transformers/streaming.js +6 -3235
- package/dist/server/type-migration.js +2 -3
- package/dist/server/utils.js +5 -0
- package/dist/ui/assets/{index-C7G0whng.css → index-BHR12ImE.css} +1 -1
- package/dist/ui/assets/index-DjdBW1yu.js +517 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/server/transformers/transformers.js +0 -1767
- package/dist/ui/assets/index-Dl-B9pXM.js +0 -514
- package/schema/claude.schema.md +0 -946
- package/schema/deepseek-chat.schema.md +0 -799
- package/schema/gemini.schema.md +0 -1408
- package/schema/openai-chat-completions.schema.md +0 -1088
- package/schema/openai-responses.schema.md +0 -226196
- package/schema/stream.md +0 -2592
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Responses API → OpenAI Chat Completions API request conversion.
|
|
4
|
+
*
|
|
5
|
+
* Converts a Responses API request body into a Chat Completions request body.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.responsesToCompletions = responsesToCompletions;
|
|
9
|
+
const effort_js_1 = require("../../thinking/effort.js");
|
|
10
|
+
const id_js_1 = require("../../utils/id.js");
|
|
11
|
+
/**
|
|
12
|
+
* Convert an OpenAI Responses API request body to a Chat Completions request body.
|
|
13
|
+
*/
|
|
14
|
+
function responsesToCompletions(body) {
|
|
15
|
+
var _a, _b;
|
|
16
|
+
const messages = [];
|
|
17
|
+
// --- instructions -> system message ---
|
|
18
|
+
if (body.instructions) {
|
|
19
|
+
messages.push({ role: 'system', content: body.instructions });
|
|
20
|
+
}
|
|
21
|
+
// --- input -> messages ---
|
|
22
|
+
if (typeof body.input === 'string') {
|
|
23
|
+
messages.push({ role: 'user', content: body.input });
|
|
24
|
+
}
|
|
25
|
+
else if (Array.isArray(body.input)) {
|
|
26
|
+
// We accumulate items that belong to the same assistant message
|
|
27
|
+
// (e.g. reasoning + content + function_calls need to merge)
|
|
28
|
+
let pendingAssistantMessage = null;
|
|
29
|
+
let pendingToolCalls = [];
|
|
30
|
+
let pendingReasoningContent;
|
|
31
|
+
for (const item of body.input) {
|
|
32
|
+
if (item.type === 'message') {
|
|
33
|
+
// Flush any pending assistant message before processing a new message
|
|
34
|
+
flushPendingAssistant(messages, pendingAssistantMessage, pendingToolCalls, pendingReasoningContent);
|
|
35
|
+
pendingAssistantMessage = null;
|
|
36
|
+
pendingToolCalls = [];
|
|
37
|
+
pendingReasoningContent = undefined;
|
|
38
|
+
if (item.role === 'system' || item.role === 'developer') {
|
|
39
|
+
// Merge system/developer messages into the system message at head
|
|
40
|
+
const text = extractContent(item.content, item.role === 'assistant' ? 'output_text' : 'input_text');
|
|
41
|
+
if (text) {
|
|
42
|
+
const existingSystem = messages.find((m) => m.role === 'system');
|
|
43
|
+
if (existingSystem) {
|
|
44
|
+
existingSystem.content += '\n' + text;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
messages.unshift({ role: 'system', content: text });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (item.role === 'user') {
|
|
52
|
+
const text = extractContent(item.content, 'input_text');
|
|
53
|
+
messages.push({ role: 'user', content: text || '' });
|
|
54
|
+
}
|
|
55
|
+
else if (item.role === 'assistant') {
|
|
56
|
+
const text = extractContent(item.content, 'output_text');
|
|
57
|
+
pendingAssistantMessage = { role: 'assistant', content: text || null };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (item.type === 'function_call') {
|
|
61
|
+
// Accumulate as tool_calls on the nearest assistant message
|
|
62
|
+
if (!pendingAssistantMessage) {
|
|
63
|
+
pendingAssistantMessage = { role: 'assistant', content: null };
|
|
64
|
+
}
|
|
65
|
+
pendingToolCalls.push({
|
|
66
|
+
id: item.call_id || (0, id_js_1.generateCallId)(),
|
|
67
|
+
type: 'function',
|
|
68
|
+
function: {
|
|
69
|
+
name: item.name || '',
|
|
70
|
+
arguments: item.arguments || '{}',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else if (item.type === 'function_call_output') {
|
|
75
|
+
// Flush any pending assistant message first
|
|
76
|
+
flushPendingAssistant(messages, pendingAssistantMessage, pendingToolCalls, pendingReasoningContent);
|
|
77
|
+
pendingAssistantMessage = null;
|
|
78
|
+
pendingToolCalls = [];
|
|
79
|
+
pendingReasoningContent = undefined;
|
|
80
|
+
messages.push({
|
|
81
|
+
role: 'tool',
|
|
82
|
+
tool_call_id: item.call_id,
|
|
83
|
+
content: item.output || '',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else if (item.type === 'reasoning') {
|
|
87
|
+
if (!pendingAssistantMessage) {
|
|
88
|
+
pendingAssistantMessage = { role: 'assistant', content: null };
|
|
89
|
+
}
|
|
90
|
+
const summaryTexts = Array.isArray(item.summary)
|
|
91
|
+
? item.summary.map((s) => s.text || '').filter(Boolean)
|
|
92
|
+
: [];
|
|
93
|
+
if (summaryTexts.length > 0) {
|
|
94
|
+
pendingReasoningContent = summaryTexts.join('\n');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Flush any remaining pending assistant message
|
|
99
|
+
flushPendingAssistant(messages, pendingAssistantMessage, pendingToolCalls, pendingReasoningContent);
|
|
100
|
+
}
|
|
101
|
+
// --- Build result ---
|
|
102
|
+
const result = {
|
|
103
|
+
model: body.model,
|
|
104
|
+
messages,
|
|
105
|
+
stream: (_a = body.stream) !== null && _a !== void 0 ? _a : false,
|
|
106
|
+
};
|
|
107
|
+
// --- Parameter mapping ---
|
|
108
|
+
if (body.max_output_tokens !== undefined) {
|
|
109
|
+
if (body.model && (0, effort_js_1.isOSeriesModel)(body.model)) {
|
|
110
|
+
result.max_completion_tokens = body.max_output_tokens;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
result.max_tokens = body.max_output_tokens;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (body.temperature !== undefined)
|
|
117
|
+
result.temperature = body.temperature;
|
|
118
|
+
if (body.top_p !== undefined)
|
|
119
|
+
result.top_p = body.top_p;
|
|
120
|
+
// --- Reasoning effort ---
|
|
121
|
+
if ((_b = body.reasoning) === null || _b === void 0 ? void 0 : _b.effort) {
|
|
122
|
+
result.reasoning_effort = body.reasoning.effort;
|
|
123
|
+
}
|
|
124
|
+
// --- Tools ---
|
|
125
|
+
// 仅转换标准 function 类型工具,过滤掉 OpenAI 私有扩展类型
|
|
126
|
+
// (custom/tool_search/web_search/file_search/code_interpreter 等)
|
|
127
|
+
// 这些非标准类型没有 name 字段,直接转换会导致上游 API 返回参数错误
|
|
128
|
+
const functionTools = (body.tools || []).filter((t) => t.type === 'function');
|
|
129
|
+
if (functionTools.length > 0) {
|
|
130
|
+
result.tools = functionTools.map((tool) => ({
|
|
131
|
+
type: 'function',
|
|
132
|
+
function: {
|
|
133
|
+
name: tool.name,
|
|
134
|
+
description: tool.description || '',
|
|
135
|
+
parameters: tool.parameters || {},
|
|
136
|
+
},
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
// --- Tool choice mapping ---
|
|
140
|
+
if (body.tool_choice !== undefined) {
|
|
141
|
+
result.tool_choice = responsesToCompletionsToolChoice(body.tool_choice);
|
|
142
|
+
}
|
|
143
|
+
// --- Auto-inject stream_options when streaming ---
|
|
144
|
+
if (result.stream) {
|
|
145
|
+
result.stream_options = { include_usage: true };
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Helpers
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
/**
|
|
153
|
+
* Extract text content from a Responses API message item's content array.
|
|
154
|
+
*/
|
|
155
|
+
function extractContent(content, textType) {
|
|
156
|
+
if (!content)
|
|
157
|
+
return '';
|
|
158
|
+
if (typeof content === 'string')
|
|
159
|
+
return content;
|
|
160
|
+
if (!Array.isArray(content))
|
|
161
|
+
return '';
|
|
162
|
+
return content
|
|
163
|
+
.filter((part) => part.type === textType || part.type === 'text')
|
|
164
|
+
.map((part) => part.text || '')
|
|
165
|
+
.join('');
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Flush a pending assistant message with accumulated tool_calls and reasoning_content.
|
|
169
|
+
*/
|
|
170
|
+
function flushPendingAssistant(messages, pendingAssistant, pendingToolCalls, pendingReasoningContent) {
|
|
171
|
+
if (!pendingAssistant && pendingToolCalls.length === 0 && !pendingReasoningContent) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const msg = {
|
|
175
|
+
role: 'assistant',
|
|
176
|
+
content: (pendingAssistant === null || pendingAssistant === void 0 ? void 0 : pendingAssistant.content) || null,
|
|
177
|
+
};
|
|
178
|
+
if (pendingReasoningContent) {
|
|
179
|
+
msg.reasoning_content = pendingReasoningContent;
|
|
180
|
+
}
|
|
181
|
+
if (pendingToolCalls.length > 0) {
|
|
182
|
+
msg.tool_calls = pendingToolCalls;
|
|
183
|
+
// When tool_calls are present but no reasoning_content was provided,
|
|
184
|
+
// inject a placeholder so the receiver can detect tool-use context
|
|
185
|
+
if (!pendingReasoningContent) {
|
|
186
|
+
msg.reasoning_content = 'tool call';
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
messages.push(msg);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Map Responses API tool_choice to Chat Completions tool_choice.
|
|
193
|
+
*/
|
|
194
|
+
function responsesToCompletionsToolChoice(toolChoice) {
|
|
195
|
+
if (typeof toolChoice === 'string') {
|
|
196
|
+
switch (toolChoice) {
|
|
197
|
+
case 'required': return 'required';
|
|
198
|
+
case 'auto': return 'auto';
|
|
199
|
+
case 'none': return 'none';
|
|
200
|
+
default: return 'auto';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (typeof toolChoice === 'object' && toolChoice.type === 'function') {
|
|
204
|
+
return { type: 'function', function: { name: toolChoice.name } };
|
|
205
|
+
}
|
|
206
|
+
return 'auto';
|
|
207
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Chat Completions → OpenAI Responses API response conversion.
|
|
4
|
+
*
|
|
5
|
+
* Converts a Chat Completions response body into an OpenAI Responses API response body.
|
|
6
|
+
* Reasoning content (reasoning_content) is converted to a standard `reasoning` output
|
|
7
|
+
* item following the official Responses API specification.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.completionsToResponsesResponse = completionsToResponsesResponse;
|
|
11
|
+
const stop_reasons_js_1 = require("../../utils/stop-reasons.js");
|
|
12
|
+
const usage_js_1 = require("../../utils/usage.js");
|
|
13
|
+
const id_js_1 = require("../../utils/id.js");
|
|
14
|
+
/**
|
|
15
|
+
* Convert a Chat Completions response to a Responses API response.
|
|
16
|
+
*/
|
|
17
|
+
function completionsToResponsesResponse(response) {
|
|
18
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
19
|
+
const choice = (_a = response.choices) === null || _a === void 0 ? void 0 : _a[0];
|
|
20
|
+
if (!choice)
|
|
21
|
+
return response;
|
|
22
|
+
const output = [];
|
|
23
|
+
// reasoning_content -> reasoning output item (official Responses API format)
|
|
24
|
+
if ((_b = choice.message) === null || _b === void 0 ? void 0 : _b.reasoning_content) {
|
|
25
|
+
output.push({
|
|
26
|
+
type: 'reasoning',
|
|
27
|
+
id: (0, id_js_1.generateCallId)().replace('call_', 'rs_'),
|
|
28
|
+
summary: [{ type: 'summary_text', text: choice.message.reasoning_content }],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// Text content -> message item
|
|
32
|
+
if ((_c = choice.message) === null || _c === void 0 ? void 0 : _c.content) {
|
|
33
|
+
const messageContent = [
|
|
34
|
+
{ type: 'output_text', text: choice.message.content, annotations: [] },
|
|
35
|
+
];
|
|
36
|
+
// Refusal -> add as refusal in message content
|
|
37
|
+
if ((_d = choice.message) === null || _d === void 0 ? void 0 : _d.refusal) {
|
|
38
|
+
messageContent.push({ type: 'refusal', refusal: choice.message.refusal });
|
|
39
|
+
}
|
|
40
|
+
output.push({
|
|
41
|
+
type: 'message',
|
|
42
|
+
status: 'completed',
|
|
43
|
+
role: 'assistant',
|
|
44
|
+
content: messageContent,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else if ((_e = choice.message) === null || _e === void 0 ? void 0 : _e.refusal) {
|
|
48
|
+
// Message with only refusal, no text content
|
|
49
|
+
output.push({
|
|
50
|
+
type: 'message',
|
|
51
|
+
status: 'completed',
|
|
52
|
+
role: 'assistant',
|
|
53
|
+
content: [
|
|
54
|
+
{ type: 'output_text', text: '', annotations: [] },
|
|
55
|
+
{ type: 'refusal', refusal: choice.message.refusal },
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Tool calls -> function_call items
|
|
60
|
+
if ((_f = choice.message) === null || _f === void 0 ? void 0 : _f.tool_calls) {
|
|
61
|
+
for (const tc of choice.message.tool_calls) {
|
|
62
|
+
output.push({
|
|
63
|
+
type: 'function_call',
|
|
64
|
+
status: 'completed',
|
|
65
|
+
call_id: tc.id,
|
|
66
|
+
name: ((_g = tc.function) === null || _g === void 0 ? void 0 : _g.name) || '',
|
|
67
|
+
arguments: ((_h = tc.function) === null || _h === void 0 ? void 0 : _h.arguments) || '{}',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// If no message was emitted (edge case: only tool calls), still emit a message
|
|
72
|
+
if (!((_j = choice.message) === null || _j === void 0 ? void 0 : _j.content) && !((_k = choice.message) === null || _k === void 0 ? void 0 : _k.refusal) && !((_l = choice.message) === null || _l === void 0 ? void 0 : _l.tool_calls)) {
|
|
73
|
+
output.push({
|
|
74
|
+
type: 'message',
|
|
75
|
+
status: 'completed',
|
|
76
|
+
role: 'assistant',
|
|
77
|
+
content: [{ type: 'output_text', text: '', annotations: [] }],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const finishReason = (0, stop_reasons_js_1.completionsToResponsesFinishReason)(choice.finish_reason);
|
|
81
|
+
const status = finishReason === 'incomplete' ? 'incomplete' : 'completed';
|
|
82
|
+
const usage = (0, usage_js_1.completionsToResponsesUsage)(response.usage);
|
|
83
|
+
const result = {
|
|
84
|
+
id: ((_m = response.id) === null || _m === void 0 ? void 0 : _m.startsWith('resp_')) ? response.id : (0, id_js_1.generateResponseId)(),
|
|
85
|
+
object: 'response',
|
|
86
|
+
status,
|
|
87
|
+
output,
|
|
88
|
+
model: response.model,
|
|
89
|
+
usage,
|
|
90
|
+
created_at: response.created || Math.floor(Date.now() / 1000),
|
|
91
|
+
};
|
|
92
|
+
if (status === 'incomplete') {
|
|
93
|
+
result.incomplete_details = { reason: 'max_output_tokens' };
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Chat Completions SSE → OpenAI Responses API SSE streaming conversion.
|
|
4
|
+
*
|
|
5
|
+
* Stateful converter that translates Chat Completions SSE events into
|
|
6
|
+
* OpenAI Responses API SSE events, following the official Responses API spec.
|
|
7
|
+
*
|
|
8
|
+
* Reasoning content (reasoning_content) is emitted as standard `reasoning`
|
|
9
|
+
* output items with `response.reasoning_summary_text.delta` events.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.CompletionsToResponsesConverter = void 0;
|
|
13
|
+
const usage_js_1 = require("../../utils/usage.js");
|
|
14
|
+
const id_js_1 = require("../../utils/id.js");
|
|
15
|
+
const streaming_helpers_js_1 = require("../../utils/streaming-helpers.js");
|
|
16
|
+
/**
|
|
17
|
+
* CompletionsToResponsesConverter: Chat Completions SSE → Responses API SSE
|
|
18
|
+
*/
|
|
19
|
+
class CompletionsToResponsesConverter {
|
|
20
|
+
constructor() {
|
|
21
|
+
Object.defineProperty(this, "started", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: false
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "responseId", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: ''
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(this, "model", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
value: ''
|
|
38
|
+
});
|
|
39
|
+
Object.defineProperty(this, "reasoningStarted", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: false
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(this, "textStarted", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
writable: true,
|
|
49
|
+
value: false
|
|
50
|
+
});
|
|
51
|
+
Object.defineProperty(this, "reasoningOutputIndex", {
|
|
52
|
+
enumerable: true,
|
|
53
|
+
configurable: true,
|
|
54
|
+
writable: true,
|
|
55
|
+
value: -1
|
|
56
|
+
});
|
|
57
|
+
Object.defineProperty(this, "messageOutputIndex", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
configurable: true,
|
|
60
|
+
writable: true,
|
|
61
|
+
value: -1
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(this, "currentToolCalls", {
|
|
64
|
+
enumerable: true,
|
|
65
|
+
configurable: true,
|
|
66
|
+
writable: true,
|
|
67
|
+
value: new Map()
|
|
68
|
+
});
|
|
69
|
+
Object.defineProperty(this, "pendingReasoningText", {
|
|
70
|
+
enumerable: true,
|
|
71
|
+
configurable: true,
|
|
72
|
+
writable: true,
|
|
73
|
+
value: ''
|
|
74
|
+
});
|
|
75
|
+
Object.defineProperty(this, "accumulatedText", {
|
|
76
|
+
enumerable: true,
|
|
77
|
+
configurable: true,
|
|
78
|
+
writable: true,
|
|
79
|
+
value: ''
|
|
80
|
+
});
|
|
81
|
+
Object.defineProperty(this, "finalized", {
|
|
82
|
+
enumerable: true,
|
|
83
|
+
configurable: true,
|
|
84
|
+
writable: true,
|
|
85
|
+
value: false
|
|
86
|
+
});
|
|
87
|
+
Object.defineProperty(this, "output", {
|
|
88
|
+
enumerable: true,
|
|
89
|
+
configurable: true,
|
|
90
|
+
writable: true,
|
|
91
|
+
value: []
|
|
92
|
+
});
|
|
93
|
+
Object.defineProperty(this, "nextOutputIndex", {
|
|
94
|
+
enumerable: true,
|
|
95
|
+
configurable: true,
|
|
96
|
+
writable: true,
|
|
97
|
+
value: 0
|
|
98
|
+
});
|
|
99
|
+
Object.defineProperty(this, "usage", {
|
|
100
|
+
enumerable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
writable: true,
|
|
103
|
+
value: null
|
|
104
|
+
});
|
|
105
|
+
Object.defineProperty(this, "finishReason", {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
configurable: true,
|
|
108
|
+
writable: true,
|
|
109
|
+
value: null
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
convertEvent(event) {
|
|
113
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
114
|
+
if (!event.data)
|
|
115
|
+
return [];
|
|
116
|
+
// [DONE] -> trigger finalize
|
|
117
|
+
if (event.data === '[DONE]' || ((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
|
|
118
|
+
return this.flush();
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const chunk = (0, streaming_helpers_js_1.parseEventData)(event.data);
|
|
122
|
+
const events = [];
|
|
123
|
+
const delta = (_c = (_b = chunk.choices) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.delta;
|
|
124
|
+
const finishReason = (_e = (_d = chunk.choices) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.finish_reason;
|
|
125
|
+
const usage = chunk.usage;
|
|
126
|
+
const chunkId = chunk.id;
|
|
127
|
+
const chunkModel = chunk.model;
|
|
128
|
+
// First chunk -> emit response.created + response.in_progress
|
|
129
|
+
if (!this.started) {
|
|
130
|
+
this.responseId = (chunkId === null || chunkId === void 0 ? void 0 : chunkId.startsWith('resp_')) ? chunkId : (0, id_js_1.generateResponseId)();
|
|
131
|
+
this.model = chunkModel || '';
|
|
132
|
+
events.push(this.makeSSE('response.created', {
|
|
133
|
+
id: this.responseId,
|
|
134
|
+
object: 'response',
|
|
135
|
+
status: 'in_progress',
|
|
136
|
+
model: this.model,
|
|
137
|
+
output: [],
|
|
138
|
+
}));
|
|
139
|
+
events.push(this.makeSSE('response.in_progress', {
|
|
140
|
+
id: this.responseId,
|
|
141
|
+
object: 'response',
|
|
142
|
+
status: 'in_progress',
|
|
143
|
+
model: this.model,
|
|
144
|
+
output: [],
|
|
145
|
+
}));
|
|
146
|
+
this.started = true;
|
|
147
|
+
}
|
|
148
|
+
// --- reasoning_content -> standard reasoning output item ---
|
|
149
|
+
if (delta === null || delta === void 0 ? void 0 : delta.reasoning_content) {
|
|
150
|
+
this.pendingReasoningText += delta.reasoning_content;
|
|
151
|
+
if (!this.reasoningStarted) {
|
|
152
|
+
this.reasoningOutputIndex = this.nextOutputIndex++;
|
|
153
|
+
const rsId = (0, id_js_1.generateCallId)().replace('call_', 'rs_');
|
|
154
|
+
events.push(this.makeSSE('response.output_item.added', {
|
|
155
|
+
output_index: this.reasoningOutputIndex,
|
|
156
|
+
item: { type: 'reasoning', id: rsId },
|
|
157
|
+
}));
|
|
158
|
+
events.push(this.makeSSE('response.reasoning_summary_part.added', {
|
|
159
|
+
output_index: this.reasoningOutputIndex,
|
|
160
|
+
summary_index: 0,
|
|
161
|
+
part: { type: 'summary_text' },
|
|
162
|
+
}));
|
|
163
|
+
this.reasoningStarted = true;
|
|
164
|
+
}
|
|
165
|
+
// Emit using official standard event name
|
|
166
|
+
events.push(this.makeSSE('response.reasoning_summary_text.delta', {
|
|
167
|
+
output_index: this.reasoningOutputIndex,
|
|
168
|
+
summary_index: 0,
|
|
169
|
+
delta: delta.reasoning_content,
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
// --- content (text) ---
|
|
173
|
+
if (delta === null || delta === void 0 ? void 0 : delta.content) {
|
|
174
|
+
this.accumulatedText += delta.content;
|
|
175
|
+
if (!this.textStarted) {
|
|
176
|
+
this.messageOutputIndex = this.nextOutputIndex++;
|
|
177
|
+
events.push(this.makeSSE('response.output_item.added', {
|
|
178
|
+
output_index: this.messageOutputIndex,
|
|
179
|
+
item: { type: 'message', status: 'in_progress', role: 'assistant', content: [] },
|
|
180
|
+
}));
|
|
181
|
+
events.push(this.makeSSE('response.content_part.added', {
|
|
182
|
+
output_index: this.messageOutputIndex,
|
|
183
|
+
content_index: 0,
|
|
184
|
+
part: { type: 'output_text', text: '', annotations: [] },
|
|
185
|
+
}));
|
|
186
|
+
this.textStarted = true;
|
|
187
|
+
}
|
|
188
|
+
events.push(this.makeSSE('response.output_text.delta', {
|
|
189
|
+
output_index: this.messageOutputIndex,
|
|
190
|
+
content_index: 0,
|
|
191
|
+
delta: delta.content,
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
// --- tool_calls ---
|
|
195
|
+
if (Array.isArray(delta === null || delta === void 0 ? void 0 : delta.tool_calls)) {
|
|
196
|
+
for (const tc of delta.tool_calls) {
|
|
197
|
+
const toolIdx = (_f = tc.index) !== null && _f !== void 0 ? _f : 0;
|
|
198
|
+
const existing = this.currentToolCalls.get(toolIdx);
|
|
199
|
+
if (!existing) {
|
|
200
|
+
// New tool call
|
|
201
|
+
const tcId = tc.id || (0, id_js_1.generateCallId)();
|
|
202
|
+
const tcName = ((_g = tc.function) === null || _g === void 0 ? void 0 : _g.name) || '';
|
|
203
|
+
const tcOutputIndex = this.nextOutputIndex++;
|
|
204
|
+
this.currentToolCalls.set(toolIdx, {
|
|
205
|
+
id: tcId,
|
|
206
|
+
name: tcName,
|
|
207
|
+
argumentsText: '',
|
|
208
|
+
outputIndex: tcOutputIndex,
|
|
209
|
+
});
|
|
210
|
+
events.push(this.makeSSE('response.output_item.added', {
|
|
211
|
+
output_index: tcOutputIndex,
|
|
212
|
+
item: {
|
|
213
|
+
type: 'function_call',
|
|
214
|
+
status: 'in_progress',
|
|
215
|
+
call_id: tcId,
|
|
216
|
+
name: tcName,
|
|
217
|
+
arguments: '',
|
|
218
|
+
},
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
// Arguments fragment
|
|
222
|
+
const argsFragment = (0, streaming_helpers_js_1.normalizeToolArgumentsFragment)((_h = tc.function) === null || _h === void 0 ? void 0 : _h.arguments);
|
|
223
|
+
if (argsFragment) {
|
|
224
|
+
const current = this.currentToolCalls.get(toolIdx);
|
|
225
|
+
if (current) {
|
|
226
|
+
current.argumentsText += argsFragment;
|
|
227
|
+
}
|
|
228
|
+
events.push(this.makeSSE('response.function_call_arguments.delta', {
|
|
229
|
+
output_index: (_j = current === null || current === void 0 ? void 0 : current.outputIndex) !== null && _j !== void 0 ? _j : this.output.length,
|
|
230
|
+
call_id: current === null || current === void 0 ? void 0 : current.id,
|
|
231
|
+
delta: argsFragment,
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// --- Finish reason ---
|
|
237
|
+
if (finishReason) {
|
|
238
|
+
this.finishReason = finishReason;
|
|
239
|
+
}
|
|
240
|
+
// --- Usage ---
|
|
241
|
+
if (usage) {
|
|
242
|
+
this.usage = usage;
|
|
243
|
+
}
|
|
244
|
+
return events;
|
|
245
|
+
}
|
|
246
|
+
catch (_k) {
|
|
247
|
+
return [event];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
flush() {
|
|
251
|
+
if (this.finalized)
|
|
252
|
+
return [];
|
|
253
|
+
this.finalized = true;
|
|
254
|
+
const events = [];
|
|
255
|
+
// Finalize reasoning
|
|
256
|
+
if (this.reasoningStarted) {
|
|
257
|
+
events.push(this.makeSSE('response.reasoning.done', {
|
|
258
|
+
output_index: this.reasoningOutputIndex,
|
|
259
|
+
summary: [{ type: 'summary_text', text: this.pendingReasoningText }],
|
|
260
|
+
}));
|
|
261
|
+
events.push(this.makeSSE('response.reasoning_summary_part.done', {
|
|
262
|
+
output_index: this.reasoningOutputIndex,
|
|
263
|
+
}));
|
|
264
|
+
events.push(this.makeSSE('response.output_item.done', {
|
|
265
|
+
output_index: this.reasoningOutputIndex,
|
|
266
|
+
item: { type: 'reasoning' },
|
|
267
|
+
}));
|
|
268
|
+
this.output.push({
|
|
269
|
+
type: 'reasoning',
|
|
270
|
+
id: (0, id_js_1.generateCallId)().replace('call_', 'rs_'),
|
|
271
|
+
summary: [{ type: 'summary_text', text: this.pendingReasoningText }],
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// Finalize text
|
|
275
|
+
if (this.textStarted) {
|
|
276
|
+
events.push(this.makeSSE('response.output_text.done', {
|
|
277
|
+
output_index: this.messageOutputIndex,
|
|
278
|
+
content_index: 0,
|
|
279
|
+
text: '',
|
|
280
|
+
}));
|
|
281
|
+
events.push(this.makeSSE('response.content_part.done', {
|
|
282
|
+
output_index: this.messageOutputIndex,
|
|
283
|
+
content_index: 0,
|
|
284
|
+
part: { type: 'output_text', text: '', annotations: [] },
|
|
285
|
+
}));
|
|
286
|
+
this.output.push({
|
|
287
|
+
type: 'message',
|
|
288
|
+
status: 'completed',
|
|
289
|
+
role: 'assistant',
|
|
290
|
+
content: [{ type: 'output_text', text: this.accumulatedText }],
|
|
291
|
+
});
|
|
292
|
+
events.push(this.makeSSE('response.output_item.done', {
|
|
293
|
+
output_index: this.messageOutputIndex,
|
|
294
|
+
item: { type: 'message', status: 'completed', role: 'assistant' },
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
// Finalize tool calls
|
|
298
|
+
for (const [, tc] of this.currentToolCalls) {
|
|
299
|
+
events.push(this.makeSSE('response.function_call_arguments.done', {
|
|
300
|
+
output_index: tc.outputIndex,
|
|
301
|
+
call_id: tc.id,
|
|
302
|
+
}));
|
|
303
|
+
events.push(this.makeSSE('response.output_item.done', {
|
|
304
|
+
output_index: tc.outputIndex,
|
|
305
|
+
item: {
|
|
306
|
+
type: 'function_call',
|
|
307
|
+
status: 'completed',
|
|
308
|
+
call_id: tc.id,
|
|
309
|
+
name: tc.name,
|
|
310
|
+
arguments: tc.argumentsText,
|
|
311
|
+
},
|
|
312
|
+
}));
|
|
313
|
+
this.output.push({
|
|
314
|
+
type: 'function_call',
|
|
315
|
+
status: 'completed',
|
|
316
|
+
call_id: tc.id,
|
|
317
|
+
name: tc.name,
|
|
318
|
+
arguments: tc.argumentsText,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
// Build full response object
|
|
322
|
+
const status = this.finishReason === 'length' ? 'incomplete' : 'completed';
|
|
323
|
+
const responseObj = {
|
|
324
|
+
id: this.responseId,
|
|
325
|
+
object: 'response',
|
|
326
|
+
status,
|
|
327
|
+
output: this.output,
|
|
328
|
+
model: this.model,
|
|
329
|
+
usage: this.usage ? (0, usage_js_1.completionsToResponsesUsage)(this.usage) : {},
|
|
330
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
331
|
+
metadata: {},
|
|
332
|
+
};
|
|
333
|
+
if (status === 'incomplete') {
|
|
334
|
+
responseObj.incomplete_details = { reason: 'max_output_tokens' };
|
|
335
|
+
}
|
|
336
|
+
events.push(this.makeSSE('response.completed', { response: responseObj }));
|
|
337
|
+
events.push({ data: '[DONE]', event: '' });
|
|
338
|
+
return events;
|
|
339
|
+
}
|
|
340
|
+
makeSSE(eventName, data) {
|
|
341
|
+
return { event: eventName, data };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
exports.CompletionsToResponsesConverter = CompletionsToResponsesConverter;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Responses API → Gemini composite request conversion.
|
|
4
|
+
*
|
|
5
|
+
* Composes: responses → completions → gemini
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.responsesToGeminiRequest = responsesToGeminiRequest;
|
|
9
|
+
const request_js_1 = require("../responses-completions/request.js");
|
|
10
|
+
const request_js_2 = require("../completions-gemini/request.js");
|
|
11
|
+
/**
|
|
12
|
+
* Convert Responses API request to Gemini request.
|
|
13
|
+
* Path: responses → completions → gemini
|
|
14
|
+
*/
|
|
15
|
+
function responsesToGeminiRequest(body) {
|
|
16
|
+
const completionsBody = (0, request_js_1.responsesToCompletions)(body);
|
|
17
|
+
return (0, request_js_2.completionsToGemini)(completionsBody);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Gemini → Responses API composite response conversion.
|
|
4
|
+
*
|
|
5
|
+
* Composes: gemini → completions → responses
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.geminiToResponsesResponse = geminiToResponsesResponse;
|
|
9
|
+
const response_js_1 = require("../completions-gemini/response.js");
|
|
10
|
+
const response_js_2 = require("../responses-completions/response.js");
|
|
11
|
+
/**
|
|
12
|
+
* Convert Gemini response to Responses API response.
|
|
13
|
+
* Path: gemini → completions → responses
|
|
14
|
+
*/
|
|
15
|
+
function geminiToResponsesResponse(response) {
|
|
16
|
+
const completionsResponse = (0, response_js_1.geminiToCompletionsResponse)(response);
|
|
17
|
+
return (0, response_js_2.completionsToResponsesResponse)(completionsResponse);
|
|
18
|
+
}
|