aicodeswitch 4.0.4 → 5.1.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.
- package/README.md +6 -5
- package/UPGRADE.md +5 -6
- package/dist/server/coding-plan.js +94 -0
- package/dist/server/config-managed-fields.js +1 -0
- package/dist/server/conversions/compact.js +613 -0
- package/dist/server/conversions/detector.js +70 -0
- package/dist/server/conversions/index.js +290 -0
- package/dist/server/conversions/pairs/claude-completions/request.js +167 -0
- package/dist/server/conversions/pairs/claude-completions/response.js +56 -0
- package/dist/server/conversions/pairs/claude-completions/streaming.js +259 -0
- package/dist/server/conversions/pairs/claude-gemini/request.js +130 -0
- package/dist/server/conversions/pairs/claude-gemini/response.js +65 -0
- package/dist/server/conversions/pairs/claude-gemini/streaming.js +199 -0
- package/dist/server/conversions/pairs/claude-responses/request.js +190 -0
- package/dist/server/conversions/pairs/claude-responses/response.js +89 -0
- package/dist/server/conversions/pairs/claude-responses/streaming.js +266 -0
- package/dist/server/conversions/pairs/completions-claude/request.js +111 -0
- package/dist/server/conversions/pairs/completions-claude/response.js +67 -0
- package/dist/server/conversions/pairs/completions-claude/streaming.js +165 -0
- package/dist/server/conversions/pairs/completions-gemini/request.js +169 -0
- package/dist/server/conversions/pairs/completions-gemini/response.js +70 -0
- package/dist/server/conversions/pairs/completions-gemini/streaming.js +132 -0
- package/dist/server/conversions/pairs/completions-responses/request.js +149 -0
- package/dist/server/conversions/pairs/completions-responses/response.js +74 -0
- package/dist/server/conversions/pairs/completions-responses/streaming.js +189 -0
- package/dist/server/conversions/pairs/gemini-claude/request.js +118 -0
- package/dist/server/conversions/pairs/gemini-claude/response.js +45 -0
- package/dist/server/conversions/pairs/gemini-claude/streaming.js +146 -0
- package/dist/server/conversions/pairs/gemini-completions/request.js +151 -0
- package/dist/server/conversions/pairs/gemini-completions/response.js +54 -0
- package/dist/server/conversions/pairs/gemini-completions/streaming.js +108 -0
- package/dist/server/conversions/pairs/gemini-responses/request.js +18 -0
- package/dist/server/conversions/pairs/gemini-responses/response.js +18 -0
- package/dist/server/conversions/pairs/gemini-responses/streaming.js +43 -0
- package/dist/server/conversions/pairs/responses-claude/request.js +180 -0
- package/dist/server/conversions/pairs/responses-claude/response.js +70 -0
- package/dist/server/conversions/pairs/responses-claude/streaming.js +345 -0
- package/dist/server/conversions/pairs/responses-completions/request.js +207 -0
- package/dist/server/conversions/pairs/responses-completions/response.js +96 -0
- package/dist/server/conversions/pairs/responses-completions/streaming.js +344 -0
- package/dist/server/conversions/pairs/responses-gemini/request.js +18 -0
- package/dist/server/conversions/pairs/responses-gemini/response.js +18 -0
- package/dist/server/conversions/pairs/responses-gemini/streaming.js +43 -0
- package/dist/server/conversions/pairs/responses-responses/request.js +115 -0
- package/dist/server/conversions/pipeline.js +296 -0
- package/dist/server/conversions/stream-converter-adapter.js +49 -0
- package/dist/server/conversions/thinking/effort.js +61 -0
- package/dist/server/conversions/thinking/mapper.js +59 -0
- package/dist/server/conversions/thinking/providers.js +80 -0
- package/dist/server/conversions/types.js +5 -0
- package/dist/server/conversions/url-normalizer.js +58 -0
- package/dist/server/conversions/utils/format-mappers.js +57 -0
- package/dist/server/conversions/utils/id.js +33 -0
- package/dist/server/conversions/utils/stop-reasons.js +95 -0
- package/dist/server/conversions/utils/streaming-helpers.js +59 -0
- package/dist/server/conversions/utils/tool-schema.js +169 -0
- package/dist/server/conversions/utils/usage.js +82 -0
- package/dist/server/fs-database.js +465 -135
- package/dist/server/main.js +93 -33
- package/dist/server/original-config-reader.js +1 -1
- package/dist/server/proxy-server.js +887 -633
- package/dist/server/transformers/chunk-collector.js +5 -1
- package/dist/server/transformers/streaming.js +6 -3235
- package/dist/server/type-migration.js +2 -3
- package/dist/server/utils.js +5 -0
- package/dist/ui/assets/{index-C7G0whng.css → index-BHR12ImE.css} +1 -1
- package/dist/ui/assets/index-Rwiqttz-.js +517 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/server/transformers/transformers.js +0 -1767
- package/dist/ui/assets/index-Dl-B9pXM.js +0 -514
- package/schema/claude.schema.md +0 -946
- package/schema/deepseek-chat.schema.md +0 -799
- package/schema/gemini.schema.md +0 -1408
- package/schema/openai-chat-completions.schema.md +0 -1088
- package/schema/openai-responses.schema.md +0 -226196
- package/schema/stream.md +0 -2592
package/dist/server/main.js
CHANGED
|
@@ -111,7 +111,10 @@ const DEFAULT_CLAUDE_EFFORT_LEVEL = 'medium';
|
|
|
111
111
|
const isClaudeEffortLevel = (value) => {
|
|
112
112
|
return typeof value === 'string' && VALID_CLAUDE_EFFORT_LEVELS.includes(value);
|
|
113
113
|
};
|
|
114
|
-
const
|
|
114
|
+
const isValidAutocompactPct = (v) => {
|
|
115
|
+
return typeof v === 'number' && Number.isInteger(v) && v >= 1 && v <= 100;
|
|
116
|
+
};
|
|
117
|
+
const writeClaudeConfig = (dbManager_1, enableAgentTeams_1, enableBypassPermissionsSupport_1, effortLevel_1, defaultModel_1, autocompactPctOverride_1, ...args_1) => __awaiter(void 0, [dbManager_1, enableAgentTeams_1, enableBypassPermissionsSupport_1, effortLevel_1, defaultModel_1, autocompactPctOverride_1, ...args_1], void 0, function* (dbManager, enableAgentTeams, enableBypassPermissionsSupport, effortLevel, defaultModel, autocompactPctOverride, options = {}) {
|
|
115
118
|
var _a;
|
|
116
119
|
try {
|
|
117
120
|
const homeDir = os_1.default.homedir();
|
|
@@ -191,6 +194,10 @@ const writeClaudeConfig = (dbManager_1, enableAgentTeams_1, enableBypassPermissi
|
|
|
191
194
|
if (defaultModel && typeof defaultModel === 'string' && defaultModel.trim()) {
|
|
192
195
|
proxySettings.model = defaultModel.trim();
|
|
193
196
|
}
|
|
197
|
+
// 如果设置了自动压缩百分比阈值,添加对应的配置项
|
|
198
|
+
if (isValidAutocompactPct(autocompactPctOverride)) {
|
|
199
|
+
claudeSettingsEnv.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE = String(autocompactPctOverride);
|
|
200
|
+
}
|
|
194
201
|
// 使用智能合并:将代理配置的管理字段写入,保留当前配置的非管理字段
|
|
195
202
|
const mergedSettings = (0, config_merge_1.mergeJsonConfig)(proxySettings, currentSettings, config_managed_fields_1.CLAUDE_SETTINGS_MANAGED_FIELDS);
|
|
196
203
|
// 原子性写入合并后的配置
|
|
@@ -538,7 +545,7 @@ const syncConfigsOnServerStartup = (dbManager) => __awaiter(void 0, void 0, void
|
|
|
538
545
|
const claudeEffortLevel = isClaudeEffortLevel(config.claudeEffortLevel)
|
|
539
546
|
? config.claudeEffortLevel
|
|
540
547
|
: DEFAULT_CLAUDE_EFFORT_LEVEL;
|
|
541
|
-
const claudeWritten = yield writeClaudeConfig(dbManager, config.enableAgentTeams, config.enableBypassPermissionsSupport, claudeEffortLevel, config.claudeDefaultModel);
|
|
548
|
+
const claudeWritten = yield writeClaudeConfig(dbManager, config.enableAgentTeams, config.enableBypassPermissionsSupport, claudeEffortLevel, config.claudeDefaultModel, config.autocompactPctOverride);
|
|
542
549
|
console.log(`[Startup Config Sync] Claude Code config ${claudeWritten ? 'written' : 'skipped'}`);
|
|
543
550
|
const modelReasoningEffort = isCodexReasoningEffort(config.codexModelReasoningEffort)
|
|
544
551
|
? config.codexModelReasoningEffort
|
|
@@ -551,7 +558,7 @@ const syncConfigsOnGlobalConfigUpdate = (dbManager) => __awaiter(void 0, void 0,
|
|
|
551
558
|
const claudeEffortLevel = isClaudeEffortLevel(config.claudeEffortLevel)
|
|
552
559
|
? config.claudeEffortLevel
|
|
553
560
|
: DEFAULT_CLAUDE_EFFORT_LEVEL;
|
|
554
|
-
const claudeUpdated = yield writeClaudeConfig(dbManager, config.enableAgentTeams, config.enableBypassPermissionsSupport, claudeEffortLevel, config.claudeDefaultModel, { allowOverwriteRefresh: true });
|
|
561
|
+
const claudeUpdated = yield writeClaudeConfig(dbManager, config.enableAgentTeams, config.enableBypassPermissionsSupport, claudeEffortLevel, config.claudeDefaultModel, config.autocompactPctOverride, { allowOverwriteRefresh: true });
|
|
555
562
|
console.log(`[Config Update Sync] Claude Code config ${claudeUpdated ? 'written' : 'skipped'}`);
|
|
556
563
|
const modelReasoningEffort = isCodexReasoningEffort(config.codexModelReasoningEffort)
|
|
557
564
|
? config.codexModelReasoningEffort
|
|
@@ -1000,46 +1007,66 @@ const registerRoutes = (dbManager, proxyServer) => {
|
|
|
1000
1007
|
app.get('/api/routes', (_req, res) => res.json(dbManager.getRoutes()));
|
|
1001
1008
|
app.post('/api/routes', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () { return res.json(yield dbManager.createRoute(req.body)); })));
|
|
1002
1009
|
app.put('/api/routes/:id', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () { return res.json(yield dbManager.updateRoute(req.params.id, req.body)); })));
|
|
1003
|
-
app.delete('/api/routes/:id', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1004
|
-
|
|
1005
|
-
|
|
1010
|
+
app.delete('/api/routes/:id', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1011
|
+
// Check if route is bound to any tool
|
|
1012
|
+
if (dbManager.isRouteBound(req.params.id)) {
|
|
1013
|
+
return res.status(400).json({ error: '该路由当前被工具使用中,请先停用后再删除' });
|
|
1014
|
+
}
|
|
1015
|
+
const result = yield dbManager.deleteRoute(req.params.id);
|
|
1016
|
+
res.json(result);
|
|
1017
|
+
})));
|
|
1018
|
+
// Tool Bindings API
|
|
1019
|
+
app.get('/api/tool-bindings', (_req, res) => {
|
|
1020
|
+
res.json(dbManager.getToolBindings());
|
|
1021
|
+
});
|
|
1022
|
+
app.post('/api/tool-bindings/activate', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1023
|
+
const { tool, routeId } = req.body;
|
|
1024
|
+
if (!tool || !routeId) {
|
|
1025
|
+
return res.status(400).json({ error: 'tool and routeId are required' });
|
|
1026
|
+
}
|
|
1027
|
+
if (tool !== 'claude-code' && tool !== 'codex') {
|
|
1028
|
+
return res.status(400).json({ error: 'Invalid tool name' });
|
|
1029
|
+
}
|
|
1030
|
+
const route = dbManager.getRoute(routeId);
|
|
1031
|
+
if (!route) {
|
|
1032
|
+
return res.status(404).json({ error: 'Route not found' });
|
|
1033
|
+
}
|
|
1034
|
+
const result = yield dbManager.activateToolRoute(tool, routeId);
|
|
1006
1035
|
if (result) {
|
|
1007
1036
|
yield proxyServer.reloadRoutes();
|
|
1008
|
-
//
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1011
|
-
if (
|
|
1012
|
-
|
|
1013
|
-
const hasMCPForTarget = mcps.some(m => { var _a; return (_a = m.targets) === null || _a === void 0 ? void 0 : _a.includes(route.targetType); });
|
|
1014
|
-
if (hasMCPForTarget) {
|
|
1015
|
-
yield writeMCPConfig(route.targetType);
|
|
1016
|
-
}
|
|
1037
|
+
// Sync MCP config for this tool
|
|
1038
|
+
const mcps = dbManager.getMCPs();
|
|
1039
|
+
const hasMCPForTarget = mcps.some(m => { var _a; return (_a = m.targets) === null || _a === void 0 ? void 0 : _a.includes(tool); });
|
|
1040
|
+
if (hasMCPForTarget) {
|
|
1041
|
+
yield writeMCPConfig(tool);
|
|
1017
1042
|
}
|
|
1018
1043
|
}
|
|
1019
|
-
res.json(result);
|
|
1044
|
+
res.json({ success: result });
|
|
1020
1045
|
})));
|
|
1021
|
-
app.post('/api/
|
|
1022
|
-
const
|
|
1046
|
+
app.post('/api/tool-bindings/deactivate', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1047
|
+
const { tool } = req.body;
|
|
1048
|
+
if (!tool || (tool !== 'claude-code' && tool !== 'codex')) {
|
|
1049
|
+
return res.status(400).json({ error: 'Invalid tool name' });
|
|
1050
|
+
}
|
|
1051
|
+
const result = yield dbManager.deactivateToolRoute(tool);
|
|
1023
1052
|
if (result) {
|
|
1024
1053
|
yield proxyServer.reloadRoutes();
|
|
1025
1054
|
}
|
|
1026
|
-
res.json(result);
|
|
1055
|
+
res.json({ success: result });
|
|
1027
1056
|
})));
|
|
1028
|
-
//
|
|
1057
|
+
// 批量停用所有工具绑定(用于应用关闭时清理)
|
|
1029
1058
|
app.post('/api/routes/deactivate-all', asyncHandler((_req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1030
|
-
console.log('[Deactivate All
|
|
1031
|
-
|
|
1032
|
-
console.log('[Deactivate All Routes] Deactivating all active routes...');
|
|
1033
|
-
const deactivatedCount = yield dbManager.deactivateAllRoutes();
|
|
1059
|
+
console.log('[Deactivate All] Starting tool-bindings deactivation...');
|
|
1060
|
+
const deactivatedCount = yield dbManager.deactivateAllToolRoutes();
|
|
1034
1061
|
if (deactivatedCount > 0) {
|
|
1035
|
-
console.log(`[Deactivate All
|
|
1062
|
+
console.log(`[Deactivate All] Deactivated ${deactivatedCount} tool binding(s), reloading routes...`);
|
|
1036
1063
|
yield proxyServer.reloadRoutes();
|
|
1037
|
-
console.log('[Deactivate All
|
|
1064
|
+
console.log('[Deactivate All] Routes reloaded successfully');
|
|
1038
1065
|
}
|
|
1039
1066
|
else {
|
|
1040
|
-
console.log('[Deactivate All
|
|
1067
|
+
console.log('[Deactivate All] No active tool bindings to deactivate');
|
|
1041
1068
|
}
|
|
1042
|
-
console.log('[Deactivate All
|
|
1069
|
+
console.log('[Deactivate All] Deactivation completed');
|
|
1043
1070
|
res.json({
|
|
1044
1071
|
success: true,
|
|
1045
1072
|
deactivatedCount
|
|
@@ -1572,7 +1599,7 @@ ${instruction}
|
|
|
1572
1599
|
const enableBypassPermissionsSupport = typeof requestedBypass === 'boolean'
|
|
1573
1600
|
? requestedBypass
|
|
1574
1601
|
: appConfig.enableBypassPermissionsSupport;
|
|
1575
|
-
const result = yield writeClaudeConfig(dbManager, enableAgentTeams, enableBypassPermissionsSupport, undefined, appConfig.claudeDefaultModel);
|
|
1602
|
+
const result = yield writeClaudeConfig(dbManager, enableAgentTeams, enableBypassPermissionsSupport, undefined, appConfig.claudeDefaultModel, appConfig.autocompactPctOverride);
|
|
1576
1603
|
res.json(result);
|
|
1577
1604
|
})));
|
|
1578
1605
|
app.post('/api/write-config/codex', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -1651,6 +1678,35 @@ ${instruction}
|
|
|
1651
1678
|
const status = (0, config_metadata_1.checkCodexConfigStatus)();
|
|
1652
1679
|
res.json(status);
|
|
1653
1680
|
});
|
|
1681
|
+
// API 路径路由映射
|
|
1682
|
+
app.get('/api/api-path-bindings', (_req, res) => {
|
|
1683
|
+
res.json({ bindings: dbManager.getApiPathBindings(), models: dbManager.getApiPathModels() });
|
|
1684
|
+
});
|
|
1685
|
+
app.put('/api/api-path-bindings', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1686
|
+
const { bindings } = req.body;
|
|
1687
|
+
const VALID_API_PATHS = ['/v1/messages', '/v1/responses', '/v1/chat/completions', '/v1beta/models', '/v1/models'];
|
|
1688
|
+
const routes = dbManager.getRoutes();
|
|
1689
|
+
const routeIds = new Set(routes.map((r) => r.id));
|
|
1690
|
+
// Validate
|
|
1691
|
+
for (const b of bindings) {
|
|
1692
|
+
if (!VALID_API_PATHS.includes(b.apiPath)) {
|
|
1693
|
+
res.status(400).json({ error: `Invalid apiPath: ${b.apiPath}` });
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
if (b.routeId !== null && !routeIds.has(b.routeId)) {
|
|
1697
|
+
res.status(400).json({ error: `Route not found: ${b.routeId}` });
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
// /v1/models does not accept route binding
|
|
1701
|
+
if (b.apiPath === '/v1/models' && b.routeId !== null) {
|
|
1702
|
+
res.status(400).json({ error: '/v1/models does not accept route binding' });
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
const { models } = req.body;
|
|
1707
|
+
yield dbManager.updateApiPathBindings(bindings.map(b => ({ apiPath: b.apiPath, routeId: b.routeId })), models);
|
|
1708
|
+
res.json({ success: true, bindings: dbManager.getApiPathBindings(), models: dbManager.getApiPathModels() });
|
|
1709
|
+
})));
|
|
1654
1710
|
app.post('/api/export', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1655
1711
|
const { password } = req.body;
|
|
1656
1712
|
const data = yield dbManager.exportData(password);
|
|
@@ -1817,12 +1873,11 @@ ${instruction}
|
|
|
1817
1873
|
app.post('/api/mcps', asyncHandler((req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1818
1874
|
const mcpData = req.body;
|
|
1819
1875
|
const result = yield dbManager.createMCP(Object.assign(Object.assign({}, mcpData), { targets: mcpData.targets || [] }));
|
|
1820
|
-
//
|
|
1876
|
+
// 如果有工具绑定的路由,立即写入MCP配置
|
|
1821
1877
|
if (mcpData.targets) {
|
|
1822
|
-
const routes = dbManager.getRoutes();
|
|
1823
1878
|
for (const target of mcpData.targets) {
|
|
1824
|
-
const
|
|
1825
|
-
if (
|
|
1879
|
+
const activeRouteId = dbManager.getActiveRouteIdForTool(target);
|
|
1880
|
+
if (activeRouteId) {
|
|
1826
1881
|
yield writeMCPConfig(target);
|
|
1827
1882
|
}
|
|
1828
1883
|
}
|
|
@@ -1969,6 +2024,11 @@ const start = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
1969
2024
|
}
|
|
1970
2025
|
const server = app.listen(port, host, () => {
|
|
1971
2026
|
console.log(`Admin server running on http://${host}:${port}`);
|
|
2027
|
+
// 启动后异步执行延迟维护任务(分片校验/修复、日志清理、会话索引构建)
|
|
2028
|
+
// 不阻塞服务启动,后台静默执行
|
|
2029
|
+
dbManager.deferredMaintenance().catch(err => {
|
|
2030
|
+
console.error('[Server] Deferred maintenance error:', err);
|
|
2031
|
+
});
|
|
1972
2032
|
});
|
|
1973
2033
|
// 创建 WebSocket 服务器用于工具安装
|
|
1974
2034
|
const toolInstallWss = (0, websocket_service_1.createToolInstallationWSServer)();
|
|
@@ -36,7 +36,7 @@ const inferSourceTypeFromBaseUrlAndWireApi = (baseUrl, wireApi) => {
|
|
|
36
36
|
return normalizedWireApi === 'chat' ? 'gemini-chat' : 'gemini';
|
|
37
37
|
}
|
|
38
38
|
if (lowerBaseUrl.includes('deepseek')) {
|
|
39
|
-
return '
|
|
39
|
+
return 'openai-chat';
|
|
40
40
|
}
|
|
41
41
|
if (normalizedWireApi === 'chat') {
|
|
42
42
|
return 'openai-chat';
|