aicodeswitch 2.0.8 → 2.0.10
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/CHANGELOG.md +4 -0
- package/CLAUDE.md +16 -1
- package/bin/stop.js +1 -2
- package/dist/server/database.js +77 -6
- package/dist/server/main.js +13 -2
- package/dist/server/proxy-server.js +162 -23
- package/dist/server/transformers/chunk-collector.js +103 -18
- package/dist/server/transformers/claude-openai.js +5 -2
- package/dist/server/transformers/streaming.js +220 -113
- package/dist/ui/assets/index-BYeFnkER.js +431 -0
- package/dist/ui/assets/index-DQ2LJr-O.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-BOY_bl12.js +0 -441
- package/dist/ui/assets/index-BOlCGnMv.css +0 -1
|
@@ -8,20 +8,45 @@ const stream_1 = require("stream");
|
|
|
8
8
|
*/
|
|
9
9
|
class ChunkCollectorTransform extends stream_1.Transform {
|
|
10
10
|
constructor() {
|
|
11
|
-
super();
|
|
11
|
+
super({ writableObjectMode: true, readableObjectMode: true });
|
|
12
12
|
Object.defineProperty(this, "chunks", {
|
|
13
13
|
enumerable: true,
|
|
14
14
|
configurable: true,
|
|
15
15
|
writable: true,
|
|
16
16
|
value: []
|
|
17
17
|
});
|
|
18
|
+
Object.defineProperty(this, "errorEmitted", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: false
|
|
23
|
+
});
|
|
24
|
+
this.on('error', (err) => {
|
|
25
|
+
console.error('[ChunkCollectorTransform] Stream error:', err);
|
|
26
|
+
this.errorEmitted = true;
|
|
27
|
+
});
|
|
18
28
|
}
|
|
19
29
|
_transform(chunk, _encoding, callback) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
if (this.errorEmitted) {
|
|
31
|
+
callback();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
// 收集chunk数据 - 支持对象和Buffer/string
|
|
36
|
+
if (typeof chunk === 'object' && chunk !== null && !Buffer.isBuffer(chunk)) {
|
|
37
|
+
this.chunks.push(JSON.stringify(chunk));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.chunks.push(chunk.toString('utf8'));
|
|
41
|
+
}
|
|
42
|
+
// 将chunk传递给下一个stream
|
|
43
|
+
this.push(chunk);
|
|
44
|
+
callback();
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.error('[ChunkCollectorTransform] Error in _transform:', error);
|
|
48
|
+
callback();
|
|
49
|
+
}
|
|
25
50
|
}
|
|
26
51
|
/**
|
|
27
52
|
* 获取收集的所有chunks
|
|
@@ -44,7 +69,7 @@ exports.ChunkCollectorTransform = ChunkCollectorTransform;
|
|
|
44
69
|
*/
|
|
45
70
|
class SSEEventCollectorTransform extends stream_1.Transform {
|
|
46
71
|
constructor() {
|
|
47
|
-
super();
|
|
72
|
+
super({ writableObjectMode: true, readableObjectMode: true });
|
|
48
73
|
Object.defineProperty(this, "buffer", {
|
|
49
74
|
enumerable: true,
|
|
50
75
|
configurable: true,
|
|
@@ -66,22 +91,82 @@ class SSEEventCollectorTransform extends stream_1.Transform {
|
|
|
66
91
|
writable: true,
|
|
67
92
|
value: []
|
|
68
93
|
});
|
|
94
|
+
Object.defineProperty(this, "errorEmitted", {
|
|
95
|
+
enumerable: true,
|
|
96
|
+
configurable: true,
|
|
97
|
+
writable: true,
|
|
98
|
+
value: false
|
|
99
|
+
});
|
|
100
|
+
this.on('error', (err) => {
|
|
101
|
+
console.error('[SSEEventCollectorTransform] Stream error:', err);
|
|
102
|
+
this.errorEmitted = true;
|
|
103
|
+
});
|
|
69
104
|
}
|
|
70
105
|
_transform(chunk, _encoding, callback) {
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
106
|
+
if (this.errorEmitted) {
|
|
107
|
+
callback();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
// 如果是对象(来自 SSEParserTransform),先转换为字符串格式进行处理
|
|
112
|
+
if (typeof chunk === 'object' && chunk !== null) {
|
|
113
|
+
const sseEvent = chunk;
|
|
114
|
+
const lines = [];
|
|
115
|
+
if (sseEvent.event)
|
|
116
|
+
lines.push(`event: ${sseEvent.event}`);
|
|
117
|
+
if (sseEvent.id)
|
|
118
|
+
lines.push(`id: ${sseEvent.id}`);
|
|
119
|
+
if (sseEvent.data !== undefined) {
|
|
120
|
+
if (typeof sseEvent.data === 'string') {
|
|
121
|
+
lines.push(`data: ${sseEvent.data}`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
lines.push(`data: ${JSON.stringify(sseEvent.data)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (lines.length > 0) {
|
|
128
|
+
this.currentEvent.rawLines.push(...lines);
|
|
129
|
+
if (sseEvent.event)
|
|
130
|
+
this.currentEvent.event = sseEvent.event;
|
|
131
|
+
if (sseEvent.id)
|
|
132
|
+
this.currentEvent.id = sseEvent.id;
|
|
133
|
+
if (sseEvent.data !== undefined) {
|
|
134
|
+
const dataStr = typeof sseEvent.data === 'string' ? sseEvent.data : JSON.stringify(sseEvent.data);
|
|
135
|
+
this.currentEvent.dataLines.push(dataStr);
|
|
136
|
+
}
|
|
137
|
+
this.flushEvent();
|
|
138
|
+
}
|
|
139
|
+
// 将原始对象传递给下一个stream
|
|
140
|
+
this.push(chunk);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// Buffer/string 模式
|
|
144
|
+
this.buffer += chunk.toString('utf8');
|
|
145
|
+
this.processBuffer();
|
|
146
|
+
// 将chunk传递给下一个stream
|
|
147
|
+
this.push(chunk);
|
|
148
|
+
}
|
|
149
|
+
callback();
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
console.error('[SSEEventCollectorTransform] Error in _transform:', error);
|
|
153
|
+
callback();
|
|
154
|
+
}
|
|
76
155
|
}
|
|
77
156
|
_flush(callback) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
this.
|
|
157
|
+
try {
|
|
158
|
+
// 处理剩余的buffer
|
|
159
|
+
if (this.buffer.trim()) {
|
|
160
|
+
this.processBuffer();
|
|
161
|
+
}
|
|
162
|
+
// 刷新最后一个事件
|
|
163
|
+
this.flushEvent();
|
|
164
|
+
callback();
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.error('[SSEEventCollectorTransform] Error in _flush:', error);
|
|
168
|
+
callback();
|
|
81
169
|
}
|
|
82
|
-
// 刷新最后一个事件
|
|
83
|
-
this.flushEvent();
|
|
84
|
-
callback();
|
|
85
170
|
}
|
|
86
171
|
processBuffer() {
|
|
87
172
|
const lines = this.buffer.split('\n');
|
|
@@ -143,7 +143,9 @@ const transformClaudeRequestToOpenAIChat = (body, targetModel) => {
|
|
|
143
143
|
// 映射 system 角色到 developer (如果需要)
|
|
144
144
|
const mappedRole = (message.role === 'system' && useDeveloperRole) ? 'developer' : message.role;
|
|
145
145
|
if (typeof message.content === 'string' || message.content === null) {
|
|
146
|
-
|
|
146
|
+
// 处理 content 为 null 的情况,使用空字符串替代
|
|
147
|
+
const content = message.content === null ? '' : message.content;
|
|
148
|
+
messages.push({ role: mappedRole, content });
|
|
147
149
|
continue;
|
|
148
150
|
}
|
|
149
151
|
if (Array.isArray(message.content)) {
|
|
@@ -179,7 +181,8 @@ const transformClaudeRequestToOpenAIChat = (body, targetModel) => {
|
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
}
|
|
182
|
-
|
|
184
|
+
// 避免 content 为 null,使用空字符串替代
|
|
185
|
+
const content = textParts.length > 0 ? textParts.join('') : '';
|
|
183
186
|
const openaiMessage = {
|
|
184
187
|
role: mappedRole,
|
|
185
188
|
content,
|
|
@@ -28,22 +28,50 @@ class SSEParserTransform extends stream_1.Transform {
|
|
|
28
28
|
writable: true,
|
|
29
29
|
value: []
|
|
30
30
|
});
|
|
31
|
+
Object.defineProperty(this, "errorEmitted", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: false
|
|
36
|
+
});
|
|
37
|
+
// 捕获流中的未处理错误,防止进程崩溃
|
|
38
|
+
this.on('error', (err) => {
|
|
39
|
+
console.error('[SSEParserTransform] Stream error:', err);
|
|
40
|
+
this.errorEmitted = true;
|
|
41
|
+
});
|
|
31
42
|
}
|
|
32
43
|
_transform(chunk, _encoding, callback) {
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
if (this.errorEmitted) {
|
|
45
|
+
callback();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
this.buffer += chunk.toString('utf8');
|
|
50
|
+
const lines = this.buffer.split('\n');
|
|
51
|
+
this.buffer = lines.pop() || '';
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
this.processLine(line);
|
|
54
|
+
}
|
|
55
|
+
callback();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error('[SSEParserTransform] Error in _transform:', error);
|
|
59
|
+
// 不传递错误,避免中断流,而是记录并继续
|
|
60
|
+
callback();
|
|
38
61
|
}
|
|
39
|
-
callback();
|
|
40
62
|
}
|
|
41
63
|
_flush(callback) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
try {
|
|
65
|
+
if (this.buffer.trim()) {
|
|
66
|
+
this.processLine(this.buffer.trim());
|
|
67
|
+
this.flushEvent();
|
|
68
|
+
}
|
|
69
|
+
callback();
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('[SSEParserTransform] Error in _flush:', error);
|
|
73
|
+
callback();
|
|
45
74
|
}
|
|
46
|
-
callback();
|
|
47
75
|
}
|
|
48
76
|
processLine(line) {
|
|
49
77
|
if (!line.trim()) {
|
|
@@ -92,30 +120,50 @@ class SSESerializerTransform extends stream_1.Transform {
|
|
|
92
120
|
writableObjectMode: true, // 接收对象
|
|
93
121
|
readableObjectMode: false, // 输出字符串/Buffer
|
|
94
122
|
});
|
|
123
|
+
Object.defineProperty(this, "errorEmitted", {
|
|
124
|
+
enumerable: true,
|
|
125
|
+
configurable: true,
|
|
126
|
+
writable: true,
|
|
127
|
+
value: false
|
|
128
|
+
});
|
|
129
|
+
this.on('error', (err) => {
|
|
130
|
+
console.error('[SSESerializerTransform] Stream error:', err);
|
|
131
|
+
this.errorEmitted = true;
|
|
132
|
+
});
|
|
95
133
|
}
|
|
96
134
|
_transform(event, _encoding, callback) {
|
|
97
135
|
var _a;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
if (event.id) {
|
|
103
|
-
output += `id: ${event.id}\n`;
|
|
136
|
+
if (this.errorEmitted) {
|
|
137
|
+
callback();
|
|
138
|
+
return;
|
|
104
139
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
140
|
+
try {
|
|
141
|
+
let output = '';
|
|
142
|
+
if (event.event) {
|
|
143
|
+
output += `event: ${event.event}\n`;
|
|
108
144
|
}
|
|
109
|
-
|
|
110
|
-
output += `
|
|
145
|
+
if (event.id) {
|
|
146
|
+
output += `id: ${event.id}\n`;
|
|
111
147
|
}
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
if (event.data !== undefined) {
|
|
149
|
+
if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
|
|
150
|
+
output += 'data: [DONE]\n';
|
|
151
|
+
}
|
|
152
|
+
else if (typeof event.data === 'string') {
|
|
153
|
+
output += `data: ${event.data}\n`;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
output += `data: ${JSON.stringify(event.data)}\n`;
|
|
157
|
+
}
|
|
114
158
|
}
|
|
159
|
+
output += '\n';
|
|
160
|
+
this.push(output);
|
|
161
|
+
callback();
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
console.error('[SSESerializerTransform] Error in _transform:', error);
|
|
165
|
+
callback();
|
|
115
166
|
}
|
|
116
|
-
output += '\n';
|
|
117
|
-
this.push(output);
|
|
118
|
-
callback();
|
|
119
167
|
}
|
|
120
168
|
}
|
|
121
169
|
exports.SSESerializerTransform = SSESerializerTransform;
|
|
@@ -206,7 +254,17 @@ class OpenAIToClaudeEventTransform extends stream_1.Transform {
|
|
|
206
254
|
writable: true,
|
|
207
255
|
value: false
|
|
208
256
|
});
|
|
257
|
+
Object.defineProperty(this, "errorEmitted", {
|
|
258
|
+
enumerable: true,
|
|
259
|
+
configurable: true,
|
|
260
|
+
writable: true,
|
|
261
|
+
value: false
|
|
262
|
+
});
|
|
209
263
|
this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
|
|
264
|
+
this.on('error', (err) => {
|
|
265
|
+
console.error('[OpenAIToClaudeEventTransform] Stream error:', err);
|
|
266
|
+
this.errorEmitted = true;
|
|
267
|
+
});
|
|
210
268
|
}
|
|
211
269
|
getUsage() {
|
|
212
270
|
if (!this.usage)
|
|
@@ -215,39 +273,62 @@ class OpenAIToClaudeEventTransform extends stream_1.Transform {
|
|
|
215
273
|
}
|
|
216
274
|
_transform(event, _encoding, callback) {
|
|
217
275
|
var _a;
|
|
218
|
-
if (this.
|
|
276
|
+
if (this.errorEmitted) {
|
|
219
277
|
callback();
|
|
220
278
|
return;
|
|
221
279
|
}
|
|
222
|
-
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
280
|
+
try {
|
|
281
|
+
if (this.finalized) {
|
|
282
|
+
callback();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
|
|
286
|
+
this.finalize();
|
|
287
|
+
callback();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const chunk = event.data;
|
|
291
|
+
if (!chunk) {
|
|
292
|
+
callback();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (chunk.id && !this.messageId) {
|
|
296
|
+
this.messageId = chunk.id;
|
|
297
|
+
}
|
|
298
|
+
if (chunk.model && !this.model) {
|
|
299
|
+
this.model = chunk.model;
|
|
300
|
+
}
|
|
301
|
+
if (chunk.usage) {
|
|
302
|
+
this.usage = (0, claude_openai_1.convertOpenAIUsageToClaude)(chunk.usage);
|
|
303
|
+
}
|
|
304
|
+
if (Array.isArray(chunk.choices)) {
|
|
305
|
+
for (const choice of chunk.choices) {
|
|
306
|
+
this.handleChoice(choice);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
229
309
|
callback();
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (chunk.id && !this.messageId) {
|
|
233
|
-
this.messageId = chunk.id;
|
|
234
310
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
this.handleChoice(choice);
|
|
311
|
+
catch (error) {
|
|
312
|
+
console.error('[OpenAIToClaudeEventTransform] Error in _transform:', error);
|
|
313
|
+
// 发送错误事件后继续
|
|
314
|
+
try {
|
|
315
|
+
this.pushEvent('error', { type: 'error', error: { type: 'api_error', message: 'Stream transformation error' } });
|
|
316
|
+
}
|
|
317
|
+
catch (e) {
|
|
318
|
+
// 忽略推送错误的错误
|
|
244
319
|
}
|
|
320
|
+
callback();
|
|
245
321
|
}
|
|
246
|
-
callback();
|
|
247
322
|
}
|
|
248
323
|
_flush(callback) {
|
|
249
|
-
|
|
250
|
-
|
|
324
|
+
try {
|
|
325
|
+
this.finalize();
|
|
326
|
+
callback();
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
console.error('[OpenAIToClaudeEventTransform] Error in _flush:', error);
|
|
330
|
+
callback();
|
|
331
|
+
}
|
|
251
332
|
}
|
|
252
333
|
assignContentBlockIndex() {
|
|
253
334
|
const index = this.contentIndex;
|
|
@@ -455,92 +536,118 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
|
|
|
455
536
|
writable: true,
|
|
456
537
|
value: null
|
|
457
538
|
});
|
|
539
|
+
Object.defineProperty(this, "errorEmitted", {
|
|
540
|
+
enumerable: true,
|
|
541
|
+
configurable: true,
|
|
542
|
+
writable: true,
|
|
543
|
+
value: false
|
|
544
|
+
});
|
|
458
545
|
this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
|
|
546
|
+
this.on('error', (err) => {
|
|
547
|
+
console.error('[ClaudeToOpenAIChatEventTransform] Stream error:', err);
|
|
548
|
+
this.errorEmitted = true;
|
|
549
|
+
});
|
|
459
550
|
}
|
|
460
551
|
getUsage() {
|
|
461
552
|
return this.usage;
|
|
462
553
|
}
|
|
463
554
|
_transform(event, _encoding, callback) {
|
|
464
|
-
if (this.
|
|
465
|
-
callback();
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
const type = event.event;
|
|
469
|
-
const data = event.data;
|
|
470
|
-
if (type === 'message_start' && (data === null || data === void 0 ? void 0 : data.message)) {
|
|
471
|
-
this.model = data.message.model || this.model;
|
|
472
|
-
this.push({ event: null, data: { id: data.message.id, model: this.model, choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }] } });
|
|
555
|
+
if (this.errorEmitted) {
|
|
473
556
|
callback();
|
|
474
557
|
return;
|
|
475
558
|
}
|
|
476
|
-
|
|
477
|
-
if (
|
|
478
|
-
|
|
559
|
+
try {
|
|
560
|
+
if (this.finished) {
|
|
561
|
+
callback();
|
|
562
|
+
return;
|
|
479
563
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
this.
|
|
564
|
+
const type = event.event;
|
|
565
|
+
const data = event.data;
|
|
566
|
+
if (type === 'message_start' && (data === null || data === void 0 ? void 0 : data.message)) {
|
|
567
|
+
this.model = data.message.model || this.model;
|
|
568
|
+
this.push({ event: null, data: { id: data.message.id, model: this.model, choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }] } });
|
|
569
|
+
callback();
|
|
570
|
+
return;
|
|
484
571
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (type === 'content_block_delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
489
|
-
if (data.delta.type === 'text_delta') {
|
|
490
|
-
const text = data.delta.text || '';
|
|
491
|
-
if (text) {
|
|
492
|
-
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { content: text } }] } });
|
|
572
|
+
if (type === 'content_block_start' && (data === null || data === void 0 ? void 0 : data.content_block)) {
|
|
573
|
+
if (data.content_block.type === 'text') {
|
|
574
|
+
// 文本块开始
|
|
493
575
|
}
|
|
576
|
+
else if (data.content_block.type === 'tool_use') {
|
|
577
|
+
this.pendingToolCallId = data.content_block.id;
|
|
578
|
+
this.pendingToolName = data.content_block.name;
|
|
579
|
+
this.pendingToolArgs = '';
|
|
580
|
+
}
|
|
581
|
+
callback();
|
|
582
|
+
return;
|
|
494
583
|
}
|
|
495
|
-
|
|
496
|
-
|
|
584
|
+
if (type === 'content_block_delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
|
|
585
|
+
if (data.delta.type === 'text_delta') {
|
|
586
|
+
const text = data.delta.text || '';
|
|
587
|
+
if (text) {
|
|
588
|
+
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { content: text } }] } });
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
else if (data.delta.type === 'input_json_delta') {
|
|
592
|
+
this.pendingToolArgs += data.delta.partial_json || '';
|
|
593
|
+
}
|
|
594
|
+
callback();
|
|
595
|
+
return;
|
|
497
596
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
597
|
+
if (type === 'content_block_stop') {
|
|
598
|
+
if (this.pendingToolCallId && this.pendingToolName !== null) {
|
|
599
|
+
const toolCall = {
|
|
600
|
+
index: this.toolCallIndex,
|
|
601
|
+
id: this.pendingToolCallId,
|
|
602
|
+
type: 'function',
|
|
603
|
+
function: {
|
|
604
|
+
name: this.pendingToolName,
|
|
605
|
+
arguments: this.pendingToolArgs,
|
|
606
|
+
},
|
|
607
|
+
};
|
|
608
|
+
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { tool_calls: [toolCall] } }] } });
|
|
609
|
+
this.toolCallIndex++;
|
|
610
|
+
this.pendingToolCallId = null;
|
|
611
|
+
this.pendingToolName = null;
|
|
612
|
+
this.pendingToolArgs = '';
|
|
613
|
+
}
|
|
614
|
+
callback();
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (type === 'message_stop' || (data === null || data === void 0 ? void 0 : data.type) === 'message_stop') {
|
|
618
|
+
this.finished = true;
|
|
619
|
+
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] } });
|
|
620
|
+
this.push({ event: 'done', data: { type: 'done' } });
|
|
621
|
+
callback();
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (data === null || data === void 0 ? void 0 : data.usage) {
|
|
625
|
+
this.usage = {
|
|
626
|
+
prompt_tokens: data.usage.input_tokens || 0,
|
|
627
|
+
completion_tokens: data.usage.output_tokens || 0,
|
|
628
|
+
total_tokens: (data.usage.input_tokens || 0) + (data.usage.output_tokens || 0),
|
|
511
629
|
};
|
|
512
|
-
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { tool_calls: [toolCall] } }] } });
|
|
513
|
-
this.toolCallIndex++;
|
|
514
|
-
this.pendingToolCallId = null;
|
|
515
|
-
this.pendingToolName = null;
|
|
516
|
-
this.pendingToolArgs = '';
|
|
517
630
|
}
|
|
518
631
|
callback();
|
|
519
|
-
return;
|
|
520
632
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] } });
|
|
524
|
-
this.push({ event: 'done', data: { type: 'done' } });
|
|
633
|
+
catch (error) {
|
|
634
|
+
console.error('[ClaudeToOpenAIChatEventTransform] Error in _transform:', error);
|
|
525
635
|
callback();
|
|
526
|
-
return;
|
|
527
|
-
}
|
|
528
|
-
if (data === null || data === void 0 ? void 0 : data.usage) {
|
|
529
|
-
this.usage = {
|
|
530
|
-
prompt_tokens: data.usage.input_tokens || 0,
|
|
531
|
-
completion_tokens: data.usage.output_tokens || 0,
|
|
532
|
-
total_tokens: (data.usage.input_tokens || 0) + (data.usage.output_tokens || 0),
|
|
533
|
-
};
|
|
534
636
|
}
|
|
535
|
-
callback();
|
|
536
637
|
}
|
|
537
638
|
_flush(callback) {
|
|
538
|
-
|
|
539
|
-
this.finished
|
|
540
|
-
|
|
541
|
-
|
|
639
|
+
try {
|
|
640
|
+
if (!this.finished) {
|
|
641
|
+
this.finished = true;
|
|
642
|
+
this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] } });
|
|
643
|
+
this.push({ event: 'done', data: { type: 'done' } });
|
|
644
|
+
}
|
|
645
|
+
callback();
|
|
646
|
+
}
|
|
647
|
+
catch (error) {
|
|
648
|
+
console.error('[ClaudeToOpenAIChatEventTransform] Error in _flush:', error);
|
|
649
|
+
callback();
|
|
542
650
|
}
|
|
543
|
-
callback();
|
|
544
651
|
}
|
|
545
652
|
}
|
|
546
653
|
exports.ClaudeToOpenAIChatEventTransform = ClaudeToOpenAIChatEventTransform;
|