aicodeswitch 4.0.3 → 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.
Files changed (77) hide show
  1. package/README.md +7 -6
  2. package/UPGRADE.md +5 -6
  3. package/dist/server/coding-plan.js +94 -0
  4. package/dist/server/config-managed-fields.js +1 -0
  5. package/dist/server/conversions/compact.js +613 -0
  6. package/dist/server/conversions/detector.js +70 -0
  7. package/dist/server/conversions/index.js +285 -0
  8. package/dist/server/conversions/pairs/claude-completions/request.js +167 -0
  9. package/dist/server/conversions/pairs/claude-completions/response.js +56 -0
  10. package/dist/server/conversions/pairs/claude-completions/streaming.js +259 -0
  11. package/dist/server/conversions/pairs/claude-gemini/request.js +130 -0
  12. package/dist/server/conversions/pairs/claude-gemini/response.js +65 -0
  13. package/dist/server/conversions/pairs/claude-gemini/streaming.js +199 -0
  14. package/dist/server/conversions/pairs/claude-responses/request.js +190 -0
  15. package/dist/server/conversions/pairs/claude-responses/response.js +89 -0
  16. package/dist/server/conversions/pairs/claude-responses/streaming.js +266 -0
  17. package/dist/server/conversions/pairs/completions-claude/request.js +111 -0
  18. package/dist/server/conversions/pairs/completions-claude/response.js +67 -0
  19. package/dist/server/conversions/pairs/completions-claude/streaming.js +165 -0
  20. package/dist/server/conversions/pairs/completions-gemini/request.js +169 -0
  21. package/dist/server/conversions/pairs/completions-gemini/response.js +70 -0
  22. package/dist/server/conversions/pairs/completions-gemini/streaming.js +132 -0
  23. package/dist/server/conversions/pairs/completions-responses/request.js +149 -0
  24. package/dist/server/conversions/pairs/completions-responses/response.js +74 -0
  25. package/dist/server/conversions/pairs/completions-responses/streaming.js +189 -0
  26. package/dist/server/conversions/pairs/gemini-claude/request.js +118 -0
  27. package/dist/server/conversions/pairs/gemini-claude/response.js +45 -0
  28. package/dist/server/conversions/pairs/gemini-claude/streaming.js +146 -0
  29. package/dist/server/conversions/pairs/gemini-completions/request.js +151 -0
  30. package/dist/server/conversions/pairs/gemini-completions/response.js +54 -0
  31. package/dist/server/conversions/pairs/gemini-completions/streaming.js +108 -0
  32. package/dist/server/conversions/pairs/gemini-responses/request.js +18 -0
  33. package/dist/server/conversions/pairs/gemini-responses/response.js +18 -0
  34. package/dist/server/conversions/pairs/gemini-responses/streaming.js +43 -0
  35. package/dist/server/conversions/pairs/responses-claude/request.js +155 -0
  36. package/dist/server/conversions/pairs/responses-claude/response.js +70 -0
  37. package/dist/server/conversions/pairs/responses-claude/streaming.js +345 -0
  38. package/dist/server/conversions/pairs/responses-completions/request.js +207 -0
  39. package/dist/server/conversions/pairs/responses-completions/response.js +96 -0
  40. package/dist/server/conversions/pairs/responses-completions/streaming.js +344 -0
  41. package/dist/server/conversions/pairs/responses-gemini/request.js +18 -0
  42. package/dist/server/conversions/pairs/responses-gemini/response.js +18 -0
  43. package/dist/server/conversions/pairs/responses-gemini/streaming.js +43 -0
  44. package/dist/server/conversions/pairs/responses-responses/request.js +115 -0
  45. package/dist/server/conversions/pipeline.js +296 -0
  46. package/dist/server/conversions/stream-converter-adapter.js +49 -0
  47. package/dist/server/conversions/thinking/effort.js +61 -0
  48. package/dist/server/conversions/thinking/mapper.js +59 -0
  49. package/dist/server/conversions/thinking/providers.js +76 -0
  50. package/dist/server/conversions/types.js +5 -0
  51. package/dist/server/conversions/url-normalizer.js +58 -0
  52. package/dist/server/conversions/utils/format-mappers.js +57 -0
  53. package/dist/server/conversions/utils/id.js +33 -0
  54. package/dist/server/conversions/utils/stop-reasons.js +95 -0
  55. package/dist/server/conversions/utils/streaming-helpers.js +59 -0
  56. package/dist/server/conversions/utils/tool-schema.js +169 -0
  57. package/dist/server/conversions/utils/usage.js +82 -0
  58. package/dist/server/fs-database.js +465 -135
  59. package/dist/server/main.js +93 -33
  60. package/dist/server/original-config-reader.js +1 -1
  61. package/dist/server/proxy-server.js +1102 -804
  62. package/dist/server/transformers/chunk-collector.js +5 -1
  63. package/dist/server/transformers/streaming.js +6 -3235
  64. package/dist/server/type-migration.js +2 -3
  65. package/dist/server/utils.js +5 -0
  66. package/dist/ui/assets/{index-C7G0whng.css → index-BHR12ImE.css} +1 -1
  67. package/dist/ui/assets/index-DjdBW1yu.js +517 -0
  68. package/dist/ui/index.html +2 -2
  69. package/package.json +1 -1
  70. package/dist/server/transformers/transformers.js +0 -1767
  71. package/dist/ui/assets/index-Nl6yJxrc.js +0 -514
  72. package/schema/claude.schema.md +0 -946
  73. package/schema/deepseek-chat.schema.md +0 -799
  74. package/schema/gemini.schema.md +0 -1408
  75. package/schema/openai-chat-completions.schema.md +0 -1088
  76. package/schema/openai-responses.schema.md +0 -226196
  77. package/schema/stream.md +0 -2592
@@ -1,84 +1,23 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.GeminiToClaudeEventTransform = exports.ResponsesToClaudeEventTransform = exports.ChatCompletionsToClaudeEventTransform = exports.GeminiToResponsesEventTransform = exports.ClaudeToResponsesEventTransform = exports.ChatCompletionsToResponsesEventTransform = exports.GeminiToOpenAIChatEventTransform = exports.ClaudeToOpenAIChatEventTransform = exports.OpenAIToClaudeEventTransform = exports.SSESerializerTransform = exports.SSEParserTransform = void 0;
3
+ exports.SSESerializerTransform = exports.SSEParserTransform = void 0;
37
4
  const stream_1 = require("stream");
38
5
  const string_decoder_1 = require("string_decoder");
39
- const crypto = __importStar(require("crypto"));
40
6
  /**
41
7
  * 检测是否是客户端断开相关的错误(这些错误是正常的,不应记录为错误)
42
8
  */
43
9
  function isClientDisconnectError(error) {
44
10
  const code = error === null || error === void 0 ? void 0 : error.code;
11
+ const name = error === null || error === void 0 ? void 0 : error.name;
45
12
  const message = typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' ? error.message.toLowerCase() : '';
46
13
  return (code === 'ERR_STREAM_PREMATURE_CLOSE' ||
47
14
  code === 'ERR_STREAM_UNABLE_TO_PIPE' ||
48
15
  code === 'ERR_STREAM_DESTROYED' ||
49
- message.includes('premature close'));
16
+ code === 'ERR_CANCELED' ||
17
+ name === 'CanceledError' ||
18
+ message.includes('premature close') ||
19
+ message.includes('canceled'));
50
20
  }
51
- /**
52
- * 将 OpenAI usage 转换为 Claude usage 格式
53
- */
54
- const convertOpenAIUsageToClaude = (usage) => {
55
- var _a, _b, _c, _d, _e, _f, _g, _h;
56
- const promptTokens = (_b = (_a = usage === null || usage === void 0 ? void 0 : usage.prompt_tokens) !== null && _a !== void 0 ? _a : usage === null || usage === void 0 ? void 0 : usage.input_tokens) !== null && _b !== void 0 ? _b : 0;
57
- const completionTokens = (_d = (_c = usage === null || usage === void 0 ? void 0 : usage.completion_tokens) !== null && _c !== void 0 ? _c : usage === null || usage === void 0 ? void 0 : usage.output_tokens) !== null && _d !== void 0 ? _d : 0;
58
- const cached = (_h = (_f = (_e = usage === null || usage === void 0 ? void 0 : usage.prompt_tokens_details) === null || _e === void 0 ? void 0 : _e.cached_tokens) !== null && _f !== void 0 ? _f : (_g = usage === null || usage === void 0 ? void 0 : usage.input_tokens_details) === null || _g === void 0 ? void 0 : _g.cached_tokens) !== null && _h !== void 0 ? _h : 0;
59
- return {
60
- input_tokens: Math.max(promptTokens - cached, 0),
61
- output_tokens: completionTokens,
62
- cache_read_input_tokens: cached,
63
- };
64
- };
65
- /**
66
- * 将 OpenAI 的 finish_reason 映射到 Claude 的 stop_reason
67
- */
68
- const mapOpenAIToClaudeStopReason = (finishReason) => {
69
- switch (finishReason) {
70
- case 'stop':
71
- return 'end_turn';
72
- case 'length':
73
- return 'max_tokens';
74
- case 'tool_calls':
75
- return 'tool_use';
76
- case 'content_filter':
77
- return 'content_filter';
78
- default:
79
- return 'end_turn';
80
- }
81
- };
82
21
  class SSEParserTransform extends stream_1.Transform {
83
22
  constructor() {
84
23
  super({ readableObjectMode: true });
@@ -278,3171 +217,3 @@ class SSESerializerTransform extends stream_1.Transform {
278
217
  }
279
218
  }
280
219
  exports.SSESerializerTransform = SSESerializerTransform;
281
- class OpenAIToClaudeEventTransform extends stream_1.Transform {
282
- constructor(options) {
283
- super({ objectMode: true });
284
- Object.defineProperty(this, "contentIndex", {
285
- enumerable: true,
286
- configurable: true,
287
- writable: true,
288
- value: 0
289
- });
290
- Object.defineProperty(this, "textBlockIndex", {
291
- enumerable: true,
292
- configurable: true,
293
- writable: true,
294
- value: null
295
- });
296
- Object.defineProperty(this, "thinkingBlockIndex", {
297
- enumerable: true,
298
- configurable: true,
299
- writable: true,
300
- value: null
301
- });
302
- Object.defineProperty(this, "toolCalls", {
303
- enumerable: true,
304
- configurable: true,
305
- writable: true,
306
- value: new Map()
307
- });
308
- Object.defineProperty(this, "toolCallIndexToBlockIndex", {
309
- enumerable: true,
310
- configurable: true,
311
- writable: true,
312
- value: new Map()
313
- });
314
- Object.defineProperty(this, "responseToolCalls", {
315
- enumerable: true,
316
- configurable: true,
317
- writable: true,
318
- value: new Map()
319
- });
320
- Object.defineProperty(this, "responseToolCallBlockIndex", {
321
- enumerable: true,
322
- configurable: true,
323
- writable: true,
324
- value: new Map()
325
- });
326
- Object.defineProperty(this, "completedToolCallIds", {
327
- enumerable: true,
328
- configurable: true,
329
- writable: true,
330
- value: new Set()
331
- });
332
- Object.defineProperty(this, "hasMessageStart", {
333
- enumerable: true,
334
- configurable: true,
335
- writable: true,
336
- value: false
337
- });
338
- Object.defineProperty(this, "stopReason", {
339
- enumerable: true,
340
- configurable: true,
341
- writable: true,
342
- value: 'end_turn'
343
- });
344
- Object.defineProperty(this, "usage", {
345
- enumerable: true,
346
- configurable: true,
347
- writable: true,
348
- value: null
349
- });
350
- Object.defineProperty(this, "messageId", {
351
- enumerable: true,
352
- configurable: true,
353
- writable: true,
354
- value: null
355
- });
356
- Object.defineProperty(this, "model", {
357
- enumerable: true,
358
- configurable: true,
359
- writable: true,
360
- value: null
361
- });
362
- Object.defineProperty(this, "finalized", {
363
- enumerable: true,
364
- configurable: true,
365
- writable: true,
366
- value: false
367
- });
368
- Object.defineProperty(this, "errorEmitted", {
369
- enumerable: true,
370
- configurable: true,
371
- writable: true,
372
- value: false
373
- });
374
- void options;
375
- this.on('error', (err) => {
376
- if (isClientDisconnectError(err)) {
377
- console.warn('[OpenAIToClaudeEventTransform] Stream closed (client disconnected)');
378
- }
379
- else {
380
- console.error('[OpenAIToClaudeEventTransform] Stream error:', err);
381
- }
382
- this.errorEmitted = true;
383
- });
384
- }
385
- getUsage() {
386
- if (!this.usage)
387
- return undefined;
388
- return Object.assign({}, this.usage);
389
- }
390
- _transform(event, _encoding, callback) {
391
- var _a, _b;
392
- if (this.errorEmitted) {
393
- callback();
394
- return;
395
- }
396
- try {
397
- if (this.finalized) {
398
- callback();
399
- return;
400
- }
401
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
402
- this.finalize();
403
- callback();
404
- return;
405
- }
406
- const responseEventType = event.event || ((_b = event.data) === null || _b === void 0 ? void 0 : _b.type);
407
- // 检查是否是 OpenAI Responses API 的事件
408
- // Responses API 事件类型如:response.reasoning_text.delta, response.output_text.delta 等
409
- if (typeof responseEventType === 'string' && responseEventType.startsWith('response.')) {
410
- this.handleResponsesAPIEvent(responseEventType, event.data);
411
- callback();
412
- return;
413
- }
414
- const chunk = event.data;
415
- if (!chunk) {
416
- callback();
417
- return;
418
- }
419
- if (chunk.id && !this.messageId) {
420
- this.messageId = chunk.id;
421
- }
422
- if (chunk.model && !this.model) {
423
- this.model = chunk.model;
424
- }
425
- if (chunk.usage) {
426
- this.usage = convertOpenAIUsageToClaude(chunk.usage);
427
- }
428
- if (Array.isArray(chunk.choices)) {
429
- for (const choice of chunk.choices) {
430
- this.handleChoice(choice);
431
- }
432
- }
433
- callback();
434
- }
435
- catch (error) {
436
- console.error('[OpenAIToClaudeEventTransform] Error in _transform:', error);
437
- // 发送错误事件后继续
438
- try {
439
- this.pushEvent('error', { type: 'error', error: { type: 'api_error', message: 'Stream transformation error' } });
440
- }
441
- catch (e) {
442
- // 忽略推送错误的错误
443
- }
444
- callback();
445
- }
446
- }
447
- _flush(callback) {
448
- try {
449
- this.finalize();
450
- callback();
451
- }
452
- catch (error) {
453
- console.error('[OpenAIToClaudeEventTransform] Error in _flush:', error);
454
- callback();
455
- }
456
- }
457
- assignContentBlockIndex() {
458
- const index = this.contentIndex;
459
- this.contentIndex += 1;
460
- return index;
461
- }
462
- pushEvent(type, data) {
463
- this.push({ event: type, data });
464
- }
465
- ensureMessageStart() {
466
- if (this.hasMessageStart)
467
- return;
468
- const message = {
469
- id: this.messageId || `msg_${crypto.randomUUID()}`,
470
- type: 'message',
471
- role: 'assistant',
472
- content: [],
473
- model: this.model || 'unknown',
474
- stop_reason: null,
475
- stop_sequence: null,
476
- usage: {
477
- input_tokens: 0,
478
- output_tokens: 0,
479
- },
480
- };
481
- this.pushEvent('message_start', { type: 'message_start', message });
482
- this.hasMessageStart = true;
483
- }
484
- handleChoice(choice) {
485
- var _a, _b, _c;
486
- const delta = choice === null || choice === void 0 ? void 0 : choice.delta;
487
- if (!delta)
488
- return;
489
- if (typeof (choice === null || choice === void 0 ? void 0 : choice.finish_reason) === 'string') {
490
- this.stopReason = mapOpenAIToClaudeStopReason(choice.finish_reason);
491
- }
492
- if (typeof delta.content === 'string') {
493
- this.ensureMessageStart();
494
- if (this.textBlockIndex === null) {
495
- this.textBlockIndex = this.assignContentBlockIndex();
496
- this.pushEvent('content_block_start', {
497
- type: 'content_block_start',
498
- index: this.textBlockIndex,
499
- content_block: { type: 'text' },
500
- });
501
- }
502
- this.pushEvent('content_block_delta', {
503
- type: 'content_block_delta',
504
- index: this.textBlockIndex,
505
- delta: {
506
- type: 'text_delta',
507
- text: delta.content,
508
- },
509
- });
510
- }
511
- // 处理 OpenAI Chat Completions API 的 thinking content
512
- if (typeof ((_a = delta.thinking) === null || _a === void 0 ? void 0 : _a.content) === 'string') {
513
- this.ensureMessageStart();
514
- if (this.thinkingBlockIndex === null) {
515
- this.thinkingBlockIndex = this.assignContentBlockIndex();
516
- this.pushEvent('content_block_start', {
517
- type: 'content_block_start',
518
- index: this.thinkingBlockIndex,
519
- content_block: { type: 'thinking', thinking: '' },
520
- });
521
- }
522
- this.pushEvent('content_block_delta', {
523
- type: 'content_block_delta',
524
- index: this.thinkingBlockIndex,
525
- delta: {
526
- type: 'thinking_delta',
527
- thinking: delta.thinking.content,
528
- },
529
- });
530
- }
531
- if (Array.isArray(delta.tool_calls)) {
532
- for (let i = 0; i < delta.tool_calls.length; i += 1) {
533
- const toolCall = delta.tool_calls[i];
534
- const toolIndex = typeof (toolCall === null || toolCall === void 0 ? void 0 : toolCall.index) === 'number' ? toolCall.index : i;
535
- const toolName = (_b = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _b === void 0 ? void 0 : _b.name;
536
- if ((toolCall === null || toolCall === void 0 ? void 0 : toolCall.id) && toolName) {
537
- this.ensureMessageStart();
538
- const toolBlockIndex = this.assignContentBlockIndex();
539
- this.toolCalls.set(toolIndex, {
540
- id: toolCall.id,
541
- name: toolName,
542
- arguments: '',
543
- });
544
- this.toolCallIndexToBlockIndex.set(toolIndex, toolBlockIndex);
545
- this.pushEvent('content_block_start', {
546
- type: 'content_block_start',
547
- index: toolBlockIndex,
548
- content_block: {
549
- type: 'tool_use',
550
- id: toolCall.id,
551
- name: toolName,
552
- },
553
- });
554
- }
555
- if ((_c = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _c === void 0 ? void 0 : _c.arguments) {
556
- this.ensureMessageStart();
557
- const stored = this.toolCalls.get(toolIndex);
558
- if (stored) {
559
- stored.arguments += toolCall.function.arguments;
560
- }
561
- const toolBlockIndex = this.toolCallIndexToBlockIndex.get(toolIndex);
562
- if (toolBlockIndex !== undefined) {
563
- this.pushEvent('content_block_delta', {
564
- type: 'content_block_delta',
565
- index: toolBlockIndex,
566
- delta: {
567
- type: 'input_json_delta',
568
- partial_json: toolCall.function.arguments,
569
- },
570
- });
571
- }
572
- }
573
- }
574
- }
575
- }
576
- // 处理 OpenAI Responses API 的流式事件
577
- handleResponsesAPIEvent(type, data) {
578
- var _a, _b, _c;
579
- // 处理 reasoning 文本增量(完整推理过程)
580
- if (type === 'response.reasoning_text.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
581
- this.ensureMessageStart();
582
- if (this.thinkingBlockIndex === null) {
583
- this.thinkingBlockIndex = this.assignContentBlockIndex();
584
- this.pushEvent('content_block_start', {
585
- type: 'content_block_start',
586
- index: this.thinkingBlockIndex,
587
- content_block: { type: 'thinking', thinking: '' },
588
- });
589
- }
590
- this.pushEvent('content_block_delta', {
591
- type: 'content_block_delta',
592
- index: this.thinkingBlockIndex,
593
- delta: {
594
- type: 'thinking_delta',
595
- thinking: data.delta,
596
- },
597
- });
598
- }
599
- // 处理 reasoning summary 文本增量(推理摘要)
600
- if (type === 'response.reasoning_summary_text.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
601
- this.ensureMessageStart();
602
- if (this.thinkingBlockIndex === null) {
603
- this.thinkingBlockIndex = this.assignContentBlockIndex();
604
- this.pushEvent('content_block_start', {
605
- type: 'content_block_start',
606
- index: this.thinkingBlockIndex,
607
- content_block: { type: 'thinking', thinking: '' },
608
- });
609
- }
610
- this.pushEvent('content_block_delta', {
611
- type: 'content_block_delta',
612
- index: this.thinkingBlockIndex,
613
- delta: {
614
- type: 'thinking_delta',
615
- thinking: data.delta,
616
- },
617
- });
618
- }
619
- // 处理普通文本增量
620
- if (type === 'response.output_text.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
621
- this.ensureMessageStart();
622
- if (this.textBlockIndex === null) {
623
- this.textBlockIndex = this.assignContentBlockIndex();
624
- this.pushEvent('content_block_start', {
625
- type: 'content_block_start',
626
- index: this.textBlockIndex,
627
- content_block: { type: 'text' },
628
- });
629
- }
630
- this.pushEvent('content_block_delta', {
631
- type: 'content_block_delta',
632
- index: this.textBlockIndex,
633
- delta: {
634
- type: 'text_delta',
635
- text: data.delta,
636
- },
637
- });
638
- }
639
- // 处理拒绝内容增量(内容过滤等)
640
- if (type === 'response.refusal.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
641
- // 拒绝内容可以作为文本发送
642
- this.ensureMessageStart();
643
- if (this.textBlockIndex === null) {
644
- this.textBlockIndex = this.assignContentBlockIndex();
645
- this.pushEvent('content_block_start', {
646
- type: 'content_block_start',
647
- index: this.textBlockIndex,
648
- content_block: { type: 'text' },
649
- });
650
- }
651
- this.pushEvent('content_block_delta', {
652
- type: 'content_block_delta',
653
- index: this.textBlockIndex,
654
- delta: {
655
- type: 'text_delta',
656
- text: data.delta,
657
- },
658
- });
659
- }
660
- // 处理函数调用参数增量
661
- if (type === 'response.function_call.start' && data) {
662
- const callId = data.call_id || data.item_id;
663
- if (callId) {
664
- this.ensureMessageStart();
665
- const blockIndex = this.assignContentBlockIndex();
666
- this.responseToolCalls.set(callId, {
667
- id: callId,
668
- name: data.name || 'tool',
669
- arguments: data.arguments || '',
670
- });
671
- this.responseToolCallBlockIndex.set(callId, blockIndex);
672
- this.pushEvent('content_block_start', {
673
- type: 'content_block_start',
674
- index: blockIndex,
675
- content_block: {
676
- type: 'tool_use',
677
- id: callId,
678
- name: data.name || 'tool',
679
- },
680
- });
681
- }
682
- }
683
- if (type === 'response.function_call_arguments.delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
684
- const callId = data.call_id || data.item_id;
685
- if (callId) {
686
- if (!this.responseToolCalls.has(callId)) {
687
- this.ensureMessageStart();
688
- const blockIndex = this.assignContentBlockIndex();
689
- this.responseToolCalls.set(callId, {
690
- id: callId,
691
- name: data.name || 'tool',
692
- arguments: '',
693
- });
694
- this.responseToolCallBlockIndex.set(callId, blockIndex);
695
- this.pushEvent('content_block_start', {
696
- type: 'content_block_start',
697
- index: blockIndex,
698
- content_block: {
699
- type: 'tool_use',
700
- id: callId,
701
- name: data.name || 'tool',
702
- },
703
- });
704
- }
705
- const stored = this.responseToolCalls.get(callId);
706
- if (stored) {
707
- stored.arguments += data.delta;
708
- }
709
- const blockIndex = this.responseToolCallBlockIndex.get(callId);
710
- if (blockIndex !== undefined) {
711
- this.pushEvent('content_block_delta', {
712
- type: 'content_block_delta',
713
- index: blockIndex,
714
- delta: {
715
- type: 'input_json_delta',
716
- partial_json: data.delta,
717
- },
718
- });
719
- }
720
- }
721
- }
722
- if (type === 'response.function_call_arguments.done' && data) {
723
- const callId = data.call_id || data.item_id;
724
- if (callId) {
725
- if (!this.responseToolCalls.has(callId)) {
726
- this.ensureMessageStart();
727
- const blockIndex = this.assignContentBlockIndex();
728
- this.responseToolCalls.set(callId, {
729
- id: callId,
730
- name: data.name || 'tool',
731
- arguments: typeof data.arguments === 'string' ? data.arguments : '',
732
- });
733
- this.responseToolCallBlockIndex.set(callId, blockIndex);
734
- this.pushEvent('content_block_start', {
735
- type: 'content_block_start',
736
- index: blockIndex,
737
- content_block: {
738
- type: 'tool_use',
739
- id: callId,
740
- name: data.name || 'tool',
741
- },
742
- });
743
- }
744
- const blockIndex = this.responseToolCallBlockIndex.get(callId);
745
- if (blockIndex !== undefined && !this.completedToolCallIds.has(callId)) {
746
- this.pushEvent('content_block_stop', {
747
- type: 'content_block_stop',
748
- index: blockIndex,
749
- });
750
- this.completedToolCallIds.add(callId);
751
- }
752
- }
753
- }
754
- // 处理响应完成事件
755
- if (type === 'response.completed' || type === 'response.failed' || type === 'response.incomplete') {
756
- if (type === 'response.incomplete' && ((_a = data === null || data === void 0 ? void 0 : data.incomplete_details) === null || _a === void 0 ? void 0 : _a.reason) === 'max_tokens') {
757
- this.stopReason = 'max_tokens';
758
- }
759
- else if (type === 'response.failed' || ((_b = data === null || data === void 0 ? void 0 : data.incomplete_details) === null || _b === void 0 ? void 0 : _b.reason) === 'content_filter') {
760
- this.stopReason = 'content_filter';
761
- }
762
- else {
763
- this.stopReason = 'end_turn';
764
- }
765
- if ((_c = data === null || data === void 0 ? void 0 : data.response) === null || _c === void 0 ? void 0 : _c.usage) {
766
- this.usage = convertOpenAIUsageToClaude(data.response.usage);
767
- }
768
- // 确保所有内容块都已关闭
769
- this.finalize();
770
- }
771
- // 处理响应创建和进行中事件
772
- if (type === 'response.created' || type === 'response.in_progress') {
773
- this.ensureMessageStart();
774
- }
775
- }
776
- finalize() {
777
- if (this.finalized)
778
- return;
779
- this.ensureMessageStart();
780
- for (const toolBlockIndex of Array.from(this.toolCallIndexToBlockIndex.values())) {
781
- this.pushEvent('content_block_stop', {
782
- type: 'content_block_stop',
783
- index: toolBlockIndex,
784
- });
785
- }
786
- for (const [callId, toolBlockIndex] of this.responseToolCallBlockIndex.entries()) {
787
- if (this.completedToolCallIds.has(callId))
788
- continue;
789
- this.pushEvent('content_block_stop', {
790
- type: 'content_block_stop',
791
- index: toolBlockIndex,
792
- });
793
- this.completedToolCallIds.add(callId);
794
- }
795
- if (this.thinkingBlockIndex !== null) {
796
- this.pushEvent('content_block_stop', {
797
- type: 'content_block_stop',
798
- index: this.thinkingBlockIndex,
799
- });
800
- this.thinkingBlockIndex = null;
801
- }
802
- if (this.textBlockIndex !== null) {
803
- this.pushEvent('content_block_stop', {
804
- type: 'content_block_stop',
805
- index: this.textBlockIndex,
806
- });
807
- this.textBlockIndex = null;
808
- }
809
- const usage = this.usage || {
810
- input_tokens: 0,
811
- output_tokens: 0,
812
- cache_read_input_tokens: 0,
813
- };
814
- this.pushEvent('message_delta', {
815
- type: 'message_delta',
816
- delta: {
817
- stop_reason: this.stopReason,
818
- stop_sequence: null,
819
- },
820
- usage,
821
- });
822
- this.pushEvent('message_stop', { type: 'message_stop' });
823
- this.finalized = true;
824
- }
825
- }
826
- exports.OpenAIToClaudeEventTransform = OpenAIToClaudeEventTransform;
827
- class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
828
- constructor(options) {
829
- super({ objectMode: true });
830
- Object.defineProperty(this, "pendingToolCallId", {
831
- enumerable: true,
832
- configurable: true,
833
- writable: true,
834
- value: null
835
- });
836
- Object.defineProperty(this, "pendingToolName", {
837
- enumerable: true,
838
- configurable: true,
839
- writable: true,
840
- value: null
841
- });
842
- Object.defineProperty(this, "pendingToolArgs", {
843
- enumerable: true,
844
- configurable: true,
845
- writable: true,
846
- value: ''
847
- });
848
- Object.defineProperty(this, "toolCallIndex", {
849
- enumerable: true,
850
- configurable: true,
851
- writable: true,
852
- value: 0
853
- });
854
- Object.defineProperty(this, "usage", {
855
- enumerable: true,
856
- configurable: true,
857
- writable: true,
858
- value: null
859
- });
860
- Object.defineProperty(this, "finished", {
861
- enumerable: true,
862
- configurable: true,
863
- writable: true,
864
- value: false
865
- });
866
- Object.defineProperty(this, "model", {
867
- enumerable: true,
868
- configurable: true,
869
- writable: true,
870
- value: null
871
- });
872
- Object.defineProperty(this, "stopReason", {
873
- enumerable: true,
874
- configurable: true,
875
- writable: true,
876
- value: 'stop'
877
- }); // OpenAI 的 finish_reason
878
- Object.defineProperty(this, "errorEmitted", {
879
- enumerable: true,
880
- configurable: true,
881
- writable: true,
882
- value: false
883
- });
884
- void options;
885
- this.on('error', (err) => {
886
- if (isClientDisconnectError(err)) {
887
- console.warn('[ClaudeToOpenAIChatEventTransform] Stream closed (client disconnected)');
888
- }
889
- else {
890
- console.error('[ClaudeToOpenAIChatEventTransform] Stream error:', err);
891
- }
892
- this.errorEmitted = true;
893
- });
894
- }
895
- getUsage() {
896
- return this.usage;
897
- }
898
- _transform(event, _encoding, callback) {
899
- var _a, _b, _c, _d, _e, _f, _g, _h;
900
- if (this.errorEmitted) {
901
- callback();
902
- return;
903
- }
904
- try {
905
- if (this.finished) {
906
- callback();
907
- return;
908
- }
909
- const type = event.event;
910
- const data = event.data;
911
- if (type === 'message_start' && (data === null || data === void 0 ? void 0 : data.message)) {
912
- this.model = data.message.model || this.model;
913
- this.push({ event: null, data: { id: data.message.id, model: this.model, choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }] } });
914
- callback();
915
- return;
916
- }
917
- if (type === 'content_block_start' && (data === null || data === void 0 ? void 0 : data.content_block)) {
918
- if (data.content_block.type === 'text') {
919
- // 文本块开始
920
- }
921
- else if (data.content_block.type === 'thinking') {
922
- // thinking 块开始(无需特殊处理)
923
- }
924
- else if (data.content_block.type === 'tool_use') {
925
- this.pendingToolCallId = data.content_block.id;
926
- this.pendingToolName = data.content_block.name;
927
- this.pendingToolArgs = '';
928
- }
929
- callback();
930
- return;
931
- }
932
- if (type === 'content_block_delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
933
- if (data.delta.type === 'text_delta') {
934
- const text = data.delta.text || '';
935
- if (text) {
936
- this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { content: text } }] } });
937
- }
938
- }
939
- else if (data.delta.type === 'thinking_delta') {
940
- // 处理 thinking 增量,转换为 OpenAI 格式
941
- const thinking = data.delta.thinking || '';
942
- if (thinking) {
943
- // OpenAI 兼容格式:使用 delta.thinking.content
944
- this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { thinking: { content: thinking } } }] } });
945
- }
946
- }
947
- else if (data.delta.type === 'input_json_delta') {
948
- this.pendingToolArgs += data.delta.partial_json || '';
949
- }
950
- callback();
951
- return;
952
- }
953
- if (type === 'content_block_stop') {
954
- if (this.pendingToolCallId && this.pendingToolName !== null) {
955
- const toolCall = {
956
- index: this.toolCallIndex,
957
- id: this.pendingToolCallId,
958
- type: 'function',
959
- function: {
960
- name: this.pendingToolName,
961
- arguments: this.pendingToolArgs,
962
- },
963
- };
964
- this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { tool_calls: [toolCall] } }] } });
965
- this.toolCallIndex++;
966
- this.pendingToolCallId = null;
967
- this.pendingToolName = null;
968
- this.pendingToolArgs = '';
969
- }
970
- callback();
971
- return;
972
- }
973
- if (type === 'message_stop' || (data === null || data === void 0 ? void 0 : data.type) === 'message_stop') {
974
- this.finished = true;
975
- // 使用映射后的 stop reason
976
- this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: this.stopReason }] } });
977
- this.push({ event: 'done', data: { type: 'done' } });
978
- callback();
979
- return;
980
- }
981
- // 处理 message_delta 事件(包含 stop_reason 和 usage)
982
- if (type === 'message_delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
983
- // 映射 Claude 的 stop_reason 到 OpenAI 的 finish_reason
984
- if (data.delta.stop_reason) {
985
- this.stopReason = this.mapStopReason(data.delta.stop_reason);
986
- }
987
- // 处理 usage 信息
988
- if (data.usage) {
989
- this.usage = {
990
- prompt_tokens: ((_a = data.usage) === null || _a === void 0 ? void 0 : _a.input_tokens) || 0,
991
- completion_tokens: ((_b = data.usage) === null || _b === void 0 ? void 0 : _b.output_tokens) || 0,
992
- total_tokens: (((_c = data.usage) === null || _c === void 0 ? void 0 : _c.input_tokens) || 0) + (((_d = data.usage) === null || _d === void 0 ? void 0 : _d.output_tokens) || 0),
993
- };
994
- }
995
- // 不发送 delta 事件,只在最终 message_stop 时发送 finish_reason
996
- callback();
997
- return;
998
- }
999
- if (data === null || data === void 0 ? void 0 : data.usage) {
1000
- this.usage = {
1001
- prompt_tokens: ((_e = data.usage) === null || _e === void 0 ? void 0 : _e.input_tokens) || 0,
1002
- completion_tokens: ((_f = data.usage) === null || _f === void 0 ? void 0 : _f.output_tokens) || 0,
1003
- total_tokens: (((_g = data.usage) === null || _g === void 0 ? void 0 : _g.input_tokens) || 0) + (((_h = data.usage) === null || _h === void 0 ? void 0 : _h.output_tokens) || 0),
1004
- };
1005
- }
1006
- callback();
1007
- }
1008
- catch (error) {
1009
- console.error('[ClaudeToOpenAIChatEventTransform] Error in _transform:', error);
1010
- callback();
1011
- }
1012
- }
1013
- _flush(callback) {
1014
- try {
1015
- if (!this.finished) {
1016
- this.finished = true;
1017
- this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: this.stopReason }] } });
1018
- this.push({ event: 'done', data: { type: 'done' } });
1019
- }
1020
- callback();
1021
- }
1022
- catch (error) {
1023
- console.error('[ClaudeToOpenAIChatEventTransform] Error in _flush:', error);
1024
- callback();
1025
- }
1026
- }
1027
- /**
1028
- * 将 Claude 的 stop_reason 映射到 OpenAI 的 finish_reason
1029
- * Claude: "end_turn" | "max_tokens" | "tool_use" | "stop_sequence" | "max_thinking_length"
1030
- * OpenAI: "stop" | "length" | "tool_calls" | "content_filter"
1031
- */
1032
- mapStopReason(stopReason) {
1033
- switch (stopReason) {
1034
- case 'end_turn':
1035
- return 'stop';
1036
- case 'max_tokens':
1037
- case 'max_thinking_length':
1038
- return 'length';
1039
- case 'tool_use':
1040
- return 'tool_calls';
1041
- case 'stop_sequence':
1042
- return 'stop';
1043
- case 'content_filter':
1044
- return 'content_filter';
1045
- default:
1046
- return 'stop';
1047
- }
1048
- }
1049
- }
1050
- exports.ClaudeToOpenAIChatEventTransform = ClaudeToOpenAIChatEventTransform;
1051
- // ============================================================================
1052
- // Gemini 流式转换器
1053
- // ============================================================================
1054
- /**
1055
- * 将 Gemini SSE 流式事件转换为 OpenAI Chat 格式
1056
- */
1057
- class GeminiToOpenAIChatEventTransform extends stream_1.Transform {
1058
- constructor(options) {
1059
- var _a;
1060
- super({ objectMode: true });
1061
- Object.defineProperty(this, "pendingToolCalls", {
1062
- enumerable: true,
1063
- configurable: true,
1064
- writable: true,
1065
- value: []
1066
- });
1067
- Object.defineProperty(this, "usage", {
1068
- enumerable: true,
1069
- configurable: true,
1070
- writable: true,
1071
- value: null
1072
- });
1073
- Object.defineProperty(this, "finished", {
1074
- enumerable: true,
1075
- configurable: true,
1076
- writable: true,
1077
- value: false
1078
- });
1079
- Object.defineProperty(this, "model", {
1080
- enumerable: true,
1081
- configurable: true,
1082
- writable: true,
1083
- value: null
1084
- });
1085
- Object.defineProperty(this, "stopReason", {
1086
- enumerable: true,
1087
- configurable: true,
1088
- writable: true,
1089
- value: 'stop'
1090
- });
1091
- Object.defineProperty(this, "errorEmitted", {
1092
- enumerable: true,
1093
- configurable: true,
1094
- writable: true,
1095
- value: false
1096
- });
1097
- Object.defineProperty(this, "accumulatedText", {
1098
- enumerable: true,
1099
- configurable: true,
1100
- writable: true,
1101
- value: ''
1102
- });
1103
- this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
1104
- this.on('error', (err) => {
1105
- if (isClientDisconnectError(err)) {
1106
- console.warn('[GeminiToOpenAIChatEventTransform] Stream closed (client disconnected)');
1107
- }
1108
- else {
1109
- console.error('[GeminiToOpenAIChatEventTransform] Stream error:', err);
1110
- }
1111
- this.errorEmitted = true;
1112
- });
1113
- }
1114
- getUsage() {
1115
- return this.usage;
1116
- }
1117
- _transform(event, _encoding, callback) {
1118
- var _a;
1119
- if (this.errorEmitted) {
1120
- callback();
1121
- return;
1122
- }
1123
- try {
1124
- if (this.finished) {
1125
- callback();
1126
- return;
1127
- }
1128
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
1129
- this.finished = true;
1130
- this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: this.stopReason }] } });
1131
- this.push({ event: 'done', data: { type: 'done' } });
1132
- callback();
1133
- return;
1134
- }
1135
- const chunk = event.data;
1136
- if (!chunk) {
1137
- callback();
1138
- return;
1139
- }
1140
- // 处理 usage
1141
- if (chunk.usageMetadata) {
1142
- this.usage = {
1143
- prompt_tokens: chunk.usageMetadata.promptTokenCount || 0,
1144
- completion_tokens: chunk.usageMetadata.candidatesTokenCount || 0,
1145
- total_tokens: chunk.usageMetadata.totalTokenCount || 0,
1146
- };
1147
- }
1148
- const candidates = Array.isArray(chunk.candidates) ? chunk.candidates : [];
1149
- for (const candidate of candidates) {
1150
- // 处理 finishReason
1151
- if (candidate.finishReason) {
1152
- this.stopReason = this.mapGeminiFinishReason(candidate.finishReason);
1153
- }
1154
- if (!candidate.content || !Array.isArray(candidate.content.parts)) {
1155
- continue;
1156
- }
1157
- // 处理 parts
1158
- for (const part of candidate.content.parts) {
1159
- // 处理文本
1160
- if (part.text && typeof part.text === 'string') {
1161
- this.accumulatedText += part.text;
1162
- this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { content: part.text } }] } });
1163
- }
1164
- // 处理 functionCall -> tool_calls
1165
- if (part.functionCall) {
1166
- const toolCallId = `call_${this.pendingToolCalls.length}_${Date.now()}`;
1167
- this.pendingToolCalls.push({
1168
- id: toolCallId,
1169
- name: part.functionCall.name || 'tool',
1170
- arguments: JSON.stringify(part.functionCall.args || {}),
1171
- });
1172
- this.push({
1173
- event: null,
1174
- data: {
1175
- id: '',
1176
- model: this.model,
1177
- choices: [{
1178
- index: 0,
1179
- delta: {
1180
- tool_calls: [{
1181
- id: toolCallId,
1182
- type: 'function',
1183
- function: {
1184
- name: part.functionCall.name || 'tool',
1185
- arguments: JSON.stringify(part.functionCall.args || {}),
1186
- },
1187
- }],
1188
- },
1189
- }],
1190
- },
1191
- });
1192
- }
1193
- // 处理 inlineData (图像输出,罕见)
1194
- if (part.inlineData) {
1195
- this.push({
1196
- event: null,
1197
- data: {
1198
- id: '',
1199
- model: this.model,
1200
- choices: [{
1201
- index: 0,
1202
- delta: {
1203
- // Chat Completions chunk 的 delta.content 应为字符串
1204
- content: '[Image content]',
1205
- },
1206
- }],
1207
- },
1208
- });
1209
- }
1210
- }
1211
- }
1212
- callback();
1213
- }
1214
- catch (error) {
1215
- console.error('[GeminiToOpenAIChatEventTransform] Error in _transform:', error);
1216
- callback();
1217
- }
1218
- }
1219
- _flush(callback) {
1220
- try {
1221
- if (!this.finished) {
1222
- this.finished = true;
1223
- this.push({
1224
- event: null,
1225
- data: {
1226
- id: '',
1227
- model: this.model,
1228
- choices: [{
1229
- index: 0,
1230
- delta: {},
1231
- finish_reason: this.stopReason,
1232
- }],
1233
- },
1234
- });
1235
- this.push({ event: 'done', data: { type: 'done' } });
1236
- }
1237
- callback();
1238
- }
1239
- catch (error) {
1240
- console.error('[GeminiToOpenAIChatEventTransform] Error in _flush:', error);
1241
- callback();
1242
- }
1243
- }
1244
- mapGeminiFinishReason(finishReason) {
1245
- switch (finishReason) {
1246
- case 'STOP':
1247
- return 'stop';
1248
- case 'MAX_TOKENS':
1249
- return 'length';
1250
- case 'SAFETY':
1251
- case 'RECITATION':
1252
- return 'content_filter';
1253
- case 'MALFORMED_FUNCTION_CALL':
1254
- return 'tool_calls';
1255
- default:
1256
- return 'stop';
1257
- }
1258
- }
1259
- }
1260
- exports.GeminiToOpenAIChatEventTransform = GeminiToOpenAIChatEventTransform;
1261
- // ======================= transform SSE for codex =======================
1262
- /**
1263
- * 将 Chat Completions SSE 流式事件转换为 Responses API 格式
1264
- * 当源是 openai-chat,目标是 codex 时使用
1265
- */
1266
- class ChatCompletionsToResponsesEventTransform extends stream_1.Transform {
1267
- constructor(options) {
1268
- var _a;
1269
- super({ objectMode: true });
1270
- Object.defineProperty(this, "responseId", {
1271
- enumerable: true,
1272
- configurable: true,
1273
- writable: true,
1274
- value: null
1275
- });
1276
- Object.defineProperty(this, "model", {
1277
- enumerable: true,
1278
- configurable: true,
1279
- writable: true,
1280
- value: null
1281
- });
1282
- Object.defineProperty(this, "responseCreatedAt", {
1283
- enumerable: true,
1284
- configurable: true,
1285
- writable: true,
1286
- value: Math.floor(Date.now() / 1000)
1287
- });
1288
- Object.defineProperty(this, "responseStarted", {
1289
- enumerable: true,
1290
- configurable: true,
1291
- writable: true,
1292
- value: false
1293
- });
1294
- Object.defineProperty(this, "sequenceNumber", {
1295
- enumerable: true,
1296
- configurable: true,
1297
- writable: true,
1298
- value: 0
1299
- });
1300
- Object.defineProperty(this, "responseStatus", {
1301
- enumerable: true,
1302
- configurable: true,
1303
- writable: true,
1304
- value: 'completed'
1305
- });
1306
- Object.defineProperty(this, "incompleteReason", {
1307
- enumerable: true,
1308
- configurable: true,
1309
- writable: true,
1310
- value: 'max_tokens'
1311
- });
1312
- Object.defineProperty(this, "usage", {
1313
- enumerable: true,
1314
- configurable: true,
1315
- writable: true,
1316
- value: null
1317
- });
1318
- Object.defineProperty(this, "messageItemId", {
1319
- enumerable: true,
1320
- configurable: true,
1321
- writable: true,
1322
- value: null
1323
- });
1324
- Object.defineProperty(this, "messageOutputAdded", {
1325
- enumerable: true,
1326
- configurable: true,
1327
- writable: true,
1328
- value: false
1329
- });
1330
- Object.defineProperty(this, "nextMessageContentIndex", {
1331
- enumerable: true,
1332
- configurable: true,
1333
- writable: true,
1334
- value: 0
1335
- });
1336
- Object.defineProperty(this, "textContentIndex", {
1337
- enumerable: true,
1338
- configurable: true,
1339
- writable: true,
1340
- value: null
1341
- });
1342
- Object.defineProperty(this, "reasoningContentIndex", {
1343
- enumerable: true,
1344
- configurable: true,
1345
- writable: true,
1346
- value: null
1347
- });
1348
- Object.defineProperty(this, "refusalContentIndex", {
1349
- enumerable: true,
1350
- configurable: true,
1351
- writable: true,
1352
- value: null
1353
- });
1354
- Object.defineProperty(this, "textPartAdded", {
1355
- enumerable: true,
1356
- configurable: true,
1357
- writable: true,
1358
- value: false
1359
- });
1360
- Object.defineProperty(this, "reasoningPartAdded", {
1361
- enumerable: true,
1362
- configurable: true,
1363
- writable: true,
1364
- value: false
1365
- });
1366
- Object.defineProperty(this, "refusalPartAdded", {
1367
- enumerable: true,
1368
- configurable: true,
1369
- writable: true,
1370
- value: false
1371
- });
1372
- Object.defineProperty(this, "textOutput", {
1373
- enumerable: true,
1374
- configurable: true,
1375
- writable: true,
1376
- value: ''
1377
- });
1378
- Object.defineProperty(this, "reasoningOutput", {
1379
- enumerable: true,
1380
- configurable: true,
1381
- writable: true,
1382
- value: ''
1383
- });
1384
- Object.defineProperty(this, "refusalOutput", {
1385
- enumerable: true,
1386
- configurable: true,
1387
- writable: true,
1388
- value: ''
1389
- });
1390
- Object.defineProperty(this, "nextOutputIndex", {
1391
- enumerable: true,
1392
- configurable: true,
1393
- writable: true,
1394
- value: 1
1395
- });
1396
- Object.defineProperty(this, "toolCalls", {
1397
- enumerable: true,
1398
- configurable: true,
1399
- writable: true,
1400
- value: new Map()
1401
- });
1402
- Object.defineProperty(this, "finalized", {
1403
- enumerable: true,
1404
- configurable: true,
1405
- writable: true,
1406
- value: false
1407
- });
1408
- Object.defineProperty(this, "errorEmitted", {
1409
- enumerable: true,
1410
- configurable: true,
1411
- writable: true,
1412
- value: false
1413
- });
1414
- this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
1415
- this.on('error', (err) => {
1416
- if (isClientDisconnectError(err)) {
1417
- console.warn('[OpenAIChatToResponsesEventTransform] Stream closed (client disconnected)');
1418
- }
1419
- else {
1420
- console.error('[OpenAIChatToResponsesEventTransform] Stream error:', err);
1421
- }
1422
- this.errorEmitted = true;
1423
- });
1424
- }
1425
- getUsage() {
1426
- return this.usage;
1427
- }
1428
- _transform(event, _encoding, callback) {
1429
- var _a;
1430
- if (this.errorEmitted) {
1431
- callback();
1432
- return;
1433
- }
1434
- try {
1435
- if (this.finalized) {
1436
- callback();
1437
- return;
1438
- }
1439
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
1440
- this.finalize();
1441
- callback();
1442
- return;
1443
- }
1444
- const chunk = event.data;
1445
- if (!chunk) {
1446
- callback();
1447
- return;
1448
- }
1449
- // 处理 OpenAI Chat Completions 事件
1450
- if (chunk.id && !this.responseId) {
1451
- this.responseId = chunk.id;
1452
- }
1453
- if (chunk.model && !this.model) {
1454
- this.model = chunk.model;
1455
- }
1456
- if (typeof chunk.created === 'number') {
1457
- this.responseCreatedAt = chunk.created;
1458
- }
1459
- // 处理 usage
1460
- if (chunk.usage) {
1461
- this.usage = {
1462
- input_tokens: chunk.usage.prompt_tokens || 0,
1463
- output_tokens: chunk.usage.completion_tokens || 0,
1464
- total_tokens: (chunk.usage.prompt_tokens || 0) + (chunk.usage.completion_tokens || 0),
1465
- };
1466
- }
1467
- // 处理 choices
1468
- if (Array.isArray(chunk.choices)) {
1469
- for (const choice of chunk.choices) {
1470
- this.handleChoice(choice);
1471
- }
1472
- }
1473
- callback();
1474
- }
1475
- catch (error) {
1476
- console.error('[OpenAIChatToResponsesEventTransform] Error in _transform:', error);
1477
- callback();
1478
- }
1479
- }
1480
- _flush(callback) {
1481
- try {
1482
- if (this.finalized) {
1483
- callback();
1484
- return;
1485
- }
1486
- this.finalize();
1487
- callback();
1488
- }
1489
- catch (error) {
1490
- console.error('[OpenAIChatToResponsesEventTransform] Error in _flush:', error);
1491
- callback();
1492
- }
1493
- }
1494
- getResponseId() {
1495
- if (!this.responseId) {
1496
- this.responseId = `response_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
1497
- }
1498
- return this.responseId;
1499
- }
1500
- pushEvent(eventType, data) {
1501
- this.push({
1502
- event: eventType,
1503
- data: Object.assign({ type: eventType, sequence_number: this.sequenceNumber++ }, data)
1504
- });
1505
- }
1506
- buildMessageOutputItem(status) {
1507
- const content = [];
1508
- if (this.textOutput) {
1509
- content.push({ type: 'output_text', text: this.textOutput });
1510
- }
1511
- if (this.refusalOutput) {
1512
- content.push({ type: 'refusal', refusal: this.refusalOutput });
1513
- }
1514
- if (content.length === 0) {
1515
- content.push({ type: 'output_text', text: '' });
1516
- }
1517
- return {
1518
- id: this.messageItemId || `msg_${this.getResponseId()}`,
1519
- type: 'message',
1520
- role: 'assistant',
1521
- status,
1522
- content,
1523
- };
1524
- }
1525
- buildFinalResponse(status) {
1526
- var _a, _b, _c;
1527
- const output = [];
1528
- if (this.messageOutputAdded) {
1529
- output.push(this.buildMessageOutputItem(status === 'completed' ? 'completed' : 'incomplete'));
1530
- }
1531
- for (const call of this.toolCalls.values()) {
1532
- output.push({
1533
- id: call.itemId,
1534
- type: 'function_call',
1535
- call_id: call.itemId,
1536
- name: call.name,
1537
- arguments: call.arguments || '{}',
1538
- status: 'completed',
1539
- });
1540
- }
1541
- const response = {
1542
- id: this.getResponseId(),
1543
- object: 'response',
1544
- created_at: this.responseCreatedAt,
1545
- model: this.model || 'unknown',
1546
- status,
1547
- output,
1548
- };
1549
- if (this.usage) {
1550
- response.usage = {
1551
- input_tokens: (_a = this.usage) === null || _a === void 0 ? void 0 : _a.input_tokens,
1552
- output_tokens: (_b = this.usage) === null || _b === void 0 ? void 0 : _b.output_tokens,
1553
- total_tokens: (_c = this.usage) === null || _c === void 0 ? void 0 : _c.total_tokens,
1554
- };
1555
- }
1556
- if (status === 'incomplete') {
1557
- response.incomplete_details = { reason: this.incompleteReason };
1558
- }
1559
- return response;
1560
- }
1561
- ensureResponseStarted() {
1562
- if (this.responseStarted)
1563
- return;
1564
- const response = {
1565
- id: this.getResponseId(),
1566
- object: 'response',
1567
- created_at: this.responseCreatedAt,
1568
- model: this.model || 'unknown',
1569
- status: 'in_progress',
1570
- output: [],
1571
- };
1572
- this.pushEvent('response.created', { response });
1573
- this.pushEvent('response.in_progress', { response });
1574
- this.responseStarted = true;
1575
- }
1576
- ensureMessageOutputItem() {
1577
- if (this.messageOutputAdded)
1578
- return;
1579
- this.ensureResponseStarted();
1580
- this.messageItemId = this.messageItemId || `msg_${this.getResponseId()}`;
1581
- this.pushEvent('response.output_item.added', {
1582
- output_index: 0,
1583
- item: this.buildMessageOutputItem('in_progress'),
1584
- });
1585
- this.messageOutputAdded = true;
1586
- }
1587
- assignMessageContentIndex() {
1588
- const index = this.nextMessageContentIndex;
1589
- this.nextMessageContentIndex += 1;
1590
- return index;
1591
- }
1592
- ensureTextPart() {
1593
- this.ensureMessageOutputItem();
1594
- if (this.textContentIndex === null) {
1595
- this.textContentIndex = this.assignMessageContentIndex();
1596
- }
1597
- if (!this.textPartAdded && this.messageItemId) {
1598
- this.pushEvent('response.content_part.added', {
1599
- output_index: 0,
1600
- item_id: this.messageItemId,
1601
- content_index: this.textContentIndex,
1602
- part: { type: 'output_text', text: '' },
1603
- });
1604
- this.textPartAdded = true;
1605
- }
1606
- }
1607
- ensureReasoningPart() {
1608
- this.ensureMessageOutputItem();
1609
- if (this.reasoningContentIndex === null) {
1610
- this.reasoningContentIndex = this.assignMessageContentIndex();
1611
- }
1612
- if (!this.reasoningPartAdded && this.messageItemId) {
1613
- this.pushEvent('response.content_part.added', {
1614
- output_index: 0,
1615
- item_id: this.messageItemId,
1616
- content_index: this.reasoningContentIndex,
1617
- part: { type: 'reasoning_text', text: '' },
1618
- });
1619
- this.reasoningPartAdded = true;
1620
- }
1621
- }
1622
- ensureRefusalPart() {
1623
- this.ensureMessageOutputItem();
1624
- if (this.refusalContentIndex === null) {
1625
- this.refusalContentIndex = this.assignMessageContentIndex();
1626
- }
1627
- if (!this.refusalPartAdded && this.messageItemId) {
1628
- this.pushEvent('response.content_part.added', {
1629
- output_index: 0,
1630
- item_id: this.messageItemId,
1631
- content_index: this.refusalContentIndex,
1632
- part: { type: 'refusal', refusal: '' },
1633
- });
1634
- this.refusalPartAdded = true;
1635
- }
1636
- }
1637
- ensureToolCall(toolIndex, toolCallId, toolName) {
1638
- const existing = this.toolCalls.get(toolIndex);
1639
- if (existing) {
1640
- return existing;
1641
- }
1642
- this.ensureResponseStarted();
1643
- const outputIndex = this.nextOutputIndex;
1644
- this.nextOutputIndex += 1;
1645
- const state = {
1646
- itemId: toolCallId,
1647
- name: toolName,
1648
- arguments: '',
1649
- outputIndex,
1650
- done: false,
1651
- };
1652
- this.toolCalls.set(toolIndex, state);
1653
- this.pushEvent('response.output_item.added', {
1654
- output_index: outputIndex,
1655
- item: {
1656
- id: state.itemId,
1657
- type: 'function_call',
1658
- call_id: state.itemId,
1659
- name: state.name,
1660
- arguments: '',
1661
- status: 'in_progress',
1662
- },
1663
- });
1664
- return state;
1665
- }
1666
- mapFinishReasonToStatus(finishReason) {
1667
- if (finishReason === 'length' || finishReason === 'max_tokens') {
1668
- this.responseStatus = 'incomplete';
1669
- this.incompleteReason = 'max_tokens';
1670
- return;
1671
- }
1672
- if (finishReason === 'content_filter') {
1673
- this.responseStatus = 'incomplete';
1674
- this.incompleteReason = 'content_filter';
1675
- return;
1676
- }
1677
- this.responseStatus = 'completed';
1678
- }
1679
- handleChoice(choice) {
1680
- var _a, _b, _c;
1681
- if (typeof (choice === null || choice === void 0 ? void 0 : choice.finish_reason) === 'string') {
1682
- this.mapFinishReasonToStatus(choice.finish_reason);
1683
- }
1684
- const delta = choice.delta;
1685
- if (!delta)
1686
- return;
1687
- // 处理文本内容(忽略空字符串,避免 DeepSeek reasoning 阶段生成无意义空增量)
1688
- if (typeof delta.content === 'string' && delta.content.length > 0) {
1689
- this.ensureTextPart();
1690
- this.textOutput += delta.content;
1691
- this.pushEvent('response.output_text.delta', {
1692
- item_id: this.messageItemId,
1693
- output_index: 0,
1694
- content_index: this.textContentIndex,
1695
- delta: delta.content,
1696
- });
1697
- }
1698
- // 处理 reasoning 内容(兼容 OpenAI 标准和 DeepSeek 的 reasoning_content 字段)
1699
- const reasoningDelta = (typeof ((_a = delta.reasoning) === null || _a === void 0 ? void 0 : _a.content) === 'string' && delta.reasoning.content.length > 0)
1700
- ? delta.reasoning.content
1701
- : (typeof delta.reasoning_content === 'string' && delta.reasoning_content.length > 0)
1702
- ? delta.reasoning_content
1703
- : null;
1704
- if (reasoningDelta) {
1705
- this.ensureReasoningPart();
1706
- this.reasoningOutput += reasoningDelta;
1707
- this.pushEvent('response.reasoning_text.delta', {
1708
- item_id: this.messageItemId,
1709
- output_index: 0,
1710
- content_index: this.reasoningContentIndex,
1711
- delta: reasoningDelta,
1712
- });
1713
- }
1714
- // 处理工具调用
1715
- if (Array.isArray(delta.tool_calls)) {
1716
- for (let i = 0; i < delta.tool_calls.length; i += 1) {
1717
- const toolCall = delta.tool_calls[i];
1718
- const toolIndex = typeof (toolCall === null || toolCall === void 0 ? void 0 : toolCall.index) === 'number' ? toolCall.index : i;
1719
- const toolName = (_b = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _b === void 0 ? void 0 : _b.name;
1720
- if (!(toolCall === null || toolCall === void 0 ? void 0 : toolCall.id) || !toolName) {
1721
- continue;
1722
- }
1723
- const stored = this.ensureToolCall(toolIndex, toolCall.id, toolName);
1724
- const argsDelta = (_c = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _c === void 0 ? void 0 : _c.arguments;
1725
- if (typeof argsDelta === 'string' && argsDelta.length > 0) {
1726
- stored.arguments += argsDelta;
1727
- this.pushEvent('response.function_call_arguments.delta', {
1728
- item_id: stored.itemId,
1729
- output_index: stored.outputIndex,
1730
- delta: argsDelta,
1731
- });
1732
- }
1733
- }
1734
- }
1735
- // 处理 refusal(拒绝内容)
1736
- if (typeof delta.refusal === 'string' && delta.refusal.length > 0) {
1737
- this.ensureRefusalPart();
1738
- this.refusalOutput += delta.refusal;
1739
- this.pushEvent('response.refusal.delta', {
1740
- item_id: this.messageItemId,
1741
- output_index: 0,
1742
- content_index: this.refusalContentIndex,
1743
- delta: delta.refusal,
1744
- });
1745
- }
1746
- }
1747
- finalize() {
1748
- var _a, _b, _c;
1749
- if (this.finalized)
1750
- return;
1751
- // 如果没有任何输出,也需要确保有一个空的 message 输出项
1752
- if (!this.messageOutputAdded && this.toolCalls.size === 0) {
1753
- this.ensureMessageOutputItem();
1754
- this.ensureTextPart();
1755
- }
1756
- if (this.messageItemId) {
1757
- if (this.textPartAdded && this.textContentIndex !== null) {
1758
- this.pushEvent('response.output_text.done', {
1759
- item_id: this.messageItemId,
1760
- output_index: 0,
1761
- content_index: this.textContentIndex,
1762
- text: this.textOutput,
1763
- });
1764
- this.pushEvent('response.content_part.done', {
1765
- item_id: this.messageItemId,
1766
- output_index: 0,
1767
- content_index: this.textContentIndex,
1768
- part: { type: 'output_text', text: this.textOutput },
1769
- });
1770
- }
1771
- if (this.reasoningPartAdded && this.reasoningContentIndex !== null) {
1772
- this.pushEvent('response.reasoning_text.done', {
1773
- item_id: this.messageItemId,
1774
- output_index: 0,
1775
- content_index: this.reasoningContentIndex,
1776
- text: this.reasoningOutput,
1777
- });
1778
- this.pushEvent('response.content_part.done', {
1779
- item_id: this.messageItemId,
1780
- output_index: 0,
1781
- content_index: this.reasoningContentIndex,
1782
- part: { type: 'reasoning_text', text: this.reasoningOutput },
1783
- });
1784
- }
1785
- if (this.refusalPartAdded && this.refusalContentIndex !== null) {
1786
- this.pushEvent('response.refusal.done', {
1787
- item_id: this.messageItemId,
1788
- output_index: 0,
1789
- content_index: this.refusalContentIndex,
1790
- refusal: this.refusalOutput,
1791
- });
1792
- this.pushEvent('response.content_part.done', {
1793
- item_id: this.messageItemId,
1794
- output_index: 0,
1795
- content_index: this.refusalContentIndex,
1796
- part: { type: 'refusal', refusal: this.refusalOutput },
1797
- });
1798
- }
1799
- }
1800
- for (const call of this.toolCalls.values()) {
1801
- if (call.done)
1802
- continue;
1803
- this.pushEvent('response.function_call_arguments.done', {
1804
- item_id: call.itemId,
1805
- output_index: call.outputIndex,
1806
- name: call.name,
1807
- arguments: call.arguments || '{}',
1808
- });
1809
- this.pushEvent('response.output_item.done', {
1810
- output_index: call.outputIndex,
1811
- item: {
1812
- id: call.itemId,
1813
- type: 'function_call',
1814
- call_id: call.itemId,
1815
- name: call.name,
1816
- arguments: call.arguments || '{}',
1817
- status: 'completed',
1818
- },
1819
- });
1820
- call.done = true;
1821
- }
1822
- if (this.messageOutputAdded) {
1823
- this.pushEvent('response.output_item.done', {
1824
- output_index: 0,
1825
- item: this.buildMessageOutputItem(this.responseStatus === 'completed' ? 'completed' : 'incomplete'),
1826
- });
1827
- }
1828
- const finalResponse = this.buildFinalResponse(this.responseStatus);
1829
- this.pushEvent(this.responseStatus === 'incomplete' ? 'response.incomplete' : 'response.completed', {
1830
- response: finalResponse,
1831
- incomplete_details: this.responseStatus === 'incomplete' ? { reason: this.incompleteReason } : undefined,
1832
- });
1833
- // 额外发送 usage 事件,兼容已有 usage 提取逻辑
1834
- if (this.usage) {
1835
- this.pushEvent('response.usage', {
1836
- input_tokens: (_a = this.usage) === null || _a === void 0 ? void 0 : _a.input_tokens,
1837
- output_tokens: (_b = this.usage) === null || _b === void 0 ? void 0 : _b.output_tokens,
1838
- total_tokens: (_c = this.usage) === null || _c === void 0 ? void 0 : _c.total_tokens,
1839
- });
1840
- }
1841
- this.finalized = true;
1842
- }
1843
- }
1844
- exports.ChatCompletionsToResponsesEventTransform = ChatCompletionsToResponsesEventTransform;
1845
- /**
1846
- * 将 Claude SSE 流式事件转换为 Responses API 格式
1847
- * 当源是 claude/claude-chat,目标是 codex 时使用
1848
- */
1849
- class ClaudeToResponsesEventTransform extends stream_1.Transform {
1850
- constructor(options) {
1851
- var _a;
1852
- super({ objectMode: true });
1853
- Object.defineProperty(this, "messageId", {
1854
- enumerable: true,
1855
- configurable: true,
1856
- writable: true,
1857
- value: null
1858
- });
1859
- Object.defineProperty(this, "model", {
1860
- enumerable: true,
1861
- configurable: true,
1862
- writable: true,
1863
- value: null
1864
- });
1865
- Object.defineProperty(this, "responseCreated", {
1866
- enumerable: true,
1867
- configurable: true,
1868
- writable: true,
1869
- value: false
1870
- });
1871
- Object.defineProperty(this, "textIndex", {
1872
- enumerable: true,
1873
- configurable: true,
1874
- writable: true,
1875
- value: 0
1876
- });
1877
- Object.defineProperty(this, "toolCalls", {
1878
- enumerable: true,
1879
- configurable: true,
1880
- writable: true,
1881
- value: new Map()
1882
- });
1883
- Object.defineProperty(this, "toolCallIndexToContentIndex", {
1884
- enumerable: true,
1885
- configurable: true,
1886
- writable: true,
1887
- value: new Map()
1888
- });
1889
- Object.defineProperty(this, "activeToolIndexByContentIndex", {
1890
- enumerable: true,
1891
- configurable: true,
1892
- writable: true,
1893
- value: new Map()
1894
- });
1895
- Object.defineProperty(this, "completedToolCallIds", {
1896
- enumerable: true,
1897
- configurable: true,
1898
- writable: true,
1899
- value: new Set()
1900
- });
1901
- Object.defineProperty(this, "stopReason", {
1902
- enumerable: true,
1903
- configurable: true,
1904
- writable: true,
1905
- value: 'completed'
1906
- });
1907
- Object.defineProperty(this, "incompleteReason", {
1908
- enumerable: true,
1909
- configurable: true,
1910
- writable: true,
1911
- value: 'max_tokens'
1912
- });
1913
- Object.defineProperty(this, "usage", {
1914
- enumerable: true,
1915
- configurable: true,
1916
- writable: true,
1917
- value: null
1918
- });
1919
- Object.defineProperty(this, "finalized", {
1920
- enumerable: true,
1921
- configurable: true,
1922
- writable: true,
1923
- value: false
1924
- });
1925
- Object.defineProperty(this, "errorEmitted", {
1926
- enumerable: true,
1927
- configurable: true,
1928
- writable: true,
1929
- value: false
1930
- });
1931
- this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
1932
- this.on('error', (err) => {
1933
- if (isClientDisconnectError(err)) {
1934
- console.warn('[ClaudeToResponsesEventTransform] Stream closed (client disconnected)');
1935
- }
1936
- else {
1937
- console.error('[ClaudeToResponsesEventTransform] Stream error:', err);
1938
- }
1939
- this.errorEmitted = true;
1940
- });
1941
- }
1942
- getUsage() {
1943
- return this.usage;
1944
- }
1945
- _transform(event, _encoding, callback) {
1946
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1947
- if (this.errorEmitted) {
1948
- callback();
1949
- return;
1950
- }
1951
- try {
1952
- if (this.finalized) {
1953
- callback();
1954
- return;
1955
- }
1956
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
1957
- this.finalize();
1958
- callback();
1959
- return;
1960
- }
1961
- const type = event.event;
1962
- const data = event.data;
1963
- // 处理 message_start
1964
- if (type === 'message_start' && (data === null || data === void 0 ? void 0 : data.message)) {
1965
- this.messageId = data.message.id;
1966
- this.model = data.message.model || this.model;
1967
- if (!this.responseCreated) {
1968
- this.pushEvent('response.created', { id: this.messageId || `response_${Date.now()}` });
1969
- this.pushEvent('response.in_progress', { id: this.messageId || `response_${Date.now()}` });
1970
- this.responseCreated = true;
1971
- }
1972
- callback();
1973
- return;
1974
- }
1975
- // 处理 content_block_start
1976
- if (type === 'content_block_start' && (data === null || data === void 0 ? void 0 : data.content_block)) {
1977
- if (data.content_block.type === 'text') {
1978
- // 文本块开始,无需特殊处理,等待 delta
1979
- }
1980
- else if (data.content_block.type === 'thinking') {
1981
- // thinking 块,处理为 reasoning 文本
1982
- if (!this.responseCreated) {
1983
- this.pushEvent('response.created', { id: this.messageId || `response_${Date.now()}` });
1984
- this.pushEvent('response.in_progress', { id: this.messageId || `response_${Date.now()}` });
1985
- this.responseCreated = true;
1986
- }
1987
- }
1988
- else if (data.content_block.type === 'tool_use') {
1989
- // 工具调用
1990
- if (!this.responseCreated) {
1991
- this.pushEvent('response.created', { id: this.messageId || `response_${Date.now()}` });
1992
- this.pushEvent('response.in_progress', { id: this.messageId || `response_${Date.now()}` });
1993
- this.responseCreated = true;
1994
- }
1995
- const contentIndex = typeof data.index === 'number' ? data.index : this.assignContentIndex();
1996
- const toolIndex = this.toolCalls.size;
1997
- this.toolCalls.set(toolIndex, {
1998
- id: data.content_block.id,
1999
- name: data.content_block.name,
2000
- arguments: '',
2001
- });
2002
- this.toolCallIndexToContentIndex.set(toolIndex, contentIndex);
2003
- this.activeToolIndexByContentIndex.set(contentIndex, toolIndex);
2004
- // 发送 function_call.start 事件
2005
- this.pushEvent('response.function_call.start', {
2006
- call_id: data.content_block.id,
2007
- item_id: data.content_block.id,
2008
- name: data.content_block.name,
2009
- arguments: '{}',
2010
- });
2011
- }
2012
- callback();
2013
- return;
2014
- }
2015
- // 处理 content_block_delta
2016
- if (type === 'content_block_delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
2017
- if (data.delta.type === 'text_delta') {
2018
- if (!this.responseCreated) {
2019
- this.pushEvent('response.created', { id: this.messageId || `response_${Date.now()}` });
2020
- this.pushEvent('response.in_progress', { id: this.messageId || `response_${Date.now()}` });
2021
- this.responseCreated = true;
2022
- }
2023
- const text = data.delta.text || '';
2024
- if (text) {
2025
- this.pushEvent('response.output_text.delta', { delta: text });
2026
- }
2027
- }
2028
- else if (data.delta.type === 'thinking_delta') {
2029
- // thinking 增量,转换为 reasoning 文本增量
2030
- const thinking = data.delta.thinking || '';
2031
- if (thinking) {
2032
- this.pushEvent('response.reasoning_text.delta', { delta: thinking });
2033
- }
2034
- }
2035
- else if (data.delta.type === 'input_json_delta') {
2036
- // 工具参数增量
2037
- const contentIndex = typeof data.index === 'number' ? data.index : undefined;
2038
- const toolIndex = contentIndex !== undefined
2039
- ? (_b = this.activeToolIndexByContentIndex.get(contentIndex)) !== null && _b !== void 0 ? _b : (this.toolCalls.size - 1)
2040
- : (this.toolCalls.size - 1);
2041
- const stored = this.toolCalls.get(toolIndex);
2042
- if (stored) {
2043
- stored.arguments += data.delta.partial_json || '';
2044
- }
2045
- const toolBlockIndex = this.toolCallIndexToContentIndex.get(toolIndex);
2046
- if (toolBlockIndex !== undefined) {
2047
- this.pushEvent('response.function_call_arguments.delta', {
2048
- call_id: (stored === null || stored === void 0 ? void 0 : stored.id) || '',
2049
- item_id: (stored === null || stored === void 0 ? void 0 : stored.id) || '',
2050
- delta: data.delta.partial_json || '',
2051
- });
2052
- }
2053
- }
2054
- callback();
2055
- return;
2056
- }
2057
- // 处理 content_block_stop
2058
- if (type === 'content_block_stop') {
2059
- const contentIndex = typeof (data === null || data === void 0 ? void 0 : data.index) === 'number' ? data.index : undefined;
2060
- const toolIndex = contentIndex !== undefined ? this.activeToolIndexByContentIndex.get(contentIndex) : undefined;
2061
- const stored = toolIndex !== undefined ? this.toolCalls.get(toolIndex) : undefined;
2062
- if (stored && !this.completedToolCallIds.has(stored.id)) {
2063
- this.pushEvent('response.function_call_arguments.done', {
2064
- call_id: stored.id,
2065
- item_id: stored.id,
2066
- name: stored.name,
2067
- arguments: stored.arguments || '{}',
2068
- });
2069
- this.completedToolCallIds.add(stored.id);
2070
- }
2071
- callback();
2072
- return;
2073
- }
2074
- // 处理 message_delta
2075
- if (type === 'message_delta' && (data === null || data === void 0 ? void 0 : data.delta)) {
2076
- // 映射 stop_reason
2077
- if (data.delta.stop_reason) {
2078
- const mapped = this.mapStopReasonToResponses(data.delta.stop_reason);
2079
- this.stopReason = mapped.status;
2080
- if (mapped.reason) {
2081
- this.incompleteReason = mapped.reason;
2082
- }
2083
- }
2084
- // 处理 usage
2085
- if (data.usage) {
2086
- this.usage = {
2087
- input_tokens: ((_c = data.usage) === null || _c === void 0 ? void 0 : _c.input_tokens) || 0,
2088
- output_tokens: ((_d = data.usage) === null || _d === void 0 ? void 0 : _d.output_tokens) || 0,
2089
- total_tokens: (((_e = data.usage) === null || _e === void 0 ? void 0 : _e.input_tokens) || 0) + (((_f = data.usage) === null || _f === void 0 ? void 0 : _f.output_tokens) || 0),
2090
- };
2091
- }
2092
- callback();
2093
- return;
2094
- }
2095
- // 处理 message_stop
2096
- if (type === 'message_stop' || (data === null || data === void 0 ? void 0 : data.type) === 'message_stop') {
2097
- this.finalize();
2098
- callback();
2099
- return;
2100
- }
2101
- // 处理 usage 字段(在顶层)
2102
- if (data === null || data === void 0 ? void 0 : data.usage) {
2103
- this.usage = {
2104
- input_tokens: ((_g = data.usage) === null || _g === void 0 ? void 0 : _g.input_tokens) || 0,
2105
- output_tokens: ((_h = data.usage) === null || _h === void 0 ? void 0 : _h.output_tokens) || 0,
2106
- total_tokens: (((_j = data.usage) === null || _j === void 0 ? void 0 : _j.input_tokens) || 0) + (((_k = data.usage) === null || _k === void 0 ? void 0 : _k.output_tokens) || 0),
2107
- };
2108
- }
2109
- callback();
2110
- }
2111
- catch (error) {
2112
- console.error('[ClaudeToResponsesEventTransform] Error in _transform:', error);
2113
- callback();
2114
- }
2115
- }
2116
- _flush(callback) {
2117
- try {
2118
- this.finalize();
2119
- callback();
2120
- }
2121
- catch (error) {
2122
- console.error('[ClaudeToResponsesEventTransform] Error in _flush:', error);
2123
- callback();
2124
- }
2125
- }
2126
- assignContentIndex() {
2127
- const index = this.textIndex;
2128
- this.textIndex += 1;
2129
- return index;
2130
- }
2131
- pushEvent(eventType, data) {
2132
- this.push({ event: eventType, data });
2133
- }
2134
- mapStopReasonToResponses(stopReason) {
2135
- switch (stopReason) {
2136
- case 'end_turn':
2137
- case 'stop_sequence':
2138
- return { status: 'completed' };
2139
- case 'max_tokens':
2140
- case 'max_thinking_length':
2141
- return { status: 'incomplete', reason: 'max_tokens' };
2142
- case 'tool_use':
2143
- return { status: 'completed' };
2144
- case 'content_filter':
2145
- return { status: 'incomplete', reason: 'content_filter' };
2146
- default:
2147
- return { status: 'completed' };
2148
- }
2149
- }
2150
- finalize() {
2151
- var _a, _b, _c;
2152
- if (this.finalized)
2153
- return;
2154
- if (!this.responseCreated) {
2155
- this.pushEvent('response.created', { id: this.messageId || `response_${Date.now()}` });
2156
- this.pushEvent('response.in_progress', { id: this.messageId || `response_${Date.now()}` });
2157
- this.responseCreated = true;
2158
- }
2159
- for (const [, call] of this.toolCalls) {
2160
- if (this.completedToolCallIds.has(call.id))
2161
- continue;
2162
- this.pushEvent('response.function_call_arguments.done', {
2163
- call_id: call.id,
2164
- item_id: call.id,
2165
- name: call.name,
2166
- arguments: call.arguments || '{}',
2167
- });
2168
- this.completedToolCallIds.add(call.id);
2169
- }
2170
- // 发送 response.completed 或 response.incomplete
2171
- if (this.stopReason === 'incomplete') {
2172
- this.pushEvent('response.incomplete', {
2173
- incomplete_details: { reason: this.incompleteReason },
2174
- });
2175
- }
2176
- else {
2177
- this.pushEvent('response.completed', {});
2178
- }
2179
- // 发送 usage(如果有)
2180
- if (this.usage) {
2181
- this.pushEvent('response.usage', {
2182
- input_tokens: (_a = this.usage) === null || _a === void 0 ? void 0 : _a.input_tokens,
2183
- output_tokens: (_b = this.usage) === null || _b === void 0 ? void 0 : _b.output_tokens,
2184
- total_tokens: (_c = this.usage) === null || _c === void 0 ? void 0 : _c.total_tokens,
2185
- });
2186
- }
2187
- this.finalized = true;
2188
- }
2189
- }
2190
- exports.ClaudeToResponsesEventTransform = ClaudeToResponsesEventTransform;
2191
- /**
2192
- * 将 Gemini SSE 流式事件转换为 Responses API 格式
2193
- * 当源是 gemini/gemini-chat,目标是 codex 时使用
2194
- */
2195
- class GeminiToResponsesEventTransform extends stream_1.Transform {
2196
- constructor(options) {
2197
- super({ objectMode: true });
2198
- Object.defineProperty(this, "responseId", {
2199
- enumerable: true,
2200
- configurable: true,
2201
- writable: true,
2202
- value: null
2203
- });
2204
- Object.defineProperty(this, "responseCreated", {
2205
- enumerable: true,
2206
- configurable: true,
2207
- writable: true,
2208
- value: false
2209
- });
2210
- Object.defineProperty(this, "stopReason", {
2211
- enumerable: true,
2212
- configurable: true,
2213
- writable: true,
2214
- value: 'completed'
2215
- });
2216
- Object.defineProperty(this, "incompleteReason", {
2217
- enumerable: true,
2218
- configurable: true,
2219
- writable: true,
2220
- value: 'max_tokens'
2221
- });
2222
- Object.defineProperty(this, "usage", {
2223
- enumerable: true,
2224
- configurable: true,
2225
- writable: true,
2226
- value: null
2227
- });
2228
- Object.defineProperty(this, "finalized", {
2229
- enumerable: true,
2230
- configurable: true,
2231
- writable: true,
2232
- value: false
2233
- });
2234
- Object.defineProperty(this, "errorEmitted", {
2235
- enumerable: true,
2236
- configurable: true,
2237
- writable: true,
2238
- value: false
2239
- });
2240
- void options;
2241
- this.on('error', (err) => {
2242
- if (isClientDisconnectError(err)) {
2243
- console.warn('[GeminiToResponsesEventTransform] Stream closed (client disconnected)');
2244
- }
2245
- else {
2246
- console.error('[GeminiToResponsesEventTransform] Stream error:', err);
2247
- }
2248
- this.errorEmitted = true;
2249
- });
2250
- }
2251
- getUsage() {
2252
- return this.usage;
2253
- }
2254
- _transform(event, _encoding, callback) {
2255
- var _a;
2256
- if (this.errorEmitted) {
2257
- callback();
2258
- return;
2259
- }
2260
- try {
2261
- if (this.finalized) {
2262
- callback();
2263
- return;
2264
- }
2265
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
2266
- this.finalize();
2267
- callback();
2268
- return;
2269
- }
2270
- const chunk = event.data;
2271
- if (!chunk) {
2272
- callback();
2273
- return;
2274
- }
2275
- // Gemini 流式响应格式: { candidates: [{ content: { parts: [...] }, finishReason: ... }], usageMetadata: {...} }
2276
- const candidates = Array.isArray(chunk.candidates) ? chunk.candidates : [];
2277
- const usageMetadata = chunk.usageMetadata;
2278
- if (!this.responseId) {
2279
- this.responseId = `response_${Date.now()}`;
2280
- }
2281
- // 处理 usage
2282
- if (usageMetadata) {
2283
- this.usage = {
2284
- input_tokens: usageMetadata.promptTokenCount || 0,
2285
- output_tokens: usageMetadata.candidatesTokenCount || 0,
2286
- total_tokens: (usageMetadata.promptTokenCount || 0) + (usageMetadata.candidatesTokenCount || 0),
2287
- };
2288
- }
2289
- // 处理 candidates
2290
- for (const candidate of candidates) {
2291
- // 处理 finishReason
2292
- if (candidate.finishReason) {
2293
- const mapped = this.mapGeminiFinishReasonToResponses(candidate.finishReason);
2294
- this.stopReason = mapped.status;
2295
- if (mapped.reason) {
2296
- this.incompleteReason = mapped.reason;
2297
- }
2298
- }
2299
- if (!candidate.content || !Array.isArray(candidate.content.parts)) {
2300
- continue;
2301
- }
2302
- // 确保响应已创建
2303
- if (!this.responseCreated) {
2304
- this.pushEvent('response.created', { id: this.responseId });
2305
- this.pushEvent('response.in_progress', { id: this.responseId });
2306
- this.responseCreated = true;
2307
- }
2308
- // 处理 parts
2309
- for (const part of candidate.content.parts) {
2310
- // 处理文本 -> output_text.delta
2311
- if (part.text && typeof part.text === 'string') {
2312
- this.pushEvent('response.output_text.delta', { delta: part.text });
2313
- }
2314
- // 处理 functionCall -> function_call.start 和 function_call_arguments.delta
2315
- if (part.functionCall) {
2316
- const callId = `call_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
2317
- const name = part.functionCall.name || 'tool';
2318
- const args = part.functionCall.args || {};
2319
- const argsJson = JSON.stringify(args);
2320
- // Gemini 通常一次返回完整参数,这里同时发 delta/done,兼容严格与宽松客户端
2321
- this.pushEvent('response.function_call_arguments.delta', {
2322
- call_id: callId,
2323
- item_id: callId,
2324
- delta: argsJson,
2325
- });
2326
- this.pushEvent('response.function_call_arguments.done', {
2327
- call_id: callId,
2328
- item_id: callId,
2329
- name: name,
2330
- arguments: argsJson,
2331
- });
2332
- }
2333
- // 处理 inlineData (图像输出,罕见)
2334
- if (part.inlineData) {
2335
- // Responses 输出流以文本/工具调用为主,图像输出块在此忽略
2336
- }
2337
- }
2338
- }
2339
- callback();
2340
- }
2341
- catch (error) {
2342
- console.error('[GeminiToResponsesEventTransform] Error in _transform:', error);
2343
- callback();
2344
- }
2345
- }
2346
- _flush(callback) {
2347
- try {
2348
- this.finalize();
2349
- callback();
2350
- }
2351
- catch (error) {
2352
- console.error('[GeminiToResponsesEventTransform] Error in _flush:', error);
2353
- callback();
2354
- }
2355
- }
2356
- pushEvent(eventType, data) {
2357
- this.push({ event: eventType, data });
2358
- }
2359
- mapGeminiFinishReasonToResponses(finishReason) {
2360
- switch (finishReason) {
2361
- case 'STOP':
2362
- return { status: 'completed' };
2363
- case 'MAX_TOKENS':
2364
- return { status: 'incomplete', reason: 'max_tokens' };
2365
- case 'SAFETY':
2366
- case 'RECITATION':
2367
- return { status: 'incomplete', reason: 'content_filter' };
2368
- case 'MALFORMED_FUNCTION_CALL':
2369
- return { status: 'completed' };
2370
- default:
2371
- return { status: 'completed' };
2372
- }
2373
- }
2374
- finalize() {
2375
- var _a, _b, _c;
2376
- if (this.finalized)
2377
- return;
2378
- // 发送 response.created 和 response.in_progress(如果还没有)
2379
- if (!this.responseCreated) {
2380
- const id = this.responseId || `response_${Date.now()}`;
2381
- this.pushEvent('response.created', { id });
2382
- this.pushEvent('response.in_progress', { id });
2383
- this.responseCreated = true;
2384
- }
2385
- // 发送 response.completed 或 response.incomplete
2386
- if (this.stopReason === 'incomplete') {
2387
- this.pushEvent('response.incomplete', {
2388
- incomplete_details: { reason: this.incompleteReason },
2389
- });
2390
- }
2391
- else {
2392
- this.pushEvent('response.completed', {});
2393
- }
2394
- // 发送 usage(如果有)
2395
- if (this.usage) {
2396
- this.pushEvent('response.usage', {
2397
- input_tokens: (_a = this.usage) === null || _a === void 0 ? void 0 : _a.input_tokens,
2398
- output_tokens: (_b = this.usage) === null || _b === void 0 ? void 0 : _b.output_tokens,
2399
- total_tokens: (_c = this.usage) === null || _c === void 0 ? void 0 : _c.total_tokens,
2400
- });
2401
- }
2402
- this.finalized = true;
2403
- }
2404
- }
2405
- exports.GeminiToResponsesEventTransform = GeminiToResponsesEventTransform;
2406
- // ======================= transform SSE for claude code =======================
2407
- /**
2408
- * 将 Chat Completions SSE 流式事件转换为 Claude SSE 格式
2409
- * 当源是 openai-chat,目标是 claude code 时使用
2410
- */
2411
- class ChatCompletionsToClaudeEventTransform extends stream_1.Transform {
2412
- constructor(options) {
2413
- var _a;
2414
- super({ objectMode: true });
2415
- Object.defineProperty(this, "contentIndex", {
2416
- enumerable: true,
2417
- configurable: true,
2418
- writable: true,
2419
- value: 0
2420
- });
2421
- Object.defineProperty(this, "textBlockIndex", {
2422
- enumerable: true,
2423
- configurable: true,
2424
- writable: true,
2425
- value: null
2426
- });
2427
- Object.defineProperty(this, "thinkingBlockIndex", {
2428
- enumerable: true,
2429
- configurable: true,
2430
- writable: true,
2431
- value: null
2432
- });
2433
- Object.defineProperty(this, "toolCalls", {
2434
- enumerable: true,
2435
- configurable: true,
2436
- writable: true,
2437
- value: new Map()
2438
- });
2439
- Object.defineProperty(this, "toolCallIndexToBlockIndex", {
2440
- enumerable: true,
2441
- configurable: true,
2442
- writable: true,
2443
- value: new Map()
2444
- });
2445
- Object.defineProperty(this, "hasMessageStart", {
2446
- enumerable: true,
2447
- configurable: true,
2448
- writable: true,
2449
- value: false
2450
- });
2451
- Object.defineProperty(this, "stopReason", {
2452
- enumerable: true,
2453
- configurable: true,
2454
- writable: true,
2455
- value: 'end_turn'
2456
- });
2457
- Object.defineProperty(this, "usage", {
2458
- enumerable: true,
2459
- configurable: true,
2460
- writable: true,
2461
- value: null
2462
- });
2463
- Object.defineProperty(this, "messageId", {
2464
- enumerable: true,
2465
- configurable: true,
2466
- writable: true,
2467
- value: null
2468
- });
2469
- Object.defineProperty(this, "model", {
2470
- enumerable: true,
2471
- configurable: true,
2472
- writable: true,
2473
- value: null
2474
- });
2475
- Object.defineProperty(this, "finalized", {
2476
- enumerable: true,
2477
- configurable: true,
2478
- writable: true,
2479
- value: false
2480
- });
2481
- Object.defineProperty(this, "errorEmitted", {
2482
- enumerable: true,
2483
- configurable: true,
2484
- writable: true,
2485
- value: false
2486
- });
2487
- this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
2488
- this.on('error', (err) => {
2489
- if (isClientDisconnectError(err)) {
2490
- console.warn('[ChatCompletionsToClaudeEventTransform] Stream closed (client disconnected)');
2491
- }
2492
- else {
2493
- console.error('[ChatCompletionsToClaudeEventTransform] Stream error:', err);
2494
- }
2495
- this.errorEmitted = true;
2496
- });
2497
- }
2498
- getUsage() {
2499
- if (!this.usage)
2500
- return undefined;
2501
- return Object.assign({}, this.usage);
2502
- }
2503
- _transform(event, _encoding, callback) {
2504
- var _a;
2505
- if (this.errorEmitted) {
2506
- callback();
2507
- return;
2508
- }
2509
- try {
2510
- if (this.finalized) {
2511
- callback();
2512
- return;
2513
- }
2514
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
2515
- this.finalize();
2516
- callback();
2517
- return;
2518
- }
2519
- const chunk = event.data;
2520
- if (!chunk) {
2521
- callback();
2522
- return;
2523
- }
2524
- // 处理 id 和 model
2525
- if (chunk.id && !this.messageId) {
2526
- this.messageId = chunk.id;
2527
- }
2528
- if (chunk.model && !this.model) {
2529
- this.model = chunk.model;
2530
- }
2531
- // 处理 usage
2532
- if (chunk.usage) {
2533
- this.usage = {
2534
- input_tokens: chunk.usage.prompt_tokens || 0,
2535
- output_tokens: chunk.usage.completion_tokens || 0,
2536
- cache_read_input_tokens: 0,
2537
- };
2538
- }
2539
- // 处理 choices
2540
- if (Array.isArray(chunk.choices)) {
2541
- for (const choice of chunk.choices) {
2542
- this.handleChoice(choice);
2543
- }
2544
- }
2545
- callback();
2546
- }
2547
- catch (error) {
2548
- console.error('[ChatCompletionsToClaudeEventTransform] Error in _transform:', error);
2549
- callback();
2550
- }
2551
- }
2552
- _flush(callback) {
2553
- try {
2554
- this.finalize();
2555
- callback();
2556
- }
2557
- catch (error) {
2558
- console.error('[ChatCompletionsToClaudeEventTransform] Error in _flush:', error);
2559
- callback();
2560
- }
2561
- }
2562
- assignContentBlockIndex() {
2563
- const index = this.contentIndex;
2564
- this.contentIndex += 1;
2565
- return index;
2566
- }
2567
- pushEvent(type, data) {
2568
- this.push({ event: type, data });
2569
- }
2570
- ensureMessageStart() {
2571
- if (this.hasMessageStart)
2572
- return;
2573
- const message = {
2574
- id: this.messageId || `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2575
- type: 'message',
2576
- role: 'assistant',
2577
- content: [],
2578
- model: this.model || 'unknown',
2579
- stop_reason: null,
2580
- stop_sequence: null,
2581
- usage: {
2582
- input_tokens: 0,
2583
- output_tokens: 0,
2584
- },
2585
- };
2586
- this.pushEvent('message_start', { type: 'message_start', message });
2587
- this.hasMessageStart = true;
2588
- }
2589
- handleChoice(choice) {
2590
- var _a, _b, _c, _d;
2591
- // 处理 finish_reason 映射
2592
- // OpenAI: "stop" | "length" | "tool_calls" | "content_filter"
2593
- // Claude: "end_turn" | "max_tokens" | "tool_use" | "stop_sequence" | "max_thinking_length"
2594
- if (typeof (choice === null || choice === void 0 ? void 0 : choice.finish_reason) === 'string') {
2595
- this.stopReason = this.mapOpenAIFinishReason(choice.finish_reason);
2596
- }
2597
- const delta = choice === null || choice === void 0 ? void 0 : choice.delta;
2598
- if (!delta)
2599
- return;
2600
- // 处理文本内容
2601
- if (typeof delta.content === 'string') {
2602
- this.ensureMessageStart();
2603
- if (this.textBlockIndex === null) {
2604
- this.textBlockIndex = this.assignContentBlockIndex();
2605
- this.pushEvent('content_block_start', {
2606
- type: 'content_block_start',
2607
- index: this.textBlockIndex,
2608
- content_block: { type: 'text' },
2609
- });
2610
- }
2611
- this.pushEvent('content_block_delta', {
2612
- type: 'content_block_delta',
2613
- index: this.textBlockIndex,
2614
- delta: {
2615
- type: 'text_delta',
2616
- text: delta.content,
2617
- },
2618
- });
2619
- }
2620
- // 处理 thinking 内容 (OpenAI 中的 reasoning)
2621
- const thinkingText = typeof ((_a = delta.reasoning) === null || _a === void 0 ? void 0 : _a.content) === 'string'
2622
- ? delta.reasoning.content
2623
- : (typeof ((_b = delta.thinking) === null || _b === void 0 ? void 0 : _b.content) === 'string' ? delta.thinking.content : null);
2624
- if (thinkingText) {
2625
- this.ensureMessageStart();
2626
- if (this.thinkingBlockIndex === null) {
2627
- this.thinkingBlockIndex = this.assignContentBlockIndex();
2628
- this.pushEvent('content_block_start', {
2629
- type: 'content_block_start',
2630
- index: this.thinkingBlockIndex,
2631
- content_block: { type: 'thinking', thinking: '' },
2632
- });
2633
- }
2634
- this.pushEvent('content_block_delta', {
2635
- type: 'content_block_delta',
2636
- index: this.thinkingBlockIndex,
2637
- delta: {
2638
- type: 'thinking_delta',
2639
- thinking: thinkingText,
2640
- },
2641
- });
2642
- }
2643
- // 处理 tool_calls
2644
- if (Array.isArray(delta.tool_calls)) {
2645
- for (let i = 0; i < delta.tool_calls.length; i++) {
2646
- const toolCall = delta.tool_calls[i];
2647
- const toolIndex = typeof (toolCall === null || toolCall === void 0 ? void 0 : toolCall.index) === 'number' ? toolCall.index : i;
2648
- const toolName = (_c = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _c === void 0 ? void 0 : _c.name;
2649
- // 发送工具调用开始
2650
- if ((toolCall === null || toolCall === void 0 ? void 0 : toolCall.id) && toolName) {
2651
- this.ensureMessageStart();
2652
- const toolBlockIndex = this.assignContentBlockIndex();
2653
- this.toolCalls.set(toolIndex, {
2654
- id: toolCall.id,
2655
- name: toolName,
2656
- arguments: '',
2657
- });
2658
- this.toolCallIndexToBlockIndex.set(toolIndex, toolBlockIndex);
2659
- this.pushEvent('content_block_start', {
2660
- type: 'content_block_start',
2661
- index: toolBlockIndex,
2662
- content_block: {
2663
- type: 'tool_use',
2664
- id: toolCall.id,
2665
- name: toolName,
2666
- },
2667
- });
2668
- }
2669
- // 发送工具参数增量
2670
- if ((_d = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _d === void 0 ? void 0 : _d.arguments) {
2671
- this.ensureMessageStart();
2672
- const stored = this.toolCalls.get(toolIndex);
2673
- if (stored) {
2674
- stored.arguments += toolCall.function.arguments;
2675
- }
2676
- const toolBlockIndex = this.toolCallIndexToBlockIndex.get(toolIndex);
2677
- if (toolBlockIndex !== undefined) {
2678
- this.pushEvent('content_block_delta', {
2679
- type: 'content_block_delta',
2680
- index: toolBlockIndex,
2681
- delta: {
2682
- type: 'input_json_delta',
2683
- partial_json: toolCall.function.arguments,
2684
- },
2685
- });
2686
- }
2687
- }
2688
- }
2689
- }
2690
- }
2691
- mapOpenAIFinishReason(finishReason) {
2692
- switch (finishReason) {
2693
- case 'stop':
2694
- return 'end_turn';
2695
- case 'length':
2696
- return 'max_tokens';
2697
- case 'tool_calls':
2698
- return 'tool_use';
2699
- case 'content_filter':
2700
- return 'content_filter';
2701
- default:
2702
- return 'end_turn';
2703
- }
2704
- }
2705
- finalize() {
2706
- if (this.finalized)
2707
- return;
2708
- this.ensureMessageStart();
2709
- // 关闭所有工具调用块
2710
- for (const toolBlockIndex of Array.from(this.toolCallIndexToBlockIndex.values())) {
2711
- this.pushEvent('content_block_stop', {
2712
- type: 'content_block_stop',
2713
- index: toolBlockIndex,
2714
- });
2715
- }
2716
- // 关闭 thinking 块
2717
- if (this.thinkingBlockIndex !== null) {
2718
- this.pushEvent('content_block_stop', {
2719
- type: 'content_block_stop',
2720
- index: this.thinkingBlockIndex,
2721
- });
2722
- this.thinkingBlockIndex = null;
2723
- }
2724
- // 关闭文本块
2725
- if (this.textBlockIndex !== null) {
2726
- this.pushEvent('content_block_stop', {
2727
- type: 'content_block_stop',
2728
- index: this.textBlockIndex,
2729
- });
2730
- this.textBlockIndex = null;
2731
- }
2732
- const usage = this.usage || {
2733
- input_tokens: 0,
2734
- output_tokens: 0,
2735
- cache_read_input_tokens: 0,
2736
- };
2737
- this.pushEvent('message_delta', {
2738
- type: 'message_delta',
2739
- delta: {
2740
- stop_reason: this.stopReason,
2741
- stop_sequence: null,
2742
- },
2743
- usage,
2744
- });
2745
- this.pushEvent('message_stop', { type: 'message_stop' });
2746
- this.finalized = true;
2747
- }
2748
- }
2749
- exports.ChatCompletionsToClaudeEventTransform = ChatCompletionsToClaudeEventTransform;
2750
- /**
2751
- * 将 Responses API SSE 流式事件转换为 Claude SSE 格式
2752
- * 当源是 openai-responses,目标是 claude code 时使用
2753
- */
2754
- class ResponsesToClaudeEventTransform extends stream_1.Transform {
2755
- constructor(options) {
2756
- var _a;
2757
- super({ objectMode: true });
2758
- Object.defineProperty(this, "contentIndex", {
2759
- enumerable: true,
2760
- configurable: true,
2761
- writable: true,
2762
- value: 0
2763
- });
2764
- Object.defineProperty(this, "textBlockIndex", {
2765
- enumerable: true,
2766
- configurable: true,
2767
- writable: true,
2768
- value: null
2769
- });
2770
- Object.defineProperty(this, "thinkingBlockIndex", {
2771
- enumerable: true,
2772
- configurable: true,
2773
- writable: true,
2774
- value: null
2775
- });
2776
- Object.defineProperty(this, "toolCalls", {
2777
- enumerable: true,
2778
- configurable: true,
2779
- writable: true,
2780
- value: new Map()
2781
- });
2782
- Object.defineProperty(this, "toolCallIndexToBlockIndex", {
2783
- enumerable: true,
2784
- configurable: true,
2785
- writable: true,
2786
- value: new Map()
2787
- });
2788
- Object.defineProperty(this, "completedToolCallIds", {
2789
- enumerable: true,
2790
- configurable: true,
2791
- writable: true,
2792
- value: new Set()
2793
- });
2794
- Object.defineProperty(this, "hasMessageStart", {
2795
- enumerable: true,
2796
- configurable: true,
2797
- writable: true,
2798
- value: false
2799
- });
2800
- Object.defineProperty(this, "stopReason", {
2801
- enumerable: true,
2802
- configurable: true,
2803
- writable: true,
2804
- value: 'end_turn'
2805
- });
2806
- Object.defineProperty(this, "usage", {
2807
- enumerable: true,
2808
- configurable: true,
2809
- writable: true,
2810
- value: null
2811
- });
2812
- Object.defineProperty(this, "messageId", {
2813
- enumerable: true,
2814
- configurable: true,
2815
- writable: true,
2816
- value: null
2817
- });
2818
- Object.defineProperty(this, "model", {
2819
- enumerable: true,
2820
- configurable: true,
2821
- writable: true,
2822
- value: null
2823
- });
2824
- Object.defineProperty(this, "finalized", {
2825
- enumerable: true,
2826
- configurable: true,
2827
- writable: true,
2828
- value: false
2829
- });
2830
- Object.defineProperty(this, "errorEmitted", {
2831
- enumerable: true,
2832
- configurable: true,
2833
- writable: true,
2834
- value: false
2835
- });
2836
- Object.defineProperty(this, "responseId", {
2837
- enumerable: true,
2838
- configurable: true,
2839
- writable: true,
2840
- value: null
2841
- });
2842
- this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
2843
- this.on('error', (err) => {
2844
- if (isClientDisconnectError(err)) {
2845
- console.warn('[ResponsesToClaudeEventTransform] Stream closed (client disconnected)');
2846
- }
2847
- else {
2848
- console.error('[ResponsesToClaudeEventTransform] Stream error:', err);
2849
- }
2850
- this.errorEmitted = true;
2851
- });
2852
- }
2853
- getUsage() {
2854
- if (!this.usage)
2855
- return undefined;
2856
- return Object.assign({}, this.usage);
2857
- }
2858
- _transform(event, _encoding, callback) {
2859
- var _a, _b, _c, _d, _e, _f, _g, _h;
2860
- if (this.errorEmitted) {
2861
- callback();
2862
- return;
2863
- }
2864
- try {
2865
- if (this.finalized) {
2866
- callback();
2867
- return;
2868
- }
2869
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
2870
- this.finalize();
2871
- callback();
2872
- return;
2873
- }
2874
- const data = event.data;
2875
- const eventType = event.event || (data === null || data === void 0 ? void 0 : data.type);
2876
- const responsePayload = (data === null || data === void 0 ? void 0 : data.response) && typeof data.response === 'object' ? data.response : undefined;
2877
- if (!eventType) {
2878
- callback();
2879
- return;
2880
- }
2881
- // 处理响应事件类型(兼容 event 字段和 data.type 字段)
2882
- if (eventType === 'response.created' || eventType === 'response.in_progress') {
2883
- this.responseId = (data === null || data === void 0 ? void 0 : data.id) || (responsePayload === null || responsePayload === void 0 ? void 0 : responsePayload.id) || this.responseId;
2884
- }
2885
- if (eventType === 'response.output_text.delta' && typeof (data === null || data === void 0 ? void 0 : data.delta) === 'string') {
2886
- this.ensureMessageStart();
2887
- if (this.textBlockIndex === null) {
2888
- this.textBlockIndex = this.assignContentBlockIndex();
2889
- this.pushEvent('content_block_start', {
2890
- type: 'content_block_start',
2891
- index: this.textBlockIndex,
2892
- content_block: { type: 'text' },
2893
- });
2894
- }
2895
- this.pushEvent('content_block_delta', {
2896
- type: 'content_block_delta',
2897
- index: this.textBlockIndex,
2898
- delta: { type: 'text_delta', text: data.delta },
2899
- });
2900
- }
2901
- if (eventType === 'response.reasoning_text.delta' && typeof (data === null || data === void 0 ? void 0 : data.delta) === 'string') {
2902
- this.ensureMessageStart();
2903
- if (this.thinkingBlockIndex === null) {
2904
- this.thinkingBlockIndex = this.assignContentBlockIndex();
2905
- this.pushEvent('content_block_start', {
2906
- type: 'content_block_start',
2907
- index: this.thinkingBlockIndex,
2908
- content_block: { type: 'thinking', thinking: '' },
2909
- });
2910
- }
2911
- this.pushEvent('content_block_delta', {
2912
- type: 'content_block_delta',
2913
- index: this.thinkingBlockIndex,
2914
- delta: { type: 'thinking_delta', thinking: data.delta },
2915
- });
2916
- }
2917
- // 兼容标准 Responses:通过 output_item.added 建立函数调用块
2918
- if (eventType === 'response.output_item.added' && ((_b = data === null || data === void 0 ? void 0 : data.item) === null || _b === void 0 ? void 0 : _b.type) === 'function_call') {
2919
- const itemId = ((_c = data.item) === null || _c === void 0 ? void 0 : _c.call_id) || ((_d = data.item) === null || _d === void 0 ? void 0 : _d.id) || (data === null || data === void 0 ? void 0 : data.item_id);
2920
- if (itemId) {
2921
- this.ensureToolCallStarted(itemId, ((_e = data.item) === null || _e === void 0 ? void 0 : _e.name) || 'tool', ((_f = data.item) === null || _f === void 0 ? void 0 : _f.arguments) || '');
2922
- }
2923
- }
2924
- if (eventType === 'response.function_call.start' && data) {
2925
- const itemId = data.call_id || data.item_id;
2926
- if (itemId) {
2927
- this.ensureToolCallStarted(itemId, data.name || 'tool', data.arguments || '');
2928
- }
2929
- }
2930
- if (eventType === 'response.function_call_arguments.delta' && data) {
2931
- const itemId = data.call_id || data.item_id;
2932
- if (itemId) {
2933
- this.ensureToolCallStarted(itemId, data.name || 'tool', '');
2934
- this.appendToolCallDelta(itemId, data.delta || '');
2935
- }
2936
- }
2937
- if (eventType === 'response.function_call_arguments.done' && data) {
2938
- const itemId = data.call_id || data.item_id;
2939
- if (itemId) {
2940
- this.ensureToolCallStarted(itemId, data.name || 'tool', '');
2941
- if (typeof data.arguments === 'string') {
2942
- const stored = this.toolCalls.get(itemId);
2943
- if (stored && data.arguments.startsWith(stored.arguments)) {
2944
- this.appendToolCallDelta(itemId, data.arguments.slice(stored.arguments.length));
2945
- }
2946
- else if (stored && stored.arguments !== data.arguments) {
2947
- // 上游直接返回完整 arguments(非增量)时,补全为单次 delta
2948
- this.appendToolCallDelta(itemId, data.arguments);
2949
- }
2950
- }
2951
- this.closeToolCall(itemId);
2952
- }
2953
- }
2954
- if (eventType === 'response.refusal.delta' && typeof (data === null || data === void 0 ? void 0 : data.delta) === 'string') {
2955
- this.ensureMessageStart();
2956
- if (this.textBlockIndex === null) {
2957
- this.textBlockIndex = this.assignContentBlockIndex();
2958
- this.pushEvent('content_block_start', {
2959
- type: 'content_block_start',
2960
- index: this.textBlockIndex,
2961
- content_block: { type: 'text' },
2962
- });
2963
- }
2964
- this.pushEvent('content_block_delta', {
2965
- type: 'content_block_delta',
2966
- index: this.textBlockIndex,
2967
- delta: { type: 'text_delta', text: data.delta },
2968
- });
2969
- }
2970
- if (eventType === 'response.usage' && data) {
2971
- this.usage = {
2972
- input_tokens: (data === null || data === void 0 ? void 0 : data.input_tokens) || 0,
2973
- output_tokens: (data === null || data === void 0 ? void 0 : data.output_tokens) || 0,
2974
- cache_read_input_tokens: (data === null || data === void 0 ? void 0 : data.cache_read_input_tokens) || 0,
2975
- };
2976
- }
2977
- if (eventType === 'response.completed' || eventType === 'response.failed' || eventType === 'response.incomplete') {
2978
- const reason = ((_g = data === null || data === void 0 ? void 0 : data.incomplete_details) === null || _g === void 0 ? void 0 : _g.reason) || ((_h = responsePayload === null || responsePayload === void 0 ? void 0 : responsePayload.incomplete_details) === null || _h === void 0 ? void 0 : _h.reason);
2979
- if (eventType === 'response.incomplete' && reason === 'max_tokens') {
2980
- this.stopReason = 'max_tokens';
2981
- }
2982
- else if (eventType === 'response.failed' || reason === 'content_filter') {
2983
- this.stopReason = 'content_filter';
2984
- }
2985
- else {
2986
- this.stopReason = 'end_turn';
2987
- }
2988
- if (responsePayload === null || responsePayload === void 0 ? void 0 : responsePayload.usage) {
2989
- this.usage = convertOpenAIUsageToClaude(responsePayload.usage);
2990
- }
2991
- this.finalize();
2992
- }
2993
- callback();
2994
- }
2995
- catch (error) {
2996
- console.error('[ResponsesToClaudeEventTransform] Error in _transform:', error);
2997
- callback();
2998
- }
2999
- }
3000
- _flush(callback) {
3001
- try {
3002
- this.finalize();
3003
- callback();
3004
- }
3005
- catch (error) {
3006
- console.error('[ResponsesToClaudeEventTransform] Error in _flush:', error);
3007
- callback();
3008
- }
3009
- }
3010
- assignContentBlockIndex() {
3011
- const index = this.contentIndex;
3012
- this.contentIndex += 1;
3013
- return index;
3014
- }
3015
- pushEvent(type, data) {
3016
- this.push({ event: type, data });
3017
- }
3018
- ensureMessageStart() {
3019
- if (this.hasMessageStart)
3020
- return;
3021
- const message = {
3022
- id: this.messageId || `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
3023
- type: 'message',
3024
- role: 'assistant',
3025
- content: [],
3026
- model: this.model || 'unknown',
3027
- stop_reason: null,
3028
- stop_sequence: null,
3029
- usage: {
3030
- input_tokens: 0,
3031
- output_tokens: 0,
3032
- },
3033
- };
3034
- this.pushEvent('message_start', { type: 'message_start', message });
3035
- this.hasMessageStart = true;
3036
- }
3037
- ensureToolCallStarted(itemId, name, initialArguments) {
3038
- if (this.toolCalls.has(itemId)) {
3039
- return;
3040
- }
3041
- this.ensureMessageStart();
3042
- const toolBlockIndex = this.assignContentBlockIndex();
3043
- this.toolCalls.set(itemId, {
3044
- id: itemId,
3045
- name: name || 'tool',
3046
- arguments: '',
3047
- });
3048
- this.toolCallIndexToBlockIndex.set(itemId, toolBlockIndex);
3049
- this.pushEvent('content_block_start', {
3050
- type: 'content_block_start',
3051
- index: toolBlockIndex,
3052
- content_block: {
3053
- type: 'tool_use',
3054
- id: itemId,
3055
- name: name || 'tool',
3056
- },
3057
- });
3058
- if (initialArguments) {
3059
- this.appendToolCallDelta(itemId, initialArguments);
3060
- }
3061
- }
3062
- appendToolCallDelta(itemId, delta) {
3063
- if (!delta)
3064
- return;
3065
- const stored = this.toolCalls.get(itemId);
3066
- if (stored) {
3067
- stored.arguments += delta;
3068
- }
3069
- const toolBlockIndex = this.toolCallIndexToBlockIndex.get(itemId);
3070
- if (toolBlockIndex !== undefined) {
3071
- this.pushEvent('content_block_delta', {
3072
- type: 'content_block_delta',
3073
- index: toolBlockIndex,
3074
- delta: {
3075
- type: 'input_json_delta',
3076
- partial_json: delta,
3077
- },
3078
- });
3079
- }
3080
- }
3081
- closeToolCall(itemId) {
3082
- if (this.completedToolCallIds.has(itemId)) {
3083
- return;
3084
- }
3085
- const toolBlockIndex = this.toolCallIndexToBlockIndex.get(itemId);
3086
- if (toolBlockIndex !== undefined) {
3087
- this.pushEvent('content_block_stop', {
3088
- type: 'content_block_stop',
3089
- index: toolBlockIndex,
3090
- });
3091
- this.completedToolCallIds.add(itemId);
3092
- }
3093
- }
3094
- finalize() {
3095
- if (this.finalized)
3096
- return;
3097
- this.ensureMessageStart();
3098
- // 关闭所有工具调用块
3099
- for (const [itemId, toolBlockIndex] of this.toolCallIndexToBlockIndex.entries()) {
3100
- if (this.completedToolCallIds.has(itemId))
3101
- continue;
3102
- this.pushEvent('content_block_stop', {
3103
- type: 'content_block_stop',
3104
- index: toolBlockIndex,
3105
- });
3106
- }
3107
- // 关闭 thinking 块
3108
- if (this.thinkingBlockIndex !== null) {
3109
- this.pushEvent('content_block_stop', {
3110
- type: 'content_block_stop',
3111
- index: this.thinkingBlockIndex,
3112
- });
3113
- this.thinkingBlockIndex = null;
3114
- }
3115
- // 关闭文本块
3116
- if (this.textBlockIndex !== null) {
3117
- this.pushEvent('content_block_stop', {
3118
- type: 'content_block_stop',
3119
- index: this.textBlockIndex,
3120
- });
3121
- this.textBlockIndex = null;
3122
- }
3123
- const usage = this.usage || {
3124
- input_tokens: 0,
3125
- output_tokens: 0,
3126
- cache_read_input_tokens: 0,
3127
- };
3128
- this.pushEvent('message_delta', {
3129
- type: 'message_delta',
3130
- delta: {
3131
- stop_reason: this.stopReason,
3132
- stop_sequence: null,
3133
- },
3134
- usage,
3135
- });
3136
- this.pushEvent('message_stop', { type: 'message_stop' });
3137
- this.finalized = true;
3138
- }
3139
- }
3140
- exports.ResponsesToClaudeEventTransform = ResponsesToClaudeEventTransform;
3141
- /**
3142
- * 将 Gemini SSE 流式事件转换为 Claude SSE 格式
3143
- * 当源是 gemini/gemini-chat,目标是 claude code 时使用
3144
- */
3145
- class GeminiToClaudeEventTransform extends stream_1.Transform {
3146
- constructor(options) {
3147
- var _a;
3148
- super({ objectMode: true });
3149
- Object.defineProperty(this, "contentIndex", {
3150
- enumerable: true,
3151
- configurable: true,
3152
- writable: true,
3153
- value: 0
3154
- });
3155
- Object.defineProperty(this, "textBlockIndex", {
3156
- enumerable: true,
3157
- configurable: true,
3158
- writable: true,
3159
- value: null
3160
- });
3161
- Object.defineProperty(this, "toolCalls", {
3162
- enumerable: true,
3163
- configurable: true,
3164
- writable: true,
3165
- value: new Map()
3166
- });
3167
- Object.defineProperty(this, "toolCallIndexToBlockIndex", {
3168
- enumerable: true,
3169
- configurable: true,
3170
- writable: true,
3171
- value: new Map()
3172
- });
3173
- Object.defineProperty(this, "hasMessageStart", {
3174
- enumerable: true,
3175
- configurable: true,
3176
- writable: true,
3177
- value: false
3178
- });
3179
- Object.defineProperty(this, "stopReason", {
3180
- enumerable: true,
3181
- configurable: true,
3182
- writable: true,
3183
- value: 'end_turn'
3184
- });
3185
- Object.defineProperty(this, "usage", {
3186
- enumerable: true,
3187
- configurable: true,
3188
- writable: true,
3189
- value: null
3190
- });
3191
- Object.defineProperty(this, "messageId", {
3192
- enumerable: true,
3193
- configurable: true,
3194
- writable: true,
3195
- value: null
3196
- });
3197
- Object.defineProperty(this, "model", {
3198
- enumerable: true,
3199
- configurable: true,
3200
- writable: true,
3201
- value: null
3202
- });
3203
- Object.defineProperty(this, "finalized", {
3204
- enumerable: true,
3205
- configurable: true,
3206
- writable: true,
3207
- value: false
3208
- });
3209
- Object.defineProperty(this, "errorEmitted", {
3210
- enumerable: true,
3211
- configurable: true,
3212
- writable: true,
3213
- value: false
3214
- });
3215
- Object.defineProperty(this, "toolCallCounter", {
3216
- enumerable: true,
3217
- configurable: true,
3218
- writable: true,
3219
- value: 0
3220
- });
3221
- this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
3222
- this.on('error', (err) => {
3223
- if (isClientDisconnectError(err)) {
3224
- console.warn('[GeminiToClaudeEventTransform] Stream closed (client disconnected)');
3225
- }
3226
- else {
3227
- console.error('[GeminiToClaudeEventTransform] Stream error:', err);
3228
- }
3229
- this.errorEmitted = true;
3230
- });
3231
- }
3232
- getUsage() {
3233
- if (!this.usage)
3234
- return undefined;
3235
- return Object.assign({}, this.usage);
3236
- }
3237
- _transform(event, _encoding, callback) {
3238
- var _a;
3239
- if (this.errorEmitted) {
3240
- callback();
3241
- return;
3242
- }
3243
- try {
3244
- if (this.finalized) {
3245
- callback();
3246
- return;
3247
- }
3248
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
3249
- this.finalize();
3250
- callback();
3251
- return;
3252
- }
3253
- const chunk = event.data;
3254
- if (!chunk) {
3255
- callback();
3256
- return;
3257
- }
3258
- // Gemini 流式响应格式: { candidates: [{ content: { parts: [...] }, finishReason: ... }], usageMetadata: {...} }
3259
- const candidates = Array.isArray(chunk.candidates) ? chunk.candidates : [];
3260
- const usageMetadata = chunk.usageMetadata;
3261
- // 处理 usage
3262
- if (usageMetadata) {
3263
- this.usage = {
3264
- input_tokens: usageMetadata.promptTokenCount || 0,
3265
- output_tokens: usageMetadata.candidatesTokenCount || 0,
3266
- cache_read_input_tokens: usageMetadata.cachedContentTokenCount || 0,
3267
- };
3268
- }
3269
- // 处理 candidates
3270
- for (const candidate of candidates) {
3271
- const content = candidate.content;
3272
- // 处理 finishReason
3273
- if (candidate.finishReason) {
3274
- this.stopReason = this.mapGeminiFinishReason(candidate.finishReason);
3275
- }
3276
- if (!content || !Array.isArray(content.parts)) {
3277
- continue;
3278
- }
3279
- this.ensureMessageStart();
3280
- // 处理 parts
3281
- for (const part of content.parts) {
3282
- // 处理文本
3283
- if (part.text && typeof part.text === 'string') {
3284
- if (this.textBlockIndex === null) {
3285
- this.textBlockIndex = this.assignContentBlockIndex();
3286
- this.pushEvent('content_block_start', {
3287
- type: 'content_block_start',
3288
- index: this.textBlockIndex,
3289
- content_block: { type: 'text' },
3290
- });
3291
- }
3292
- this.pushEvent('content_block_delta', {
3293
- type: 'content_block_delta',
3294
- index: this.textBlockIndex,
3295
- delta: {
3296
- type: 'text_delta',
3297
- text: part.text,
3298
- },
3299
- });
3300
- }
3301
- // 处理 functionCall -> tool_use
3302
- if (part.functionCall) {
3303
- const toolIndex = this.toolCallCounter++;
3304
- const toolBlockIndex = this.assignContentBlockIndex();
3305
- this.toolCalls.set(toolIndex, {
3306
- id: `tool_${toolIndex}_${Date.now()}`,
3307
- name: part.functionCall.name || 'tool',
3308
- arguments: JSON.stringify(part.functionCall.args || {}),
3309
- });
3310
- this.toolCallIndexToBlockIndex.set(toolIndex, toolBlockIndex);
3311
- this.pushEvent('content_block_start', {
3312
- type: 'content_block_start',
3313
- index: toolBlockIndex,
3314
- content_block: {
3315
- type: 'tool_use',
3316
- id: this.toolCalls.get(toolIndex).id,
3317
- name: part.functionCall.name || 'tool',
3318
- },
3319
- });
3320
- // 发送完整的参数
3321
- this.pushEvent('content_block_delta', {
3322
- type: 'content_block_delta',
3323
- index: toolBlockIndex,
3324
- delta: {
3325
- type: 'input_json_delta',
3326
- partial_json: JSON.stringify(part.functionCall.args || {}),
3327
- },
3328
- });
3329
- }
3330
- // 处理 inlineData (图像输出,罕见)
3331
- if (part.inlineData) {
3332
- // 图像输出作为单独的内容块
3333
- const imageBlockIndex = this.assignContentBlockIndex();
3334
- this.pushEvent('content_block_start', {
3335
- type: 'content_block_start',
3336
- index: imageBlockIndex,
3337
- content_block: {
3338
- type: 'image',
3339
- source: {
3340
- type: 'base64',
3341
- media_type: part.inlineData.mimeType,
3342
- data: part.inlineData.data,
3343
- },
3344
- },
3345
- });
3346
- this.pushEvent('content_block_stop', {
3347
- type: 'content_block_stop',
3348
- index: imageBlockIndex,
3349
- });
3350
- }
3351
- }
3352
- }
3353
- callback();
3354
- }
3355
- catch (error) {
3356
- console.error('[GeminiToClaudeEventTransform] Error in _transform:', error);
3357
- callback();
3358
- }
3359
- }
3360
- _flush(callback) {
3361
- try {
3362
- this.finalize();
3363
- callback();
3364
- }
3365
- catch (error) {
3366
- console.error('[GeminiToClaudeEventTransform] Error in _flush:', error);
3367
- callback();
3368
- }
3369
- }
3370
- assignContentBlockIndex() {
3371
- const index = this.contentIndex;
3372
- this.contentIndex += 1;
3373
- return index;
3374
- }
3375
- pushEvent(type, data) {
3376
- this.push({ event: type, data });
3377
- }
3378
- ensureMessageStart() {
3379
- if (this.hasMessageStart)
3380
- return;
3381
- const message = {
3382
- id: this.messageId || `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
3383
- type: 'message',
3384
- role: 'assistant',
3385
- content: [],
3386
- model: this.model || 'gemini',
3387
- stop_reason: null,
3388
- stop_sequence: null,
3389
- usage: {
3390
- input_tokens: 0,
3391
- output_tokens: 0,
3392
- },
3393
- };
3394
- this.pushEvent('message_start', { type: 'message_start', message });
3395
- this.hasMessageStart = true;
3396
- }
3397
- mapGeminiFinishReason(finishReason) {
3398
- switch (finishReason) {
3399
- case 'STOP':
3400
- return 'end_turn';
3401
- case 'MAX_TOKENS':
3402
- return 'max_tokens';
3403
- case 'SAFETY':
3404
- case 'RECITATION':
3405
- return 'content_filter';
3406
- case 'MALFORMED_FUNCTION_CALL':
3407
- return 'tool_use';
3408
- default:
3409
- return 'end_turn';
3410
- }
3411
- }
3412
- finalize() {
3413
- if (this.finalized)
3414
- return;
3415
- this.ensureMessageStart();
3416
- // 关闭所有工具调用块
3417
- for (const toolBlockIndex of Array.from(this.toolCallIndexToBlockIndex.values())) {
3418
- this.pushEvent('content_block_stop', {
3419
- type: 'content_block_stop',
3420
- index: toolBlockIndex,
3421
- });
3422
- }
3423
- // 关闭文本块
3424
- if (this.textBlockIndex !== null) {
3425
- this.pushEvent('content_block_stop', {
3426
- type: 'content_block_stop',
3427
- index: this.textBlockIndex,
3428
- });
3429
- this.textBlockIndex = null;
3430
- }
3431
- const usage = this.usage || {
3432
- input_tokens: 0,
3433
- output_tokens: 0,
3434
- cache_read_input_tokens: 0,
3435
- };
3436
- this.pushEvent('message_delta', {
3437
- type: 'message_delta',
3438
- delta: {
3439
- stop_reason: this.stopReason,
3440
- stop_sequence: null,
3441
- },
3442
- usage,
3443
- });
3444
- this.pushEvent('message_stop', { type: 'message_stop' });
3445
- this.finalized = true;
3446
- }
3447
- }
3448
- exports.GeminiToClaudeEventTransform = GeminiToClaudeEventTransform;