aicodeswitch 5.1.3 → 5.2.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.
@@ -10,12 +10,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.rulesStatusBroadcaster = exports.RulesStatusBroadcaster = void 0;
13
+ const events_1 = require("events");
13
14
  /**
14
15
  * 规则状态管理服务
15
16
  * 负责管理所有规则的状态(使用中、空闲、错误、挂起)
16
17
  */
17
- class RulesStatusBroadcaster {
18
+ class RulesStatusBroadcaster extends events_1.EventEmitter {
18
19
  constructor() {
20
+ super();
19
21
  Object.defineProperty(this, "ruleStates", {
20
22
  enumerable: true,
21
23
  configurable: true,
@@ -70,6 +72,8 @@ class RulesStatusBroadcaster {
70
72
  writable: true,
71
73
  value: 30000
72
74
  }); // error 状态30秒后自动恢复
75
+ // 允许多标签页场景下的多连接监听
76
+ this.setMaxListeners(50);
73
77
  // 启动定期状态检查定时器
74
78
  this.startSyncInterval();
75
79
  }
@@ -99,7 +103,7 @@ class RulesStatusBroadcaster {
99
103
  data.timestamp &&
100
104
  now - data.timestamp > this.ERROR_RECOVERY_TIMEOUT) {
101
105
  console.log(`[RulesStatusBroadcaster] 规则 ${ruleId} 错误状态已超时,自动恢复为 idle 状态`);
102
- this.ruleStates.set(ruleId, {
106
+ this.updateRuleStatus({
103
107
  ruleId,
104
108
  status: 'idle',
105
109
  routeId: data.routeId,
@@ -130,7 +134,7 @@ class RulesStatusBroadcaster {
130
134
  if (!isBlacklisted) {
131
135
  // 黑名单已过期,恢复为 idle 状态
132
136
  console.log(`[RulesStatusBroadcaster] 规则 ${ruleId} 黑名单已过期,恢复为 idle 状态`);
133
- this.ruleStates.set(ruleId, {
137
+ this.updateRuleStatus({
134
138
  ruleId,
135
139
  status: 'idle',
136
140
  routeId,
@@ -172,6 +176,8 @@ class RulesStatusBroadcaster {
172
176
  updateRuleStatus(data) {
173
177
  // 更新本地状态
174
178
  this.ruleStates.set(data.ruleId, data);
179
+ // 通知 SSE 客户端状态已变更
180
+ this.emit('statusChanged', data);
175
181
  }
176
182
  /**
177
183
  * 标记规则正在使用
@@ -288,6 +294,12 @@ class RulesStatusBroadcaster {
288
294
  */
289
295
  clearRuleStatus(ruleId) {
290
296
  this.ruleStates.delete(ruleId);
297
+ // 通知 SSE 客户端状态已清除(恢复为 idle)
298
+ this.emit('statusChanged', {
299
+ ruleId,
300
+ status: 'idle',
301
+ timestamp: Date.now(),
302
+ });
291
303
  }
292
304
  /**
293
305
  * 获取当前活动的规则列表
@@ -320,6 +332,7 @@ class RulesStatusBroadcaster {
320
332
  this.idleDebounceTimeouts.forEach((timeout) => clearTimeout(timeout));
321
333
  this.idleDebounceTimeouts.clear();
322
334
  this.ruleStates.clear();
335
+ this.removeAllListeners();
323
336
  }
324
337
  }
325
338
  exports.RulesStatusBroadcaster = RulesStatusBroadcaster;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ModelRewriteTransform = void 0;
4
+ exports.rewriteResponseModel = rewriteResponseModel;
5
+ const stream_1 = require("stream");
6
+ const string_decoder_1 = require("string_decoder");
7
+ /**
8
+ * 流式 SSE 响应中的 model 字段回写 Transform。
9
+ *
10
+ * 插入位置:SSESerializerTransform 之后、ChunkCollectorTransform 之前。
11
+ * 输入/输出均为 text mode(字符串),通过正则替换 SSE data 行中的
12
+ * "model":"上游模型名" → "model":"客户端原始模型名"。
13
+ */
14
+ class ModelRewriteTransform extends stream_1.Transform {
15
+ constructor(originalModel) {
16
+ super({
17
+ writableObjectMode: false, // 接收序列化后的文本
18
+ readableObjectMode: false, // 输出文本
19
+ });
20
+ Object.defineProperty(this, "modelRegex", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: void 0
25
+ });
26
+ Object.defineProperty(this, "replacement", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: void 0
31
+ });
32
+ Object.defineProperty(this, "modelVersionRegex", {
33
+ enumerable: true,
34
+ configurable: true,
35
+ writable: true,
36
+ value: null
37
+ });
38
+ Object.defineProperty(this, "modelVersionReplacement", {
39
+ enumerable: true,
40
+ configurable: true,
41
+ writable: true,
42
+ value: null
43
+ });
44
+ Object.defineProperty(this, "stringDecoder", {
45
+ enumerable: true,
46
+ configurable: true,
47
+ writable: true,
48
+ value: new string_decoder_1.StringDecoder('utf8')
49
+ });
50
+ Object.defineProperty(this, "buffer", {
51
+ enumerable: true,
52
+ configurable: true,
53
+ writable: true,
54
+ value: ''
55
+ });
56
+ // 转义原始模型名中的特殊字符,防止 JSON 注入
57
+ const escaped = originalModel.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
58
+ this.replacement = `"model":"${escaped}"`;
59
+ this.modelRegex = /"model"\s*:\s*"[^"]*"/g;
60
+ // 处理 Gemini 直通场景中的 modelVersion 字段
61
+ if (originalModel) {
62
+ this.modelVersionReplacement = `"modelVersion":"${escaped}"`;
63
+ this.modelVersionRegex = /"modelVersion"\s*:\s*"[^"]*"/g;
64
+ }
65
+ }
66
+ _transform(chunk, _encoding, callback) {
67
+ try {
68
+ this.buffer += this.stringDecoder.write(chunk);
69
+ // 按行处理(SSE 协议以 \n 分隔)
70
+ const lines = this.buffer.split('\n');
71
+ this.buffer = lines.pop() || '';
72
+ for (const line of lines) {
73
+ this.push(this.rewriteLine(line) + '\n');
74
+ }
75
+ callback();
76
+ }
77
+ catch (error) {
78
+ callback(error);
79
+ }
80
+ }
81
+ _flush(callback) {
82
+ try {
83
+ const remaining = this.stringDecoder.end();
84
+ if (remaining)
85
+ this.buffer += remaining;
86
+ if (this.buffer) {
87
+ this.push(this.rewriteLine(this.buffer));
88
+ }
89
+ callback();
90
+ }
91
+ catch (error) {
92
+ callback(error);
93
+ }
94
+ }
95
+ rewriteLine(line) {
96
+ // 只处理 SSE data 行
97
+ if (!line.startsWith('data:'))
98
+ return line;
99
+ let result = line;
100
+ // 重置正则 lastIndex(因为带 g 标志)
101
+ this.modelRegex.lastIndex = 0;
102
+ result = result.replace(this.modelRegex, this.replacement);
103
+ if (this.modelVersionRegex && this.modelVersionReplacement) {
104
+ this.modelVersionRegex.lastIndex = 0;
105
+ result = result.replace(this.modelVersionRegex, this.modelVersionReplacement);
106
+ }
107
+ return result;
108
+ }
109
+ }
110
+ exports.ModelRewriteTransform = ModelRewriteTransform;
111
+ /**
112
+ * 非流式响应中的 model 字段回写。
113
+ *
114
+ * 将响应对象的 model(以及 Gemini 的 modelVersion)改写为客户端原始模型名。
115
+ * 直接修改传入对象(原地修改)。
116
+ */
117
+ function rewriteResponseModel(responseData, originalModel) {
118
+ if (!responseData || !originalModel || typeof responseData !== 'object')
119
+ return;
120
+ // 所有格式在转换后统一使用 "model" 字段
121
+ if ('model' in responseData) {
122
+ responseData.model = originalModel;
123
+ }
124
+ // Gemini 直通场景可能保留 modelVersion
125
+ if ('modelVersion' in responseData) {
126
+ responseData.modelVersion = originalModel;
127
+ }
128
+ }