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
|
@@ -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.readOriginalConfig = exports.readCodexOriginalConfig = exports.readClaudeOriginalConfig = void 0;
|
|
6
|
+
exports.readOriginalConfig = exports.readOpencodeOriginalConfig = exports.readCodexOriginalConfig = exports.readClaudeOriginalConfig = 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"));
|
|
@@ -232,6 +232,73 @@ const readCodexOriginalConfig = () => {
|
|
|
232
232
|
}
|
|
233
233
|
};
|
|
234
234
|
exports.readCodexOriginalConfig = readCodexOriginalConfig;
|
|
235
|
+
/**
|
|
236
|
+
* 读取 OpenCode 原始配置
|
|
237
|
+
* fallback 场景下仅从备份文件(~/.config/opencode/opencode.json.aicodeswitch_backup)读取
|
|
238
|
+
*
|
|
239
|
+
* OpenCode 的模型形如 "<providerId>/<modelId>",真实上游由用户原始 opencode.json 中的
|
|
240
|
+
* provider 段(options.baseURL + options.apiKey)决定。此处解析备份中的真实 provider。
|
|
241
|
+
*/
|
|
242
|
+
const readOpencodeOriginalConfig = () => {
|
|
243
|
+
var _a, _b;
|
|
244
|
+
try {
|
|
245
|
+
const homeDir = os_1.default.homedir();
|
|
246
|
+
const configBakPath = path_1.default.join(homeDir, '.config', 'opencode', 'opencode.json.aicodeswitch_backup');
|
|
247
|
+
if (!fs_1.default.existsSync(configBakPath)) {
|
|
248
|
+
console.log('No OpenCode backup config file found');
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
const content = fs_1.default.readFileSync(configBakPath, 'utf-8');
|
|
252
|
+
const config = JSON.parse(content);
|
|
253
|
+
// 解析 model:"providerId/modelId"
|
|
254
|
+
const modelField = typeof config.model === 'string' ? config.model : '';
|
|
255
|
+
const [providerId, modelId] = modelField.split('/');
|
|
256
|
+
const providers = (config.provider && typeof config.provider === 'object') ? config.provider : {};
|
|
257
|
+
// 选定真实 provider:优先 model 中声明的 providerId,否则取第一个非 aicodeswitch 的 provider
|
|
258
|
+
let providerConfig;
|
|
259
|
+
let resolvedProviderId = '';
|
|
260
|
+
if (providerId && providers[providerId]) {
|
|
261
|
+
providerConfig = providers[providerId];
|
|
262
|
+
resolvedProviderId = providerId;
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
for (const [pid, pc] of Object.entries(providers)) {
|
|
266
|
+
if (pid !== 'aicodeswitch' && pc && typeof pc === 'object') {
|
|
267
|
+
providerConfig = pc;
|
|
268
|
+
resolvedProviderId = pid;
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const baseUrlRaw = ((_a = providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.options) === null || _a === void 0 ? void 0 : _a.baseURL) || '';
|
|
274
|
+
const baseUrl = normalizeApiUrl(baseUrlRaw);
|
|
275
|
+
// apiKey 可能内联在 options.apiKey,也可能经 {env:XXX}/{file:xxx} 引用(fallback 无法解析,置空)
|
|
276
|
+
let apiKey = '';
|
|
277
|
+
if (typeof ((_b = providerConfig === null || providerConfig === void 0 ? void 0 : providerConfig.options) === null || _b === void 0 ? void 0 : _b.apiKey) === 'string') {
|
|
278
|
+
const raw = providerConfig.options.apiKey.trim();
|
|
279
|
+
if (raw && !raw.startsWith('{env:') && !raw.startsWith('{file:')) {
|
|
280
|
+
apiKey = raw;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (!baseUrl) {
|
|
284
|
+
console.log('No baseURL found in OpenCode backup config provider:', resolvedProviderId);
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
const sourceType = inferSourceTypeFromBaseUrlAndWireApi(baseUrl, undefined);
|
|
288
|
+
return {
|
|
289
|
+
apiUrl: baseUrl,
|
|
290
|
+
apiKey,
|
|
291
|
+
authType: inferAuthTypeFromSource(sourceType),
|
|
292
|
+
sourceType,
|
|
293
|
+
model: modelId || modelField || undefined,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
console.error('Failed to read OpenCode original config:', error);
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
exports.readOpencodeOriginalConfig = readOpencodeOriginalConfig;
|
|
235
302
|
/**
|
|
236
303
|
* 根据目标类型读取原始配置
|
|
237
304
|
*/
|
|
@@ -242,6 +309,9 @@ const readOriginalConfig = (targetType) => {
|
|
|
242
309
|
else if (targetType === 'codex') {
|
|
243
310
|
return (0, exports.readCodexOriginalConfig)();
|
|
244
311
|
}
|
|
312
|
+
else if (targetType === 'opencode') {
|
|
313
|
+
return (0, exports.readOpencodeOriginalConfig)();
|
|
314
|
+
}
|
|
245
315
|
return null;
|
|
246
316
|
};
|
|
247
317
|
exports.readOriginalConfig = readOriginalConfig;
|
|
@@ -68,8 +68,12 @@ class ServicePerformanceTracker {
|
|
|
68
68
|
try {
|
|
69
69
|
const raw = yield promises_1.default.readFile(this.filePath, 'utf-8');
|
|
70
70
|
const parsed = JSON.parse(raw);
|
|
71
|
-
if (parsed && parsed.vendors)
|
|
71
|
+
if (parsed && parsed.vendors) {
|
|
72
72
|
this.file = parsed;
|
|
73
|
+
// 旧数据文件可能缺新增的 token 字段(sumInputTokens/sumTotalTokens),
|
|
74
|
+
// 直接累加会得到 undefined+N=NaN,污染派生值。这里补齐为 0。
|
|
75
|
+
this.migrateBuckets(this.file);
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
catch (_a) {
|
|
75
79
|
// 首次启动或文件损坏,使用空桶
|
|
@@ -77,6 +81,42 @@ class ServicePerformanceTracker {
|
|
|
77
81
|
}
|
|
78
82
|
});
|
|
79
83
|
}
|
|
84
|
+
/** 加载后补齐旧数据缺失的桶字段,避免 undefined 累加成 NaN */
|
|
85
|
+
migrateBuckets(file) {
|
|
86
|
+
for (const v of Object.values(file.vendors)) {
|
|
87
|
+
if (v.vendorRollup)
|
|
88
|
+
this.normalizeAggregate(v.vendorRollup);
|
|
89
|
+
for (const s of Object.values(v.services || {})) {
|
|
90
|
+
if (s.serviceRollup)
|
|
91
|
+
this.normalizeAggregate(s.serviceRollup);
|
|
92
|
+
for (const agg of Object.values(s.models || {})) {
|
|
93
|
+
this.normalizeAggregate(agg);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
normalizeAggregate(agg) {
|
|
99
|
+
this.normalizeBucket(agg.precise);
|
|
100
|
+
this.normalizeBucket(agg.estimated);
|
|
101
|
+
for (const b of Object.values(agg.hourly || {}))
|
|
102
|
+
this.normalizeBucket(b);
|
|
103
|
+
}
|
|
104
|
+
normalizeBucket(b) {
|
|
105
|
+
if (!b)
|
|
106
|
+
return;
|
|
107
|
+
if (typeof b.count !== 'number')
|
|
108
|
+
b.count = 0;
|
|
109
|
+
if (typeof b.sumTtftMs !== 'number')
|
|
110
|
+
b.sumTtftMs = 0;
|
|
111
|
+
if (typeof b.sumTps !== 'number')
|
|
112
|
+
b.sumTps = 0;
|
|
113
|
+
if (typeof b.totalOutputTokens !== 'number')
|
|
114
|
+
b.totalOutputTokens = 0;
|
|
115
|
+
if (typeof b.sumInputTokens !== 'number')
|
|
116
|
+
b.sumInputTokens = 0;
|
|
117
|
+
if (typeof b.sumTotalTokens !== 'number')
|
|
118
|
+
b.sumTotalTokens = 0;
|
|
119
|
+
}
|
|
80
120
|
/**
|
|
81
121
|
* 记录一次请求的性能数据点(三级同步聚合)。
|
|
82
122
|
* 纯内存操作,不阻塞调用方。
|
|
@@ -257,7 +297,7 @@ class ServicePerformanceTracker {
|
|
|
257
297
|
};
|
|
258
298
|
}
|
|
259
299
|
emptyBucket() {
|
|
260
|
-
return { count: 0, sumTtftMs: 0, sumTps: 0, totalOutputTokens: 0 };
|
|
300
|
+
return { count: 0, sumTtftMs: 0, sumTps: 0, totalOutputTokens: 0, sumInputTokens: 0, sumTotalTokens: 0 };
|
|
261
301
|
}
|
|
262
302
|
accumulate(agg, m, hour, withExtremes) {
|
|
263
303
|
var _a;
|
|
@@ -268,6 +308,7 @@ class ServicePerformanceTracker {
|
|
|
268
308
|
const bucket = m.timingAccuracy === 'precise' ? agg.precise : agg.estimated;
|
|
269
309
|
const hasTtft = m.timingAccuracy === 'precise' && typeof m.ttftMs === 'number';
|
|
270
310
|
const hasTps = typeof m.tokensPerSecond === 'number';
|
|
311
|
+
// token 量与计时精度无关,precise/estimated 桶都累加
|
|
271
312
|
bucket.count += 1;
|
|
272
313
|
if (hasTtft)
|
|
273
314
|
bucket.sumTtftMs += m.ttftMs;
|
|
@@ -275,18 +316,37 @@ class ServicePerformanceTracker {
|
|
|
275
316
|
bucket.sumTps += m.tokensPerSecond;
|
|
276
317
|
if (m.outputTokens)
|
|
277
318
|
bucket.totalOutputTokens += m.outputTokens;
|
|
278
|
-
|
|
319
|
+
if (m.inputTokens)
|
|
320
|
+
bucket.sumInputTokens += m.inputTokens;
|
|
321
|
+
if (m.totalTokens)
|
|
322
|
+
bucket.sumTotalTokens += m.totalTokens;
|
|
323
|
+
// 小时走势桶:
|
|
324
|
+
// - count/sumTtftMs/sumTps 仅精确样本计入(避免估算样本污染 TTFT/TPM 均值)
|
|
325
|
+
// - token 三项与精度无关,所有样本都计入走势(含非流式)
|
|
326
|
+
const hb = (_a = agg.hourly[hour]) !== null && _a !== void 0 ? _a : (agg.hourly[hour] = this.emptyBucket());
|
|
327
|
+
let touchedHourly = false;
|
|
279
328
|
if (m.timingAccuracy === 'precise') {
|
|
280
|
-
const hb = (_a = agg.hourly[hour]) !== null && _a !== void 0 ? _a : (agg.hourly[hour] = this.emptyBucket());
|
|
281
329
|
hb.count += 1;
|
|
282
330
|
if (hasTtft)
|
|
283
331
|
hb.sumTtftMs += m.ttftMs;
|
|
284
332
|
if (hasTps)
|
|
285
333
|
hb.sumTps += m.tokensPerSecond;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
334
|
+
touchedHourly = true;
|
|
335
|
+
}
|
|
336
|
+
if (m.outputTokens) {
|
|
337
|
+
hb.totalOutputTokens += m.outputTokens;
|
|
338
|
+
touchedHourly = true;
|
|
339
|
+
}
|
|
340
|
+
if (m.inputTokens) {
|
|
341
|
+
hb.sumInputTokens += m.inputTokens;
|
|
342
|
+
touchedHourly = true;
|
|
289
343
|
}
|
|
344
|
+
if (m.totalTokens) {
|
|
345
|
+
hb.sumTotalTokens += m.totalTokens;
|
|
346
|
+
touchedHourly = true;
|
|
347
|
+
}
|
|
348
|
+
if (touchedHourly)
|
|
349
|
+
this.trimHourly(agg.hourly);
|
|
290
350
|
// 极值(仅模型级、仅精确样本)
|
|
291
351
|
if (withExtremes && m.timingAccuracy === 'precise') {
|
|
292
352
|
if (hasTtft) {
|
|
@@ -315,9 +375,14 @@ class ServicePerformanceTracker {
|
|
|
315
375
|
// ---------------- 内部:派生 ----------------
|
|
316
376
|
derive(agg) {
|
|
317
377
|
const p = agg.precise;
|
|
378
|
+
const e = agg.estimated;
|
|
318
379
|
const count = p.count;
|
|
319
380
|
const avgTtftMs = count > 0 ? p.sumTtftMs / count : 0;
|
|
320
381
|
const avgTps = count > 0 ? p.sumTps / count : 0;
|
|
382
|
+
// token 量跨 precise+estimated 求和(含非流式样本)
|
|
383
|
+
const totalOutputTokens = p.totalOutputTokens + e.totalOutputTokens;
|
|
384
|
+
const totalInputTokens = p.sumInputTokens + e.sumInputTokens;
|
|
385
|
+
const totalTokens = p.sumTotalTokens + e.sumTotalTokens;
|
|
321
386
|
return {
|
|
322
387
|
count,
|
|
323
388
|
avgTtftMs,
|
|
@@ -327,7 +392,9 @@ class ServicePerformanceTracker {
|
|
|
327
392
|
minTps: agg.minTps,
|
|
328
393
|
maxTps: agg.maxTps,
|
|
329
394
|
errorCount: agg.errorCount,
|
|
330
|
-
totalOutputTokens
|
|
395
|
+
totalOutputTokens,
|
|
396
|
+
totalInputTokens,
|
|
397
|
+
totalTokens,
|
|
331
398
|
successRate: count + agg.errorCount > 0 ? count / (count + agg.errorCount) : 0,
|
|
332
399
|
};
|
|
333
400
|
}
|
|
@@ -355,6 +422,9 @@ class ServicePerformanceTracker {
|
|
|
355
422
|
count: b.count,
|
|
356
423
|
avgTtftMs: b.count > 0 ? b.sumTtftMs / b.count : 0,
|
|
357
424
|
avgTpm: b.count > 0 ? (b.sumTps / b.count) * 60 : 0,
|
|
425
|
+
inputTokens: b.sumInputTokens,
|
|
426
|
+
outputTokens: b.totalOutputTokens,
|
|
427
|
+
totalTokens: b.sumTotalTokens,
|
|
358
428
|
}));
|
|
359
429
|
}
|
|
360
430
|
locateService(serviceId) {
|