aicodeswitch 5.2.13 → 6.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.
- package/bin/restore.js +67 -4
- package/bin/utils/managed-fields.js +12 -0
- package/dist/server/agent-map/activity-extractor.js +8 -0
- package/dist/server/agent-map/agent-map-service.js +364 -65
- package/dist/server/coding-plan.js +3 -0
- package/dist/server/config-managed-fields.js +20 -1
- package/dist/server/config-metadata.js +78 -1
- package/dist/server/conversions/index.js +10 -2
- package/dist/server/conversions/thinking/providers.js +12 -7
- package/dist/server/fs-database.js +10 -1
- package/dist/server/main.js +412 -37
- package/dist/server/original-config-reader.js +71 -1
- package/dist/server/performance-tracker.js +78 -8
- package/dist/server/proxy-server.js +159 -34
- package/dist/server/session-migration.js +1 -0
- package/dist/server/transformers/chunk-collector.js +112 -25
- package/dist/ui/assets/index-BeM4AIzn.js +1187 -0
- package/dist/ui/assets/index-DqRzbMIU.css +1 -0
- package/dist/ui/assets/three-CFpmPosW.js +3802 -0
- package/dist/ui/index.html +3 -2
- package/package.json +3 -1
- package/scripts/dev.js +76 -30
- package/dist/server/tools-service.js +0 -203
- package/dist/server/websocket-service.js +0 -148
- package/dist/ui/assets/index-4liE4bV8.css +0 -1
- package/dist/ui/assets/index-CJMAVkIN.js +0 -813
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getManagedFields = exports.CODEX_AUTH_MANAGED_FIELDS = exports.CODEX_CONFIG_MANAGED_FIELDS = exports.CLAUDE_JSON_MANAGED_FIELDS = exports.CLAUDE_SETTINGS_MANAGED_FIELDS = void 0;
|
|
3
|
+
exports.getManagedFields = exports.OPENCODE_CONFIG_MANAGED_FIELDS = exports.CODEX_AUTH_MANAGED_FIELDS = exports.CODEX_CONFIG_MANAGED_FIELDS = exports.CLAUDE_JSON_MANAGED_FIELDS = exports.CLAUDE_SETTINGS_MANAGED_FIELDS = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Claude Code settings.json 管理字段定义
|
|
6
6
|
*/
|
|
@@ -50,6 +50,20 @@ exports.CODEX_CONFIG_MANAGED_FIELDS = [
|
|
|
50
50
|
exports.CODEX_AUTH_MANAGED_FIELDS = [
|
|
51
51
|
{ path: ['OPENAI_API_KEY'] },
|
|
52
52
|
];
|
|
53
|
+
/**
|
|
54
|
+
* OpenCode opencode.json 管理字段定义
|
|
55
|
+
*
|
|
56
|
+
* OpenCode 配置为纯 JSON,使用自定义 provider 指向本代理。
|
|
57
|
+
* 托管整个 `provider.aicodeswitch` section(npm/name/options/models)
|
|
58
|
+
* 以及 `model` / `small_model` 两个模型选择字段。其余字段(其它 provider、
|
|
59
|
+
* agent、command、mcp、theme 等)一律保留给用户。
|
|
60
|
+
*/
|
|
61
|
+
exports.OPENCODE_CONFIG_MANAGED_FIELDS = [
|
|
62
|
+
{ path: ['provider', 'aicodeswitch'], isSection: true },
|
|
63
|
+
{ path: ['model'] },
|
|
64
|
+
{ path: ['small_model'], optional: true },
|
|
65
|
+
{ path: ['mcp'], isSection: true, optional: true },
|
|
66
|
+
];
|
|
53
67
|
/**
|
|
54
68
|
* 根据配置类型和文件路径获取管理字段列表
|
|
55
69
|
*/
|
|
@@ -70,6 +84,11 @@ const getManagedFields = (configType, filePath) => {
|
|
|
70
84
|
return exports.CODEX_AUTH_MANAGED_FIELDS;
|
|
71
85
|
}
|
|
72
86
|
}
|
|
87
|
+
else if (configType === 'opencode') {
|
|
88
|
+
if (filePath.endsWith('opencode.json')) {
|
|
89
|
+
return exports.OPENCODE_CONFIG_MANAGED_FIELDS;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
73
92
|
return [];
|
|
74
93
|
};
|
|
75
94
|
exports.getManagedFields = getManagedFields;
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.cleanupInvalidMetadata = exports.checkCodexConfigStatus = exports.checkClaudeConfigStatus = exports.deleteMetadata = exports.loadMetadata = exports.saveMetadata = void 0;
|
|
6
|
+
exports.cleanupInvalidMetadata = exports.checkOpencodeConfigStatus = exports.getOpencodeConfigPath = exports.checkCodexConfigStatus = exports.checkClaudeConfigStatus = exports.deleteMetadata = exports.loadMetadata = exports.saveMetadata = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
@@ -270,6 +270,83 @@ const checkCodexConfigStatus = () => {
|
|
|
270
270
|
};
|
|
271
271
|
};
|
|
272
272
|
exports.checkCodexConfigStatus = checkCodexConfigStatus;
|
|
273
|
+
/**
|
|
274
|
+
* 检查 OpenCode 配置文件是否包含我们的代理特征
|
|
275
|
+
*/
|
|
276
|
+
const isOpencodeProxyConfig = (filePath) => {
|
|
277
|
+
var _a, _b;
|
|
278
|
+
try {
|
|
279
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
const content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
283
|
+
const config = JSON.parse(content);
|
|
284
|
+
// 检查是否包含我们的自定义 provider(provider.aicodeswitch)
|
|
285
|
+
const provider = (_a = config === null || config === void 0 ? void 0 : config.provider) === null || _a === void 0 ? void 0 : _a.aicodeswitch;
|
|
286
|
+
if (provider && typeof provider === 'object') {
|
|
287
|
+
const baseUrl = (_b = provider.options) === null || _b === void 0 ? void 0 : _b.baseURL;
|
|
288
|
+
// baseURL 指向本代理的 /opencode 路径
|
|
289
|
+
if (baseUrl && typeof baseUrl === 'string' && /\/opencode(\/|$)/.test(baseUrl)) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
console.error(`Failed to check OpenCode config:`, error);
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* OpenCode 配置文件路径(~/.config/opencode/opencode.json)
|
|
302
|
+
*/
|
|
303
|
+
const getOpencodeConfigPath = () => {
|
|
304
|
+
const homeDir = os_1.default.homedir();
|
|
305
|
+
return path_1.default.join(homeDir, '.config', 'opencode', 'opencode.json');
|
|
306
|
+
};
|
|
307
|
+
exports.getOpencodeConfigPath = getOpencodeConfigPath;
|
|
308
|
+
/**
|
|
309
|
+
* 检查 OpenCode 配置状态
|
|
310
|
+
*/
|
|
311
|
+
const checkOpencodeConfigStatus = () => {
|
|
312
|
+
var _a;
|
|
313
|
+
const configPath = (0, exports.getOpencodeConfigPath)();
|
|
314
|
+
const configBakPath = `${configPath}.aicodeswitch_backup`;
|
|
315
|
+
// 检查备份文件是否存在
|
|
316
|
+
const hasBackup = fs_1.default.existsSync(configBakPath);
|
|
317
|
+
// 尝试加载元数据
|
|
318
|
+
const metadata = (0, exports.loadMetadata)('opencode');
|
|
319
|
+
if (metadata) {
|
|
320
|
+
const currentHash = calculateFileHash(configPath);
|
|
321
|
+
const isProxyConfig = isOpencodeProxyConfig(configPath);
|
|
322
|
+
let isModified = false;
|
|
323
|
+
if (currentHash && ((_a = metadata.files[0]) === null || _a === void 0 ? void 0 : _a.currentHash)) {
|
|
324
|
+
isModified = currentHash !== metadata.files[0].currentHash;
|
|
325
|
+
}
|
|
326
|
+
const isOverwritten = isProxyConfig;
|
|
327
|
+
return {
|
|
328
|
+
isOverwritten,
|
|
329
|
+
isModified,
|
|
330
|
+
hasBackup,
|
|
331
|
+
metadata
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (hasBackup) {
|
|
335
|
+
const isProxyConfig = isOpencodeProxyConfig(configPath);
|
|
336
|
+
return {
|
|
337
|
+
isOverwritten: isProxyConfig,
|
|
338
|
+
isModified: false,
|
|
339
|
+
hasBackup
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
const isProxyConfig = isOpencodeProxyConfig(configPath);
|
|
343
|
+
return {
|
|
344
|
+
isOverwritten: isProxyConfig,
|
|
345
|
+
isModified: false,
|
|
346
|
+
hasBackup: false
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
exports.checkOpencodeConfigStatus = checkOpencodeConfigStatus;
|
|
273
350
|
/**
|
|
274
351
|
* 清理无效的元数据
|
|
275
352
|
* 当备份文件不存在但元数据存在时,说明状态不一致,需要清理
|
|
@@ -276,8 +276,16 @@ function buildTargetBody(options) {
|
|
|
276
276
|
if (result.messages) {
|
|
277
277
|
result.messages = (0, mapper_js_2.fixThinkingHistory)(result.messages, 'completions');
|
|
278
278
|
}
|
|
279
|
-
//
|
|
280
|
-
|
|
279
|
+
// stream_options 剥离策略由 providerConfig.streamOptions 决定:
|
|
280
|
+
// 'supported' → 保留(DeepSeek 等支持 include_usage,能拿到真实 usage)
|
|
281
|
+
// 'unsupported' → 剥离(已知会报错的供应商)
|
|
282
|
+
// 'auto'/缺省 → 维持历史行为:reasoning_content 剥离
|
|
283
|
+
const streamOpt = providerConfig.streamOptions || 'auto';
|
|
284
|
+
const shouldStripStreamOptions = streamOpt === 'unsupported' ||
|
|
285
|
+
(streamOpt === 'auto' && isReasoningContentCompletion);
|
|
286
|
+
if (shouldStripStreamOptions) {
|
|
287
|
+
delete result.stream_options;
|
|
288
|
+
}
|
|
281
289
|
}
|
|
282
290
|
// 注入 thinking 参数(如 thinking: { type: 'enabled' })和 effort 参数
|
|
283
291
|
if (providerConfig.supportsThinking || providerConfig.supportsEffort) {
|
|
@@ -6,17 +6,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.DEFAULT_CONFIG = void 0;
|
|
7
7
|
exports.getReasoningConfig = getReasoningConfig;
|
|
8
8
|
exports.applyReasoningConfig = applyReasoningConfig;
|
|
9
|
+
// streamOptions 语义(决定流式请求是否保留 stream_options.include_usage):
|
|
10
|
+
// 'supported' → 已知支持 include_usage 的供应商,保留 → 流式可拿到真实 usage
|
|
11
|
+
// 'unsupported' → 已知会对 stream_options 报错的供应商,剥离
|
|
12
|
+
// 'auto' → 未明确,由 conversions/index.ts 按 outputFormat 兜底(reasoning_content 剥离,其余保留)
|
|
9
13
|
const PROVIDER_CONFIGS = [
|
|
10
|
-
{ patterns: ['deepseek'], config: { supportsThinking: true, supportsEffort: true, thinkingParam: 'thinking', effortParam: 'reasoning_effort', effortValueMode: 'deepseek', outputFormat: 'reasoning_content' } },
|
|
11
|
-
{ patterns: ['moonshot', 'kimi'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
|
|
12
|
-
{ patterns: ['qwen', 'dashscope'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'enable_thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
|
|
13
|
-
{ patterns: ['zhipu', 'glm', 'bigmodel'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
|
|
14
|
+
{ patterns: ['deepseek'], config: { supportsThinking: true, supportsEffort: true, thinkingParam: 'thinking', effortParam: 'reasoning_effort', effortValueMode: 'deepseek', outputFormat: 'reasoning_content', streamOptions: 'supported' } },
|
|
15
|
+
{ patterns: ['moonshot', 'kimi'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content', streamOptions: 'supported' } },
|
|
16
|
+
{ patterns: ['qwen', 'dashscope'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'enable_thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content', streamOptions: 'supported' } },
|
|
17
|
+
{ patterns: ['zhipu', 'glm', 'bigmodel'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content', streamOptions: 'supported' } },
|
|
14
18
|
{ patterns: ['minimax'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'reasoning_split', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_details' } },
|
|
15
|
-
{ patterns: ['mimo', 'xiaomimimo'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
|
|
19
|
+
{ patterns: ['mimo', 'xiaomimimo'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content', streamOptions: 'auto' } },
|
|
16
20
|
{ patterns: ['openrouter'], config: { supportsThinking: false, supportsEffort: true, thinkingParam: 'none', effortParam: 'reasoning.effort', effortValueMode: 'openrouter', outputFormat: 'reasoning' } },
|
|
17
|
-
{ patterns: ['siliconflow'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'enable_thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
|
|
21
|
+
{ patterns: ['siliconflow'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'enable_thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content', streamOptions: 'supported' } },
|
|
18
22
|
{ patterns: ['stepfun', 'step'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'none', effortParam: 'reasoning_effort', effortValueMode: 'low_high', outputFormat: 'reasoning' } },
|
|
19
|
-
{ patterns: ['agnes'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'chat_template_kwargs', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
|
|
23
|
+
{ patterns: ['agnes'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'chat_template_kwargs', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content', streamOptions: 'auto' } },
|
|
20
24
|
];
|
|
21
25
|
const DEFAULT_CONFIG = {
|
|
22
26
|
supportsThinking: false,
|
|
@@ -25,6 +29,7 @@ const DEFAULT_CONFIG = {
|
|
|
25
29
|
effortParam: 'none',
|
|
26
30
|
effortValueMode: 'passthrough',
|
|
27
31
|
outputFormat: 'reasoning_content',
|
|
32
|
+
streamOptions: 'auto',
|
|
28
33
|
};
|
|
29
34
|
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
30
35
|
/** Detect reasoning config for a given provider */
|
|
@@ -190,6 +190,7 @@ class FileSystemDatabaseManager {
|
|
|
190
190
|
value: {
|
|
191
191
|
'claude-code': { tool: 'claude-code', routeId: null },
|
|
192
192
|
'codex': { tool: 'codex', routeId: null },
|
|
193
|
+
'opencode': { tool: 'opencode', routeId: null },
|
|
193
194
|
}
|
|
194
195
|
});
|
|
195
196
|
// 持久化统计数据
|
|
@@ -552,6 +553,7 @@ class FileSystemDatabaseManager {
|
|
|
552
553
|
this.toolBindings = {
|
|
553
554
|
'claude-code': parsed['claude-code'] || { tool: 'claude-code', routeId: null },
|
|
554
555
|
'codex': parsed['codex'] || { tool: 'codex', routeId: null },
|
|
556
|
+
'opencode': parsed['opencode'] || { tool: 'opencode', routeId: null },
|
|
555
557
|
};
|
|
556
558
|
}
|
|
557
559
|
catch (_a) {
|
|
@@ -559,6 +561,7 @@ class FileSystemDatabaseManager {
|
|
|
559
561
|
this.toolBindings = {
|
|
560
562
|
'claude-code': { tool: 'claude-code', routeId: null },
|
|
561
563
|
'codex': { tool: 'codex', routeId: null },
|
|
564
|
+
'opencode': { tool: 'opencode', routeId: null },
|
|
562
565
|
};
|
|
563
566
|
}
|
|
564
567
|
});
|
|
@@ -908,7 +911,7 @@ class FileSystemDatabaseManager {
|
|
|
908
911
|
// Only migrate routes that are explicitly active and have a targetType
|
|
909
912
|
if (route.isActive === true && route.targetType) {
|
|
910
913
|
const tool = route.targetType;
|
|
911
|
-
if (tool === 'claude-code' || tool === 'codex') {
|
|
914
|
+
if (tool === 'claude-code' || tool === 'codex' || tool === 'opencode') {
|
|
912
915
|
// Only write if tool-bindings doesn't already have a binding
|
|
913
916
|
// (avoid overwriting user's newer tool-binding choices)
|
|
914
917
|
if (!((_a = this.toolBindings[tool]) === null || _a === void 0 ? void 0 : _a.routeId)) {
|
|
@@ -2323,6 +2326,8 @@ class FileSystemDatabaseManager {
|
|
|
2323
2326
|
lastRequestAt: now,
|
|
2324
2327
|
requestCount: 1,
|
|
2325
2328
|
totalTokens: 0,
|
|
2329
|
+
inputTokens: 0,
|
|
2330
|
+
outputTokens: 0,
|
|
2326
2331
|
};
|
|
2327
2332
|
this.sessions.push(session);
|
|
2328
2333
|
yield this.saveSessions();
|
|
@@ -2478,6 +2483,8 @@ class FileSystemDatabaseManager {
|
|
|
2478
2483
|
existing.lastRequestAt = now;
|
|
2479
2484
|
existing.requestCount++;
|
|
2480
2485
|
existing.totalTokens += session.totalTokens || 0;
|
|
2486
|
+
existing.inputTokens = (existing.inputTokens || 0) + (session.inputTokens || 0);
|
|
2487
|
+
existing.outputTokens = (existing.outputTokens || 0) + (session.outputTokens || 0);
|
|
2481
2488
|
if (session.vendorId !== undefined)
|
|
2482
2489
|
existing.vendorId = session.vendorId;
|
|
2483
2490
|
if (session.vendorName !== undefined)
|
|
@@ -2510,6 +2517,8 @@ class FileSystemDatabaseManager {
|
|
|
2510
2517
|
lastRequestAt: now,
|
|
2511
2518
|
requestCount: 1,
|
|
2512
2519
|
totalTokens: session.totalTokens || 0,
|
|
2520
|
+
inputTokens: session.inputTokens || 0,
|
|
2521
|
+
outputTokens: session.outputTokens || 0,
|
|
2513
2522
|
vendorId: session.vendorId,
|
|
2514
2523
|
vendorName: session.vendorName,
|
|
2515
2524
|
serviceId: session.serviceId,
|