aicodeswitch 1.7.0 → 1.7.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.
@@ -228,10 +228,24 @@ class ProxyServer {
228
228
  requestHeaders: this.normalizeHeaders(req.headers),
229
229
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
230
230
  });
231
- res.status(503).json({
232
- error: 'All services failed',
233
- details: lastError === null || lastError === void 0 ? void 0 : lastError.message
234
- });
231
+ // 根据路径判断目标类型并返回适当的错误格式
232
+ const isClaudeCode = req.path.startsWith('/claude-code/');
233
+ if (isClaudeCode) {
234
+ const claudeError = {
235
+ type: 'error',
236
+ error: {
237
+ type: 'api_error',
238
+ message: 'All API services failed. Please try again later.'
239
+ }
240
+ };
241
+ res.status(503).json(claudeError);
242
+ }
243
+ else {
244
+ res.status(503).json({
245
+ error: 'All services failed',
246
+ details: lastError === null || lastError === void 0 ? void 0 : lastError.message
247
+ });
248
+ }
235
249
  }
236
250
  catch (error) {
237
251
  console.error('Proxy error:', error);
@@ -256,7 +270,21 @@ class ProxyServer {
256
270
  requestHeaders: this.normalizeHeaders(req.headers),
257
271
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
258
272
  });
259
- res.status(500).json({ error: error.message });
273
+ // 根据路径判断目标类型并返回适当的错误格式
274
+ const isClaudeCode = req.path.startsWith('/claude-code/');
275
+ if (isClaudeCode) {
276
+ const claudeError = {
277
+ type: 'error',
278
+ error: {
279
+ type: 'api_error',
280
+ message: error.message || 'Internal server error'
281
+ }
282
+ };
283
+ res.status(500).json(claudeError);
284
+ }
285
+ else {
286
+ res.status(500).json({ error: error.message });
287
+ }
260
288
  }
261
289
  }));
262
290
  }
@@ -350,10 +378,24 @@ class ProxyServer {
350
378
  requestHeaders: this.normalizeHeaders(req.headers),
351
379
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
352
380
  });
353
- res.status(503).json({
354
- error: 'All services failed',
355
- details: lastError === null || lastError === void 0 ? void 0 : lastError.message
356
- });
381
+ // 根据路径判断目标类型并返回适当的错误格式
382
+ const isClaudeCode = req.path.startsWith('/claude-code/');
383
+ if (isClaudeCode) {
384
+ const claudeError = {
385
+ type: 'error',
386
+ error: {
387
+ type: 'api_error',
388
+ message: 'All API services failed. Please try again later.'
389
+ }
390
+ };
391
+ res.status(503).json(claudeError);
392
+ }
393
+ else {
394
+ res.status(503).json({
395
+ error: 'All services failed',
396
+ details: lastError === null || lastError === void 0 ? void 0 : lastError.message
397
+ });
398
+ }
357
399
  }
358
400
  catch (error) {
359
401
  console.error(`Fixed route error for ${targetType}:`, error);
@@ -873,7 +915,7 @@ class ProxyServer {
873
915
  }
874
916
  proxyRequest(req, res, route, rule, service) {
875
917
  return __awaiter(this, void 0, void 0, function* () {
876
- var _a;
918
+ var _a, _b;
877
919
  res.locals.skipLog = true;
878
920
  const startTime = Date.now();
879
921
  const sourceType = (service.sourceType || 'openai-chat');
@@ -1118,25 +1160,44 @@ class ProxyServer {
1118
1160
  }
1119
1161
  catch (error) {
1120
1162
  console.error('Proxy error:', error);
1121
- yield finalizeLog(500, error.message);
1163
+ // 检测是否是 timeout 错误
1164
+ const isTimeout = error.code === 'ECONNABORTED' ||
1165
+ ((_b = error.message) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('timeout')) ||
1166
+ (error.errno && error.errno === 'ETIMEDOUT');
1167
+ const errorMessage = isTimeout
1168
+ ? 'Request timeout - the upstream API took too long to respond'
1169
+ : (error.message || 'Internal server error');
1170
+ yield finalizeLog(500, errorMessage);
1122
1171
  // 根据请求类型返回适当格式的错误响应
1123
1172
  const streamRequested = this.isStreamRequested(req, req.body || {});
1124
- if (streamRequested && route.targetType === 'claude-code') {
1125
- // 对于 Claude Code 的流式请求,返回 SSE 格式的错误响应
1126
- res.setHeader('Content-Type', 'text/event-stream');
1127
- res.setHeader('Cache-Control', 'no-cache');
1128
- res.setHeader('Connection', 'keep-alive');
1129
- res.status(500);
1130
- // 发送错误事件
1131
- const errorEvent = `event: error\ndata: ${JSON.stringify({ error: error.message })}\n\n`;
1132
- const doneEvent = `data: [DONE]\n\n`;
1133
- res.write(errorEvent);
1134
- res.write(doneEvent);
1135
- res.end();
1173
+ if (route.targetType === 'claude-code') {
1174
+ // 对于 Claude Code,返回符合 Claude API 标准的错误响应
1175
+ const claudeError = {
1176
+ type: 'error',
1177
+ error: {
1178
+ type: isTimeout ? 'api_error' : 'api_error',
1179
+ message: errorMessage
1180
+ }
1181
+ };
1182
+ if (streamRequested) {
1183
+ // 流式请求:使用 SSE 格式
1184
+ res.setHeader('Content-Type', 'text/event-stream');
1185
+ res.setHeader('Cache-Control', 'no-cache');
1186
+ res.setHeader('Connection', 'keep-alive');
1187
+ res.status(200);
1188
+ // 发送错误事件(使用 Claude API 的标准格式)
1189
+ const errorEvent = `event: error\ndata: ${JSON.stringify(claudeError)}\n\n`;
1190
+ res.write(errorEvent);
1191
+ res.end();
1192
+ }
1193
+ else {
1194
+ // 非流式请求:返回 JSON 格式
1195
+ res.status(500).json(claudeError);
1196
+ }
1136
1197
  }
1137
1198
  else {
1138
- // 对于非流式请求,返回 JSON 格式的错误响应
1139
- res.status(500).json({ error: error.message });
1199
+ // 对于 Codex,返回 JSON 格式的错误响应
1200
+ res.status(500).json({ error: errorMessage });
1140
1201
  }
1141
1202
  }
1142
1203
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicodeswitch",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "A tool to help you manage AI programming tools to access large language models locally. It allows your Claude Code, Codex and other tools to no longer be limited to official models.",
5
5
  "author": "tangshuang",
6
6
  "license": "GPL-3.0",