@adversity/coding-tool-x 3.1.1 → 3.1.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/CHANGELOG.md +41 -0
- package/dist/web/assets/Analytics-BIqc8Rin.css +1 -0
- package/dist/web/assets/Analytics-D2V09DHH.js +39 -0
- package/dist/web/assets/{ConfigTemplates-ZrK_s7ma.js → ConfigTemplates-Bf_11LhH.js} +1 -1
- package/dist/web/assets/Home-BRnW4FTS.js +1 -0
- package/dist/web/assets/Home-CyCIx4BA.css +1 -0
- package/dist/web/assets/{PluginManager-BD7QUZbU.js → PluginManager-B9J32GhW.js} +1 -1
- package/dist/web/assets/{ProjectList-DRb1DuHV.js → ProjectList-5a19MWJk.js} +1 -1
- package/dist/web/assets/SessionList-CXUr6S7w.css +1 -0
- package/dist/web/assets/SessionList-Cxg5bAdT.js +1 -0
- package/dist/web/assets/{SkillManager-C1xG5B4Q.js → SkillManager-CVBr0CLi.js} +1 -1
- package/dist/web/assets/{Terminal-DksBo_lM.js → Terminal-D2Xe_Q0H.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-Burx7XOo.js → WorkspaceManager-C7dwV94C.js} +1 -1
- package/dist/web/assets/icons-BxcwoY5F.js +1 -0
- package/dist/web/assets/index-BS9RA6SN.js +2 -0
- package/dist/web/assets/index-DUNAVDGb.css +1 -0
- package/dist/web/assets/naive-ui-BIXcURHZ.js +1 -0
- package/dist/web/assets/{vendors-CO3Upi1d.js → vendors-i5CBGnlm.js} +1 -1
- package/dist/web/assets/{vue-vendor-DqyWIXEb.js → vue-vendor-PKd8utv_.js} +1 -1
- package/dist/web/index.html +6 -6
- package/package.json +1 -1
- package/src/config/default.js +7 -27
- package/src/config/loader.js +6 -3
- package/src/config/model-metadata.js +167 -0
- package/src/config/model-metadata.json +125 -0
- package/src/config/model-pricing.js +23 -93
- package/src/server/api/channels.js +16 -39
- package/src/server/api/codex-channels.js +15 -43
- package/src/server/api/commands.js +0 -77
- package/src/server/api/config.js +4 -1
- package/src/server/api/gemini-channels.js +16 -40
- package/src/server/api/opencode-channels.js +108 -56
- package/src/server/api/opencode-proxy.js +42 -33
- package/src/server/api/opencode-sessions.js +4 -69
- package/src/server/api/sessions.js +11 -68
- package/src/server/api/settings.js +138 -0
- package/src/server/api/skills.js +0 -44
- package/src/server/api/statistics.js +115 -1
- package/src/server/codex-proxy-server.js +32 -59
- package/src/server/gemini-proxy-server.js +21 -18
- package/src/server/index.js +13 -7
- package/src/server/opencode-proxy-server.js +1232 -197
- package/src/server/proxy-server.js +8 -8
- package/src/server/services/codex-sessions.js +105 -6
- package/src/server/services/commands-service.js +0 -29
- package/src/server/services/config-templates-service.js +38 -28
- package/src/server/services/env-checker.js +97 -9
- package/src/server/services/env-manager.js +29 -1
- package/src/server/services/opencode-channels.js +3 -1
- package/src/server/services/opencode-sessions.js +486 -218
- package/src/server/services/opencode-settings-manager.js +172 -36
- package/src/server/services/plugins-service.js +37 -28
- package/src/server/services/pty-manager.js +22 -18
- package/src/server/services/response-decoder.js +21 -0
- package/src/server/services/skill-service.js +1 -49
- package/src/server/services/speed-test.js +40 -3
- package/src/server/services/statistics-service.js +238 -1
- package/src/server/utils/pricing.js +51 -60
- package/src/server/websocket-server.js +24 -5
- package/dist/web/assets/Home-B8YfhZ3c.js +0 -1
- package/dist/web/assets/Home-Di2qsylF.css +0 -1
- package/dist/web/assets/SessionList-BGJWyneI.css +0 -1
- package/dist/web/assets/SessionList-lZ0LKzfT.js +0 -1
- package/dist/web/assets/icons-kcfLIMBB.js +0 -1
- package/dist/web/assets/index-Ufv5rCa5.css +0 -1
- package/dist/web/assets/index-lAkrRC3h.js +0 -2
- package/dist/web/assets/naive-ui-CSrLusZZ.js +0 -1
- package/src/server/api/convert.js +0 -260
- package/src/server/services/session-converter.js +0 -577
|
@@ -7,11 +7,11 @@ const { allocateChannel, releaseChannel, getSchedulerState } = require('./servic
|
|
|
7
7
|
const { recordSuccess, recordFailure } = require('./services/channel-health');
|
|
8
8
|
const { loadConfig } = require('../config/loader');
|
|
9
9
|
const DEFAULT_CONFIG = require('../config/default');
|
|
10
|
-
const {
|
|
10
|
+
const { resolveModelPricing } = require('./utils/pricing');
|
|
11
11
|
const { recordRequest: recordCodexRequest } = require('./services/codex-statistics-service');
|
|
12
12
|
const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
|
|
13
|
+
const { createDecodedStream } = require('./services/response-decoder');
|
|
13
14
|
const { getEnabledChannels, writeCodexConfigForMultiChannel, getEffectiveApiKey } = require('./services/codex-channels');
|
|
14
|
-
const { CLAUDE_MODEL_PRICING } = require('../config/model-pricing');
|
|
15
15
|
|
|
16
16
|
let proxyServer = null;
|
|
17
17
|
let proxyApp = null;
|
|
@@ -25,7 +25,7 @@ const requestMetadata = new Map();
|
|
|
25
25
|
const printedRedirectCache = new Map();
|
|
26
26
|
|
|
27
27
|
// OpenAI 模型定价(每百万 tokens 的价格,单位:美元)
|
|
28
|
-
//
|
|
28
|
+
// 作为 model-metadata 未覆盖时的兜底值
|
|
29
29
|
const PRICING = {
|
|
30
30
|
'gpt-4o': { input: 2.5, output: 10 },
|
|
31
31
|
'gpt-4o-2024-11-20': { input: 2.5, output: 10 },
|
|
@@ -142,61 +142,33 @@ function resolveCodexTarget(baseUrl = '', requestPath = '') {
|
|
|
142
142
|
* 计算请求成本
|
|
143
143
|
*/
|
|
144
144
|
function calculateCost(model, tokens) {
|
|
145
|
-
let
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 非 Claude 模型,使用 PRICING 对象(OpenAI 等)
|
|
169
|
-
pricing = PRICING[model];
|
|
170
|
-
|
|
171
|
-
// 如果没有精确匹配,尝试模糊匹配
|
|
172
|
-
if (!pricing) {
|
|
173
|
-
const modelLower = model.toLowerCase();
|
|
174
|
-
if (modelLower.includes('gpt-4o-mini')) {
|
|
175
|
-
pricing = PRICING['gpt-4o-mini'];
|
|
176
|
-
} else if (modelLower.includes('gpt-4o')) {
|
|
177
|
-
pricing = PRICING['gpt-4o'];
|
|
178
|
-
} else if (modelLower.includes('gpt-4')) {
|
|
179
|
-
pricing = PRICING['gpt-4'];
|
|
180
|
-
} else if (modelLower.includes('gpt-3.5')) {
|
|
181
|
-
pricing = PRICING['gpt-3.5-turbo'];
|
|
182
|
-
} else if (modelLower.includes('o1-mini')) {
|
|
183
|
-
pricing = PRICING['o1-mini'];
|
|
184
|
-
} else if (modelLower.includes('o1-pro')) {
|
|
185
|
-
pricing = PRICING['o1-pro'];
|
|
186
|
-
} else if (modelLower.includes('o1')) {
|
|
187
|
-
pricing = PRICING['o1'];
|
|
188
|
-
} else if (modelLower.includes('o3-mini')) {
|
|
189
|
-
pricing = PRICING['o3-mini'];
|
|
190
|
-
} else if (modelLower.includes('o3')) {
|
|
191
|
-
pricing = PRICING['o3'];
|
|
192
|
-
} else if (modelLower.includes('o4-mini')) {
|
|
193
|
-
pricing = PRICING['o4-mini'];
|
|
194
|
-
}
|
|
145
|
+
let fallbackPricing = PRICING[model];
|
|
146
|
+
if (!fallbackPricing) {
|
|
147
|
+
const modelLower = String(model || '').toLowerCase();
|
|
148
|
+
if (modelLower.includes('gpt-4o-mini')) {
|
|
149
|
+
fallbackPricing = PRICING['gpt-4o-mini'];
|
|
150
|
+
} else if (modelLower.includes('gpt-4o')) {
|
|
151
|
+
fallbackPricing = PRICING['gpt-4o'];
|
|
152
|
+
} else if (modelLower.includes('gpt-4')) {
|
|
153
|
+
fallbackPricing = PRICING['gpt-4'];
|
|
154
|
+
} else if (modelLower.includes('gpt-3.5')) {
|
|
155
|
+
fallbackPricing = PRICING['gpt-3.5-turbo'];
|
|
156
|
+
} else if (modelLower.includes('o1-mini')) {
|
|
157
|
+
fallbackPricing = PRICING['o1-mini'];
|
|
158
|
+
} else if (modelLower.includes('o1-pro')) {
|
|
159
|
+
fallbackPricing = PRICING['o1-pro'];
|
|
160
|
+
} else if (modelLower.includes('o1')) {
|
|
161
|
+
fallbackPricing = PRICING['o1'];
|
|
162
|
+
} else if (modelLower.includes('o3-mini')) {
|
|
163
|
+
fallbackPricing = PRICING['o3-mini'];
|
|
164
|
+
} else if (modelLower.includes('o3')) {
|
|
165
|
+
fallbackPricing = PRICING['o3'];
|
|
166
|
+
} else if (modelLower.includes('o4-mini')) {
|
|
167
|
+
fallbackPricing = PRICING['o4-mini'];
|
|
195
168
|
}
|
|
196
169
|
}
|
|
197
170
|
|
|
198
|
-
|
|
199
|
-
pricing = resolvePricing('codex', pricing, CODEX_BASE_PRICING);
|
|
171
|
+
const pricing = resolveModelPricing('codex', model, fallbackPricing, CODEX_BASE_PRICING);
|
|
200
172
|
const inputRate = typeof pricing.input === 'number' ? pricing.input : CODEX_BASE_PRICING.input;
|
|
201
173
|
const outputRate = typeof pricing.output === 'number' ? pricing.output : CODEX_BASE_PRICING.output;
|
|
202
174
|
|
|
@@ -402,14 +374,15 @@ async function startCodexProxyServer(options = {}) {
|
|
|
402
374
|
totalTokens: 0,
|
|
403
375
|
model: ''
|
|
404
376
|
};
|
|
377
|
+
const parsedStream = createDecodedStream(proxyRes);
|
|
405
378
|
|
|
406
|
-
|
|
379
|
+
parsedStream.on('data', (chunk) => {
|
|
407
380
|
// 如果响应已关闭,停止处理
|
|
408
381
|
if (isResponseClosed) {
|
|
409
382
|
return;
|
|
410
383
|
}
|
|
411
384
|
|
|
412
|
-
buffer += chunk.toString();
|
|
385
|
+
buffer += chunk.toString('utf8');
|
|
413
386
|
|
|
414
387
|
// 检查是否是 SSE 流
|
|
415
388
|
if (proxyRes.headers['content-type']?.includes('text/event-stream')) {
|
|
@@ -475,7 +448,7 @@ async function startCodexProxyServer(options = {}) {
|
|
|
475
448
|
}
|
|
476
449
|
});
|
|
477
450
|
|
|
478
|
-
|
|
451
|
+
parsedStream.on('end', () => {
|
|
479
452
|
// 如果不是流式响应,尝试从完整响应中解析
|
|
480
453
|
if (!proxyRes.headers['content-type']?.includes('text/event-stream')) {
|
|
481
454
|
try {
|
|
@@ -558,7 +531,7 @@ async function startCodexProxyServer(options = {}) {
|
|
|
558
531
|
}
|
|
559
532
|
});
|
|
560
533
|
|
|
561
|
-
|
|
534
|
+
parsedStream.on('error', (err) => {
|
|
562
535
|
// 忽略代理响应错误(可能是网络问题)
|
|
563
536
|
if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
|
|
564
537
|
console.error('Proxy response error:', err);
|
|
@@ -7,9 +7,10 @@ const { allocateChannel, releaseChannel, getSchedulerState } = require('./servic
|
|
|
7
7
|
const { recordSuccess, recordFailure } = require('./services/channel-health');
|
|
8
8
|
const { loadConfig } = require('../config/loader');
|
|
9
9
|
const DEFAULT_CONFIG = require('../config/default');
|
|
10
|
-
const {
|
|
10
|
+
const { resolveModelPricing } = require('./utils/pricing');
|
|
11
11
|
const { recordRequest: recordGeminiRequest } = require('./services/gemini-statistics-service');
|
|
12
12
|
const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
|
|
13
|
+
const { createDecodedStream } = require('./services/response-decoder');
|
|
13
14
|
const { getEffectiveApiKey } = require('./services/gemini-channels');
|
|
14
15
|
|
|
15
16
|
let proxyServer = null;
|
|
@@ -24,6 +25,7 @@ const requestMetadata = new Map();
|
|
|
24
25
|
const printedGeminiRedirectCache = new Map();
|
|
25
26
|
|
|
26
27
|
// Gemini 模型定价(每百万 tokens 的价格,单位:美元)
|
|
28
|
+
// 作为 model-metadata 未覆盖时的兜底值
|
|
27
29
|
const PRICING = {
|
|
28
30
|
'gemini-2.5-pro': { input: 1.25, output: 5 },
|
|
29
31
|
'gemini-2.5-flash': { input: 0.075, output: 0.3 },
|
|
@@ -78,33 +80,33 @@ function redirectModel(originalModel, channel) {
|
|
|
78
80
|
*/
|
|
79
81
|
function calculateCost(model, tokens) {
|
|
80
82
|
// 尝试精确匹配
|
|
81
|
-
let
|
|
83
|
+
let fallbackPricing = PRICING[model];
|
|
82
84
|
|
|
83
85
|
// 如果没有精确匹配,尝试模糊匹配
|
|
84
|
-
if (!
|
|
85
|
-
const modelLower = model.toLowerCase();
|
|
86
|
+
if (!fallbackPricing) {
|
|
87
|
+
const modelLower = String(model || '').toLowerCase();
|
|
86
88
|
if (modelLower.includes('gemini-2.5-pro')) {
|
|
87
|
-
|
|
89
|
+
fallbackPricing = PRICING['gemini-2.5-pro'];
|
|
88
90
|
} else if (modelLower.includes('gemini-2.5-flash')) {
|
|
89
|
-
|
|
91
|
+
fallbackPricing = PRICING['gemini-2.5-flash'];
|
|
90
92
|
} else if (modelLower.includes('gemini-2.0-flash-thinking')) {
|
|
91
|
-
|
|
93
|
+
fallbackPricing = PRICING['gemini-2.0-flash-thinking-exp-1219'];
|
|
92
94
|
} else if (modelLower.includes('gemini-2.0-flash')) {
|
|
93
|
-
|
|
95
|
+
fallbackPricing = PRICING['gemini-2.0-flash-exp'];
|
|
94
96
|
} else if (modelLower.includes('gemini-1.5-pro')) {
|
|
95
|
-
|
|
97
|
+
fallbackPricing = PRICING['gemini-1.5-pro'];
|
|
96
98
|
} else if (modelLower.includes('gemini-1.5-flash-8b')) {
|
|
97
|
-
|
|
99
|
+
fallbackPricing = PRICING['gemini-1.5-flash-8b'];
|
|
98
100
|
} else if (modelLower.includes('gemini-1.5-flash')) {
|
|
99
|
-
|
|
101
|
+
fallbackPricing = PRICING['gemini-1.5-flash'];
|
|
100
102
|
} else if (modelLower.includes('gemini-1.0-pro')) {
|
|
101
|
-
|
|
103
|
+
fallbackPricing = PRICING['gemini-1.0-pro'];
|
|
102
104
|
} else if (modelLower.includes('gemini-pro')) {
|
|
103
|
-
|
|
105
|
+
fallbackPricing = PRICING['gemini-pro'];
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
pricing =
|
|
109
|
+
const pricing = resolveModelPricing('gemini', model, fallbackPricing, GEMINI_BASE_PRICING);
|
|
108
110
|
const inputRate = typeof pricing.input === 'number' ? pricing.input : GEMINI_BASE_PRICING.input;
|
|
109
111
|
const outputRate = typeof pricing.output === 'number' ? pricing.output : GEMINI_BASE_PRICING.output;
|
|
110
112
|
|
|
@@ -289,14 +291,15 @@ async function startGeminiProxyServer(options = {}) {
|
|
|
289
291
|
totalTokens: 0,
|
|
290
292
|
model: ''
|
|
291
293
|
};
|
|
294
|
+
const parsedStream = createDecodedStream(proxyRes);
|
|
292
295
|
|
|
293
|
-
|
|
296
|
+
parsedStream.on('data', (chunk) => {
|
|
294
297
|
// 如果响应已关闭,停止处理
|
|
295
298
|
if (isResponseClosed) {
|
|
296
299
|
return;
|
|
297
300
|
}
|
|
298
301
|
|
|
299
|
-
buffer += chunk.toString();
|
|
302
|
+
buffer += chunk.toString('utf8');
|
|
300
303
|
|
|
301
304
|
// 检查是否是 SSE 流
|
|
302
305
|
if (proxyRes.headers['content-type']?.includes('text/event-stream')) {
|
|
@@ -360,7 +363,7 @@ async function startGeminiProxyServer(options = {}) {
|
|
|
360
363
|
}
|
|
361
364
|
});
|
|
362
365
|
|
|
363
|
-
|
|
366
|
+
parsedStream.on('end', () => {
|
|
364
367
|
// 如果不是流式响应,尝试从完整响应中解析
|
|
365
368
|
if (!proxyRes.headers['content-type']?.includes('text/event-stream')) {
|
|
366
369
|
try {
|
|
@@ -467,7 +470,7 @@ async function startGeminiProxyServer(options = {}) {
|
|
|
467
470
|
}
|
|
468
471
|
});
|
|
469
472
|
|
|
470
|
-
|
|
473
|
+
parsedStream.on('error', (err) => {
|
|
471
474
|
// 忽略代理响应错误(可能是网络问题)
|
|
472
475
|
if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
|
|
473
476
|
console.error('Proxy response error:', err);
|
package/src/server/index.js
CHANGED
|
@@ -15,7 +15,7 @@ const { setProxyConfig: setOpenCodeProxyConfig } = require('./services/opencode-
|
|
|
15
15
|
const { startProxyServer } = require('./proxy-server');
|
|
16
16
|
const { startCodexProxyServer } = require('./codex-proxy-server');
|
|
17
17
|
const { startGeminiProxyServer } = require('./gemini-proxy-server');
|
|
18
|
-
const { startOpenCodeProxyServer } = require('./opencode-proxy-server');
|
|
18
|
+
const { startOpenCodeProxyServer, collectProxyModelList } = require('./opencode-proxy-server');
|
|
19
19
|
const { createRemoteMutationGuard, createRemoteRouteGuard } = require('./services/network-access');
|
|
20
20
|
|
|
21
21
|
function isInteractivePortConflictMode(options = {}) {
|
|
@@ -158,9 +158,6 @@ async function startServer(port, host = '127.0.0.1', options = {}) {
|
|
|
158
158
|
app.use('/api/opencode/proxy', require('./api/opencode-proxy'));
|
|
159
159
|
app.use('/api/opencode/statistics', require('./api/opencode-statistics'));
|
|
160
160
|
|
|
161
|
-
// 会话格式转换 API
|
|
162
|
-
app.use('/api/convert', require('./api/convert'));
|
|
163
|
-
|
|
164
161
|
app.use('/api/aliases', require('./api/aliases')());
|
|
165
162
|
app.use('/api/favorites', require('./api/favorites'));
|
|
166
163
|
app.use('/api/ui-config', require('./api/ui-config'));
|
|
@@ -269,8 +266,8 @@ async function startServer(port, host = '127.0.0.1', options = {}) {
|
|
|
269
266
|
// 自动恢复代理状态
|
|
270
267
|
autoRestoreProxies();
|
|
271
268
|
|
|
272
|
-
//
|
|
273
|
-
performStartupHealthCheck();
|
|
269
|
+
// 延迟执行健康检查,避免阻塞启动
|
|
270
|
+
setTimeout(() => performStartupHealthCheck(), 2000);
|
|
274
271
|
|
|
275
272
|
return server;
|
|
276
273
|
}
|
|
@@ -349,7 +346,7 @@ function autoRestoreProxies() {
|
|
|
349
346
|
console.log(chalk.cyan('\n🔄 检测到 OpenCode 代理状态文件,正在自动启动...'));
|
|
350
347
|
const opencodeProxyPort = config.ports?.opencodeProxy || 20091;
|
|
351
348
|
startOpenCodeProxyServer(opencodeProxyPort)
|
|
352
|
-
.then((result) => {
|
|
349
|
+
.then(async (result) => {
|
|
353
350
|
if (result.success) {
|
|
354
351
|
console.log(chalk.green(`✅ OpenCode 代理已自动启动,端口: ${result.port}`));
|
|
355
352
|
try {
|
|
@@ -365,6 +362,15 @@ function autoRestoreProxies() {
|
|
|
365
362
|
}
|
|
366
363
|
});
|
|
367
364
|
});
|
|
365
|
+
const detectedModels = await collectProxyModelList(enabledChs, { useCacheOnly: true });
|
|
366
|
+
if (Array.isArray(detectedModels)) {
|
|
367
|
+
detectedModels.forEach((m) => {
|
|
368
|
+
if (typeof m === 'string' && m.trim() && !seen.has(m.trim().toLowerCase())) {
|
|
369
|
+
seen.add(m.trim().toLowerCase());
|
|
370
|
+
allModels.push(m.trim());
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}
|
|
368
374
|
const firstChannel = enabledChs[0];
|
|
369
375
|
const activeModel = firstChannel && (firstChannel.model || firstChannel.speedTestModel) || null;
|
|
370
376
|
const cfgResult = setOpenCodeProxyConfig(result.port, { model: activeModel, models: allModels });
|