@tokenaut/opentoken 1.4.9 → 1.4.10
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 +33 -0
- package/package.json +1 -1
- package/src/cli.js +60 -0
- package/src/test-connection.js +146 -0
- package/src/tools/atomcode.js +35 -1
- package/src/tools/claude.js +42 -4
- package/src/tools/claude_desktop.js +36 -3
- package/src/tools/codex.js +42 -4
- package/src/tools/hermes.js +35 -1
- package/src/tools/openclaw.js +36 -2
- package/src/tools/opencode.js +36 -2
package/README.md
CHANGED
|
@@ -146,6 +146,39 @@ opentoken cx -k <api_key> -u https://gw.opentoken.io/v1 -m <model_id>
|
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
149
|
+
## 连接测试
|
|
150
|
+
|
|
151
|
+
验证各工具的 API Key、Base URL、模型是否配置正确,发送最小请求检测连通性:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
opentoken cc test
|
|
155
|
+
opentoken cdt test
|
|
156
|
+
opentoken ac test
|
|
157
|
+
opentoken hm test
|
|
158
|
+
opentoken oc test
|
|
159
|
+
opentoken od test
|
|
160
|
+
opentoken cx test
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 查看可用模型
|
|
166
|
+
|
|
167
|
+
查看默认节点所有可用模型(自动使用已配置的 API Key):
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
opentoken models
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
使用指定 Key 查询:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
opentoken models -k <api_key>
|
|
177
|
+
opentoken models --key <api_key>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
149
182
|
## 环境
|
|
150
183
|
|
|
151
184
|
Node.js >= 14 · MIT
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -12,6 +12,8 @@ const openclaw = require('./tools/openclaw');
|
|
|
12
12
|
const opencode = require('./tools/opencode');
|
|
13
13
|
const codex = require('./tools/codex');
|
|
14
14
|
const { DEFAULT_BASE_URL } = require('./models');
|
|
15
|
+
const { fetchModelsForBaseUrl } = require('./fetch-models');
|
|
16
|
+
const { getCurrentConfig } = require('./config');
|
|
15
17
|
|
|
16
18
|
function isCcCommand(tool) {
|
|
17
19
|
return tool === 'cc' || tool === 'claude';
|
|
@@ -51,6 +53,8 @@ function printHelp() {
|
|
|
51
53
|
console.log(chalk.bold('常用:'));
|
|
52
54
|
console.log(' opentoken help | --help | -h 显示本帮助');
|
|
53
55
|
console.log(' opentoken version | --version | -v | -V 显示版本号');
|
|
56
|
+
console.log(' opentoken models 查看默认节点所有可用模型');
|
|
57
|
+
console.log(' opentoken models -k <apikey> 使用指定 Key 查看模型');
|
|
54
58
|
console.log('');
|
|
55
59
|
console.log(chalk.bold('用法:'));
|
|
56
60
|
console.log(' opentoken 进入主菜单');
|
|
@@ -97,6 +101,15 @@ function printHelp() {
|
|
|
97
101
|
console.log(' opentoken cdt --url <baseurl> 设置 Base URL(inferenceGatewayBaseUrl)');
|
|
98
102
|
console.log(' opentoken cdt -k <k> -u <u> 一键设置 Key 与 URL');
|
|
99
103
|
console.log('');
|
|
104
|
+
console.log(chalk.bold('连接测试:'));
|
|
105
|
+
console.log(' opentoken cc test 测试 Claude Code 连接');
|
|
106
|
+
console.log(' opentoken cdt test 测试 Claude Desktop 连接');
|
|
107
|
+
console.log(' opentoken ac test 测试 Atomcode 连接');
|
|
108
|
+
console.log(' opentoken hm test 测试 Hermes 连接');
|
|
109
|
+
console.log(' opentoken oc test 测试 OpenClaw 连接');
|
|
110
|
+
console.log(' opentoken od test 测试 OpenCode 连接');
|
|
111
|
+
console.log(' opentoken cx test 测试 Codex 连接');
|
|
112
|
+
console.log('');
|
|
100
113
|
console.log(chalk.bold('快捷别名(--key / -k,--url / -u,--model / -m)'));
|
|
101
114
|
console.log('');
|
|
102
115
|
console.log(chalk.bold('示例:'));
|
|
@@ -120,6 +133,7 @@ function parseArgs(argv) {
|
|
|
120
133
|
const args = argv.slice(2);
|
|
121
134
|
const result = {
|
|
122
135
|
tool: null,
|
|
136
|
+
subcommand: null,
|
|
123
137
|
key: null,
|
|
124
138
|
url: null,
|
|
125
139
|
model: null,
|
|
@@ -134,6 +148,11 @@ function parseArgs(argv) {
|
|
|
134
148
|
i = 1;
|
|
135
149
|
}
|
|
136
150
|
|
|
151
|
+
if (args[i] && !args[i].startsWith('-')) {
|
|
152
|
+
result.subcommand = args[i].toLowerCase();
|
|
153
|
+
i++;
|
|
154
|
+
}
|
|
155
|
+
|
|
137
156
|
for (; i < args.length; i++) {
|
|
138
157
|
const a = args[i];
|
|
139
158
|
const next = args[i + 1];
|
|
@@ -228,6 +247,47 @@ async function run() {
|
|
|
228
247
|
return;
|
|
229
248
|
}
|
|
230
249
|
|
|
250
|
+
if (args.tool === 'models') {
|
|
251
|
+
const apiKey = args.key || getCurrentConfig().apiKey;
|
|
252
|
+
const maskKey = (k) => {
|
|
253
|
+
if (!k || k.length < 8) return k || '';
|
|
254
|
+
return k.slice(0, 6) + '****' + k.slice(-4);
|
|
255
|
+
};
|
|
256
|
+
console.log('');
|
|
257
|
+
console.log(chalk.bold(chalk.cyan('可用模型列表')) + chalk.gray('(' + DEFAULT_BASE_URL + ')'));
|
|
258
|
+
console.log('');
|
|
259
|
+
if (!apiKey) {
|
|
260
|
+
console.log(chalk.red(' ✗ 未配置 API Key,请使用 opentoken models -k <apikey> 或先配置 Key'));
|
|
261
|
+
console.log('');
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const result = await fetchModelsForBaseUrl(DEFAULT_BASE_URL, apiKey);
|
|
265
|
+
if (result.ok && result.models.length > 0) {
|
|
266
|
+
result.models.forEach((id) => console.log(' ' + id));
|
|
267
|
+
console.log('');
|
|
268
|
+
console.log(chalk.gray('共 ' + result.models.length + ' 个模型'));
|
|
269
|
+
} else {
|
|
270
|
+
console.log(chalk.red(' ✗ 获取失败:' + (result.error || '未知错误')));
|
|
271
|
+
}
|
|
272
|
+
console.log(chalk.gray('API Key : ' + maskKey(apiKey)));
|
|
273
|
+
console.log('');
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (args.subcommand === 'test') {
|
|
278
|
+
clearScreen();
|
|
279
|
+
printLogo();
|
|
280
|
+
if (isCcCommand(args.tool)) { await claude.test(); return; }
|
|
281
|
+
if (isClaudeDesktopCommand(args.tool)) { await claudeDesktop.test(); return; }
|
|
282
|
+
if (isAtomcodeCommand(args.tool)) { await atomcode.test(); return; }
|
|
283
|
+
if (isHermesCommand(args.tool)) { await hermes.test(); return; }
|
|
284
|
+
if (isOpenclawCommand(args.tool)) { await openclaw.test(); return; }
|
|
285
|
+
if (isOpencodeCommand(args.tool)) { await opencode.test(); return; }
|
|
286
|
+
if (isCodexCommand(args.tool)) { await codex.test(); return; }
|
|
287
|
+
console.log(chalk.red('未知工具:' + args.tool));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
231
291
|
if (isCcCommand(args.tool) && (args.key || args.url || args.model)) {
|
|
232
292
|
clearScreen();
|
|
233
293
|
printLogo();
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const http = require('http');
|
|
5
|
+
const { URL } = require('url');
|
|
6
|
+
|
|
7
|
+
const TIMEOUT_MS = 30000;
|
|
8
|
+
|
|
9
|
+
function request(method, urlStr, headers, body) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const parsed = new URL(urlStr);
|
|
12
|
+
const mod = parsed.protocol === 'https:' ? https : http;
|
|
13
|
+
const opts = {
|
|
14
|
+
method,
|
|
15
|
+
hostname: parsed.hostname,
|
|
16
|
+
port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
|
|
17
|
+
path: parsed.pathname + parsed.search,
|
|
18
|
+
headers: {
|
|
19
|
+
...headers,
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
},
|
|
22
|
+
timeout: TIMEOUT_MS,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const req = mod.request(opts, (res) => {
|
|
26
|
+
let data = '';
|
|
27
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
28
|
+
res.on('end', () => {
|
|
29
|
+
resolve({ statusCode: res.statusCode, body: data });
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
req.on('error', (err) => {
|
|
34
|
+
reject(err);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
req.on('timeout', () => {
|
|
38
|
+
req.destroy();
|
|
39
|
+
reject(new Error('请求超时(' + TIMEOUT_MS / 1000 + '秒)'));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (body) {
|
|
43
|
+
req.write(JSON.stringify(body));
|
|
44
|
+
}
|
|
45
|
+
req.end();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function testAnthropic({ baseUrl, apiKey, model }) {
|
|
50
|
+
const start = Date.now();
|
|
51
|
+
try {
|
|
52
|
+
const url = baseUrl.replace(/\/+$/, '') + '/v1/messages';
|
|
53
|
+
const headers = {
|
|
54
|
+
'x-api-key': apiKey,
|
|
55
|
+
'anthropic-version': '2023-06-01',
|
|
56
|
+
};
|
|
57
|
+
const body = {
|
|
58
|
+
model,
|
|
59
|
+
max_tokens: 1,
|
|
60
|
+
messages: [{ role: 'user', content: 'hi' }],
|
|
61
|
+
};
|
|
62
|
+
const res = await request('POST', url, headers, body);
|
|
63
|
+
const latency = Date.now() - start;
|
|
64
|
+
|
|
65
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
66
|
+
return { ok: true, latency_ms: latency };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let errMsg = 'HTTP ' + res.statusCode;
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(res.body);
|
|
72
|
+
if (parsed.error && parsed.error.message) {
|
|
73
|
+
errMsg += ' — ' + parsed.error.message;
|
|
74
|
+
}
|
|
75
|
+
} catch (_) {}
|
|
76
|
+
return { ok: false, error: errMsg };
|
|
77
|
+
} catch (err) {
|
|
78
|
+
return { ok: false, error: err.message };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function testOpenAI({ baseUrl, apiKey, model }) {
|
|
83
|
+
const start = Date.now();
|
|
84
|
+
try {
|
|
85
|
+
const url = baseUrl.replace(/\/+$/, '') + '/chat/completions';
|
|
86
|
+
const headers = {
|
|
87
|
+
'Authorization': 'Bearer ' + apiKey,
|
|
88
|
+
};
|
|
89
|
+
const body = {
|
|
90
|
+
model,
|
|
91
|
+
max_tokens: 1,
|
|
92
|
+
messages: [{ role: 'user', content: 'hi' }],
|
|
93
|
+
};
|
|
94
|
+
const res = await request('POST', url, headers, body);
|
|
95
|
+
const latency = Date.now() - start;
|
|
96
|
+
|
|
97
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
98
|
+
return { ok: true, latency_ms: latency };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let errMsg = 'HTTP ' + res.statusCode;
|
|
102
|
+
try {
|
|
103
|
+
const parsed = JSON.parse(res.body);
|
|
104
|
+
if (parsed.error && parsed.error.message) {
|
|
105
|
+
errMsg += ' — ' + parsed.error.message;
|
|
106
|
+
}
|
|
107
|
+
} catch (_) {}
|
|
108
|
+
return { ok: false, error: errMsg };
|
|
109
|
+
} catch (err) {
|
|
110
|
+
return { ok: false, error: err.message };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function testOpenAIResponses({ baseUrl, apiKey, model }) {
|
|
115
|
+
const start = Date.now();
|
|
116
|
+
try {
|
|
117
|
+
const url = baseUrl.replace(/\/+$/, '') + '/responses';
|
|
118
|
+
const headers = {
|
|
119
|
+
'Authorization': 'Bearer ' + apiKey,
|
|
120
|
+
};
|
|
121
|
+
const body = {
|
|
122
|
+
model,
|
|
123
|
+
input: 'hi',
|
|
124
|
+
max_output_tokens: 1,
|
|
125
|
+
};
|
|
126
|
+
const res = await request('POST', url, headers, body);
|
|
127
|
+
const latency = Date.now() - start;
|
|
128
|
+
|
|
129
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
130
|
+
return { ok: true, latency_ms: latency };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let errMsg = 'HTTP ' + res.statusCode;
|
|
134
|
+
try {
|
|
135
|
+
const parsed = JSON.parse(res.body);
|
|
136
|
+
if (parsed.error && parsed.error.message) {
|
|
137
|
+
errMsg += ' — ' + parsed.error.message;
|
|
138
|
+
}
|
|
139
|
+
} catch (_) {}
|
|
140
|
+
return { ok: false, error: errMsg };
|
|
141
|
+
} catch (err) {
|
|
142
|
+
return { ok: false, error: err.message };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = { testAnthropic, testOpenAI, testOpenAIResponses };
|
package/src/tools/atomcode.js
CHANGED
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
} = require('../atomcode-config');
|
|
12
12
|
const { printLogo } = require('../logo');
|
|
13
13
|
const { clearScreen } = require('../screen');
|
|
14
|
+
const { testOpenAI } = require('../test-connection');
|
|
14
15
|
|
|
15
16
|
let pendingConfig = { apiKey: null, model: null };
|
|
16
17
|
|
|
@@ -252,4 +253,37 @@ function quickSet({ key, model }) {
|
|
|
252
253
|
return true;
|
|
253
254
|
}
|
|
254
255
|
|
|
255
|
-
|
|
256
|
+
async function test() {
|
|
257
|
+
const config = getCurrentAtomcodeConfig();
|
|
258
|
+
|
|
259
|
+
if (!config.apiKey) {
|
|
260
|
+
console.log(chalk.red(' ✗ 请先配置 API Key'));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (!config.model) {
|
|
264
|
+
console.log(chalk.red(' ✗ 请先配置模型'));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
console.log('');
|
|
269
|
+
console.log(chalk.bold(chalk.cyan('正在测试 Atomcode 连接...')));
|
|
270
|
+
console.log(chalk.gray(' Base URL : ') + ATOMCODE_OPENTOKEN_BASE_URL);
|
|
271
|
+
console.log(chalk.gray(' 模型 : ') + config.model);
|
|
272
|
+
console.log(chalk.gray(' API Key : ') + maskApiKey(config.apiKey));
|
|
273
|
+
console.log('');
|
|
274
|
+
|
|
275
|
+
const result = await testOpenAI({
|
|
276
|
+
baseUrl: ATOMCODE_OPENTOKEN_BASE_URL,
|
|
277
|
+
apiKey: config.apiKey,
|
|
278
|
+
model: config.model,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (result.ok) {
|
|
282
|
+
console.log(chalk.green(' ✓ 连接成功!延迟 ' + result.latency_ms + 'ms'));
|
|
283
|
+
} else {
|
|
284
|
+
console.log(chalk.red(' ✗ 连接失败:' + result.error));
|
|
285
|
+
}
|
|
286
|
+
console.log('');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
module.exports = { run, quickSet, test };
|
package/src/tools/claude.js
CHANGED
|
@@ -7,6 +7,7 @@ const { fetchModelsForBaseUrl } = require('../fetch-models');
|
|
|
7
7
|
const { getCurrentConfig, applyConfig } = require('../config');
|
|
8
8
|
const { printLogo } = require('../logo');
|
|
9
9
|
const { clearScreen } = require('../screen');
|
|
10
|
+
const { testAnthropic } = require('../test-connection');
|
|
10
11
|
|
|
11
12
|
let pendingConfig = { apiKey: null, baseUrl: null, model: null };
|
|
12
13
|
|
|
@@ -294,12 +295,49 @@ function quickSet({ key, url, model }) {
|
|
|
294
295
|
|
|
295
296
|
console.log('');
|
|
296
297
|
console.log(chalk.bold(chalk.cyan('Claude Code 配置已更新:')));
|
|
297
|
-
if (
|
|
298
|
-
console.log(chalk.green(' ✓ Base URL : ') +
|
|
299
|
-
console.log(chalk.green(' ✓ 模型 : ') +
|
|
298
|
+
if (toWrite.apiKey) console.log(chalk.green(' ✓ API Key : ') + maskApiKey(toWrite.apiKey));
|
|
299
|
+
if (toWrite.baseUrl) console.log(chalk.green(' ✓ Base URL : ') + toWrite.baseUrl);
|
|
300
|
+
if (toWrite.model) console.log(chalk.green(' ✓ 模型 : ') + toWrite.model);
|
|
300
301
|
console.log('');
|
|
301
302
|
|
|
302
303
|
return true;
|
|
303
304
|
}
|
|
304
305
|
|
|
305
|
-
|
|
306
|
+
async function test() {
|
|
307
|
+
const config = getCurrentConfig();
|
|
308
|
+
|
|
309
|
+
if (!config.apiKey) {
|
|
310
|
+
console.log(chalk.red(' ✗ 请先配置 API Key'));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (!config.baseUrl) {
|
|
314
|
+
console.log(chalk.red(' ✗ 请先配置 Base URL'));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (!config.model) {
|
|
318
|
+
console.log(chalk.red(' ✗ 请先配置模型'));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
console.log('');
|
|
323
|
+
console.log(chalk.bold(chalk.cyan('正在测试 Claude Code 连接...')));
|
|
324
|
+
console.log(chalk.gray(' Base URL : ') + config.baseUrl);
|
|
325
|
+
console.log(chalk.gray(' 模型 : ') + config.model);
|
|
326
|
+
console.log(chalk.gray(' API Key : ') + maskApiKey(config.apiKey));
|
|
327
|
+
console.log('');
|
|
328
|
+
|
|
329
|
+
const result = await testAnthropic({
|
|
330
|
+
baseUrl: config.baseUrl,
|
|
331
|
+
apiKey: config.apiKey,
|
|
332
|
+
model: config.model,
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
if (result.ok) {
|
|
336
|
+
console.log(chalk.green(' ✓ 连接成功!延迟 ' + result.latency_ms + 'ms'));
|
|
337
|
+
} else {
|
|
338
|
+
console.log(chalk.red(' ✗ 连接失败:' + result.error));
|
|
339
|
+
}
|
|
340
|
+
console.log('');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
module.exports = { run, quickSet, test };
|
|
@@ -6,6 +6,7 @@ const { API_NODES, DEFAULT_BASE_URL } = require('../models');
|
|
|
6
6
|
const { getCurrentConfig, applyConfig } = require('../claude-desktop-config');
|
|
7
7
|
const { printLogo } = require('../logo');
|
|
8
8
|
const { clearScreen } = require('../screen');
|
|
9
|
+
const { testAnthropic } = require('../test-connection');
|
|
9
10
|
|
|
10
11
|
let pendingConfig = { apiKey: null, baseUrl: null };
|
|
11
12
|
|
|
@@ -177,11 +178,43 @@ function quickSet({ key, url }) {
|
|
|
177
178
|
|
|
178
179
|
console.log('');
|
|
179
180
|
console.log(chalk.bold(chalk.cyan('Claude Desktop 配置已更新:')));
|
|
180
|
-
if (
|
|
181
|
-
console.log(chalk.green(' ✓ Base URL : ') +
|
|
181
|
+
if (toWrite.apiKey) console.log(chalk.green(' ✓ API Key : ') + maskApiKey(toWrite.apiKey));
|
|
182
|
+
if (toWrite.baseUrl) console.log(chalk.green(' ✓ Base URL : ') + toWrite.baseUrl);
|
|
182
183
|
console.log('');
|
|
183
184
|
|
|
184
185
|
return true;
|
|
185
186
|
}
|
|
186
187
|
|
|
187
|
-
|
|
188
|
+
async function test() {
|
|
189
|
+
const config = getCurrentConfig();
|
|
190
|
+
|
|
191
|
+
if (!config.apiKey) {
|
|
192
|
+
console.log(chalk.red(' ✗ 请先配置 API Key'));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (!config.baseUrl) {
|
|
196
|
+
console.log(chalk.red(' ✗ 请先配置 Base URL'));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
console.log('');
|
|
201
|
+
console.log(chalk.bold(chalk.cyan('正在测试 Claude Desktop 连接...')));
|
|
202
|
+
console.log(chalk.gray(' Base URL : ') + config.baseUrl);
|
|
203
|
+
console.log(chalk.gray(' API Key : ') + maskApiKey(config.apiKey));
|
|
204
|
+
console.log('');
|
|
205
|
+
|
|
206
|
+
const result = await testAnthropic({
|
|
207
|
+
baseUrl: config.baseUrl,
|
|
208
|
+
apiKey: config.apiKey,
|
|
209
|
+
model: 'claude-sonnet-4-6',
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (result.ok) {
|
|
213
|
+
console.log(chalk.green(' ✓ 连接成功!延迟 ' + result.latency_ms + 'ms'));
|
|
214
|
+
} else {
|
|
215
|
+
console.log(chalk.red(' ✗ 连接失败:' + result.error));
|
|
216
|
+
}
|
|
217
|
+
console.log('');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
module.exports = { run, quickSet, test };
|
package/src/tools/codex.js
CHANGED
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
} = require('../codex-config');
|
|
13
13
|
const { printLogo } = require('../logo');
|
|
14
14
|
const { clearScreen } = require('../screen');
|
|
15
|
+
const { testOpenAIResponses } = require('../test-connection');
|
|
15
16
|
|
|
16
17
|
let pendingConfig = { apiKey: null, baseUrl: null, model: null, models: null };
|
|
17
18
|
|
|
@@ -312,9 +313,9 @@ async function quickSet({ key, url, model }) {
|
|
|
312
313
|
|
|
313
314
|
console.log('');
|
|
314
315
|
console.log(chalk.bold(chalk.cyan('Codex 配置已更新:')));
|
|
315
|
-
if (
|
|
316
|
-
console.log(chalk.green(' ✓ Base URL : ') +
|
|
317
|
-
console.log(chalk.green(' ✓ 模型 : ') + toWrite.model);
|
|
316
|
+
if (toWrite.apiKey) console.log(chalk.green(' ✓ API Key : ') + maskApiKey(toWrite.apiKey));
|
|
317
|
+
if (toWrite.baseUrl) console.log(chalk.green(' ✓ Base URL : ') + toWrite.baseUrl);
|
|
318
|
+
if (toWrite.model) console.log(chalk.green(' ✓ 模型 : ') + toWrite.model);
|
|
318
319
|
if (toWrite.models) {
|
|
319
320
|
console.log(chalk.gray(' (包含 ' + toWrite.models.length + ' 个 responses 模型)'));
|
|
320
321
|
}
|
|
@@ -326,4 +327,41 @@ async function quickSet({ key, url, model }) {
|
|
|
326
327
|
return true;
|
|
327
328
|
}
|
|
328
329
|
|
|
329
|
-
|
|
330
|
+
async function test() {
|
|
331
|
+
const config = getCurrentCodexConfig();
|
|
332
|
+
|
|
333
|
+
if (!config.apiKey) {
|
|
334
|
+
console.log(chalk.red(' ✗ 请先配置 API Key'));
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (!config.baseUrl) {
|
|
338
|
+
console.log(chalk.red(' ✗ 请先配置 Base URL'));
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (!config.model) {
|
|
342
|
+
console.log(chalk.red(' ✗ 请先配置模型'));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log('');
|
|
347
|
+
console.log(chalk.bold(chalk.cyan('正在测试 Codex 连接...')));
|
|
348
|
+
console.log(chalk.gray(' Base URL : ') + config.baseUrl);
|
|
349
|
+
console.log(chalk.gray(' 模型 : ') + config.model);
|
|
350
|
+
console.log(chalk.gray(' API Key : ') + maskApiKey(config.apiKey));
|
|
351
|
+
console.log('');
|
|
352
|
+
|
|
353
|
+
const result = await testOpenAIResponses({
|
|
354
|
+
baseUrl: config.baseUrl,
|
|
355
|
+
apiKey: config.apiKey,
|
|
356
|
+
model: config.model,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
if (result.ok) {
|
|
360
|
+
console.log(chalk.green(' ✓ 连接成功!延迟 ' + result.latency_ms + 'ms'));
|
|
361
|
+
} else {
|
|
362
|
+
console.log(chalk.red(' ✗ 连接失败:' + result.error));
|
|
363
|
+
}
|
|
364
|
+
console.log('');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
module.exports = { run, quickSet, test };
|
package/src/tools/hermes.js
CHANGED
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
} = require('../hermes-config');
|
|
13
13
|
const { printLogo } = require('../logo');
|
|
14
14
|
const { clearScreen } = require('../screen');
|
|
15
|
+
const { testOpenAI } = require('../test-connection');
|
|
15
16
|
|
|
16
17
|
let pendingConfig = { apiKey: null, model: null };
|
|
17
18
|
|
|
@@ -273,4 +274,37 @@ function quickSet({ key, model }) {
|
|
|
273
274
|
return true;
|
|
274
275
|
}
|
|
275
276
|
|
|
276
|
-
|
|
277
|
+
async function test() {
|
|
278
|
+
const config = getCurrentHermesConfig();
|
|
279
|
+
|
|
280
|
+
if (!config.apiKey) {
|
|
281
|
+
console.log(chalk.red(' ✗ 请先配置 API Key'));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (!config.model) {
|
|
285
|
+
console.log(chalk.red(' ✗ 请先配置模型'));
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
console.log('');
|
|
290
|
+
console.log(chalk.bold(chalk.cyan('正在测试 Hermes 连接...')));
|
|
291
|
+
console.log(chalk.gray(' Base URL : ') + HERMES_OPENTOKEN_BASE_URL);
|
|
292
|
+
console.log(chalk.gray(' 模型 : ') + config.model);
|
|
293
|
+
console.log(chalk.gray(' API Key : ') + maskApiKey(config.apiKey));
|
|
294
|
+
console.log('');
|
|
295
|
+
|
|
296
|
+
const result = await testOpenAI({
|
|
297
|
+
baseUrl: HERMES_OPENTOKEN_BASE_URL,
|
|
298
|
+
apiKey: config.apiKey,
|
|
299
|
+
model: config.model,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
if (result.ok) {
|
|
303
|
+
console.log(chalk.green(' ✓ 连接成功!延迟 ' + result.latency_ms + 'ms'));
|
|
304
|
+
} else {
|
|
305
|
+
console.log(chalk.red(' ✗ 连接失败:' + result.error));
|
|
306
|
+
}
|
|
307
|
+
console.log('');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
module.exports = { run, quickSet, test };
|
package/src/tools/openclaw.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
|
-
const { DEFAULT_BASE_URL, OPENCLAW_PROVIDER_KEY, GENERAL_DEFAULT_MODEL } = require('../models');
|
|
5
|
+
const { DEFAULT_BASE_URL, OPENCLAW_PROVIDER_KEY, OPENCLAW_OPENTOKEN_BASE_URL, GENERAL_DEFAULT_MODEL } = require('../models');
|
|
6
6
|
const { fetchModelsForBaseUrl } = require('../fetch-models');
|
|
7
7
|
const {
|
|
8
8
|
OPENCLAW_JSON_PATH,
|
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
} = require('../openclaw-config');
|
|
12
12
|
const { printLogo } = require('../logo');
|
|
13
13
|
const { clearScreen } = require('../screen');
|
|
14
|
+
const { testOpenAI } = require('../test-connection');
|
|
14
15
|
|
|
15
16
|
let pendingConfig = { apiKey: null, model: null };
|
|
16
17
|
|
|
@@ -241,4 +242,37 @@ function quickSet({ key, model }) {
|
|
|
241
242
|
return true;
|
|
242
243
|
}
|
|
243
244
|
|
|
244
|
-
|
|
245
|
+
async function test() {
|
|
246
|
+
const config = getCurrentOpenclawOpentokenConfig();
|
|
247
|
+
|
|
248
|
+
if (!config.apiKey) {
|
|
249
|
+
console.log(chalk.red(' ✗ 请先配置 API Key'));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (!config.model) {
|
|
253
|
+
console.log(chalk.red(' ✗ 请先配置模型'));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
console.log('');
|
|
258
|
+
console.log(chalk.bold(chalk.cyan('正在测试 OpenClaw 连接...')));
|
|
259
|
+
console.log(chalk.gray(' Base URL : ') + OPENCLAW_OPENTOKEN_BASE_URL);
|
|
260
|
+
console.log(chalk.gray(' 模型 : ') + OPENCLAW_PROVIDER_KEY + '/' + config.model);
|
|
261
|
+
console.log(chalk.gray(' API Key : ') + maskApiKey(config.apiKey));
|
|
262
|
+
console.log('');
|
|
263
|
+
|
|
264
|
+
const result = await testOpenAI({
|
|
265
|
+
baseUrl: OPENCLAW_OPENTOKEN_BASE_URL,
|
|
266
|
+
apiKey: config.apiKey,
|
|
267
|
+
model: config.model,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
if (result.ok) {
|
|
271
|
+
console.log(chalk.green(' ✓ 连接成功!延迟 ' + result.latency_ms + 'ms'));
|
|
272
|
+
} else {
|
|
273
|
+
console.log(chalk.red(' ✗ 连接失败:' + result.error));
|
|
274
|
+
}
|
|
275
|
+
console.log('');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
module.exports = { run, quickSet, test };
|
package/src/tools/opencode.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
|
-
const { DEFAULT_BASE_URL, OPENCODE_PROVIDER_KEY, GENERAL_DEFAULT_MODEL } = require('../models');
|
|
5
|
+
const { DEFAULT_BASE_URL, OPENCODE_PROVIDER_KEY, OPENCODE_OPENTOKEN_BASE_URL, GENERAL_DEFAULT_MODEL } = require('../models');
|
|
6
6
|
const { fetchModelsForBaseUrl } = require('../fetch-models');
|
|
7
7
|
const {
|
|
8
8
|
OPENCODE_JSON_PATH,
|
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
} = require('../opencode-config');
|
|
12
12
|
const { printLogo } = require('../logo');
|
|
13
13
|
const { clearScreen } = require('../screen');
|
|
14
|
+
const { testOpenAI } = require('../test-connection');
|
|
14
15
|
|
|
15
16
|
let pendingConfig = { apiKey: null, model: null };
|
|
16
17
|
|
|
@@ -255,4 +256,37 @@ async function quickSet({ key, model }) {
|
|
|
255
256
|
return true;
|
|
256
257
|
}
|
|
257
258
|
|
|
258
|
-
|
|
259
|
+
async function test() {
|
|
260
|
+
const config = getCurrentOpencodeOpentokenConfig();
|
|
261
|
+
|
|
262
|
+
if (!config.apiKey) {
|
|
263
|
+
console.log(chalk.red(' ✗ 请先配置 API Key'));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (!config.model) {
|
|
267
|
+
console.log(chalk.red(' ✗ 请先配置模型'));
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.log('');
|
|
272
|
+
console.log(chalk.bold(chalk.cyan('正在测试 OpenCode 连接...')));
|
|
273
|
+
console.log(chalk.gray(' Base URL : ') + OPENCODE_OPENTOKEN_BASE_URL);
|
|
274
|
+
console.log(chalk.gray(' 模型 : ') + config.model);
|
|
275
|
+
console.log(chalk.gray(' API Key : ') + maskApiKey(config.apiKey));
|
|
276
|
+
console.log('');
|
|
277
|
+
|
|
278
|
+
const result = await testOpenAI({
|
|
279
|
+
baseUrl: OPENCODE_OPENTOKEN_BASE_URL,
|
|
280
|
+
apiKey: config.apiKey,
|
|
281
|
+
model: config.model,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (result.ok) {
|
|
285
|
+
console.log(chalk.green(' ✓ 连接成功!延迟 ' + result.latency_ms + 'ms'));
|
|
286
|
+
} else {
|
|
287
|
+
console.log(chalk.red(' ✗ 连接失败:' + result.error));
|
|
288
|
+
}
|
|
289
|
+
console.log('');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
module.exports = { run, quickSet, test };
|