aicodeswitch 3.0.3 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,41 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
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
+ })();
5
35
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ClaudeToOpenAIChatEventTransform = exports.OpenAIToClaudeEventTransform = exports.rewriteStream = exports.SSESerializerTransform = exports.SSEParserTransform = void 0;
36
+ exports.GeminiToOpenAIChatEventTransform = exports.GeminiToClaudeEventTransform = exports.ClaudeToOpenAIChatEventTransform = exports.OpenAIToClaudeEventTransform = exports.rewriteStream = exports.SSESerializerTransform = exports.SSEParserTransform = void 0;
7
37
  const stream_1 = require("stream");
8
- const crypto_1 = __importDefault(require("crypto"));
38
+ const crypto = __importStar(require("crypto"));
9
39
  const claude_openai_1 = require("./claude-openai");
10
40
  class SSEParserTransform extends stream_1.Transform {
11
41
  constructor() {
@@ -349,7 +379,7 @@ class OpenAIToClaudeEventTransform extends stream_1.Transform {
349
379
  if (this.hasMessageStart)
350
380
  return;
351
381
  const message = {
352
- id: this.messageId || `msg_${crypto_1.default.randomUUID()}`,
382
+ id: this.messageId || `msg_${crypto.randomUUID()}`,
353
383
  type: 'message',
354
384
  role: 'assistant',
355
385
  content: [],
@@ -561,7 +591,7 @@ class OpenAIToClaudeEventTransform extends stream_1.Transform {
561
591
  if (this.finalized)
562
592
  return;
563
593
  this.ensureMessageStart();
564
- for (const toolBlockIndex of this.toolCallIndexToBlockIndex.values()) {
594
+ for (const toolBlockIndex of Array.from(this.toolCallIndexToBlockIndex.values())) {
565
595
  this.pushEvent('content_block_stop', {
566
596
  type: 'content_block_stop',
567
597
  index: toolBlockIndex,
@@ -818,3 +848,529 @@ class ClaudeToOpenAIChatEventTransform extends stream_1.Transform {
818
848
  }
819
849
  }
820
850
  exports.ClaudeToOpenAIChatEventTransform = ClaudeToOpenAIChatEventTransform;
851
+ // ============================================================================
852
+ // Gemini 流式转换器
853
+ // ============================================================================
854
+ /**
855
+ * 将 Gemini SSE 流式事件转换为 Claude 格式
856
+ */
857
+ class GeminiToClaudeEventTransform extends stream_1.Transform {
858
+ constructor(options) {
859
+ var _a;
860
+ super({ objectMode: true });
861
+ Object.defineProperty(this, "contentIndex", {
862
+ enumerable: true,
863
+ configurable: true,
864
+ writable: true,
865
+ value: 0
866
+ });
867
+ Object.defineProperty(this, "textBlockIndex", {
868
+ enumerable: true,
869
+ configurable: true,
870
+ writable: true,
871
+ value: null
872
+ });
873
+ Object.defineProperty(this, "toolCalls", {
874
+ enumerable: true,
875
+ configurable: true,
876
+ writable: true,
877
+ value: new Map()
878
+ });
879
+ Object.defineProperty(this, "toolCallIndexToBlockIndex", {
880
+ enumerable: true,
881
+ configurable: true,
882
+ writable: true,
883
+ value: new Map()
884
+ });
885
+ Object.defineProperty(this, "hasMessageStart", {
886
+ enumerable: true,
887
+ configurable: true,
888
+ writable: true,
889
+ value: false
890
+ });
891
+ Object.defineProperty(this, "stopReason", {
892
+ enumerable: true,
893
+ configurable: true,
894
+ writable: true,
895
+ value: 'end_turn'
896
+ });
897
+ Object.defineProperty(this, "usage", {
898
+ enumerable: true,
899
+ configurable: true,
900
+ writable: true,
901
+ value: null
902
+ });
903
+ Object.defineProperty(this, "messageId", {
904
+ enumerable: true,
905
+ configurable: true,
906
+ writable: true,
907
+ value: null
908
+ });
909
+ Object.defineProperty(this, "model", {
910
+ enumerable: true,
911
+ configurable: true,
912
+ writable: true,
913
+ value: null
914
+ });
915
+ Object.defineProperty(this, "finalized", {
916
+ enumerable: true,
917
+ configurable: true,
918
+ writable: true,
919
+ value: false
920
+ });
921
+ Object.defineProperty(this, "errorEmitted", {
922
+ enumerable: true,
923
+ configurable: true,
924
+ writable: true,
925
+ value: false
926
+ });
927
+ Object.defineProperty(this, "accumulatedText", {
928
+ enumerable: true,
929
+ configurable: true,
930
+ writable: true,
931
+ value: new Map()
932
+ }); // 累积每个候选的文本
933
+ Object.defineProperty(this, "accumulatedToolCalls", {
934
+ enumerable: true,
935
+ configurable: true,
936
+ writable: true,
937
+ value: new Map()
938
+ });
939
+ this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
940
+ this.on('error', (err) => {
941
+ console.error('[GeminiToClaudeEventTransform] Stream error:', err);
942
+ this.errorEmitted = true;
943
+ });
944
+ }
945
+ getUsage() {
946
+ if (!this.usage)
947
+ return undefined;
948
+ return Object.assign({}, this.usage);
949
+ }
950
+ _transform(event, _encoding, callback) {
951
+ var _a;
952
+ if (this.errorEmitted) {
953
+ callback();
954
+ return;
955
+ }
956
+ try {
957
+ if (this.finalized) {
958
+ callback();
959
+ return;
960
+ }
961
+ if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
962
+ this.finalize();
963
+ callback();
964
+ return;
965
+ }
966
+ const chunk = event.data;
967
+ if (!chunk) {
968
+ callback();
969
+ return;
970
+ }
971
+ // Gemini 流式响应格式: { candidates: [{ content: { parts: [...] }, finishReason: ... }], usageMetadata: {...} }
972
+ const candidates = Array.isArray(chunk.candidates) ? chunk.candidates : [];
973
+ const usageMetadata = chunk.usageMetadata;
974
+ // 处理 usage
975
+ if (usageMetadata) {
976
+ this.usage = {
977
+ input_tokens: usageMetadata.promptTokenCount || 0,
978
+ output_tokens: usageMetadata.candidatesTokenCount || 0,
979
+ cache_read_input_tokens: usageMetadata.cachedContentTokenCount || 0,
980
+ };
981
+ }
982
+ // 处理 candidates
983
+ for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
984
+ const candidate = candidates[candidateIndex];
985
+ const content = candidate.content;
986
+ // 处理 finishReason
987
+ if (candidate.finishReason) {
988
+ this.stopReason = this.mapGeminiFinishReason(candidate.finishReason);
989
+ }
990
+ if (!content || !Array.isArray(content.parts)) {
991
+ continue;
992
+ }
993
+ this.ensureMessageStart();
994
+ // 处理 parts
995
+ for (const part of content.parts) {
996
+ // 处理文本
997
+ if (part.text && typeof part.text === 'string') {
998
+ if (this.textBlockIndex === null) {
999
+ this.textBlockIndex = this.assignContentBlockIndex();
1000
+ this.pushEvent('content_block_start', {
1001
+ type: 'content_block_start',
1002
+ index: this.textBlockIndex,
1003
+ content_block: { type: 'text' },
1004
+ });
1005
+ }
1006
+ // 累积文本
1007
+ const currentText = this.accumulatedText.get(candidateIndex) || '';
1008
+ this.accumulatedText.set(candidateIndex, currentText + part.text);
1009
+ this.pushEvent('content_block_delta', {
1010
+ type: 'content_block_delta',
1011
+ index: this.textBlockIndex,
1012
+ delta: {
1013
+ type: 'text_delta',
1014
+ text: part.text,
1015
+ },
1016
+ });
1017
+ }
1018
+ // 处理 functionCall -> tool_use
1019
+ if (part.functionCall) {
1020
+ const toolCalls = this.accumulatedToolCalls.get(candidateIndex) || [];
1021
+ toolCalls.push({
1022
+ name: part.functionCall.name || 'tool',
1023
+ args: part.functionCall.args || {},
1024
+ });
1025
+ this.accumulatedToolCalls.set(candidateIndex, toolCalls);
1026
+ const toolBlockIndex = this.assignContentBlockIndex();
1027
+ this.toolCalls.set(toolCalls.length - 1, {
1028
+ id: `tool_${toolCalls.length}_${Date.now()}`,
1029
+ name: part.functionCall.name || 'tool',
1030
+ arguments: JSON.stringify(part.functionCall.args || {}),
1031
+ });
1032
+ this.toolCallIndexToBlockIndex.set(toolCalls.length - 1, toolBlockIndex);
1033
+ this.pushEvent('content_block_start', {
1034
+ type: 'content_block_start',
1035
+ index: toolBlockIndex,
1036
+ content_block: {
1037
+ type: 'tool_use',
1038
+ id: this.toolCalls.get(toolCalls.length - 1).id,
1039
+ name: part.functionCall.name || 'tool',
1040
+ },
1041
+ });
1042
+ // 发送完整的参数
1043
+ this.pushEvent('content_block_delta', {
1044
+ type: 'content_block_delta',
1045
+ index: toolBlockIndex,
1046
+ delta: {
1047
+ type: 'input_json_delta',
1048
+ partial_json: JSON.stringify(part.functionCall.args || {}),
1049
+ },
1050
+ });
1051
+ }
1052
+ // 处理 inlineData (图像输出,罕见)
1053
+ if (part.inlineData) {
1054
+ // 图像输出作为单独的内容块
1055
+ const imageBlockIndex = this.assignContentBlockIndex();
1056
+ this.pushEvent('content_block_start', {
1057
+ type: 'content_block_start',
1058
+ index: imageBlockIndex,
1059
+ content_block: {
1060
+ type: 'image',
1061
+ source: {
1062
+ type: 'base64',
1063
+ media_type: part.inlineData.mimeType,
1064
+ data: part.inlineData.data,
1065
+ },
1066
+ },
1067
+ });
1068
+ this.pushEvent('content_block_stop', {
1069
+ type: 'content_block_stop',
1070
+ index: imageBlockIndex,
1071
+ });
1072
+ }
1073
+ }
1074
+ }
1075
+ callback();
1076
+ }
1077
+ catch (error) {
1078
+ console.error('[GeminiToClaudeEventTransform] Error in _transform:', error);
1079
+ callback();
1080
+ }
1081
+ }
1082
+ _flush(callback) {
1083
+ try {
1084
+ this.finalize();
1085
+ callback();
1086
+ }
1087
+ catch (error) {
1088
+ console.error('[GeminiToClaudeEventTransform] Error in _flush:', error);
1089
+ callback();
1090
+ }
1091
+ }
1092
+ assignContentBlockIndex() {
1093
+ const index = this.contentIndex;
1094
+ this.contentIndex += 1;
1095
+ return index;
1096
+ }
1097
+ pushEvent(type, data) {
1098
+ this.push({ event: type, data });
1099
+ }
1100
+ ensureMessageStart() {
1101
+ if (this.hasMessageStart)
1102
+ return;
1103
+ const message = {
1104
+ id: this.messageId || `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
1105
+ type: 'message',
1106
+ role: 'assistant',
1107
+ content: [],
1108
+ model: this.model || 'gemini',
1109
+ stop_reason: null,
1110
+ stop_sequence: null,
1111
+ usage: {
1112
+ input_tokens: 0,
1113
+ output_tokens: 0,
1114
+ },
1115
+ };
1116
+ this.pushEvent('message_start', { type: 'message_start', message });
1117
+ this.hasMessageStart = true;
1118
+ }
1119
+ mapGeminiFinishReason(finishReason) {
1120
+ switch (finishReason) {
1121
+ case 'STOP':
1122
+ return 'end_turn';
1123
+ case 'MAX_TOKENS':
1124
+ return 'max_tokens';
1125
+ case 'SAFETY':
1126
+ case 'RECITATION':
1127
+ return 'content_filter';
1128
+ case 'MALFORMED_FUNCTION_CALL':
1129
+ return 'tool_use';
1130
+ default:
1131
+ return 'end_turn';
1132
+ }
1133
+ }
1134
+ finalize() {
1135
+ if (this.finalized)
1136
+ return;
1137
+ this.ensureMessageStart();
1138
+ // 关闭所有工具调用块
1139
+ for (const toolBlockIndex of Array.from(this.toolCallIndexToBlockIndex.values())) {
1140
+ this.pushEvent('content_block_stop', {
1141
+ type: 'content_block_stop',
1142
+ index: toolBlockIndex,
1143
+ });
1144
+ }
1145
+ // 关闭文本块
1146
+ if (this.textBlockIndex !== null) {
1147
+ this.pushEvent('content_block_stop', {
1148
+ type: 'content_block_stop',
1149
+ index: this.textBlockIndex,
1150
+ });
1151
+ this.textBlockIndex = null;
1152
+ }
1153
+ const usage = this.usage || {
1154
+ input_tokens: 0,
1155
+ output_tokens: 0,
1156
+ cache_read_input_tokens: 0,
1157
+ };
1158
+ this.pushEvent('message_delta', {
1159
+ type: 'message_delta',
1160
+ delta: {
1161
+ stop_reason: this.stopReason,
1162
+ stop_sequence: null,
1163
+ },
1164
+ usage,
1165
+ });
1166
+ this.pushEvent('message_stop', { type: 'message_stop' });
1167
+ this.finalized = true;
1168
+ }
1169
+ }
1170
+ exports.GeminiToClaudeEventTransform = GeminiToClaudeEventTransform;
1171
+ /**
1172
+ * 将 Gemini SSE 流式事件转换为 OpenAI Chat 格式
1173
+ */
1174
+ class GeminiToOpenAIChatEventTransform extends stream_1.Transform {
1175
+ constructor(options) {
1176
+ var _a;
1177
+ super({ objectMode: true });
1178
+ Object.defineProperty(this, "pendingToolCalls", {
1179
+ enumerable: true,
1180
+ configurable: true,
1181
+ writable: true,
1182
+ value: []
1183
+ });
1184
+ Object.defineProperty(this, "usage", {
1185
+ enumerable: true,
1186
+ configurable: true,
1187
+ writable: true,
1188
+ value: null
1189
+ });
1190
+ Object.defineProperty(this, "finished", {
1191
+ enumerable: true,
1192
+ configurable: true,
1193
+ writable: true,
1194
+ value: false
1195
+ });
1196
+ Object.defineProperty(this, "model", {
1197
+ enumerable: true,
1198
+ configurable: true,
1199
+ writable: true,
1200
+ value: null
1201
+ });
1202
+ Object.defineProperty(this, "stopReason", {
1203
+ enumerable: true,
1204
+ configurable: true,
1205
+ writable: true,
1206
+ value: 'stop'
1207
+ });
1208
+ Object.defineProperty(this, "errorEmitted", {
1209
+ enumerable: true,
1210
+ configurable: true,
1211
+ writable: true,
1212
+ value: false
1213
+ });
1214
+ Object.defineProperty(this, "accumulatedText", {
1215
+ enumerable: true,
1216
+ configurable: true,
1217
+ writable: true,
1218
+ value: ''
1219
+ });
1220
+ this.model = (_a = options === null || options === void 0 ? void 0 : options.model) !== null && _a !== void 0 ? _a : null;
1221
+ this.on('error', (err) => {
1222
+ console.error('[GeminiToOpenAIChatEventTransform] Stream error:', err);
1223
+ this.errorEmitted = true;
1224
+ });
1225
+ }
1226
+ getUsage() {
1227
+ return this.usage;
1228
+ }
1229
+ _transform(event, _encoding, callback) {
1230
+ var _a;
1231
+ if (this.errorEmitted) {
1232
+ callback();
1233
+ return;
1234
+ }
1235
+ try {
1236
+ if (this.finished) {
1237
+ callback();
1238
+ return;
1239
+ }
1240
+ if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'done') {
1241
+ this.finished = true;
1242
+ this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: {}, finish_reason: this.stopReason }] } });
1243
+ this.push({ event: 'done', data: { type: 'done' } });
1244
+ callback();
1245
+ return;
1246
+ }
1247
+ const chunk = event.data;
1248
+ if (!chunk) {
1249
+ callback();
1250
+ return;
1251
+ }
1252
+ // 处理 usage
1253
+ if (chunk.usageMetadata) {
1254
+ this.usage = {
1255
+ prompt_tokens: chunk.usageMetadata.promptTokenCount || 0,
1256
+ completion_tokens: chunk.usageMetadata.candidatesTokenCount || 0,
1257
+ total_tokens: chunk.usageMetadata.totalTokenCount || 0,
1258
+ };
1259
+ }
1260
+ const candidates = Array.isArray(chunk.candidates) ? chunk.candidates : [];
1261
+ for (const candidate of candidates) {
1262
+ // 处理 finishReason
1263
+ if (candidate.finishReason) {
1264
+ this.stopReason = this.mapGeminiFinishReason(candidate.finishReason);
1265
+ }
1266
+ if (!candidate.content || !Array.isArray(candidate.content.parts)) {
1267
+ continue;
1268
+ }
1269
+ // 处理 parts
1270
+ for (const part of candidate.content.parts) {
1271
+ // 处理文本
1272
+ if (part.text && typeof part.text === 'string') {
1273
+ this.accumulatedText += part.text;
1274
+ this.push({ event: null, data: { id: '', model: this.model, choices: [{ index: 0, delta: { content: part.text } }] } });
1275
+ }
1276
+ // 处理 functionCall -> tool_calls
1277
+ if (part.functionCall) {
1278
+ const toolCallId = `call_${this.pendingToolCalls.length}_${Date.now()}`;
1279
+ this.pendingToolCalls.push({
1280
+ id: toolCallId,
1281
+ name: part.functionCall.name || 'tool',
1282
+ arguments: JSON.stringify(part.functionCall.args || {}),
1283
+ });
1284
+ this.push({
1285
+ event: null,
1286
+ data: {
1287
+ id: '',
1288
+ model: this.model,
1289
+ choices: [{
1290
+ index: 0,
1291
+ delta: {
1292
+ tool_calls: [{
1293
+ id: toolCallId,
1294
+ type: 'function',
1295
+ function: {
1296
+ name: part.functionCall.name || 'tool',
1297
+ arguments: JSON.stringify(part.functionCall.args || {}),
1298
+ },
1299
+ }],
1300
+ },
1301
+ }],
1302
+ },
1303
+ });
1304
+ }
1305
+ // 处理 inlineData (图像输出,罕见)
1306
+ if (part.inlineData) {
1307
+ // 图像作为 content 的一部分发送
1308
+ const imageDataUrl = `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`;
1309
+ this.push({
1310
+ event: null,
1311
+ data: {
1312
+ id: '',
1313
+ model: this.model,
1314
+ choices: [{
1315
+ index: 0,
1316
+ delta: {
1317
+ content: [{
1318
+ type: 'image_url',
1319
+ image_url: { url: imageDataUrl },
1320
+ }],
1321
+ },
1322
+ }],
1323
+ },
1324
+ });
1325
+ }
1326
+ }
1327
+ }
1328
+ callback();
1329
+ }
1330
+ catch (error) {
1331
+ console.error('[GeminiToOpenAIChatEventTransform] Error in _transform:', error);
1332
+ callback();
1333
+ }
1334
+ }
1335
+ _flush(callback) {
1336
+ try {
1337
+ if (!this.finished) {
1338
+ this.finished = true;
1339
+ this.push({
1340
+ event: null,
1341
+ data: {
1342
+ id: '',
1343
+ model: this.model,
1344
+ choices: [{
1345
+ index: 0,
1346
+ delta: {},
1347
+ finish_reason: this.stopReason,
1348
+ }],
1349
+ },
1350
+ });
1351
+ this.push({ event: 'done', data: { type: 'done' } });
1352
+ }
1353
+ callback();
1354
+ }
1355
+ catch (error) {
1356
+ console.error('[GeminiToOpenAIChatEventTransform] Error in _flush:', error);
1357
+ callback();
1358
+ }
1359
+ }
1360
+ mapGeminiFinishReason(finishReason) {
1361
+ switch (finishReason) {
1362
+ case 'STOP':
1363
+ return 'stop';
1364
+ case 'MAX_TOKENS':
1365
+ return 'length';
1366
+ case 'SAFETY':
1367
+ case 'RECITATION':
1368
+ return 'content_filter';
1369
+ case 'MALFORMED_FUNCTION_CALL':
1370
+ return 'tool_calls';
1371
+ default:
1372
+ return 'stop';
1373
+ }
1374
+ }
1375
+ }
1376
+ exports.GeminiToOpenAIChatEventTransform = GeminiToOpenAIChatEventTransform;
@@ -6,6 +6,7 @@ var AuthType;
6
6
  (function (AuthType) {
7
7
  AuthType["AUTH_TOKEN"] = "authorization";
8
8
  AuthType["API_KEY"] = "x-api-key";
9
+ AuthType["G_API_KEY"] = "x-goog-api-key";
9
10
  AuthType["AUTO"] = "auto";
10
11
  })(AuthType || (exports.AuthType = AuthType = {}));
11
12
  ;