protocol-proxy 2.3.2 → 2.3.4
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/lib/converters/anthropic-to-gemini.js +4 -2
- package/lib/converters/anthropic-to-openai.js +23 -10
- package/lib/converters/gemini-to-anthropic.js +4 -2
- package/lib/converters/gemini-to-openai.js +4 -2
- package/lib/converters/openai-to-anthropic.js +4 -2
- package/lib/converters/openai-to-gemini.js +4 -2
- package/package.json +1 -1
|
@@ -133,12 +133,14 @@ function mapFinishReason(reason) {
|
|
|
133
133
|
// ==================== SSE 流式转换 ====================
|
|
134
134
|
|
|
135
135
|
function createSSEConverter() {
|
|
136
|
-
const state = { started: false, textBlockStarted: false, textBlockClosed: false, blockIndex: 0, sentFunctionCall: new Map() };
|
|
136
|
+
const state = { started: false, textBlockStarted: false, textBlockClosed: false, blockIndex: 0, sentFunctionCall: new Map(), buffer: '' };
|
|
137
137
|
|
|
138
138
|
return {
|
|
139
139
|
convertChunk(chunkText) {
|
|
140
140
|
let output = '';
|
|
141
|
-
|
|
141
|
+
state.buffer += chunkText;
|
|
142
|
+
const lines = state.buffer.split('\n');
|
|
143
|
+
state.buffer = lines.pop() || '';
|
|
142
144
|
|
|
143
145
|
for (const line of lines) {
|
|
144
146
|
const trimmed = line.trim();
|
|
@@ -218,7 +218,10 @@ function createSSEConverter(targetModel) {
|
|
|
218
218
|
messageId: null,
|
|
219
219
|
started: false,
|
|
220
220
|
textBlockStarted: false,
|
|
221
|
-
|
|
221
|
+
textBlockClosed: false,
|
|
222
|
+
textBlockIndex: 0,
|
|
223
|
+
blockIndex: 0,
|
|
224
|
+
toolCalls: new Map(), // index -> { id, name, args, blockIndex }
|
|
222
225
|
buffer: '',
|
|
223
226
|
};
|
|
224
227
|
|
|
@@ -292,32 +295,41 @@ function processLine(line, state, targetModel) {
|
|
|
292
295
|
if (delta.content !== undefined && delta.content !== null) {
|
|
293
296
|
if (!state.textBlockStarted) {
|
|
294
297
|
state.textBlockStarted = true;
|
|
298
|
+
state.textBlockIndex = state.blockIndex++;
|
|
295
299
|
output += encodeAnthropicEvent('content_block_start', {
|
|
296
300
|
type: 'content_block_start',
|
|
297
|
-
index:
|
|
301
|
+
index: state.textBlockIndex,
|
|
298
302
|
content_block: { type: 'text', text: '' },
|
|
299
303
|
});
|
|
300
304
|
}
|
|
301
305
|
output += encodeAnthropicEvent('content_block_delta', {
|
|
302
306
|
type: 'content_block_delta',
|
|
303
|
-
index:
|
|
307
|
+
index: state.textBlockIndex,
|
|
304
308
|
delta: { type: 'text_delta', text: delta.content },
|
|
305
309
|
});
|
|
306
310
|
}
|
|
307
311
|
|
|
308
312
|
// tool_calls
|
|
309
313
|
if (delta.tool_calls && Array.isArray(delta.tool_calls)) {
|
|
314
|
+
// 在首个 tool_call 前关闭 text block
|
|
315
|
+
if (state.textBlockStarted && !state.textBlockClosed) {
|
|
316
|
+
state.textBlockClosed = true;
|
|
317
|
+
output += encodeAnthropicEvent('content_block_stop', {
|
|
318
|
+
type: 'content_block_stop',
|
|
319
|
+
index: state.textBlockIndex,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
310
322
|
for (const tc of delta.tool_calls) {
|
|
311
323
|
const idx = tc.index || 0;
|
|
312
324
|
let tool = state.toolCalls.get(idx);
|
|
313
325
|
|
|
314
326
|
if (!tool) {
|
|
315
327
|
// 新的 tool_call
|
|
316
|
-
tool = { id: tc.id, name: tc.function?.name, args: '' };
|
|
328
|
+
tool = { id: tc.id, name: tc.function?.name, args: '', blockIndex: state.blockIndex++ };
|
|
317
329
|
state.toolCalls.set(idx, tool);
|
|
318
330
|
output += encodeAnthropicEvent('content_block_start', {
|
|
319
331
|
type: 'content_block_start',
|
|
320
|
-
index:
|
|
332
|
+
index: tool.blockIndex,
|
|
321
333
|
content_block: {
|
|
322
334
|
type: 'tool_use',
|
|
323
335
|
id: tc.id,
|
|
@@ -331,7 +343,7 @@ function processLine(line, state, targetModel) {
|
|
|
331
343
|
tool.args += tc.function.arguments;
|
|
332
344
|
output += encodeAnthropicEvent('content_block_delta', {
|
|
333
345
|
type: 'content_block_delta',
|
|
334
|
-
index:
|
|
346
|
+
index: tool.blockIndex,
|
|
335
347
|
delta: { type: 'input_json_delta', partial_json: tc.function.arguments },
|
|
336
348
|
});
|
|
337
349
|
}
|
|
@@ -341,16 +353,17 @@ function processLine(line, state, targetModel) {
|
|
|
341
353
|
// finish_reason
|
|
342
354
|
if (choice.finish_reason) {
|
|
343
355
|
const stopReason = mapFinishReason(choice.finish_reason);
|
|
344
|
-
if (state.textBlockStarted) {
|
|
356
|
+
if (state.textBlockStarted && !state.textBlockClosed) {
|
|
357
|
+
state.textBlockClosed = true;
|
|
345
358
|
output += encodeAnthropicEvent('content_block_stop', {
|
|
346
359
|
type: 'content_block_stop',
|
|
347
|
-
index:
|
|
360
|
+
index: state.textBlockIndex,
|
|
348
361
|
});
|
|
349
362
|
}
|
|
350
|
-
for (
|
|
363
|
+
for (const [, tool] of state.toolCalls) {
|
|
351
364
|
output += encodeAnthropicEvent('content_block_stop', {
|
|
352
365
|
type: 'content_block_stop',
|
|
353
|
-
index:
|
|
366
|
+
index: tool.blockIndex,
|
|
354
367
|
});
|
|
355
368
|
}
|
|
356
369
|
output += encodeAnthropicEvent('message_delta', {
|
|
@@ -155,12 +155,14 @@ function mapFinishReason(reason) {
|
|
|
155
155
|
// ==================== SSE 流式转换 ====================
|
|
156
156
|
|
|
157
157
|
function createSSEConverter(nameToId = new Map()) {
|
|
158
|
-
const state = { started: false, textBlockStarted: false, textBlockClosed: false, blockIndex: 0, sentFunctionCall: new Map(), nameToId };
|
|
158
|
+
const state = { started: false, textBlockStarted: false, textBlockClosed: false, blockIndex: 0, sentFunctionCall: new Map(), nameToId, buffer: '' };
|
|
159
159
|
|
|
160
160
|
return {
|
|
161
161
|
convertChunk(chunkText) {
|
|
162
162
|
let output = '';
|
|
163
|
-
|
|
163
|
+
state.buffer += chunkText;
|
|
164
|
+
const lines = state.buffer.split('\n');
|
|
165
|
+
state.buffer = lines.pop() || '';
|
|
164
166
|
|
|
165
167
|
for (const line of lines) {
|
|
166
168
|
const trimmed = line.trim();
|
|
@@ -152,12 +152,14 @@ function mapFinishReason(reason) {
|
|
|
152
152
|
// ==================== SSE 流式转换 ====================
|
|
153
153
|
|
|
154
154
|
function createSSEConverter() {
|
|
155
|
-
const state = { started: false, sentFunctionCall: new Map() };
|
|
155
|
+
const state = { started: false, sentFunctionCall: new Map(), buffer: '' };
|
|
156
156
|
|
|
157
157
|
return {
|
|
158
158
|
convertChunk(chunkText) {
|
|
159
159
|
let output = '';
|
|
160
|
-
|
|
160
|
+
state.buffer += chunkText;
|
|
161
|
+
const lines = state.buffer.split('\n');
|
|
162
|
+
state.buffer = lines.pop() || '';
|
|
161
163
|
|
|
162
164
|
for (const line of lines) {
|
|
163
165
|
const trimmed = line.trim();
|
|
@@ -188,6 +188,7 @@ function createSSEConverter(targetModel) {
|
|
|
188
188
|
blockIndex: 0,
|
|
189
189
|
toolUseId: null,
|
|
190
190
|
toolName: null,
|
|
191
|
+
toolCallIndex: -1,
|
|
191
192
|
sentRole: false,
|
|
192
193
|
sentToolInit: false,
|
|
193
194
|
buffer: '',
|
|
@@ -243,6 +244,7 @@ function processLine(line, state, targetModel) {
|
|
|
243
244
|
if (state.blockType === 'tool_use') {
|
|
244
245
|
state.toolUseId = event.content_block.id;
|
|
245
246
|
state.toolName = event.content_block.name;
|
|
247
|
+
state.toolCallIndex = (state.toolCallIndex || 0) + 1;
|
|
246
248
|
}
|
|
247
249
|
return '';
|
|
248
250
|
}
|
|
@@ -267,7 +269,7 @@ function processLine(line, state, targetModel) {
|
|
|
267
269
|
state.sentToolInit = true;
|
|
268
270
|
const toolCallChunk = {
|
|
269
271
|
tool_calls: [{
|
|
270
|
-
index:
|
|
272
|
+
index: state.toolCallIndex,
|
|
271
273
|
id: state.toolUseId,
|
|
272
274
|
type: 'function',
|
|
273
275
|
function: { name: state.toolName, arguments: delta.partial_json },
|
|
@@ -276,7 +278,7 @@ function processLine(line, state, targetModel) {
|
|
|
276
278
|
return prefix + encodeOpenAIChunk(state.messageId, targetModel, toolCallChunk);
|
|
277
279
|
}
|
|
278
280
|
return prefix + encodeOpenAIChunk(state.messageId, targetModel, {
|
|
279
|
-
tool_calls: [{ index:
|
|
281
|
+
tool_calls: [{ index: state.toolCallIndex, function: { arguments: delta.partial_json } }],
|
|
280
282
|
});
|
|
281
283
|
}
|
|
282
284
|
|
|
@@ -183,12 +183,14 @@ function mapFinishReason(reason) {
|
|
|
183
183
|
// ==================== SSE 流式转换 ====================
|
|
184
184
|
|
|
185
185
|
function createSSEConverter() {
|
|
186
|
-
const state = { started: false, sentFunctionCall: new Map() };
|
|
186
|
+
const state = { started: false, sentFunctionCall: new Map(), buffer: '' };
|
|
187
187
|
|
|
188
188
|
return {
|
|
189
189
|
convertChunk(chunkText) {
|
|
190
190
|
let output = '';
|
|
191
|
-
|
|
191
|
+
state.buffer += chunkText;
|
|
192
|
+
const lines = state.buffer.split('\n');
|
|
193
|
+
state.buffer = lines.pop() || '';
|
|
192
194
|
|
|
193
195
|
for (const line of lines) {
|
|
194
196
|
const trimmed = line.trim();
|