aicodeswitch 3.6.2 → 3.6.3

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.
@@ -243,10 +243,29 @@ const updateClaudeAgentTeamsConfig = (enableAgentTeams) => __awaiter(void 0, voi
243
243
  return false;
244
244
  }
245
245
  });
246
- const writeCodexConfig = (dbManager) => __awaiter(void 0, void 0, void 0, function* () {
246
+ const VALID_CODEX_REASONING_EFFORTS = ['low', 'medium', 'high'];
247
+ const DEFAULT_CODEX_REASONING_EFFORT = 'high';
248
+ const isCodexReasoningEffort = (value) => {
249
+ return typeof value === 'string' && VALID_CODEX_REASONING_EFFORTS.includes(value);
250
+ };
251
+ const buildCodexConfigToml = (modelReasoningEffort) => {
252
+ const localPort = process.env.PORT ? parseInt(process.env.PORT, 10) : 4567;
253
+ return `model_provider = "aicodeswitch"
254
+ model = "gpt-5.1-codex"
255
+ model_reasoning_effort = "${modelReasoningEffort}"
256
+ disable_response_storage = true
257
+
258
+
259
+ [model_providers.aicodeswitch]
260
+ name = "aicodeswitch"
261
+ base_url = "http://${host}:${localPort}/codex"
262
+ wire_api = "responses"
263
+ requires_openai_auth = true
264
+ `;
265
+ };
266
+ const writeCodexConfig = (dbManager_1, ...args_1) => __awaiter(void 0, [dbManager_1, ...args_1], void 0, function* (dbManager, modelReasoningEffort = DEFAULT_CODEX_REASONING_EFFORT) {
247
267
  try {
248
268
  const homeDir = os_1.default.homedir();
249
- const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 4567;
250
269
  const config = dbManager.getConfig();
251
270
  // Codex config.toml
252
271
  const codexDir = path_1.default.join(homeDir, '.codex');
@@ -277,19 +296,7 @@ const writeCodexConfig = (dbManager) => __awaiter(void 0, void 0, void 0, functi
277
296
  if (!fs_1.default.existsSync(codexDir)) {
278
297
  fs_1.default.mkdirSync(codexDir, { recursive: true });
279
298
  }
280
- const codexConfig = `model_provider = "aicodeswitch"
281
- model = "gpt-5.1-codex"
282
- model_reasoning_effort = "high"
283
- disable_response_storage = true
284
-
285
-
286
- [model_providers.aicodeswitch]
287
- name = "aicodeswitch"
288
- base_url = "http://${host}:${port}/codex"
289
- wire_api = "responses"
290
- requires_openai_auth = true
291
- `;
292
- fs_1.default.writeFileSync(codexConfigPath, codexConfig);
299
+ fs_1.default.writeFileSync(codexConfigPath, buildCodexConfigToml(modelReasoningEffort));
293
300
  // Codex auth.json
294
301
  const codexAuthPath = path_1.default.join(codexDir, 'auth.json');
295
302
  // 同样处理 auth.json 的备份
@@ -308,7 +315,7 @@ requires_openai_auth = true
308
315
  configType: 'codex',
309
316
  timestamp: Date.now(),
310
317
  originalHash: originalConfigHash,
311
- proxyMarker: `http://${host}:${port}/codex`,
318
+ proxyMarker: `http://${host}:${process.env.PORT ? parseInt(process.env.PORT, 10) : 4567}/codex`,
312
319
  files: [
313
320
  {
314
321
  originalPath: codexConfigPath,
@@ -329,6 +336,35 @@ requires_openai_auth = true
329
336
  return false;
330
337
  }
331
338
  });
339
+ const updateCodexReasoningEffortConfig = (modelReasoningEffort) => __awaiter(void 0, void 0, void 0, function* () {
340
+ try {
341
+ const homeDir = os_1.default.homedir();
342
+ const codexConfigPath = path_1.default.join(homeDir, '.codex/config.toml');
343
+ if (!fs_1.default.existsSync(codexConfigPath)) {
344
+ console.error('Codex config.toml does not exist');
345
+ return false;
346
+ }
347
+ const configStatus = (0, config_metadata_1.checkCodexConfigStatus)();
348
+ if (!configStatus.isOverwritten) {
349
+ console.error('Codex config is not overwritten by proxy. Please activate a route first.');
350
+ return false;
351
+ }
352
+ fs_1.default.writeFileSync(codexConfigPath, buildCodexConfigToml(modelReasoningEffort));
353
+ const metadata = (0, config_metadata_1.loadMetadata)('codex');
354
+ if (metadata && metadata.files[0]) {
355
+ metadata.files[0].currentHash = (0, crypto_1.createHash)('sha256')
356
+ .update(fs_1.default.readFileSync(codexConfigPath, 'utf-8'))
357
+ .digest('hex');
358
+ metadata.timestamp = Date.now();
359
+ (0, config_metadata_1.saveMetadata)(metadata);
360
+ }
361
+ return true;
362
+ }
363
+ catch (error) {
364
+ console.error('Failed to update Codex reasoning effort config:', error);
365
+ return false;
366
+ }
367
+ });
332
368
  const restoreClaudeConfig = () => __awaiter(void 0, void 0, void 0, function* () {
333
369
  try {
334
370
  const homeDir = os_1.default.homedir();
@@ -1384,8 +1420,12 @@ ${instruction}
1384
1420
  const result = yield writeClaudeConfig(dbManager, enableAgentTeams);
1385
1421
  res.json(result);
1386
1422
  })));
1387
- app.post('/api/write-config/codex', asyncHandler((_req, res) => __awaiter(void 0, void 0, void 0, function* () {
1388
- const result = yield writeCodexConfig(dbManager);
1423
+ app.post('/api/write-config/codex', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
1424
+ const requestedEffort = req.body.modelReasoningEffort;
1425
+ const modelReasoningEffort = isCodexReasoningEffort(requestedEffort)
1426
+ ? requestedEffort
1427
+ : DEFAULT_CODEX_REASONING_EFFORT;
1428
+ const result = yield writeCodexConfig(dbManager, modelReasoningEffort);
1389
1429
  res.json(result);
1390
1430
  })));
1391
1431
  // 更新Claude Code配置中的Agent Teams设置(当路由已激活时)
@@ -1394,6 +1434,15 @@ ${instruction}
1394
1434
  const result = yield updateClaudeAgentTeamsConfig(enableAgentTeams);
1395
1435
  res.json(result);
1396
1436
  })));
1437
+ app.post('/api/update-codex-reasoning-effort', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
1438
+ const requestedEffort = req.body.modelReasoningEffort;
1439
+ if (!isCodexReasoningEffort(requestedEffort)) {
1440
+ res.status(400).json({ error: 'Invalid modelReasoningEffort' });
1441
+ return;
1442
+ }
1443
+ const result = yield updateCodexReasoningEffortConfig(requestedEffort);
1444
+ res.json(result);
1445
+ })));
1397
1446
  app.post('/api/restore-config/claude', asyncHandler((_req, res) => __awaiter(void 0, void 0, void 0, function* () {
1398
1447
  const result = yield restoreClaudeConfig();
1399
1448
  res.json(result);
@@ -1551,6 +1551,22 @@ class ProxyServer {
1551
1551
  isChatType(sourceType) {
1552
1552
  return sourceType.endsWith('-chat') || sourceType === 'gemini';
1553
1553
  }
1554
+ /**
1555
+ * 构建 OpenAI Responses 类型的完整 URL
1556
+ * - baseUrl 以 /v{number} 结尾时,直接拼接请求路径
1557
+ * - baseUrl 不带版本时,自动补 /v1 再拼接请求路径
1558
+ * - 兼容请求路径本身已携带版本前缀(如 /v1/responses)场景
1559
+ */
1560
+ buildOpenAIResponsesUrl(baseUrl, mappedPath) {
1561
+ const trimmedBase = baseUrl.trim().replace(/\/+$/, '');
1562
+ const normalizedPath = mappedPath.startsWith('/') || mappedPath === '' ? mappedPath : `/${mappedPath}`;
1563
+ const baseHasVersionSuffix = /\/v\d+$/i.test(trimmedBase);
1564
+ const pathHasVersionPrefix = /^\/v\d+(?:\/|$)/i.test(normalizedPath);
1565
+ if (baseHasVersionSuffix || pathHasVersionPrefix) {
1566
+ return `${trimmedBase}${normalizedPath}`;
1567
+ }
1568
+ return `${trimmedBase}/v1${normalizedPath}`;
1569
+ }
1554
1570
  /**
1555
1571
  * 构建 Gemini API 的完整 URL
1556
1572
  * 用户只填写 base 地址(如 https://generativelanguage.googleapis.com)
@@ -2282,6 +2298,10 @@ class ProxyServer {
2282
2298
  const model = requestBody.model || rule.targetModel || 'gemini-pro';
2283
2299
  upstreamUrl = this.buildGeminiUrl(service.apiUrl, model, streamRequested);
2284
2300
  }
2301
+ else if (sourceType === 'openai') {
2302
+ // OpenAI Responses 兼容模式:自动处理 baseUrl 是否包含 /v{number}
2303
+ upstreamUrl = this.buildOpenAIResponsesUrl(service.apiUrl, mappedPath);
2304
+ }
2285
2305
  else if (this.isChatType(sourceType) || this.isGeminiChatSource(sourceType)) {
2286
2306
  // Chat 类型(包括 gemini-chat)直接使用用户配置的完整 URL
2287
2307
  upstreamUrl = service.apiUrl;
@@ -446,11 +446,11 @@ const transformClaudeRequestToOpenAIChat = (body, targetModel) => {
446
446
  openaiBody.thinking = { type: claudeThinking.type };
447
447
  }
448
448
  // 为 OpenAI Responses API 添加 reasoning 配置
449
- // 映射关系:enabled->medium, disabled->minimal, auto->low
449
+ // 映射关系:enabled->medium, disabled->low, auto->low
450
450
  if (claudeThinking.type) {
451
451
  const effortMap = {
452
452
  'enabled': 'medium',
453
- 'disabled': 'minimal',
453
+ 'disabled': 'low',
454
454
  'auto': 'low'
455
455
  };
456
456
  openaiBody.reasoning = {