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.
package/dist/server/main.js
CHANGED
|
@@ -243,10 +243,29 @@ const updateClaudeAgentTeamsConfig = (enableAgentTeams) => __awaiter(void 0, voi
|
|
|
243
243
|
return false;
|
|
244
244
|
}
|
|
245
245
|
});
|
|
246
|
-
const
|
|
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
|
-
|
|
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}:${
|
|
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((
|
|
1388
|
-
const
|
|
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->
|
|
449
|
+
// 映射关系:enabled->medium, disabled->low, auto->low
|
|
450
450
|
if (claudeThinking.type) {
|
|
451
451
|
const effortMap = {
|
|
452
452
|
'enabled': 'medium',
|
|
453
|
-
'disabled': '
|
|
453
|
+
'disabled': 'low',
|
|
454
454
|
'auto': 'low'
|
|
455
455
|
};
|
|
456
456
|
openaiBody.reasoning = {
|