@antseed/node 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/p2p/connection-manager.d.ts.map +1 -1
- package/dist/p2p/connection-manager.js +14 -8
- package/dist/p2p/connection-manager.js.map +1 -1
- package/dist/proxy/service-api-adapter.d.ts +1 -39
- package/dist/proxy/service-api-adapter.d.ts.map +1 -1
- package/dist/proxy/service-api-adapter.js +3 -1495
- package/dist/proxy/service-api-adapter.js.map +1 -1
- package/package.json +3 -2
|
@@ -1,1496 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
try {
|
|
5
|
-
const parsed = JSON.parse(new TextDecoder().decode(body));
|
|
6
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
return parsed;
|
|
10
|
-
}
|
|
11
|
-
catch {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
function encodeJson(value) {
|
|
16
|
-
return new TextEncoder().encode(JSON.stringify(value));
|
|
17
|
-
}
|
|
18
|
-
function toStringContent(value) {
|
|
19
|
-
if (typeof value === 'string') {
|
|
20
|
-
return value;
|
|
21
|
-
}
|
|
22
|
-
if (Array.isArray(value)) {
|
|
23
|
-
return value
|
|
24
|
-
.map((entry) => {
|
|
25
|
-
if (!entry || typeof entry !== 'object') {
|
|
26
|
-
return '';
|
|
27
|
-
}
|
|
28
|
-
const block = entry;
|
|
29
|
-
if ((block.type === 'text' || block.type === 'input_text') && typeof block.text === 'string') {
|
|
30
|
-
return block.text;
|
|
31
|
-
}
|
|
32
|
-
if (block.type === 'output_text' && typeof block.text === 'string') {
|
|
33
|
-
return block.text;
|
|
34
|
-
}
|
|
35
|
-
if (block.type === 'refusal' && typeof block.refusal === 'string') {
|
|
36
|
-
return block.refusal;
|
|
37
|
-
}
|
|
38
|
-
if (block.type === 'tool_result') {
|
|
39
|
-
return toStringContent(block.content);
|
|
40
|
-
}
|
|
41
|
-
return '';
|
|
42
|
-
})
|
|
43
|
-
.filter((entry) => entry.length > 0)
|
|
44
|
-
.join('\n');
|
|
45
|
-
}
|
|
46
|
-
if (value === null || value === undefined) {
|
|
47
|
-
return '';
|
|
48
|
-
}
|
|
49
|
-
// Handle a single content block object (e.g. {type:'text', text:'...'})
|
|
50
|
-
if (typeof value === 'object') {
|
|
51
|
-
const block = value;
|
|
52
|
-
if ((block.type === 'text' || block.type === 'input_text') && typeof block.text === 'string') {
|
|
53
|
-
return block.text;
|
|
54
|
-
}
|
|
55
|
-
if (block.type === 'output_text' && typeof block.text === 'string') {
|
|
56
|
-
return block.text;
|
|
57
|
-
}
|
|
58
|
-
if (block.type === 'refusal' && typeof block.refusal === 'string') {
|
|
59
|
-
return block.refusal;
|
|
60
|
-
}
|
|
61
|
-
if (block.type === 'tool_result') {
|
|
62
|
-
return toStringContent(block.content);
|
|
63
|
-
}
|
|
64
|
-
return '';
|
|
65
|
-
}
|
|
66
|
-
return String(value);
|
|
67
|
-
}
|
|
68
|
-
function parseJsonSafe(raw) {
|
|
69
|
-
try {
|
|
70
|
-
return JSON.parse(raw);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return raw;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function mapFinishReasonToAnthropicStopReason(value) {
|
|
77
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
if (value === 'stop')
|
|
81
|
-
return 'end_turn';
|
|
82
|
-
if (value === 'length')
|
|
83
|
-
return 'max_tokens';
|
|
84
|
-
if (value === 'tool_calls' || value === 'function_call')
|
|
85
|
-
return 'tool_use';
|
|
86
|
-
return value;
|
|
87
|
-
}
|
|
88
|
-
function toNonNegativeInt(value) {
|
|
89
|
-
const parsed = Number(value);
|
|
90
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
91
|
-
return 0;
|
|
92
|
-
}
|
|
93
|
-
return Math.floor(parsed);
|
|
94
|
-
}
|
|
95
|
-
function convertAnthropicMessagesToOpenAI(body) {
|
|
96
|
-
const out = [];
|
|
97
|
-
if (body.system !== undefined) {
|
|
98
|
-
const systemText = toStringContent(body.system);
|
|
99
|
-
if (systemText.length > 0) {
|
|
100
|
-
out.push({ role: 'system', content: systemText });
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
const messagesRaw = body.messages;
|
|
104
|
-
if (!Array.isArray(messagesRaw)) {
|
|
105
|
-
return out;
|
|
106
|
-
}
|
|
107
|
-
for (const messageRaw of messagesRaw) {
|
|
108
|
-
if (!messageRaw || typeof messageRaw !== 'object') {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
const message = messageRaw;
|
|
112
|
-
const role = typeof message.role === 'string' ? message.role : 'user';
|
|
113
|
-
const content = message.content;
|
|
114
|
-
if (role === 'assistant' && Array.isArray(content)) {
|
|
115
|
-
const textParts = [];
|
|
116
|
-
const toolCalls = [];
|
|
117
|
-
for (const blockRaw of content) {
|
|
118
|
-
if (!blockRaw || typeof blockRaw !== 'object') {
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
const block = blockRaw;
|
|
122
|
-
const blockType = typeof block.type === 'string' ? block.type : '';
|
|
123
|
-
if (blockType === 'tool_use') {
|
|
124
|
-
const callName = typeof block.name === 'string' && block.name.length > 0 ? block.name : 'tool';
|
|
125
|
-
const callId = typeof block.id === 'string' && block.id.length > 0
|
|
126
|
-
? block.id
|
|
127
|
-
: `call_${toolCalls.length + 1}`;
|
|
128
|
-
const input = block.input && typeof block.input === 'object' ? block.input : {};
|
|
129
|
-
toolCalls.push({
|
|
130
|
-
id: callId,
|
|
131
|
-
type: 'function',
|
|
132
|
-
function: {
|
|
133
|
-
name: callName,
|
|
134
|
-
arguments: JSON.stringify(input),
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
const text = toStringContent(block);
|
|
140
|
-
if (text.length > 0) {
|
|
141
|
-
textParts.push(text);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
const assistantMessage = {
|
|
145
|
-
role: 'assistant',
|
|
146
|
-
content: textParts.join('\n'),
|
|
147
|
-
};
|
|
148
|
-
if (toolCalls.length > 0) {
|
|
149
|
-
assistantMessage.tool_calls = toolCalls;
|
|
150
|
-
}
|
|
151
|
-
out.push(assistantMessage);
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
if (role === 'user' && Array.isArray(content)) {
|
|
155
|
-
const textParts = [];
|
|
156
|
-
const toolResults = [];
|
|
157
|
-
for (const blockRaw of content) {
|
|
158
|
-
if (!blockRaw || typeof blockRaw !== 'object') {
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
const block = blockRaw;
|
|
162
|
-
const blockType = typeof block.type === 'string' ? block.type : '';
|
|
163
|
-
if (blockType === 'tool_result') {
|
|
164
|
-
const toolCallId = typeof block.tool_use_id === 'string' ? block.tool_use_id : '';
|
|
165
|
-
if (toolCallId.length > 0) {
|
|
166
|
-
toolResults.push({
|
|
167
|
-
role: 'tool',
|
|
168
|
-
tool_call_id: toolCallId,
|
|
169
|
-
content: toStringContent(block.content),
|
|
170
|
-
});
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const text = toStringContent(block);
|
|
175
|
-
if (text.length > 0) {
|
|
176
|
-
textParts.push(text);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (textParts.length > 0) {
|
|
180
|
-
out.push({
|
|
181
|
-
role: 'user',
|
|
182
|
-
content: textParts.join('\n'),
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
out.push(...toolResults);
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
out.push({
|
|
189
|
-
role,
|
|
190
|
-
content: toStringContent(content),
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
return out;
|
|
194
|
-
}
|
|
195
|
-
function convertAnthropicToolsToOpenAI(toolsRaw) {
|
|
196
|
-
if (!Array.isArray(toolsRaw) || toolsRaw.length === 0) {
|
|
197
|
-
return undefined;
|
|
198
|
-
}
|
|
199
|
-
const out = [];
|
|
200
|
-
for (const toolRaw of toolsRaw) {
|
|
201
|
-
if (!toolRaw || typeof toolRaw !== 'object') {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
const tool = toolRaw;
|
|
205
|
-
if (typeof tool.name !== 'string' || tool.name.length === 0) {
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
out.push({
|
|
209
|
-
type: 'function',
|
|
210
|
-
function: {
|
|
211
|
-
name: tool.name,
|
|
212
|
-
...(typeof tool.description === 'string' && tool.description.length > 0
|
|
213
|
-
? { description: tool.description }
|
|
214
|
-
: {}),
|
|
215
|
-
parameters: tool.input_schema && typeof tool.input_schema === 'object'
|
|
216
|
-
? tool.input_schema
|
|
217
|
-
: { type: 'object', properties: {} },
|
|
218
|
-
},
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
return out.length > 0 ? out : undefined;
|
|
222
|
-
}
|
|
223
|
-
function convertAnthropicToolChoiceToOpenAI(toolChoice) {
|
|
224
|
-
if (typeof toolChoice === 'string') {
|
|
225
|
-
if (toolChoice === 'auto' || toolChoice === 'none' || toolChoice === 'required') {
|
|
226
|
-
return toolChoice;
|
|
227
|
-
}
|
|
228
|
-
return undefined;
|
|
229
|
-
}
|
|
230
|
-
if (!toolChoice || typeof toolChoice !== 'object') {
|
|
231
|
-
return undefined;
|
|
232
|
-
}
|
|
233
|
-
const choice = toolChoice;
|
|
234
|
-
const type = typeof choice.type === 'string' ? choice.type : '';
|
|
235
|
-
if (type === 'auto') {
|
|
236
|
-
return 'auto';
|
|
237
|
-
}
|
|
238
|
-
if (type === 'any') {
|
|
239
|
-
return 'required';
|
|
240
|
-
}
|
|
241
|
-
if (type === 'tool' && typeof choice.name === 'string' && choice.name.length > 0) {
|
|
242
|
-
return {
|
|
243
|
-
type: 'function',
|
|
244
|
-
function: {
|
|
245
|
-
name: choice.name,
|
|
246
|
-
},
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
return undefined;
|
|
250
|
-
}
|
|
251
|
-
function buildAnthropicStreamFromMessage(message) {
|
|
252
|
-
const chunks = [];
|
|
253
|
-
const pushEvent = (event, data) => {
|
|
254
|
-
chunks.push(`event: ${event}\n`);
|
|
255
|
-
chunks.push(`data: ${JSON.stringify(data)}\n\n`);
|
|
256
|
-
};
|
|
257
|
-
pushEvent('message_start', {
|
|
258
|
-
type: 'message_start',
|
|
259
|
-
message: {
|
|
260
|
-
id: message.id,
|
|
261
|
-
type: 'message',
|
|
262
|
-
role: 'assistant',
|
|
263
|
-
model: message.service,
|
|
264
|
-
content: [],
|
|
265
|
-
stop_reason: null,
|
|
266
|
-
stop_sequence: null,
|
|
267
|
-
usage: {
|
|
268
|
-
input_tokens: message.usage.inputTokens,
|
|
269
|
-
output_tokens: 0,
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
message.content.forEach((block, index) => {
|
|
274
|
-
pushEvent('content_block_start', {
|
|
275
|
-
type: 'content_block_start',
|
|
276
|
-
index,
|
|
277
|
-
content_block: block.type === 'text'
|
|
278
|
-
? { type: 'text', text: '' }
|
|
279
|
-
: { type: 'tool_use', id: block.id, name: block.name, input: {} },
|
|
280
|
-
});
|
|
281
|
-
if (block.type === 'text' && block.text.length > 0) {
|
|
282
|
-
pushEvent('content_block_delta', {
|
|
283
|
-
type: 'content_block_delta',
|
|
284
|
-
index,
|
|
285
|
-
delta: {
|
|
286
|
-
type: 'text_delta',
|
|
287
|
-
text: block.text,
|
|
288
|
-
},
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
if (block.type === 'tool_use') {
|
|
292
|
-
pushEvent('content_block_delta', {
|
|
293
|
-
type: 'content_block_delta',
|
|
294
|
-
index,
|
|
295
|
-
delta: {
|
|
296
|
-
type: 'input_json_delta',
|
|
297
|
-
partial_json: JSON.stringify(block.input),
|
|
298
|
-
},
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
pushEvent('content_block_stop', {
|
|
302
|
-
type: 'content_block_stop',
|
|
303
|
-
index,
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
pushEvent('message_delta', {
|
|
307
|
-
type: 'message_delta',
|
|
308
|
-
delta: {
|
|
309
|
-
stop_reason: message.stopReason,
|
|
310
|
-
stop_sequence: null,
|
|
311
|
-
},
|
|
312
|
-
usage: {
|
|
313
|
-
output_tokens: message.usage.outputTokens,
|
|
314
|
-
},
|
|
315
|
-
});
|
|
316
|
-
pushEvent('message_stop', {
|
|
317
|
-
type: 'message_stop',
|
|
318
|
-
});
|
|
319
|
-
return new TextEncoder().encode(chunks.join(''));
|
|
320
|
-
}
|
|
321
|
-
export function createOpenAIChatToAnthropicStreamingAdapter(options) {
|
|
322
|
-
let rawBuffer = '';
|
|
323
|
-
const decoder = new TextDecoder();
|
|
324
|
-
let messageStarted = false;
|
|
325
|
-
let textBlockStarted = false;
|
|
326
|
-
let hadTextBlock = false;
|
|
327
|
-
let outputTokens = 0;
|
|
328
|
-
let stopReason = null;
|
|
329
|
-
let messageId = options.fallbackModel ? `msg_${options.fallbackModel}` : 'msg_stream';
|
|
330
|
-
let service = options.fallbackModel ?? 'unknown';
|
|
331
|
-
const toolBlocks = new Map();
|
|
332
|
-
let openToolBlockIndex = null;
|
|
333
|
-
const getToolBlockIndex = (index) => (hadTextBlock ? 1 : 0) + index;
|
|
334
|
-
const startMessage = () => {
|
|
335
|
-
if (messageStarted)
|
|
336
|
-
return [];
|
|
337
|
-
messageStarted = true;
|
|
338
|
-
return [{
|
|
339
|
-
event: 'message_start',
|
|
340
|
-
data: {
|
|
341
|
-
type: 'message_start',
|
|
342
|
-
message: {
|
|
343
|
-
id: messageId,
|
|
344
|
-
type: 'message',
|
|
345
|
-
role: 'assistant',
|
|
346
|
-
model: service,
|
|
347
|
-
content: [],
|
|
348
|
-
stop_reason: null,
|
|
349
|
-
stop_sequence: null,
|
|
350
|
-
usage: {
|
|
351
|
-
input_tokens: 0,
|
|
352
|
-
output_tokens: 0,
|
|
353
|
-
},
|
|
354
|
-
},
|
|
355
|
-
},
|
|
356
|
-
}];
|
|
357
|
-
};
|
|
358
|
-
const startTextBlock = () => {
|
|
359
|
-
if (textBlockStarted)
|
|
360
|
-
return [];
|
|
361
|
-
textBlockStarted = true;
|
|
362
|
-
hadTextBlock = true;
|
|
363
|
-
return [{
|
|
364
|
-
event: 'content_block_start',
|
|
365
|
-
data: {
|
|
366
|
-
type: 'content_block_start',
|
|
367
|
-
index: 0,
|
|
368
|
-
content_block: {
|
|
369
|
-
type: 'text',
|
|
370
|
-
text: '',
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
}];
|
|
374
|
-
};
|
|
375
|
-
const finishMessage = () => {
|
|
376
|
-
const events = [];
|
|
377
|
-
if (!messageStarted) {
|
|
378
|
-
events.push(...startMessage());
|
|
379
|
-
}
|
|
380
|
-
if (textBlockStarted) {
|
|
381
|
-
events.push({
|
|
382
|
-
event: 'content_block_stop',
|
|
383
|
-
data: {
|
|
384
|
-
type: 'content_block_stop',
|
|
385
|
-
index: 0,
|
|
386
|
-
},
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
events.push({
|
|
390
|
-
event: 'message_delta',
|
|
391
|
-
data: {
|
|
392
|
-
type: 'message_delta',
|
|
393
|
-
delta: {
|
|
394
|
-
stop_reason: stopReason,
|
|
395
|
-
stop_sequence: null,
|
|
396
|
-
},
|
|
397
|
-
usage: {
|
|
398
|
-
output_tokens: outputTokens,
|
|
399
|
-
},
|
|
400
|
-
},
|
|
401
|
-
});
|
|
402
|
-
events.push({
|
|
403
|
-
event: 'message_stop',
|
|
404
|
-
data: {
|
|
405
|
-
type: 'message_stop',
|
|
406
|
-
},
|
|
407
|
-
});
|
|
408
|
-
return events;
|
|
409
|
-
};
|
|
410
|
-
return {
|
|
411
|
-
adaptStart(response) {
|
|
412
|
-
return {
|
|
413
|
-
...response,
|
|
414
|
-
headers: {
|
|
415
|
-
...response.headers,
|
|
416
|
-
'content-type': 'text/event-stream',
|
|
417
|
-
'cache-control': 'no-cache',
|
|
418
|
-
},
|
|
419
|
-
body: new Uint8Array(0),
|
|
420
|
-
};
|
|
421
|
-
},
|
|
422
|
-
adaptChunk(chunk) {
|
|
423
|
-
const out = [];
|
|
424
|
-
if (chunk.data.length > 0) {
|
|
425
|
-
rawBuffer += decoder.decode(chunk.data, { stream: !chunk.done });
|
|
426
|
-
}
|
|
427
|
-
const { events, remainder } = parseSseBuffer(rawBuffer);
|
|
428
|
-
rawBuffer = remainder;
|
|
429
|
-
const emitted = [];
|
|
430
|
-
for (const event of events) {
|
|
431
|
-
if (event.data === '[DONE]') {
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
const parsed = parseJsonSafe(event.data);
|
|
435
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
436
|
-
continue;
|
|
437
|
-
}
|
|
438
|
-
const payload = parsed;
|
|
439
|
-
if (typeof payload.id === 'string' && payload.id.length > 0) {
|
|
440
|
-
messageId = payload.id;
|
|
441
|
-
}
|
|
442
|
-
if (typeof payload.model === 'string' && payload.model.length > 0) {
|
|
443
|
-
service = payload.model;
|
|
444
|
-
}
|
|
445
|
-
const usage = payload.usage && typeof payload.usage === 'object'
|
|
446
|
-
? payload.usage
|
|
447
|
-
: null;
|
|
448
|
-
if (usage) {
|
|
449
|
-
outputTokens = toNonNegativeInt(usage.completion_tokens ?? usage.output_tokens);
|
|
450
|
-
}
|
|
451
|
-
const choices = Array.isArray(payload.choices) ? payload.choices : [];
|
|
452
|
-
const firstChoice = choices[0] && typeof choices[0] === 'object'
|
|
453
|
-
? choices[0]
|
|
454
|
-
: null;
|
|
455
|
-
const delta = firstChoice?.delta && typeof firstChoice.delta === 'object'
|
|
456
|
-
? firstChoice.delta
|
|
457
|
-
: null;
|
|
458
|
-
if (typeof firstChoice?.finish_reason === 'string' && firstChoice.finish_reason.length > 0) {
|
|
459
|
-
stopReason = mapFinishReasonToAnthropicStopReason(firstChoice.finish_reason);
|
|
460
|
-
}
|
|
461
|
-
const textDelta = typeof delta?.content === 'string' ? delta.content : '';
|
|
462
|
-
if (textDelta.length > 0) {
|
|
463
|
-
emitted.push(...startMessage());
|
|
464
|
-
emitted.push(...startTextBlock());
|
|
465
|
-
emitted.push({
|
|
466
|
-
event: 'content_block_delta',
|
|
467
|
-
data: {
|
|
468
|
-
type: 'content_block_delta',
|
|
469
|
-
index: 0,
|
|
470
|
-
delta: {
|
|
471
|
-
type: 'text_delta',
|
|
472
|
-
text: textDelta,
|
|
473
|
-
},
|
|
474
|
-
},
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
const toolCalls = Array.isArray(delta?.tool_calls) ? delta.tool_calls : [];
|
|
478
|
-
for (const toolCallRaw of toolCalls) {
|
|
479
|
-
if (!toolCallRaw || typeof toolCallRaw !== 'object') {
|
|
480
|
-
continue;
|
|
481
|
-
}
|
|
482
|
-
const toolCall = toolCallRaw;
|
|
483
|
-
const rawIndex = typeof toolCall.index === 'number' ? toolCall.index : 0;
|
|
484
|
-
const index = Number.isFinite(rawIndex) ? Math.max(0, Math.floor(rawIndex)) : 0;
|
|
485
|
-
const functionPayload = toolCall.function && typeof toolCall.function === 'object'
|
|
486
|
-
? toolCall.function
|
|
487
|
-
: {};
|
|
488
|
-
const existing = toolBlocks.get(index);
|
|
489
|
-
const id = typeof toolCall.id === 'string' && toolCall.id.length > 0
|
|
490
|
-
? toolCall.id
|
|
491
|
-
: (existing?.id ?? `toolu_${index + 1}`);
|
|
492
|
-
const name = typeof functionPayload.name === 'string' && functionPayload.name.length > 0
|
|
493
|
-
? functionPayload.name
|
|
494
|
-
: (existing?.name ?? 'tool');
|
|
495
|
-
if (!existing) {
|
|
496
|
-
if (textBlockStarted) {
|
|
497
|
-
emitted.push({
|
|
498
|
-
event: 'content_block_stop',
|
|
499
|
-
data: {
|
|
500
|
-
type: 'content_block_stop',
|
|
501
|
-
index: 0,
|
|
502
|
-
},
|
|
503
|
-
});
|
|
504
|
-
textBlockStarted = false;
|
|
505
|
-
}
|
|
506
|
-
if (openToolBlockIndex !== null && openToolBlockIndex !== index) {
|
|
507
|
-
emitted.push({
|
|
508
|
-
event: 'content_block_stop',
|
|
509
|
-
data: {
|
|
510
|
-
type: 'content_block_stop',
|
|
511
|
-
index: getToolBlockIndex(openToolBlockIndex),
|
|
512
|
-
},
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
const toolBlockIndex = getToolBlockIndex(index);
|
|
516
|
-
emitted.push(...startMessage());
|
|
517
|
-
emitted.push({
|
|
518
|
-
event: 'content_block_start',
|
|
519
|
-
data: {
|
|
520
|
-
type: 'content_block_start',
|
|
521
|
-
index: toolBlockIndex,
|
|
522
|
-
content_block: {
|
|
523
|
-
type: 'tool_use',
|
|
524
|
-
id,
|
|
525
|
-
name,
|
|
526
|
-
input: {},
|
|
527
|
-
},
|
|
528
|
-
},
|
|
529
|
-
});
|
|
530
|
-
openToolBlockIndex = index;
|
|
531
|
-
}
|
|
532
|
-
toolBlocks.set(index, { id, name });
|
|
533
|
-
const argumentsDelta = typeof functionPayload.arguments === 'string'
|
|
534
|
-
? functionPayload.arguments
|
|
535
|
-
: '';
|
|
536
|
-
if (argumentsDelta.length > 0) {
|
|
537
|
-
emitted.push({
|
|
538
|
-
event: 'content_block_delta',
|
|
539
|
-
data: {
|
|
540
|
-
type: 'content_block_delta',
|
|
541
|
-
index: getToolBlockIndex(index),
|
|
542
|
-
delta: {
|
|
543
|
-
type: 'input_json_delta',
|
|
544
|
-
partial_json: argumentsDelta,
|
|
545
|
-
},
|
|
546
|
-
},
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
if (chunk.done) {
|
|
552
|
-
if (openToolBlockIndex !== null) {
|
|
553
|
-
emitted.push({
|
|
554
|
-
event: 'content_block_stop',
|
|
555
|
-
data: {
|
|
556
|
-
type: 'content_block_stop',
|
|
557
|
-
index: getToolBlockIndex(openToolBlockIndex),
|
|
558
|
-
},
|
|
559
|
-
});
|
|
560
|
-
openToolBlockIndex = null;
|
|
561
|
-
}
|
|
562
|
-
emitted.push(...finishMessage());
|
|
563
|
-
}
|
|
564
|
-
if (emitted.length > 0) {
|
|
565
|
-
out.push({
|
|
566
|
-
requestId: chunk.requestId,
|
|
567
|
-
data: encodeSseEvents(emitted),
|
|
568
|
-
done: chunk.done,
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
else if (chunk.done) {
|
|
572
|
-
out.push({
|
|
573
|
-
requestId: chunk.requestId,
|
|
574
|
-
data: new Uint8Array(0),
|
|
575
|
-
done: true,
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
return out;
|
|
579
|
-
},
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
export function detectRequestServiceApiProtocol(request) {
|
|
583
|
-
const normalizedPath = request.path.toLowerCase();
|
|
584
|
-
if (normalizedPath.startsWith('/v1/messages') || normalizedPath.startsWith('/v1/complete')) {
|
|
585
|
-
return 'anthropic-messages';
|
|
586
|
-
}
|
|
587
|
-
if (normalizedPath.startsWith('/v1/chat/completions')) {
|
|
588
|
-
return 'openai-chat-completions';
|
|
589
|
-
}
|
|
590
|
-
if (normalizedPath.startsWith('/v1/completions')) {
|
|
591
|
-
return 'openai-completions';
|
|
592
|
-
}
|
|
593
|
-
if (normalizedPath.startsWith('/v1/responses')) {
|
|
594
|
-
return 'openai-responses';
|
|
595
|
-
}
|
|
596
|
-
const hasAnthropicVersionHeader = Object.keys(request.headers)
|
|
597
|
-
.some((key) => key.toLowerCase() === 'anthropic-version');
|
|
598
|
-
if (hasAnthropicVersionHeader) {
|
|
599
|
-
return 'anthropic-messages';
|
|
600
|
-
}
|
|
601
|
-
return null;
|
|
602
|
-
}
|
|
603
|
-
export function inferProviderDefaultServiceApiProtocols(providerName) {
|
|
604
|
-
const normalized = providerName.trim().toLowerCase();
|
|
605
|
-
if (normalized.length === 0) {
|
|
606
|
-
return [];
|
|
607
|
-
}
|
|
608
|
-
if (ANTHROPIC_PROVIDER_NAMES.has(normalized)) {
|
|
609
|
-
return ['anthropic-messages'];
|
|
610
|
-
}
|
|
611
|
-
if (OPENAI_CHAT_PROVIDER_NAMES.has(normalized)) {
|
|
612
|
-
return ['openai-chat-completions'];
|
|
613
|
-
}
|
|
614
|
-
return [];
|
|
615
|
-
}
|
|
616
|
-
export function selectTargetProtocolForRequest(requestProtocol, supportedProtocols) {
|
|
617
|
-
if (!requestProtocol) {
|
|
618
|
-
return null;
|
|
619
|
-
}
|
|
620
|
-
if (supportedProtocols.includes(requestProtocol)) {
|
|
621
|
-
return { targetProtocol: requestProtocol, requiresTransform: false };
|
|
622
|
-
}
|
|
623
|
-
if (requestProtocol === 'anthropic-messages' && supportedProtocols.includes('openai-chat-completions')) {
|
|
624
|
-
return { targetProtocol: 'openai-chat-completions', requiresTransform: true };
|
|
625
|
-
}
|
|
626
|
-
if (requestProtocol === 'openai-responses' && supportedProtocols.includes('openai-chat-completions')) {
|
|
627
|
-
return { targetProtocol: 'openai-chat-completions', requiresTransform: true };
|
|
628
|
-
}
|
|
629
|
-
return null;
|
|
630
|
-
}
|
|
631
|
-
export function transformAnthropicMessagesRequestToOpenAIChat(request) {
|
|
632
|
-
if (!request.path.toLowerCase().startsWith('/v1/messages')) {
|
|
633
|
-
return null;
|
|
634
|
-
}
|
|
635
|
-
const body = parseJsonObject(request.body);
|
|
636
|
-
if (!body) {
|
|
637
|
-
return null;
|
|
638
|
-
}
|
|
639
|
-
const streamRequested = body.stream === true;
|
|
640
|
-
const requestedModel = typeof body.model === 'string' && body.model.trim().length > 0
|
|
641
|
-
? body.model.trim()
|
|
642
|
-
: null;
|
|
643
|
-
const mappedMessages = convertAnthropicMessagesToOpenAI(body);
|
|
644
|
-
const mappedTools = convertAnthropicToolsToOpenAI(body.tools);
|
|
645
|
-
const mappedToolChoice = convertAnthropicToolChoiceToOpenAI(body.tool_choice);
|
|
646
|
-
const transformedBody = {
|
|
647
|
-
...(requestedModel ? { model: requestedModel } : {}),
|
|
648
|
-
messages: mappedMessages,
|
|
649
|
-
stream: streamRequested,
|
|
650
|
-
...(streamRequested ? { stream_options: { include_usage: true } } : {}),
|
|
651
|
-
};
|
|
652
|
-
if (typeof body.max_tokens === 'number') {
|
|
653
|
-
transformedBody.max_tokens = body.max_tokens;
|
|
654
|
-
}
|
|
655
|
-
if (typeof body.temperature === 'number') {
|
|
656
|
-
transformedBody.temperature = body.temperature;
|
|
657
|
-
}
|
|
658
|
-
if (typeof body.top_p === 'number') {
|
|
659
|
-
transformedBody.top_p = body.top_p;
|
|
660
|
-
}
|
|
661
|
-
if (Array.isArray(body.stop_sequences)) {
|
|
662
|
-
transformedBody.stop = body.stop_sequences;
|
|
663
|
-
}
|
|
664
|
-
if (mappedTools) {
|
|
665
|
-
transformedBody.tools = mappedTools;
|
|
666
|
-
}
|
|
667
|
-
if (mappedToolChoice !== undefined) {
|
|
668
|
-
transformedBody.tool_choice = mappedToolChoice;
|
|
669
|
-
}
|
|
670
|
-
if (body.metadata && typeof body.metadata === 'object' && !Array.isArray(body.metadata)) {
|
|
671
|
-
transformedBody.metadata = body.metadata;
|
|
672
|
-
}
|
|
673
|
-
if (typeof body.user === 'string') {
|
|
674
|
-
transformedBody.user = body.user;
|
|
675
|
-
}
|
|
676
|
-
const transformedHeaders = { ...request.headers };
|
|
677
|
-
for (const headerName of Object.keys(transformedHeaders)) {
|
|
678
|
-
const lower = headerName.toLowerCase();
|
|
679
|
-
if (lower === 'anthropic-version' || lower === 'anthropic-beta') {
|
|
680
|
-
delete transformedHeaders[headerName];
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
transformedHeaders['content-type'] = 'application/json';
|
|
684
|
-
return {
|
|
685
|
-
request: {
|
|
686
|
-
...request,
|
|
687
|
-
path: '/v1/chat/completions',
|
|
688
|
-
headers: transformedHeaders,
|
|
689
|
-
body: encodeJson(transformedBody),
|
|
690
|
-
},
|
|
691
|
-
streamRequested,
|
|
692
|
-
requestedModel,
|
|
693
|
-
};
|
|
694
|
-
}
|
|
695
|
-
export function transformOpenAIChatResponseToAnthropicMessage(response, options) {
|
|
696
|
-
const parsed = parseJsonObject(response.body);
|
|
697
|
-
if (!parsed) {
|
|
698
|
-
return response;
|
|
699
|
-
}
|
|
700
|
-
if (response.statusCode >= 400) {
|
|
701
|
-
const openaiError = parsed.error && typeof parsed.error === 'object'
|
|
702
|
-
? parsed.error
|
|
703
|
-
: null;
|
|
704
|
-
const message = openaiError && typeof openaiError.message === 'string'
|
|
705
|
-
? openaiError.message
|
|
706
|
-
: 'Upstream error';
|
|
707
|
-
const anthropicError = {
|
|
708
|
-
type: 'error',
|
|
709
|
-
error: {
|
|
710
|
-
type: 'api_error',
|
|
711
|
-
message,
|
|
712
|
-
},
|
|
713
|
-
};
|
|
714
|
-
return {
|
|
715
|
-
...response,
|
|
716
|
-
headers: {
|
|
717
|
-
...response.headers,
|
|
718
|
-
'content-type': options.streamRequested ? 'text/event-stream' : 'application/json',
|
|
719
|
-
},
|
|
720
|
-
body: options.streamRequested
|
|
721
|
-
? new TextEncoder().encode(`event: error\ndata: ${JSON.stringify(anthropicError)}\n\n`)
|
|
722
|
-
: encodeJson(anthropicError),
|
|
723
|
-
};
|
|
724
|
-
}
|
|
725
|
-
const choices = Array.isArray(parsed.choices) ? parsed.choices : [];
|
|
726
|
-
const firstChoice = choices[0] && typeof choices[0] === 'object'
|
|
727
|
-
? choices[0]
|
|
728
|
-
: null;
|
|
729
|
-
const message = firstChoice?.message && typeof firstChoice.message === 'object'
|
|
730
|
-
? firstChoice.message
|
|
731
|
-
: null;
|
|
732
|
-
const finishReason = mapFinishReasonToAnthropicStopReason(firstChoice?.finish_reason);
|
|
733
|
-
const contentBlocks = [];
|
|
734
|
-
const textContent = toStringContent(message?.content);
|
|
735
|
-
if (textContent.length > 0) {
|
|
736
|
-
contentBlocks.push({ type: 'text', text: textContent });
|
|
737
|
-
}
|
|
738
|
-
const toolCalls = Array.isArray(message?.tool_calls) ? message.tool_calls : [];
|
|
739
|
-
for (const [index, toolCallRaw] of toolCalls.entries()) {
|
|
740
|
-
if (!toolCallRaw || typeof toolCallRaw !== 'object') {
|
|
741
|
-
continue;
|
|
742
|
-
}
|
|
743
|
-
const toolCall = toolCallRaw;
|
|
744
|
-
const functionPayload = toolCall.function && typeof toolCall.function === 'object'
|
|
745
|
-
? toolCall.function
|
|
746
|
-
: {};
|
|
747
|
-
const id = typeof toolCall.id === 'string' && toolCall.id.length > 0
|
|
748
|
-
? toolCall.id
|
|
749
|
-
: `toolu_${index + 1}`;
|
|
750
|
-
const name = typeof functionPayload.name === 'string' && functionPayload.name.length > 0
|
|
751
|
-
? functionPayload.name
|
|
752
|
-
: 'tool';
|
|
753
|
-
const argsRaw = typeof functionPayload.arguments === 'string' ? functionPayload.arguments : '{}';
|
|
754
|
-
const parsedArgs = parseJsonSafe(argsRaw);
|
|
755
|
-
contentBlocks.push({
|
|
756
|
-
type: 'tool_use',
|
|
757
|
-
id,
|
|
758
|
-
name,
|
|
759
|
-
input: parsedArgs && typeof parsedArgs === 'object' && !Array.isArray(parsedArgs)
|
|
760
|
-
? parsedArgs
|
|
761
|
-
: { raw: argsRaw },
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
const usage = parsed.usage && typeof parsed.usage === 'object'
|
|
765
|
-
? parsed.usage
|
|
766
|
-
: {};
|
|
767
|
-
const inputTokens = toNonNegativeInt(usage.prompt_tokens ?? usage.input_tokens);
|
|
768
|
-
const outputTokens = toNonNegativeInt(usage.completion_tokens ?? usage.output_tokens);
|
|
769
|
-
const id = typeof parsed.id === 'string' && parsed.id.length > 0 ? parsed.id : `msg_${response.requestId}`;
|
|
770
|
-
const service = typeof parsed.model === 'string' && parsed.model.length > 0
|
|
771
|
-
? parsed.model
|
|
772
|
-
: (options.fallbackModel ?? 'unknown');
|
|
773
|
-
const anthropicMessage = {
|
|
774
|
-
id,
|
|
775
|
-
type: 'message',
|
|
776
|
-
role: 'assistant',
|
|
777
|
-
model: service,
|
|
778
|
-
content: contentBlocks,
|
|
779
|
-
stop_reason: finishReason,
|
|
780
|
-
stop_sequence: null,
|
|
781
|
-
usage: {
|
|
782
|
-
input_tokens: inputTokens,
|
|
783
|
-
output_tokens: outputTokens,
|
|
784
|
-
},
|
|
785
|
-
};
|
|
786
|
-
if (options.streamRequested) {
|
|
787
|
-
return {
|
|
788
|
-
...response,
|
|
789
|
-
headers: {
|
|
790
|
-
...response.headers,
|
|
791
|
-
'content-type': 'text/event-stream',
|
|
792
|
-
'cache-control': 'no-cache',
|
|
793
|
-
},
|
|
794
|
-
body: buildAnthropicStreamFromMessage({
|
|
795
|
-
id,
|
|
796
|
-
service,
|
|
797
|
-
content: contentBlocks,
|
|
798
|
-
stopReason: finishReason,
|
|
799
|
-
usage: {
|
|
800
|
-
inputTokens,
|
|
801
|
-
outputTokens,
|
|
802
|
-
},
|
|
803
|
-
}),
|
|
804
|
-
};
|
|
805
|
-
}
|
|
806
|
-
return {
|
|
807
|
-
...response,
|
|
808
|
-
headers: {
|
|
809
|
-
...response.headers,
|
|
810
|
-
'content-type': 'application/json',
|
|
811
|
-
},
|
|
812
|
-
body: encodeJson(anthropicMessage),
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
function parseSseBuffer(buffer) {
|
|
816
|
-
const normalized = buffer.replace(/\r\n/g, '\n');
|
|
817
|
-
const blocks = normalized.split('\n\n');
|
|
818
|
-
const remainder = blocks.pop() ?? '';
|
|
819
|
-
const events = [];
|
|
820
|
-
for (const block of blocks) {
|
|
821
|
-
const lines = block.split('\n');
|
|
822
|
-
let event = null;
|
|
823
|
-
const dataLines = [];
|
|
824
|
-
for (const line of lines) {
|
|
825
|
-
if (line.startsWith('event: ')) {
|
|
826
|
-
event = line.slice('event: '.length);
|
|
827
|
-
}
|
|
828
|
-
else if (line.startsWith('data: ')) {
|
|
829
|
-
dataLines.push(line.slice('data: '.length));
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
if (dataLines.length > 0) {
|
|
833
|
-
events.push({ event, data: dataLines.join('\n') });
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
return { events, remainder };
|
|
837
|
-
}
|
|
838
|
-
function encodeSseEvents(events) {
|
|
839
|
-
const chunks = [];
|
|
840
|
-
for (const item of events) {
|
|
841
|
-
if (item.event) {
|
|
842
|
-
chunks.push(`event: ${item.event}\n`);
|
|
843
|
-
}
|
|
844
|
-
const data = typeof item.data === 'string' ? item.data : JSON.stringify(item.data);
|
|
845
|
-
chunks.push(`data: ${data}\n\n`);
|
|
846
|
-
}
|
|
847
|
-
return new TextEncoder().encode(chunks.join(''));
|
|
848
|
-
}
|
|
849
|
-
function convertResponsesToolsToChatTools(tools) {
|
|
850
|
-
const out = [];
|
|
851
|
-
for (const toolRaw of tools) {
|
|
852
|
-
if (!toolRaw || typeof toolRaw !== 'object') {
|
|
853
|
-
continue;
|
|
854
|
-
}
|
|
855
|
-
const tool = toolRaw;
|
|
856
|
-
if (typeof tool.name !== 'string' || tool.name.length === 0) {
|
|
857
|
-
continue;
|
|
858
|
-
}
|
|
859
|
-
out.push({
|
|
860
|
-
type: 'function',
|
|
861
|
-
function: {
|
|
862
|
-
name: tool.name,
|
|
863
|
-
...(typeof tool.description === 'string' ? { description: tool.description } : {}),
|
|
864
|
-
...(tool.parameters && typeof tool.parameters === 'object' ? { parameters: tool.parameters } : {}),
|
|
865
|
-
},
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
return out.length > 0 ? out : undefined;
|
|
869
|
-
}
|
|
870
|
-
function convertResponsesInputToMessages(body) {
|
|
871
|
-
const out = [];
|
|
872
|
-
// "instructions" maps to a system message
|
|
873
|
-
if (typeof body.instructions === 'string' && body.instructions.length > 0) {
|
|
874
|
-
out.push({ role: 'system', content: body.instructions });
|
|
875
|
-
}
|
|
876
|
-
const input = body.input;
|
|
877
|
-
// Simple string input → single user message
|
|
878
|
-
if (typeof input === 'string') {
|
|
879
|
-
out.push({ role: 'user', content: input });
|
|
880
|
-
return out;
|
|
881
|
-
}
|
|
882
|
-
// Array of message objects
|
|
883
|
-
if (Array.isArray(input)) {
|
|
884
|
-
for (const item of input) {
|
|
885
|
-
if (!item || typeof item !== 'object') {
|
|
886
|
-
continue;
|
|
887
|
-
}
|
|
888
|
-
const msg = item;
|
|
889
|
-
const type = typeof msg.type === 'string' ? msg.type : '';
|
|
890
|
-
// function_call_output → tool role message with tool_call_id
|
|
891
|
-
if (type === 'function_call_output') {
|
|
892
|
-
out.push({
|
|
893
|
-
role: 'tool',
|
|
894
|
-
tool_call_id: typeof msg.call_id === 'string' ? msg.call_id : '',
|
|
895
|
-
content: typeof msg.output === 'string' ? msg.output : toStringContent(msg.output),
|
|
896
|
-
});
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
// function_call → assistant message with tool_calls
|
|
900
|
-
if (type === 'function_call') {
|
|
901
|
-
const chatCallId = typeof msg.call_id === 'string' && msg.call_id.length > 0
|
|
902
|
-
? msg.call_id
|
|
903
|
-
: (typeof msg.id === 'string' ? msg.id : '');
|
|
904
|
-
out.push({
|
|
905
|
-
role: 'assistant',
|
|
906
|
-
content: null,
|
|
907
|
-
tool_calls: [{
|
|
908
|
-
id: chatCallId,
|
|
909
|
-
type: 'function',
|
|
910
|
-
function: {
|
|
911
|
-
name: typeof msg.name === 'string' ? msg.name : '',
|
|
912
|
-
arguments: typeof msg.arguments === 'string' ? msg.arguments : JSON.stringify(msg.arguments ?? {}),
|
|
913
|
-
},
|
|
914
|
-
}],
|
|
915
|
-
});
|
|
916
|
-
continue;
|
|
917
|
-
}
|
|
918
|
-
const role = typeof msg.role === 'string' ? msg.role : 'user';
|
|
919
|
-
out.push({ role, content: toStringContent(msg.content) });
|
|
920
|
-
}
|
|
921
|
-
return out;
|
|
922
|
-
}
|
|
923
|
-
return out;
|
|
924
|
-
}
|
|
925
|
-
export function transformOpenAIResponsesRequestToOpenAIChat(request) {
|
|
926
|
-
if (!request.path.toLowerCase().startsWith('/v1/responses')) {
|
|
927
|
-
return null;
|
|
928
|
-
}
|
|
929
|
-
const body = parseJsonObject(request.body);
|
|
930
|
-
if (!body) {
|
|
931
|
-
return null;
|
|
932
|
-
}
|
|
933
|
-
const streamRequested = body.stream === true;
|
|
934
|
-
const requestedModel = typeof body.model === 'string' && body.model.trim().length > 0
|
|
935
|
-
? body.model.trim()
|
|
936
|
-
: null;
|
|
937
|
-
const messages = convertResponsesInputToMessages(body);
|
|
938
|
-
const transformedBody = {
|
|
939
|
-
...(requestedModel ? { model: requestedModel } : {}),
|
|
940
|
-
messages,
|
|
941
|
-
stream: streamRequested,
|
|
942
|
-
...(streamRequested ? { stream_options: { include_usage: true } } : {}),
|
|
943
|
-
};
|
|
944
|
-
if (typeof body.max_output_tokens === 'number') {
|
|
945
|
-
transformedBody.max_tokens = body.max_output_tokens;
|
|
946
|
-
}
|
|
947
|
-
if (typeof body.temperature === 'number') {
|
|
948
|
-
transformedBody.temperature = body.temperature;
|
|
949
|
-
}
|
|
950
|
-
if (typeof body.top_p === 'number') {
|
|
951
|
-
transformedBody.top_p = body.top_p;
|
|
952
|
-
}
|
|
953
|
-
if (Array.isArray(body.tools)) {
|
|
954
|
-
const chatTools = convertResponsesToolsToChatTools(body.tools);
|
|
955
|
-
if (chatTools) {
|
|
956
|
-
transformedBody.tools = chatTools;
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
if (body.tool_choice !== undefined) {
|
|
960
|
-
const tc = body.tool_choice;
|
|
961
|
-
if (tc && typeof tc === 'object' && !Array.isArray(tc)) {
|
|
962
|
-
const tcObj = tc;
|
|
963
|
-
if (tcObj.type === 'function' && typeof tcObj.name === 'string') {
|
|
964
|
-
transformedBody.tool_choice = { type: 'function', function: { name: tcObj.name } };
|
|
965
|
-
}
|
|
966
|
-
else {
|
|
967
|
-
transformedBody.tool_choice = tc;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
else {
|
|
971
|
-
transformedBody.tool_choice = tc;
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
if (body.metadata && typeof body.metadata === 'object' && !Array.isArray(body.metadata)) {
|
|
975
|
-
transformedBody.metadata = body.metadata;
|
|
976
|
-
}
|
|
977
|
-
return {
|
|
978
|
-
request: {
|
|
979
|
-
...request,
|
|
980
|
-
path: '/v1/chat/completions',
|
|
981
|
-
headers: { ...request.headers, 'content-type': 'application/json' },
|
|
982
|
-
body: encodeJson(transformedBody),
|
|
983
|
-
},
|
|
984
|
-
streamRequested,
|
|
985
|
-
requestedModel,
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
function buildOpenAIResponsesBody(response, parsed, options) {
|
|
989
|
-
const choices = Array.isArray(parsed.choices) ? parsed.choices : [];
|
|
990
|
-
const firstChoice = choices[0] && typeof choices[0] === 'object'
|
|
991
|
-
? choices[0]
|
|
992
|
-
: null;
|
|
993
|
-
const message = firstChoice?.message && typeof firstChoice.message === 'object'
|
|
994
|
-
? firstChoice.message
|
|
995
|
-
: null;
|
|
996
|
-
const outputItems = [];
|
|
997
|
-
const textContent = toStringContent(message?.content);
|
|
998
|
-
if (textContent.length > 0) {
|
|
999
|
-
outputItems.push({
|
|
1000
|
-
type: 'message',
|
|
1001
|
-
id: `${typeof parsed.id === 'string' && parsed.id.length > 0 ? parsed.id : `resp_${response.requestId}`}_msg_1`,
|
|
1002
|
-
role: 'assistant',
|
|
1003
|
-
status: 'completed',
|
|
1004
|
-
content: [{
|
|
1005
|
-
type: 'output_text',
|
|
1006
|
-
text: textContent,
|
|
1007
|
-
annotations: [],
|
|
1008
|
-
}],
|
|
1009
|
-
});
|
|
1010
|
-
}
|
|
1011
|
-
const toolCalls = Array.isArray(message?.tool_calls) ? message.tool_calls : [];
|
|
1012
|
-
for (const [index, toolCallRaw] of toolCalls.entries()) {
|
|
1013
|
-
if (!toolCallRaw || typeof toolCallRaw !== 'object') {
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
const toolCall = toolCallRaw;
|
|
1017
|
-
const functionPayload = toolCall.function && typeof toolCall.function === 'object'
|
|
1018
|
-
? toolCall.function
|
|
1019
|
-
: {};
|
|
1020
|
-
const callId = typeof toolCall.id === 'string' && toolCall.id.length > 0
|
|
1021
|
-
? toolCall.id
|
|
1022
|
-
: `call_${index + 1}`;
|
|
1023
|
-
outputItems.push({
|
|
1024
|
-
type: 'function_call',
|
|
1025
|
-
id: callId,
|
|
1026
|
-
call_id: callId,
|
|
1027
|
-
name: typeof functionPayload.name === 'string' ? functionPayload.name : '',
|
|
1028
|
-
arguments: typeof functionPayload.arguments === 'string' ? functionPayload.arguments : '{}',
|
|
1029
|
-
status: 'completed',
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
const usage = parsed.usage && typeof parsed.usage === 'object'
|
|
1033
|
-
? parsed.usage
|
|
1034
|
-
: {};
|
|
1035
|
-
const inputTokens = toNonNegativeInt(usage.prompt_tokens ?? usage.input_tokens);
|
|
1036
|
-
const outputTokens = toNonNegativeInt(usage.completion_tokens ?? usage.output_tokens);
|
|
1037
|
-
const id = typeof parsed.id === 'string' && parsed.id.length > 0 ? parsed.id : `resp_${response.requestId}`;
|
|
1038
|
-
const service = typeof parsed.model === 'string' && parsed.model.length > 0
|
|
1039
|
-
? parsed.model
|
|
1040
|
-
: (options.fallbackModel ?? 'unknown');
|
|
1041
|
-
return {
|
|
1042
|
-
id,
|
|
1043
|
-
object: 'response',
|
|
1044
|
-
model: service,
|
|
1045
|
-
status: 'completed',
|
|
1046
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
1047
|
-
output: outputItems,
|
|
1048
|
-
output_text: textContent,
|
|
1049
|
-
usage: {
|
|
1050
|
-
input_tokens: inputTokens,
|
|
1051
|
-
output_tokens: outputTokens,
|
|
1052
|
-
total_tokens: inputTokens + outputTokens,
|
|
1053
|
-
},
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
function buildOpenAIResponsesStream(body) {
|
|
1057
|
-
const sseEvents = [];
|
|
1058
|
-
let sequenceNumber = 0;
|
|
1059
|
-
const pushEvent = (event, data) => {
|
|
1060
|
-
sseEvents.push(`event: ${event}\ndata: ${JSON.stringify({ type: event, sequence_number: sequenceNumber++, ...data })}\n\n`);
|
|
1061
|
-
};
|
|
1062
|
-
pushEvent('response.created', {
|
|
1063
|
-
response: {
|
|
1064
|
-
...body,
|
|
1065
|
-
status: 'in_progress',
|
|
1066
|
-
output: [],
|
|
1067
|
-
output_text: '',
|
|
1068
|
-
},
|
|
1069
|
-
});
|
|
1070
|
-
for (const [outputIndex, outputItem] of body.output.entries()) {
|
|
1071
|
-
if (outputItem.type === 'message') {
|
|
1072
|
-
const pendingItem = {
|
|
1073
|
-
...outputItem,
|
|
1074
|
-
status: 'in_progress',
|
|
1075
|
-
content: outputItem.content.map((part) => ({ ...part, text: '' })),
|
|
1076
|
-
};
|
|
1077
|
-
pushEvent('response.output_item.added', {
|
|
1078
|
-
output_index: outputIndex,
|
|
1079
|
-
item: pendingItem,
|
|
1080
|
-
});
|
|
1081
|
-
for (const [contentIndex, part] of outputItem.content.entries()) {
|
|
1082
|
-
const pendingPart = { ...part, text: '' };
|
|
1083
|
-
pushEvent('response.content_part.added', {
|
|
1084
|
-
output_index: outputIndex,
|
|
1085
|
-
item_id: outputItem.id,
|
|
1086
|
-
content_index: contentIndex,
|
|
1087
|
-
part: pendingPart,
|
|
1088
|
-
});
|
|
1089
|
-
pushEvent('response.output_text.delta', {
|
|
1090
|
-
output_index: outputIndex,
|
|
1091
|
-
item_id: outputItem.id,
|
|
1092
|
-
content_index: contentIndex,
|
|
1093
|
-
delta: part.text,
|
|
1094
|
-
logprobs: [],
|
|
1095
|
-
});
|
|
1096
|
-
pushEvent('response.output_text.done', {
|
|
1097
|
-
output_index: outputIndex,
|
|
1098
|
-
item_id: outputItem.id,
|
|
1099
|
-
content_index: contentIndex,
|
|
1100
|
-
text: part.text,
|
|
1101
|
-
logprobs: [],
|
|
1102
|
-
});
|
|
1103
|
-
pushEvent('response.content_part.done', {
|
|
1104
|
-
output_index: outputIndex,
|
|
1105
|
-
item_id: outputItem.id,
|
|
1106
|
-
content_index: contentIndex,
|
|
1107
|
-
part,
|
|
1108
|
-
});
|
|
1109
|
-
}
|
|
1110
|
-
pushEvent('response.output_item.done', {
|
|
1111
|
-
output_index: outputIndex,
|
|
1112
|
-
item: outputItem,
|
|
1113
|
-
});
|
|
1114
|
-
continue;
|
|
1115
|
-
}
|
|
1116
|
-
const pendingItem = {
|
|
1117
|
-
...outputItem,
|
|
1118
|
-
status: 'in_progress',
|
|
1119
|
-
arguments: '',
|
|
1120
|
-
};
|
|
1121
|
-
pushEvent('response.output_item.added', {
|
|
1122
|
-
output_index: outputIndex,
|
|
1123
|
-
item: pendingItem,
|
|
1124
|
-
});
|
|
1125
|
-
pushEvent('response.function_call_arguments.delta', {
|
|
1126
|
-
output_index: outputIndex,
|
|
1127
|
-
item_id: outputItem.id,
|
|
1128
|
-
call_id: outputItem.call_id,
|
|
1129
|
-
delta: outputItem.arguments,
|
|
1130
|
-
});
|
|
1131
|
-
pushEvent('response.function_call_arguments.done', {
|
|
1132
|
-
output_index: outputIndex,
|
|
1133
|
-
item_id: outputItem.id,
|
|
1134
|
-
call_id: outputItem.call_id,
|
|
1135
|
-
name: outputItem.name,
|
|
1136
|
-
arguments: outputItem.arguments,
|
|
1137
|
-
});
|
|
1138
|
-
pushEvent('response.output_item.done', {
|
|
1139
|
-
output_index: outputIndex,
|
|
1140
|
-
item: outputItem,
|
|
1141
|
-
});
|
|
1142
|
-
}
|
|
1143
|
-
pushEvent('response.completed', { response: body });
|
|
1144
|
-
sseEvents.push('data: [DONE]\n\n');
|
|
1145
|
-
return new TextEncoder().encode(sseEvents.join(''));
|
|
1146
|
-
}
|
|
1147
|
-
export function createOpenAIChatToResponsesStreamingAdapter(options) {
|
|
1148
|
-
let rawBuffer = '';
|
|
1149
|
-
const decoder = new TextDecoder();
|
|
1150
|
-
let sequenceNumber = 0;
|
|
1151
|
-
let responseCreated = false;
|
|
1152
|
-
let outputStarted = false;
|
|
1153
|
-
let outputDone = false;
|
|
1154
|
-
let responseId = options.fallbackModel ? `resp_${options.fallbackModel}` : 'resp_stream';
|
|
1155
|
-
let responseModel = options.fallbackModel ?? 'unknown';
|
|
1156
|
-
let textBuffer = '';
|
|
1157
|
-
let inputTokens = 0;
|
|
1158
|
-
let outputTokens = 0;
|
|
1159
|
-
const toolCallMap = new Map();
|
|
1160
|
-
const pushEvent = (emitted, event, data) => {
|
|
1161
|
-
emitted.push({
|
|
1162
|
-
event,
|
|
1163
|
-
data: {
|
|
1164
|
-
type: event,
|
|
1165
|
-
sequence_number: sequenceNumber++,
|
|
1166
|
-
...data,
|
|
1167
|
-
},
|
|
1168
|
-
});
|
|
1169
|
-
};
|
|
1170
|
-
const ensureResponseCreated = (emitted) => {
|
|
1171
|
-
if (!responseCreated) {
|
|
1172
|
-
responseCreated = true;
|
|
1173
|
-
pushEvent(emitted, 'response.created', {
|
|
1174
|
-
response: {
|
|
1175
|
-
id: responseId,
|
|
1176
|
-
object: 'response',
|
|
1177
|
-
model: responseModel,
|
|
1178
|
-
status: 'in_progress',
|
|
1179
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
1180
|
-
output: [],
|
|
1181
|
-
output_text: '',
|
|
1182
|
-
usage: {
|
|
1183
|
-
input_tokens: 0,
|
|
1184
|
-
output_tokens: 0,
|
|
1185
|
-
total_tokens: 0,
|
|
1186
|
-
},
|
|
1187
|
-
},
|
|
1188
|
-
});
|
|
1189
|
-
}
|
|
1190
|
-
};
|
|
1191
|
-
const ensureTextOutputStarted = (emitted) => {
|
|
1192
|
-
ensureResponseCreated(emitted);
|
|
1193
|
-
if (!outputStarted) {
|
|
1194
|
-
outputStarted = true;
|
|
1195
|
-
pushEvent(emitted, 'response.output_item.added', {
|
|
1196
|
-
output_index: 0,
|
|
1197
|
-
item: {
|
|
1198
|
-
type: 'message',
|
|
1199
|
-
id: `${responseId}_msg_1`,
|
|
1200
|
-
role: 'assistant',
|
|
1201
|
-
status: 'in_progress',
|
|
1202
|
-
content: [{
|
|
1203
|
-
type: 'output_text',
|
|
1204
|
-
text: '',
|
|
1205
|
-
annotations: [],
|
|
1206
|
-
}],
|
|
1207
|
-
},
|
|
1208
|
-
});
|
|
1209
|
-
pushEvent(emitted, 'response.content_part.added', {
|
|
1210
|
-
output_index: 0,
|
|
1211
|
-
item_id: `${responseId}_msg_1`,
|
|
1212
|
-
content_index: 0,
|
|
1213
|
-
part: {
|
|
1214
|
-
type: 'output_text',
|
|
1215
|
-
text: '',
|
|
1216
|
-
annotations: [],
|
|
1217
|
-
},
|
|
1218
|
-
});
|
|
1219
|
-
}
|
|
1220
|
-
};
|
|
1221
|
-
const getToolOutputIndex = (index) => index + (outputStarted ? 1 : 0);
|
|
1222
|
-
const finalize = (emitted) => {
|
|
1223
|
-
ensureResponseCreated(emitted);
|
|
1224
|
-
if (!outputDone) {
|
|
1225
|
-
outputDone = true;
|
|
1226
|
-
if (outputStarted) {
|
|
1227
|
-
pushEvent(emitted, 'response.output_text.done', {
|
|
1228
|
-
output_index: 0,
|
|
1229
|
-
item_id: `${responseId}_msg_1`,
|
|
1230
|
-
content_index: 0,
|
|
1231
|
-
text: textBuffer,
|
|
1232
|
-
logprobs: [],
|
|
1233
|
-
});
|
|
1234
|
-
pushEvent(emitted, 'response.content_part.done', {
|
|
1235
|
-
output_index: 0,
|
|
1236
|
-
item_id: `${responseId}_msg_1`,
|
|
1237
|
-
content_index: 0,
|
|
1238
|
-
part: {
|
|
1239
|
-
type: 'output_text',
|
|
1240
|
-
text: textBuffer,
|
|
1241
|
-
annotations: [],
|
|
1242
|
-
},
|
|
1243
|
-
});
|
|
1244
|
-
pushEvent(emitted, 'response.output_item.done', {
|
|
1245
|
-
output_index: 0,
|
|
1246
|
-
item: {
|
|
1247
|
-
type: 'message',
|
|
1248
|
-
id: `${responseId}_msg_1`,
|
|
1249
|
-
role: 'assistant',
|
|
1250
|
-
status: 'completed',
|
|
1251
|
-
content: [{
|
|
1252
|
-
type: 'output_text',
|
|
1253
|
-
text: textBuffer,
|
|
1254
|
-
annotations: [],
|
|
1255
|
-
}],
|
|
1256
|
-
},
|
|
1257
|
-
});
|
|
1258
|
-
}
|
|
1259
|
-
for (const [index, toolCall] of [...toolCallMap.entries()].sort((a, b) => a[0] - b[0])) {
|
|
1260
|
-
const outputIndex = getToolOutputIndex(index);
|
|
1261
|
-
pushEvent(emitted, 'response.function_call_arguments.done', {
|
|
1262
|
-
output_index: outputIndex,
|
|
1263
|
-
item_id: toolCall.id,
|
|
1264
|
-
call_id: toolCall.id,
|
|
1265
|
-
name: toolCall.name,
|
|
1266
|
-
arguments: toolCall.arguments,
|
|
1267
|
-
});
|
|
1268
|
-
pushEvent(emitted, 'response.output_item.done', {
|
|
1269
|
-
output_index: outputIndex,
|
|
1270
|
-
item: {
|
|
1271
|
-
type: 'function_call',
|
|
1272
|
-
id: toolCall.id,
|
|
1273
|
-
call_id: toolCall.id,
|
|
1274
|
-
name: toolCall.name,
|
|
1275
|
-
arguments: toolCall.arguments,
|
|
1276
|
-
status: 'completed',
|
|
1277
|
-
},
|
|
1278
|
-
});
|
|
1279
|
-
}
|
|
1280
|
-
pushEvent(emitted, 'response.completed', {
|
|
1281
|
-
response: {
|
|
1282
|
-
id: responseId,
|
|
1283
|
-
object: 'response',
|
|
1284
|
-
model: responseModel,
|
|
1285
|
-
status: 'completed',
|
|
1286
|
-
created_at: Math.floor(Date.now() / 1000),
|
|
1287
|
-
output: [
|
|
1288
|
-
...(outputStarted ? [{
|
|
1289
|
-
type: 'message',
|
|
1290
|
-
id: `${responseId}_msg_1`,
|
|
1291
|
-
role: 'assistant',
|
|
1292
|
-
status: 'completed',
|
|
1293
|
-
content: [{
|
|
1294
|
-
type: 'output_text',
|
|
1295
|
-
text: textBuffer,
|
|
1296
|
-
annotations: [],
|
|
1297
|
-
}],
|
|
1298
|
-
}] : []),
|
|
1299
|
-
...[...toolCallMap.entries()]
|
|
1300
|
-
.sort((a, b) => a[0] - b[0])
|
|
1301
|
-
.map(([, toolCall]) => ({
|
|
1302
|
-
type: 'function_call',
|
|
1303
|
-
id: toolCall.id,
|
|
1304
|
-
call_id: toolCall.id,
|
|
1305
|
-
name: toolCall.name,
|
|
1306
|
-
arguments: toolCall.arguments,
|
|
1307
|
-
status: 'completed',
|
|
1308
|
-
})),
|
|
1309
|
-
],
|
|
1310
|
-
output_text: textBuffer,
|
|
1311
|
-
usage: {
|
|
1312
|
-
input_tokens: inputTokens,
|
|
1313
|
-
output_tokens: outputTokens,
|
|
1314
|
-
total_tokens: inputTokens + outputTokens,
|
|
1315
|
-
},
|
|
1316
|
-
},
|
|
1317
|
-
});
|
|
1318
|
-
emitted.push({ data: '[DONE]' });
|
|
1319
|
-
}
|
|
1320
|
-
};
|
|
1321
|
-
return {
|
|
1322
|
-
adaptStart(response) {
|
|
1323
|
-
return {
|
|
1324
|
-
...response,
|
|
1325
|
-
headers: {
|
|
1326
|
-
...response.headers,
|
|
1327
|
-
'content-type': 'text/event-stream',
|
|
1328
|
-
'cache-control': 'no-cache',
|
|
1329
|
-
},
|
|
1330
|
-
body: new Uint8Array(0),
|
|
1331
|
-
};
|
|
1332
|
-
},
|
|
1333
|
-
adaptChunk(chunk) {
|
|
1334
|
-
const out = [];
|
|
1335
|
-
if (chunk.data.length > 0) {
|
|
1336
|
-
rawBuffer += decoder.decode(chunk.data, { stream: !chunk.done });
|
|
1337
|
-
}
|
|
1338
|
-
const { events, remainder } = parseSseBuffer(rawBuffer);
|
|
1339
|
-
rawBuffer = remainder;
|
|
1340
|
-
const emitted = [];
|
|
1341
|
-
for (const event of events) {
|
|
1342
|
-
if (event.data === '[DONE]') {
|
|
1343
|
-
continue;
|
|
1344
|
-
}
|
|
1345
|
-
const parsed = parseJsonSafe(event.data);
|
|
1346
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
1347
|
-
continue;
|
|
1348
|
-
}
|
|
1349
|
-
const payload = parsed;
|
|
1350
|
-
if (typeof payload.id === 'string' && payload.id.length > 0) {
|
|
1351
|
-
responseId = payload.id;
|
|
1352
|
-
}
|
|
1353
|
-
if (typeof payload.model === 'string' && payload.model.length > 0) {
|
|
1354
|
-
responseModel = payload.model;
|
|
1355
|
-
}
|
|
1356
|
-
const usage = payload.usage && typeof payload.usage === 'object'
|
|
1357
|
-
? payload.usage
|
|
1358
|
-
: null;
|
|
1359
|
-
if (usage) {
|
|
1360
|
-
inputTokens = toNonNegativeInt(usage.prompt_tokens ?? usage.input_tokens);
|
|
1361
|
-
outputTokens = toNonNegativeInt(usage.completion_tokens ?? usage.output_tokens);
|
|
1362
|
-
}
|
|
1363
|
-
const choices = Array.isArray(payload.choices) ? payload.choices : [];
|
|
1364
|
-
const firstChoice = choices[0] && typeof choices[0] === 'object'
|
|
1365
|
-
? choices[0]
|
|
1366
|
-
: null;
|
|
1367
|
-
const delta = firstChoice?.delta && typeof firstChoice.delta === 'object'
|
|
1368
|
-
? firstChoice.delta
|
|
1369
|
-
: null;
|
|
1370
|
-
const textDelta = typeof delta?.content === 'string' ? delta.content : '';
|
|
1371
|
-
if (textDelta.length > 0) {
|
|
1372
|
-
ensureTextOutputStarted(emitted);
|
|
1373
|
-
textBuffer += textDelta;
|
|
1374
|
-
pushEvent(emitted, 'response.output_text.delta', {
|
|
1375
|
-
output_index: 0,
|
|
1376
|
-
item_id: `${responseId}_msg_1`,
|
|
1377
|
-
content_index: 0,
|
|
1378
|
-
delta: textDelta,
|
|
1379
|
-
logprobs: [],
|
|
1380
|
-
});
|
|
1381
|
-
}
|
|
1382
|
-
const deltaToolCalls = Array.isArray(delta?.tool_calls) ? delta.tool_calls : [];
|
|
1383
|
-
for (const toolCallRaw of deltaToolCalls) {
|
|
1384
|
-
if (!toolCallRaw || typeof toolCallRaw !== 'object') {
|
|
1385
|
-
continue;
|
|
1386
|
-
}
|
|
1387
|
-
const toolCall = toolCallRaw;
|
|
1388
|
-
const rawIndex = typeof toolCall.index === 'number' ? toolCall.index : toolCallMap.size;
|
|
1389
|
-
const index = Number.isFinite(rawIndex) ? Math.max(0, Math.floor(rawIndex)) : toolCallMap.size;
|
|
1390
|
-
const functionPayload = toolCall.function && typeof toolCall.function === 'object'
|
|
1391
|
-
? toolCall.function
|
|
1392
|
-
: {};
|
|
1393
|
-
const existing = toolCallMap.get(index);
|
|
1394
|
-
const id = typeof toolCall.id === 'string' && toolCall.id.length > 0
|
|
1395
|
-
? toolCall.id
|
|
1396
|
-
: (existing?.id ?? `call_${index + 1}`);
|
|
1397
|
-
const name = typeof functionPayload.name === 'string' && functionPayload.name.length > 0
|
|
1398
|
-
? functionPayload.name
|
|
1399
|
-
: (existing?.name ?? '');
|
|
1400
|
-
const argumentsDelta = typeof functionPayload.arguments === 'string'
|
|
1401
|
-
? functionPayload.arguments
|
|
1402
|
-
: '';
|
|
1403
|
-
if (!existing) {
|
|
1404
|
-
ensureResponseCreated(emitted);
|
|
1405
|
-
const outputIndex = getToolOutputIndex(index);
|
|
1406
|
-
pushEvent(emitted, 'response.output_item.added', {
|
|
1407
|
-
output_index: outputIndex,
|
|
1408
|
-
item: {
|
|
1409
|
-
type: 'function_call',
|
|
1410
|
-
id,
|
|
1411
|
-
call_id: id,
|
|
1412
|
-
name,
|
|
1413
|
-
arguments: '',
|
|
1414
|
-
status: 'in_progress',
|
|
1415
|
-
},
|
|
1416
|
-
});
|
|
1417
|
-
}
|
|
1418
|
-
if (argumentsDelta.length > 0) {
|
|
1419
|
-
const outputIndex = getToolOutputIndex(index);
|
|
1420
|
-
pushEvent(emitted, 'response.function_call_arguments.delta', {
|
|
1421
|
-
output_index: outputIndex,
|
|
1422
|
-
item_id: id,
|
|
1423
|
-
call_id: id,
|
|
1424
|
-
delta: argumentsDelta,
|
|
1425
|
-
});
|
|
1426
|
-
}
|
|
1427
|
-
toolCallMap.set(index, {
|
|
1428
|
-
id,
|
|
1429
|
-
name,
|
|
1430
|
-
arguments: (existing?.arguments ?? '') + argumentsDelta,
|
|
1431
|
-
});
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
if (chunk.done) {
|
|
1435
|
-
finalize(emitted);
|
|
1436
|
-
}
|
|
1437
|
-
if (emitted.length > 0) {
|
|
1438
|
-
out.push({
|
|
1439
|
-
requestId: chunk.requestId,
|
|
1440
|
-
data: encodeSseEvents(emitted),
|
|
1441
|
-
done: chunk.done,
|
|
1442
|
-
});
|
|
1443
|
-
}
|
|
1444
|
-
else if (chunk.done) {
|
|
1445
|
-
out.push({
|
|
1446
|
-
requestId: chunk.requestId,
|
|
1447
|
-
data: new Uint8Array(0),
|
|
1448
|
-
done: true,
|
|
1449
|
-
});
|
|
1450
|
-
}
|
|
1451
|
-
return out;
|
|
1452
|
-
},
|
|
1453
|
-
};
|
|
1454
|
-
}
|
|
1455
|
-
export function transformOpenAIChatResponseToOpenAIResponses(response, options) {
|
|
1456
|
-
const parsed = parseJsonObject(response.body);
|
|
1457
|
-
if (!parsed) {
|
|
1458
|
-
return response;
|
|
1459
|
-
}
|
|
1460
|
-
if (response.statusCode >= 400) {
|
|
1461
|
-
const errorPayload = parsed.error && typeof parsed.error === 'object'
|
|
1462
|
-
? parsed.error
|
|
1463
|
-
: parsed;
|
|
1464
|
-
const errorBody = errorPayload === parsed ? parsed : { error: errorPayload };
|
|
1465
|
-
if (options.streamRequested) {
|
|
1466
|
-
return {
|
|
1467
|
-
...response,
|
|
1468
|
-
headers: {
|
|
1469
|
-
...response.headers,
|
|
1470
|
-
'content-type': 'text/event-stream',
|
|
1471
|
-
'cache-control': 'no-cache',
|
|
1472
|
-
},
|
|
1473
|
-
body: new TextEncoder().encode(`event: error\ndata: ${JSON.stringify(errorBody)}\n\n`),
|
|
1474
|
-
};
|
|
1475
|
-
}
|
|
1476
|
-
return {
|
|
1477
|
-
...response,
|
|
1478
|
-
headers: { ...response.headers, 'content-type': 'application/json' },
|
|
1479
|
-
body: encodeJson(errorBody),
|
|
1480
|
-
};
|
|
1481
|
-
}
|
|
1482
|
-
const responsesBody = buildOpenAIResponsesBody(response, parsed, options);
|
|
1483
|
-
if (!options.streamRequested) {
|
|
1484
|
-
return {
|
|
1485
|
-
...response,
|
|
1486
|
-
headers: { ...response.headers, 'content-type': 'application/json' },
|
|
1487
|
-
body: encodeJson(responsesBody),
|
|
1488
|
-
};
|
|
1489
|
-
}
|
|
1490
|
-
return {
|
|
1491
|
-
...response,
|
|
1492
|
-
headers: { ...response.headers, 'content-type': 'text/event-stream', 'cache-control': 'no-cache' },
|
|
1493
|
-
body: buildOpenAIResponsesStream(responsesBody),
|
|
1494
|
-
};
|
|
1495
|
-
}
|
|
1
|
+
// Re-export everything from @antseed/api-adapter for backward compatibility.
|
|
2
|
+
// The adapter source now lives in packages/api-adapter.
|
|
3
|
+
export { createOpenAIChatToAnthropicStreamingAdapter, createOpenAIChatToResponsesStreamingAdapter, detectRequestServiceApiProtocol, inferProviderDefaultServiceApiProtocols, selectTargetProtocolForRequest, transformAnthropicMessagesRequestToOpenAIChat, transformOpenAIChatResponseToAnthropicMessage, transformOpenAIResponsesRequestToOpenAIChat, transformOpenAIChatResponseToOpenAIResponses, } from '@antseed/api-adapter';
|
|
1496
4
|
//# sourceMappingURL=service-api-adapter.js.map
|