aicodeswitch 3.9.4 → 4.0.1

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,197 +1,311 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RulesStatusWS = exports.rulesStatusBroadcaster = exports.RulesStatusBroadcaster = void 0;
4
- exports.createRulesStatusWSServer = createRulesStatusWSServer;
5
- // @ts-ignore - ws 类型声明可能需要手动安装 @types/ws
6
- const ws_1 = require("ws");
12
+ exports.rulesStatusBroadcaster = exports.RulesStatusBroadcaster = void 0;
7
13
  /**
8
- * 规则状态 WebSocket 连接管理
14
+ * 规则状态管理服务
15
+ * 负责管理所有规则的状态(使用中、空闲、错误、挂起)
9
16
  */
10
- class RulesStatusWS {
11
- constructor(ws, req) {
12
- Object.defineProperty(this, "ws", {
17
+ class RulesStatusBroadcaster {
18
+ constructor() {
19
+ Object.defineProperty(this, "ruleStates", {
13
20
  enumerable: true,
14
21
  configurable: true,
15
22
  writable: true,
16
- value: void 0
17
- });
18
- this.ws = ws;
19
- console.log(`[RulesStatusWS] 新的 WebSocket 连接: ${req.socket.remoteAddress}`);
20
- this.ws.on('close', () => {
21
- console.log(`[RulesStatusWS] WebSocket 连接关闭`);
22
- });
23
- this.ws.on('error', (err) => {
24
- console.error(`[RulesStatusWS] WebSocket 错误:`, err);
25
- });
26
- }
27
- /**
28
- * 发送规则状态消息到客户端
29
- */
30
- sendStatus(message) {
31
- if (this.ws.readyState === ws_1.WebSocket.OPEN) {
32
- this.ws.send(JSON.stringify(message));
33
- }
34
- }
35
- }
36
- exports.RulesStatusWS = RulesStatusWS;
37
- /**
38
- * 规则状态广播服务
39
- * 管理所有连接的客户端,负责广播规则使用状态
40
- */
41
- class RulesStatusBroadcaster {
42
- constructor() {
43
- Object.defineProperty(this, "clients", {
23
+ value: new Map()
24
+ }); // ruleId -> RuleStatusData
25
+ Object.defineProperty(this, "ruleTimeouts", {
44
26
  enumerable: true,
45
27
  configurable: true,
46
28
  writable: true,
47
- value: new Set()
29
+ value: new Map()
48
30
  });
49
- Object.defineProperty(this, "activeRules", {
31
+ Object.defineProperty(this, "idleDebounceTimeouts", {
50
32
  enumerable: true,
51
33
  configurable: true,
52
34
  writable: true,
53
35
  value: new Map()
54
- }); // routeId -> Set of ruleIds
55
- Object.defineProperty(this, "ruleTimeouts", {
36
+ });
37
+ Object.defineProperty(this, "syncInterval", {
56
38
  enumerable: true,
57
39
  configurable: true,
58
40
  writable: true,
59
- value: new Map()
41
+ value: null
42
+ });
43
+ Object.defineProperty(this, "blacklistChecker", {
44
+ enumerable: true,
45
+ configurable: true,
46
+ writable: true,
47
+ value: null
60
48
  });
61
49
  Object.defineProperty(this, "INACTIVITY_TIMEOUT", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: 10000
54
+ }); // 10秒无活动后标记为空闲
55
+ Object.defineProperty(this, "IDLE_DEBOUNCE_DELAY", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: 3000
60
+ }); // idle 延迟3秒,避免对话快速进入 in_use 时闪烁
61
+ Object.defineProperty(this, "SYNC_INTERVAL", {
62
+ enumerable: true,
63
+ configurable: true,
64
+ writable: true,
65
+ value: 10000
66
+ }); // 每10秒检查一次 suspended 和 error 状态
67
+ Object.defineProperty(this, "ERROR_RECOVERY_TIMEOUT", {
62
68
  enumerable: true,
63
69
  configurable: true,
64
70
  writable: true,
65
71
  value: 30000
66
- }); // 30秒无活动后标记为空闲
72
+ }); // error 状态30秒后自动恢复
73
+ // 启动定期状态检查定时器
74
+ this.startSyncInterval();
67
75
  }
68
76
  /**
69
- * 添加客户端
77
+ * 设置黑名单检查函数
70
78
  */
71
- addClient(client) {
72
- this.clients.add(client);
73
- console.log(`[RulesStatusBroadcaster] 客户端已连接,当前客户端数: ${this.clients.size}`);
79
+ setBlacklistChecker(checker) {
80
+ this.blacklistChecker = checker;
74
81
  }
75
82
  /**
76
- * 移除客户端
83
+ * 启动定期状态检查定时器
77
84
  */
78
- removeClient(client) {
79
- this.clients.delete(client);
80
- console.log(`[RulesStatusBroadcaster] 客户端已断开,当前客户端数: ${this.clients.size}`);
85
+ startSyncInterval() {
86
+ this.syncInterval = setInterval(() => {
87
+ this.checkSuspendedAndErrorRules();
88
+ }, this.SYNC_INTERVAL);
81
89
  }
82
90
  /**
83
- * 标记规则正在使用
91
+ * 检查 suspended 和 error 状态的规则是否已恢复
84
92
  */
85
- markRuleInUse(routeId, ruleId) {
86
- // 添加到活动规则集合
87
- if (!this.activeRules.has(routeId)) {
88
- this.activeRules.set(routeId, new Set());
89
- }
90
- this.activeRules.get(routeId).add(ruleId);
91
- // 清除之前的超时定时器
92
- const timeoutKey = `${routeId}:${ruleId}`;
93
+ checkSuspendedAndErrorRules() {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ const now = Date.now();
96
+ // 1. 检查所有 error 状态的规则,如果超过恢复时间则自动恢复为 idle
97
+ this.ruleStates.forEach((data, ruleId) => {
98
+ if (data.status === 'error' &&
99
+ data.timestamp &&
100
+ now - data.timestamp > this.ERROR_RECOVERY_TIMEOUT) {
101
+ console.log(`[RulesStatusBroadcaster] 规则 ${ruleId} 错误状态已超时,自动恢复为 idle 状态`);
102
+ this.ruleStates.set(ruleId, {
103
+ ruleId,
104
+ status: 'idle',
105
+ routeId: data.routeId,
106
+ timestamp: now,
107
+ });
108
+ }
109
+ });
110
+ // 2. 检查所有 suspended 状态的规则,如果黑名单已过期则恢复为 idle
111
+ if (this.blacklistChecker) {
112
+ const suspendedRules = [];
113
+ this.ruleStates.forEach((data, ruleId) => {
114
+ if (data.status === 'suspended' &&
115
+ data.serviceId &&
116
+ data.routeId &&
117
+ data.contentType) {
118
+ suspendedRules.push({
119
+ ruleId,
120
+ serviceId: data.serviceId,
121
+ routeId: data.routeId,
122
+ contentType: data.contentType,
123
+ });
124
+ }
125
+ });
126
+ // 检查每个 suspended 规则的黑名单状态
127
+ for (const { ruleId, serviceId, routeId, contentType } of suspendedRules) {
128
+ try {
129
+ const isBlacklisted = yield this.blacklistChecker(serviceId, routeId, contentType);
130
+ if (!isBlacklisted) {
131
+ // 黑名单已过期,恢复为 idle 状态
132
+ console.log(`[RulesStatusBroadcaster] 规则 ${ruleId} 黑名单已过期,恢复为 idle 状态`);
133
+ this.ruleStates.set(ruleId, {
134
+ ruleId,
135
+ status: 'idle',
136
+ routeId,
137
+ contentType,
138
+ timestamp: now,
139
+ });
140
+ }
141
+ }
142
+ catch (error) {
143
+ console.error(`[RulesStatusBroadcaster] 检查黑名单状态失败:`, error);
144
+ }
145
+ }
146
+ }
147
+ });
148
+ }
149
+ /**
150
+ * 清除规则的超时定时器
151
+ */
152
+ clearRuleTimeout(timeoutKey) {
93
153
  const existingTimeout = this.ruleTimeouts.get(timeoutKey);
94
154
  if (existingTimeout) {
95
155
  clearTimeout(existingTimeout);
156
+ this.ruleTimeouts.delete(timeoutKey);
96
157
  }
97
- // 广播状态
98
- this.broadcastStatus({
99
- type: 'rule_status',
100
- data: {
101
- ruleId,
102
- status: 'in_use',
103
- timestamp: Date.now(),
104
- },
158
+ }
159
+ /**
160
+ * 清除规则的 idle debounce 定时器
161
+ */
162
+ clearIdleDebounce(timeoutKey) {
163
+ const existing = this.idleDebounceTimeouts.get(timeoutKey);
164
+ if (existing) {
165
+ clearTimeout(existing);
166
+ this.idleDebounceTimeouts.delete(timeoutKey);
167
+ }
168
+ }
169
+ /**
170
+ * 更新规则状态
171
+ */
172
+ updateRuleStatus(data) {
173
+ // 更新本地状态
174
+ this.ruleStates.set(data.ruleId, data);
175
+ }
176
+ /**
177
+ * 标记规则正在使用
178
+ */
179
+ markRuleInUse(routeId, ruleId) {
180
+ const timeoutKey = `${routeId}:${ruleId}`;
181
+ // 清除之前的超时定时器和 idle debounce
182
+ this.clearRuleTimeout(timeoutKey);
183
+ this.clearIdleDebounce(timeoutKey);
184
+ // 更新状态
185
+ this.updateRuleStatus({
186
+ ruleId,
187
+ status: 'in_use',
188
+ routeId,
189
+ timestamp: Date.now(),
105
190
  });
106
- // 设置超时定时器,如果30秒内没有新活动则标记为空闲
191
+ // 设置超时定时器,如果10秒内没有新活动则标记为空闲
107
192
  const timeout = setTimeout(() => {
108
193
  this.markRuleIdle(routeId, ruleId);
109
194
  }, this.INACTIVITY_TIMEOUT);
110
195
  this.ruleTimeouts.set(timeoutKey, timeout);
111
196
  }
112
197
  /**
113
- * 标记规则空闲
198
+ * 标记规则空闲(带3秒 debounce,避免对话快速进入 in_use 时状态闪烁)
114
199
  */
115
200
  markRuleIdle(routeId, ruleId) {
116
201
  const timeoutKey = `${routeId}:${ruleId}`;
117
202
  // 清除超时定时器
118
- const existingTimeout = this.ruleTimeouts.get(timeoutKey);
119
- if (existingTimeout) {
120
- clearTimeout(existingTimeout);
121
- this.ruleTimeouts.delete(timeoutKey);
122
- }
123
- // 从活动规则集合中移除
124
- if (this.activeRules.has(routeId)) {
125
- this.activeRules.get(routeId).delete(ruleId);
126
- if (this.activeRules.get(routeId).size === 0) {
127
- this.activeRules.delete(routeId);
128
- }
129
- }
130
- // 广播空闲状态
131
- this.broadcastStatus({
132
- type: 'rule_status',
133
- data: {
203
+ this.clearRuleTimeout(timeoutKey);
204
+ // 清除已有的 idle debounce,重新计时
205
+ this.clearIdleDebounce(timeoutKey);
206
+ const debounce = setTimeout(() => {
207
+ this.idleDebounceTimeouts.delete(timeoutKey);
208
+ this.updateRuleStatus({
134
209
  ruleId,
135
210
  status: 'idle',
211
+ routeId,
136
212
  timestamp: Date.now(),
137
- },
138
- });
213
+ });
214
+ }, this.IDLE_DEBOUNCE_DELAY);
215
+ this.idleDebounceTimeouts.set(timeoutKey, debounce);
139
216
  }
140
217
  /**
141
- * 广播规则使用量更新
218
+ * 标记规则错误
142
219
  */
143
- broadcastUsageUpdate(ruleId, totalTokensUsed, totalRequestsUsed) {
144
- this.broadcastStatus({
145
- type: 'rule_status',
146
- data: {
147
- ruleId,
148
- status: 'in_use',
149
- totalTokensUsed,
150
- totalRequestsUsed,
151
- timestamp: Date.now(),
152
- },
220
+ markRuleError(routeId, ruleId, errorMessage) {
221
+ const timeoutKey = `${routeId}:${ruleId}`;
222
+ // 清除超时定时器和 idle debounce,避免 error 状态被延迟的 idle 覆盖
223
+ this.clearRuleTimeout(timeoutKey);
224
+ this.clearIdleDebounce(timeoutKey);
225
+ // 更新状态
226
+ this.updateRuleStatus({
227
+ ruleId,
228
+ status: 'error',
229
+ routeId,
230
+ errorMessage,
231
+ timestamp: Date.now(),
153
232
  });
154
233
  }
155
234
  /**
156
- * 广播消息到所有客户端
235
+ * 标记规则被挂起(进入黑名单)
157
236
  */
158
- broadcastStatus(message) {
159
- const deadClients = [];
160
- this.clients.forEach((client) => {
161
- try {
162
- client.sendStatus(message);
163
- }
164
- catch (error) {
165
- console.error('[RulesStatusBroadcaster] 发送消息失败:', error);
166
- deadClients.push(client);
167
- }
237
+ markRuleSuspended(routeId, ruleId, serviceId, contentType, errorMessage, errorType) {
238
+ const timeoutKey = `${routeId}:${ruleId}`;
239
+ // 清除超时定时器和 idle debounce,避免 suspended 状态被延迟的 idle 覆盖
240
+ this.clearRuleTimeout(timeoutKey);
241
+ this.clearIdleDebounce(timeoutKey);
242
+ // 更新状态,同时存储 routeId、serviceId 和 contentType 用于恢复检查
243
+ this.updateRuleStatus({
244
+ ruleId,
245
+ status: 'suspended',
246
+ routeId,
247
+ serviceId,
248
+ contentType,
249
+ errorMessage,
250
+ errorType,
251
+ timestamp: Date.now(),
168
252
  });
169
- // 清理断开的客户端
170
- deadClients.forEach((client) => {
171
- this.removeClient(client);
253
+ }
254
+ /**
255
+ * 更新规则使用量
256
+ */
257
+ updateRuleUsage(ruleId, totalTokensUsed, totalRequestsUsed) {
258
+ // 获取当前状态,保留其他字段
259
+ const currentStatus = this.ruleStates.get(ruleId);
260
+ this.updateRuleStatus({
261
+ ruleId,
262
+ status: (currentStatus === null || currentStatus === void 0 ? void 0 : currentStatus.status) || 'in_use',
263
+ routeId: currentStatus === null || currentStatus === void 0 ? void 0 : currentStatus.routeId,
264
+ contentType: currentStatus === null || currentStatus === void 0 ? void 0 : currentStatus.contentType,
265
+ totalTokensUsed,
266
+ totalRequestsUsed,
267
+ timestamp: Date.now(),
172
268
  });
173
269
  }
270
+ /**
271
+ * 清除指定规则的状态
272
+ */
273
+ clearRuleStatus(ruleId) {
274
+ this.ruleStates.delete(ruleId);
275
+ }
174
276
  /**
175
277
  * 获取当前活动的规则列表
176
278
  */
177
279
  getActiveRules() {
178
- return new Map(this.activeRules);
280
+ const activeRuleIds = [];
281
+ this.ruleStates.forEach((data, ruleId) => {
282
+ if (data.status === 'in_use') {
283
+ activeRuleIds.push(ruleId);
284
+ }
285
+ });
286
+ return activeRuleIds;
287
+ }
288
+ /**
289
+ * 获取所有规则的状态(用于 HTTP 轮询)
290
+ */
291
+ getAllRuleStatuses() {
292
+ return Array.from(this.ruleStates.values());
293
+ }
294
+ /**
295
+ * 销毁广播器(清理定时器)
296
+ */
297
+ destroy() {
298
+ if (this.syncInterval) {
299
+ clearInterval(this.syncInterval);
300
+ this.syncInterval = null;
301
+ }
302
+ this.ruleTimeouts.forEach((timeout) => clearTimeout(timeout));
303
+ this.ruleTimeouts.clear();
304
+ this.idleDebounceTimeouts.forEach((timeout) => clearTimeout(timeout));
305
+ this.idleDebounceTimeouts.clear();
306
+ this.ruleStates.clear();
179
307
  }
180
308
  }
181
309
  exports.RulesStatusBroadcaster = RulesStatusBroadcaster;
182
310
  // 全局单例
183
311
  exports.rulesStatusBroadcaster = new RulesStatusBroadcaster();
184
- /**
185
- * 创建 WebSocket 服务器用于规则状态
186
- */
187
- function createRulesStatusWSServer() {
188
- const wss = new ws_1.WebSocketServer({ noServer: true });
189
- wss.on('connection', (ws, req) => {
190
- const wsHandler = new RulesStatusWS(ws, req);
191
- exports.rulesStatusBroadcaster.addClient(wsHandler);
192
- ws.on('close', () => {
193
- exports.rulesStatusBroadcaster.removeClient(wsHandler);
194
- });
195
- });
196
- return wss;
197
- }
@@ -2,6 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SSEEventCollectorTransform = exports.ChunkCollectorTransform = void 0;
4
4
  const stream_1 = require("stream");
5
+ const string_decoder_1 = require("string_decoder");
6
+ /**
7
+ * 检测是否是客户端断开相关的错误(这些错误是正常的,不应记录为错误)
8
+ */
9
+ function isClientDisconnectError(error) {
10
+ const code = error === null || error === void 0 ? void 0 : error.code;
11
+ const message = typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' ? error.message.toLowerCase() : '';
12
+ return (code === 'ERR_STREAM_PREMATURE_CLOSE' ||
13
+ code === 'ERR_STREAM_UNABLE_TO_PIPE' ||
14
+ code === 'ERR_STREAM_DESTROYED' ||
15
+ message.includes('premature close'));
16
+ }
5
17
  /**
6
18
  * ChunkCollectorTransform - 收集stream chunks用于日志记录
7
19
  * 这个Transform会记录所有经过它的数据块,同时将数据原封不动地传递给下一个stream
@@ -21,8 +33,19 @@ class ChunkCollectorTransform extends stream_1.Transform {
21
33
  writable: true,
22
34
  value: false
23
35
  });
36
+ Object.defineProperty(this, "stringDecoder", {
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true,
40
+ value: new string_decoder_1.StringDecoder('utf8')
41
+ });
24
42
  this.on('error', (err) => {
25
- console.error('[ChunkCollectorTransform] Stream error:', err);
43
+ if (isClientDisconnectError(err)) {
44
+ console.warn('[ChunkCollectorTransform] Stream closed (client disconnected)');
45
+ }
46
+ else {
47
+ console.error('[ChunkCollectorTransform] Stream error:', err);
48
+ }
26
49
  this.errorEmitted = true;
27
50
  });
28
51
  }
@@ -37,7 +60,8 @@ class ChunkCollectorTransform extends stream_1.Transform {
37
60
  this.chunks.push(JSON.stringify(chunk));
38
61
  }
39
62
  else {
40
- this.chunks.push(chunk.toString('utf8'));
63
+ // 使用 StringDecoder 正确处理多字节字符边界,避免中文乱码
64
+ this.chunks.push(this.stringDecoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
41
65
  }
42
66
  // 将chunk传递给下一个stream
43
67
  this.push(chunk);
@@ -48,6 +72,20 @@ class ChunkCollectorTransform extends stream_1.Transform {
48
72
  callback();
49
73
  }
50
74
  }
75
+ _flush(callback) {
76
+ try {
77
+ // 处理 StringDecoder 中剩余的字节
78
+ const remaining = this.stringDecoder.end();
79
+ if (remaining) {
80
+ this.chunks.push(remaining);
81
+ }
82
+ callback();
83
+ }
84
+ catch (error) {
85
+ console.error('[ChunkCollectorTransform] Error in _flush:', error);
86
+ callback();
87
+ }
88
+ }
51
89
  /**
52
90
  * 获取收集的所有chunks
53
91
  */
@@ -97,8 +135,19 @@ class SSEEventCollectorTransform extends stream_1.Transform {
97
135
  writable: true,
98
136
  value: false
99
137
  });
138
+ Object.defineProperty(this, "stringDecoder", {
139
+ enumerable: true,
140
+ configurable: true,
141
+ writable: true,
142
+ value: new string_decoder_1.StringDecoder('utf8')
143
+ });
100
144
  this.on('error', (err) => {
101
- console.error('[SSEEventCollectorTransform] Stream error:', err);
145
+ if (isClientDisconnectError(err)) {
146
+ console.warn('[SSEEventCollectorTransform] Stream closed (client disconnected)');
147
+ }
148
+ else {
149
+ console.error('[SSEEventCollectorTransform] Stream error:', err);
150
+ }
102
151
  this.errorEmitted = true;
103
152
  });
104
153
  }
@@ -108,7 +157,7 @@ class SSEEventCollectorTransform extends stream_1.Transform {
108
157
  return;
109
158
  }
110
159
  try {
111
- // 如果是对象(来自 SSEParserTransform),先转换为字符串格式进行处理
160
+ // 如果是对象(来自 SSEParserTransform 或上游转换器),先转换为字符串格式进行处理
112
161
  if (typeof chunk === 'object' && chunk !== null) {
113
162
  const sseEvent = chunk;
114
163
  const lines = [];
@@ -136,12 +185,12 @@ class SSEEventCollectorTransform extends stream_1.Transform {
136
185
  }
137
186
  this.flushEvent();
138
187
  }
139
- // 将原始对象传递给下一个stream
188
+ // 对象模式下保持原样透传,避免影响后续转换器读取 event/data 字段
140
189
  this.push(chunk);
141
190
  }
142
191
  else {
143
- // Buffer/string 模式
144
- this.buffer += chunk.toString('utf8');
192
+ // Buffer/string 模式 - 使用 StringDecoder 正确处理多字节字符边界
193
+ this.buffer += this.stringDecoder.write(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
145
194
  this.processBuffer();
146
195
  // 将chunk传递给下一个stream
147
196
  this.push(chunk);
@@ -155,12 +204,18 @@ class SSEEventCollectorTransform extends stream_1.Transform {
155
204
  }
156
205
  _flush(callback) {
157
206
  try {
207
+ // 处理 StringDecoder 中剩余的字节
208
+ const remaining = this.stringDecoder.end();
209
+ if (remaining) {
210
+ this.buffer += remaining;
211
+ }
158
212
  // 处理剩余的buffer
159
213
  if (this.buffer.trim()) {
160
214
  this.processBuffer();
161
215
  }
162
216
  // 刷新最后一个事件
163
217
  this.flushEvent();
218
+ // 不调用 this.end(),让 Node.js 自动管理流的生命周期
164
219
  callback();
165
220
  }
166
221
  catch (error) {
@@ -259,8 +314,8 @@ class SSEEventCollectorTransform extends stream_1.Transform {
259
314
  }
260
315
  }
261
316
  // 4. 直接在顶级的usage字段
262
- if (data.input_tokens !== undefined || data.output_tokens !== undefined ||
263
- data.prompt_tokens !== undefined || data.completion_tokens !== undefined) {
317
+ if ((data === null || data === void 0 ? void 0 : data.input_tokens) !== undefined || (data === null || data === void 0 ? void 0 : data.output_tokens) !== undefined ||
318
+ (data === null || data === void 0 ? void 0 : data.prompt_tokens) !== undefined || (data === null || data === void 0 ? void 0 : data.completion_tokens) !== undefined) {
264
319
  return data;
265
320
  }
266
321
  }