yymaxapi 1.0.85 → 1.0.87
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/yymaxapi.js +108 -87
- package/package.json +1 -1
package/bin/yymaxapi.js
CHANGED
|
@@ -2025,6 +2025,53 @@ function getAgentModelState(agent) {
|
|
|
2025
2025
|
return { primary, fallbacks };
|
|
2026
2026
|
}
|
|
2027
2027
|
|
|
2028
|
+
function findAgentById(config, agentId) {
|
|
2029
|
+
if (!Array.isArray(config?.agents?.list) || !agentId) return null;
|
|
2030
|
+
return config.agents.list.find(agent => agent && typeof agent === 'object' && agent.id === agentId) || null;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
function resolveOpenClawTestTarget(config, args = {}) {
|
|
2034
|
+
const requestedAgentId = String(args.agent || args['agent-id'] || '').trim();
|
|
2035
|
+
const requestedAgent = requestedAgentId ? findAgentById(config, requestedAgentId) : null;
|
|
2036
|
+
const defaultPrimary = String(config?.agents?.defaults?.model?.primary || '').trim();
|
|
2037
|
+
const defaultFallbacks = Array.isArray(config?.agents?.defaults?.model?.fallbacks)
|
|
2038
|
+
? [...config.agents.defaults.model.fallbacks]
|
|
2039
|
+
: [];
|
|
2040
|
+
|
|
2041
|
+
let primary = defaultPrimary;
|
|
2042
|
+
let fallbacks = defaultFallbacks;
|
|
2043
|
+
let agentId = null;
|
|
2044
|
+
let agentName = '';
|
|
2045
|
+
|
|
2046
|
+
if (requestedAgent) {
|
|
2047
|
+
const agentState = getAgentModelState(requestedAgent);
|
|
2048
|
+
if (agentState.primary) {
|
|
2049
|
+
primary = agentState.primary;
|
|
2050
|
+
fallbacks = agentState.fallbacks;
|
|
2051
|
+
agentId = requestedAgent.id;
|
|
2052
|
+
agentName = String(requestedAgent.name || '').trim();
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
const providerName = primary.includes('/') ? primary.split('/')[0] : '';
|
|
2057
|
+
const provider = providerName ? (config.models?.providers?.[providerName] || null) : null;
|
|
2058
|
+
const apiType = provider?.api || '';
|
|
2059
|
+
const typeLabel = apiType.startsWith('anthropic')
|
|
2060
|
+
? 'Claude'
|
|
2061
|
+
: (apiType.startsWith('openai') ? 'Codex' : '模型');
|
|
2062
|
+
|
|
2063
|
+
return {
|
|
2064
|
+
agentId,
|
|
2065
|
+
agentName,
|
|
2066
|
+
primary,
|
|
2067
|
+
fallbacks,
|
|
2068
|
+
providerName,
|
|
2069
|
+
provider,
|
|
2070
|
+
typeLabel,
|
|
2071
|
+
defaultPrimary
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2028
2075
|
function hasManagedYunyiFootprint(config) {
|
|
2029
2076
|
const providers = config?.models?.providers || {};
|
|
2030
2077
|
if (Object.entries(providers).some(([name, provider]) => isYunyiProviderEntry(name, provider, 'claude') || isYunyiProviderEntry(name, provider, 'codex'))) {
|
|
@@ -2103,6 +2150,18 @@ function buildManagedYunyiProviderConfig(type, endpointUrl, apiKey, existingProv
|
|
|
2103
2150
|
return next;
|
|
2104
2151
|
}
|
|
2105
2152
|
|
|
2153
|
+
function buildGatewayAgentSubcommand({ sessionId, agentId, message = '请回复你的模型名称' }) {
|
|
2154
|
+
const agentArg = agentId ? ` --agent ${shellQuote(agentId)}` : '';
|
|
2155
|
+
return `agent${agentArg} --session-id ${shellQuote(sessionId)} --message ${shellQuote(message)} --json --timeout 120`;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
function buildGatewayAgentCliCommand({ cliBinary, nodeInfo, useNode, sessionId, agentId, message = '请回复你的模型名称' }) {
|
|
2159
|
+
const subcommand = buildGatewayAgentSubcommand({ sessionId, agentId, message });
|
|
2160
|
+
return useNode
|
|
2161
|
+
? `${shellQuote(nodeInfo.path)} ${shellQuote(cliBinary)} ${subcommand}`
|
|
2162
|
+
: `${shellQuote(cliBinary)} ${subcommand}`;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2106
2165
|
function ensureAgentList(config) {
|
|
2107
2166
|
if (!config.agents) config.agents = {};
|
|
2108
2167
|
if (!Array.isArray(config.agents.list)) config.agents.list = [];
|
|
@@ -2309,13 +2368,10 @@ function applyManagedYunyiOpenClawLayout(config, options = {}) {
|
|
|
2309
2368
|
|
|
2310
2369
|
function printYunyiOpenClawSwitchHint(result = {}) {
|
|
2311
2370
|
if (!result?.applied) return;
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
}
|
|
2317
|
-
console.log(chalk.gray(' GPT 入口是 yunyi-gpt'));
|
|
2318
|
-
console.log(chalk.yellow(' 提示: 当前 OpenClaw Web 顶部模型下拉跨 provider 切换可能报错,建议通过左侧会话/agent 切换 Claude 和 GPT'));
|
|
2371
|
+
const summary = result.preservedMain && result.claudeAgentId === YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID
|
|
2372
|
+
? 'OpenClaw: main 已保留, Claude=yunyi-claude, GPT=yunyi-gpt'
|
|
2373
|
+
: 'OpenClaw: main=yunyi-claude, GPT=yunyi-gpt';
|
|
2374
|
+
console.log(chalk.cyan(` ${summary}`));
|
|
2319
2375
|
}
|
|
2320
2376
|
|
|
2321
2377
|
function pruneProvidersByPrefix(config, prefixBase, keepProviders = []) {
|
|
@@ -3889,17 +3945,13 @@ async function presetClaude(paths, args = {}) {
|
|
|
3889
3945
|
updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_CLAUDE_PROVIDER, apiKey);
|
|
3890
3946
|
updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_GPT_PROVIDER, apiKey);
|
|
3891
3947
|
}
|
|
3892
|
-
|
|
3948
|
+
syncExternalTools('claude', baseUrl, apiKey, { claudeModelId: modelId, opencodeDefaultModelKey: `yunyi-claude/${modelId}` });
|
|
3893
3949
|
writeSpinner.succeed('配置写入完成');
|
|
3894
3950
|
|
|
3895
3951
|
console.log(chalk.green('\n✅ Claude 节点配置完成!'));
|
|
3896
|
-
|
|
3897
|
-
console.log(chalk.cyan(` ${providerName}${tag}: ${buildFullUrl(selectedEndpoint.url, 'claude')}`));
|
|
3898
|
-
console.log(chalk.gray(` 模型: ${modelName}`));
|
|
3899
|
-
console.log(chalk.gray(' API Key: 已设置'));
|
|
3900
|
-
if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
|
|
3952
|
+
console.log(chalk.cyan(` Claude: ${modelName}`));
|
|
3901
3953
|
if (repairResult.renamedProviders.length > 0) {
|
|
3902
|
-
console.log(chalk.
|
|
3954
|
+
console.log(chalk.cyan(` 已修复 provider 冲突: ${repairResult.renamedProviders.map(item => `${item.from}→${item.to}`).join(', ')}`));
|
|
3903
3955
|
}
|
|
3904
3956
|
printYunyiOpenClawSwitchHint(yunyiLayoutResult);
|
|
3905
3957
|
|
|
@@ -4076,17 +4128,13 @@ async function presetCodex(paths, args = {}) {
|
|
|
4076
4128
|
updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_CLAUDE_PROVIDER, apiKey);
|
|
4077
4129
|
updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_GPT_PROVIDER, apiKey);
|
|
4078
4130
|
}
|
|
4079
|
-
|
|
4131
|
+
syncExternalTools('codex', baseUrl, apiKey, { modelId });
|
|
4080
4132
|
writeSpinner2.succeed('配置写入完成');
|
|
4081
4133
|
|
|
4082
4134
|
console.log(chalk.green('\n✅ Codex 节点配置完成!'));
|
|
4083
|
-
|
|
4084
|
-
console.log(chalk.cyan(` ${providerName}${tag}: ${baseUrl}`));
|
|
4085
|
-
console.log(chalk.gray(` 模型: ${modelName}`));
|
|
4086
|
-
console.log(chalk.gray(' API Key: 已设置'));
|
|
4087
|
-
if (extSynced2.length > 0) console.log(chalk.gray(` 同步: ${extSynced2.join(', ')}`));
|
|
4135
|
+
console.log(chalk.cyan(` Codex: ${modelName}`));
|
|
4088
4136
|
if (repairResult.renamedProviders.length > 0) {
|
|
4089
|
-
console.log(chalk.
|
|
4137
|
+
console.log(chalk.cyan(` 已修复 provider 冲突: ${repairResult.renamedProviders.map(item => `${item.from}→${item.to}`).join(', ')}`));
|
|
4090
4138
|
}
|
|
4091
4139
|
printYunyiOpenClawSwitchHint(yunyiLayoutResult);
|
|
4092
4140
|
|
|
@@ -4271,22 +4319,15 @@ async function autoActivate(paths, args = {}) {
|
|
|
4271
4319
|
writeConfigWithSync(paths, config);
|
|
4272
4320
|
updateAuthProfilesWithSync(paths, claudeProviderName, apiKey);
|
|
4273
4321
|
updateAuthProfilesWithSync(paths, codexProviderName, apiKey);
|
|
4274
|
-
const extSynced = [];
|
|
4275
4322
|
const opencodeDefaultModelKey = isClaudePrimary ? `yunyi-claude/${claudeModelId}` : `yunyi-codex/${codexModelId}`;
|
|
4276
|
-
try {
|
|
4277
|
-
try {
|
|
4323
|
+
try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl, claudeModelId, opencodeDefaultModelKey }); } catch { /* ignore */ }
|
|
4324
|
+
try { syncExternalTools('codex', codexBaseUrl, apiKey, { modelId: codexModelId }); } catch { /* ignore */ }
|
|
4278
4325
|
writeSpinner.succeed('配置写入完成');
|
|
4279
4326
|
|
|
4280
4327
|
// ---- 输出结果 ----
|
|
4281
|
-
const primaryLabel = isClaudePrimary ? 'Claude' : 'GPT';
|
|
4282
4328
|
const selectedModel = isClaudePrimary ? claudeModel : codexModel;
|
|
4283
4329
|
console.log(chalk.green('\n✅ 配置完成!'));
|
|
4284
|
-
console.log(chalk.cyan(` 外部工具默认: ${selectedModel.name}
|
|
4285
|
-
console.log(chalk.gray(` 节点: ${selectedEndpoint.url} (${selectedEndpoint.name})`));
|
|
4286
|
-
console.log(chalk.gray(' API Key: 已设置'));
|
|
4287
|
-
if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
|
|
4288
|
-
console.log(chalk.gray(' 若遇 certificate 报错,请新开终端或执行 source ~/.zshrc 后重试(已放宽 TLS 校验)'));
|
|
4289
|
-
console.log(chalk.gray(` 使用 OpenCode 时可在界面中切换 ${getOpencodeSwitchHint()};Codex 仅支持 GPT`));
|
|
4330
|
+
console.log(chalk.cyan(` 外部工具默认: ${selectedModel.name}`));
|
|
4290
4331
|
printYunyiOpenClawSwitchHint(yunyiLayoutResult);
|
|
4291
4332
|
|
|
4292
4333
|
const gwPort = config.gateway?.port || 18789;
|
|
@@ -4308,7 +4349,10 @@ async function autoActivate(paths, args = {}) {
|
|
|
4308
4349
|
}]);
|
|
4309
4350
|
|
|
4310
4351
|
if (nextAction === 'test') {
|
|
4311
|
-
|
|
4352
|
+
const selectedOpenClawAgentId = isClaudePrimary
|
|
4353
|
+
? (yunyiLayoutResult.claudeAgentId || YYMAXAPI_OPENCLAW_MAIN_AGENT_ID)
|
|
4354
|
+
: YYMAXAPI_OPENCLAW_GPT_AGENT_ID;
|
|
4355
|
+
await testConnection(paths, { ...args, agent: selectedOpenClawAgentId });
|
|
4312
4356
|
} else {
|
|
4313
4357
|
console.log(chalk.cyan('👋 再见!\n'));
|
|
4314
4358
|
process.exit(0);
|
|
@@ -4728,12 +4772,8 @@ async function yycodeQuickSetup(paths) {
|
|
|
4728
4772
|
|
|
4729
4773
|
// ---- 结果 ----
|
|
4730
4774
|
console.log(chalk.green('\n✅ 配置完成!'));
|
|
4731
|
-
console.log(chalk.cyan(` Claude Code: ${
|
|
4732
|
-
console.log(chalk.
|
|
4733
|
-
console.log(chalk.cyan(` Codex CLI: ${codexBaseUrl}`));
|
|
4734
|
-
console.log(chalk.gray(` 模型: ${codexModel.name}`));
|
|
4735
|
-
console.log(chalk.gray(' API Key: 已设置'));
|
|
4736
|
-
console.log(chalk.gray(' 同步: Claude Code settings, Opencode config, Codex CLI config'));
|
|
4775
|
+
console.log(chalk.cyan(` Claude Code: ${claudeModel.name}`));
|
|
4776
|
+
console.log(chalk.cyan(` Codex CLI: ${codexModel.name}`));
|
|
4737
4777
|
printYunyiOpenClawSwitchHint(yunyiLayoutResult);
|
|
4738
4778
|
console.log('');
|
|
4739
4779
|
}
|
|
@@ -4866,7 +4906,9 @@ async function main() {
|
|
|
4866
4906
|
// 获取当前配置状态摘要
|
|
4867
4907
|
function getConfigStatusLine(paths) {
|
|
4868
4908
|
try {
|
|
4869
|
-
const config = readConfig(paths.openclawConfig);
|
|
4909
|
+
const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
|
|
4910
|
+
applyConfigRepairsWithSync(config, paths);
|
|
4911
|
+
applyManagedYunyiOpenClawLayout(config);
|
|
4870
4912
|
if (!config?.models?.providers) return null;
|
|
4871
4913
|
|
|
4872
4914
|
const providers = Object.keys(config.models.providers);
|
|
@@ -5008,9 +5050,7 @@ async function selectNode(paths, type) {
|
|
|
5008
5050
|
if (managedGptKey) updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_GPT_PROVIDER, managedGptKey);
|
|
5009
5051
|
|
|
5010
5052
|
console.log(chalk.green(`\n✅ ${typeLabel} 节点配置完成!`));
|
|
5011
|
-
console.log(chalk.cyan(`
|
|
5012
|
-
console.log(chalk.gray(` 模型: ${modelConfig.name} (主模型)`));
|
|
5013
|
-
console.log(chalk.gray(` API Key: ${oldApiKey ? '已设置' : '未设置'}`));
|
|
5053
|
+
console.log(chalk.cyan(` ${typeLabel}: ${modelConfig.name}`));
|
|
5014
5054
|
printYunyiOpenClawSwitchHint(yunyiLayoutResult);
|
|
5015
5055
|
}
|
|
5016
5056
|
|
|
@@ -5065,9 +5105,7 @@ async function activate(paths, type) {
|
|
|
5065
5105
|
writeAuthStore(paths.authProfiles, authStore);
|
|
5066
5106
|
|
|
5067
5107
|
console.log(chalk.green(`\n✅ 已激活 ${typeLabel}`));
|
|
5068
|
-
console.log(chalk.cyan(`
|
|
5069
|
-
console.log(chalk.gray(` 模型: ${modelConfig.name}`));
|
|
5070
|
-
console.log(chalk.gray(` API Key: 已设置`));
|
|
5108
|
+
console.log(chalk.cyan(` ${typeLabel}: ${modelConfig.name}`));
|
|
5071
5109
|
printYunyiOpenClawSwitchHint(yunyiLayoutResult);
|
|
5072
5110
|
}
|
|
5073
5111
|
|
|
@@ -5343,30 +5381,28 @@ async function testConnection(paths, args = {}) {
|
|
|
5343
5381
|
|
|
5344
5382
|
const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
|
|
5345
5383
|
applyConfigRepairsWithSync(config, paths);
|
|
5384
|
+
applyManagedYunyiOpenClawLayout(config);
|
|
5346
5385
|
|
|
5347
5386
|
if (!config || !config.models) {
|
|
5348
5387
|
console.log(chalk.yellow('配置文件不存在,请先选择节点'));
|
|
5349
5388
|
return;
|
|
5350
5389
|
}
|
|
5351
5390
|
|
|
5352
|
-
|
|
5353
|
-
|
|
5391
|
+
const testTarget = resolveOpenClawTestTarget(config, args);
|
|
5392
|
+
const primary = testTarget.primary;
|
|
5354
5393
|
if (!primary.includes('/')) {
|
|
5355
5394
|
console.log(chalk.yellow('⚠️ 主模型未设置,请先通过「切换 OpenClaw 模型」或「一键配置」设置主模型'));
|
|
5356
5395
|
return;
|
|
5357
5396
|
}
|
|
5358
5397
|
|
|
5359
|
-
const providerName =
|
|
5360
|
-
const provider =
|
|
5398
|
+
const providerName = testTarget.providerName;
|
|
5399
|
+
const provider = testTarget.provider;
|
|
5361
5400
|
if (!provider) {
|
|
5362
5401
|
console.log(chalk.yellow(`⚠️ 主模型对应的中转站不存在: ${providerName}`));
|
|
5363
5402
|
return;
|
|
5364
5403
|
}
|
|
5365
5404
|
|
|
5366
|
-
const
|
|
5367
|
-
const typeLabel = apiType.startsWith('anthropic')
|
|
5368
|
-
? 'Claude'
|
|
5369
|
-
: (apiType.startsWith('openai') ? 'Codex' : '模型');
|
|
5405
|
+
const typeLabel = testTarget.typeLabel;
|
|
5370
5406
|
|
|
5371
5407
|
if (!provider.apiKey) {
|
|
5372
5408
|
console.log(chalk.yellow(`⚠️ ${typeLabel} API Key 未设置`));
|
|
@@ -5376,10 +5412,11 @@ async function testConnection(paths, args = {}) {
|
|
|
5376
5412
|
// 获取 Gateway 配置
|
|
5377
5413
|
const gatewayPort = config.gateway?.port || 18789;
|
|
5378
5414
|
|
|
5379
|
-
console.log(chalk.
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5415
|
+
console.log(chalk.cyan(`当前测试: ${typeLabel}`));
|
|
5416
|
+
if (testTarget.agentId) {
|
|
5417
|
+
console.log(chalk.cyan(`测试入口: ${testTarget.agentId}${testTarget.agentName ? ` (${testTarget.agentName})` : ''}`));
|
|
5418
|
+
}
|
|
5419
|
+
console.log(chalk.cyan(`模型: ${primary}\n`));
|
|
5383
5420
|
// 获取 Gateway token
|
|
5384
5421
|
const gatewayToken = config.gateway?.auth?.token;
|
|
5385
5422
|
if (!gatewayToken) {
|
|
@@ -5452,7 +5489,7 @@ async function testConnection(paths, args = {}) {
|
|
|
5452
5489
|
console.log(chalk.cyan(`\n步骤 2/2: 测试 Gateway API 端点...`));
|
|
5453
5490
|
|
|
5454
5491
|
try {
|
|
5455
|
-
const cliResult = await testGatewayViaAgent(primary);
|
|
5492
|
+
const cliResult = await testGatewayViaAgent(primary, testTarget.agentId);
|
|
5456
5493
|
let cliPassed = false;
|
|
5457
5494
|
|
|
5458
5495
|
if (cliResult.usedCli) {
|
|
@@ -5477,7 +5514,7 @@ async function testConnection(paths, args = {}) {
|
|
|
5477
5514
|
console.log(chalk.red(` 期望: ${primary}`));
|
|
5478
5515
|
console.log(chalk.cyan(` 实际: ${actualModelKey}`));
|
|
5479
5516
|
console.log(chalk.gray(` 这意味着 ${primary} 无法正常工作,请检查该模型的中转配置`));
|
|
5480
|
-
const configuredFallbacks =
|
|
5517
|
+
const configuredFallbacks = testTarget.fallbacks || [];
|
|
5481
5518
|
if (configuredFallbacks.length > 0 && !configuredFallbacks.includes(actualModelKey)) {
|
|
5482
5519
|
console.log(chalk.yellow(` ⚠️ 实际回退模型不在当前配置的 fallbacks 中,疑似读到了另一份配置`));
|
|
5483
5520
|
console.log(chalk.gray(` 当前 fallbacks: ${configuredFallbacks.join(', ')}`));
|
|
@@ -5506,17 +5543,6 @@ async function testConnection(paths, args = {}) {
|
|
|
5506
5543
|
console.log(chalk.cyan(` Provider: ${cliResult.provider}`));
|
|
5507
5544
|
console.log(chalk.cyan(` Model: ${cliResult.model}`));
|
|
5508
5545
|
}
|
|
5509
|
-
if (cliResult.message) {
|
|
5510
|
-
const reply = sanitizeModelReply(cliResult.message, {
|
|
5511
|
-
provider: cliResult.provider,
|
|
5512
|
-
model: cliResult.model,
|
|
5513
|
-
modelKey: primary
|
|
5514
|
-
});
|
|
5515
|
-
console.log(chalk.yellow(` 模型回复: ${reply}`));
|
|
5516
|
-
}
|
|
5517
|
-
if (!isFallback) {
|
|
5518
|
-
console.log(chalk.gray(' 将继续验证 Web 鉴权端点(避免"CLI 正常但网页 401")...'));
|
|
5519
|
-
}
|
|
5520
5546
|
}
|
|
5521
5547
|
}
|
|
5522
5548
|
|
|
@@ -5547,7 +5573,6 @@ async function testConnection(paths, args = {}) {
|
|
|
5547
5573
|
const primaryApi = config.models?.providers?.[primaryProvider]?.api || '';
|
|
5548
5574
|
const isAnthropic = primaryApi.startsWith('anthropic');
|
|
5549
5575
|
const testEndpoint = isAnthropic ? '/v1/messages' : '/v1/chat/completions';
|
|
5550
|
-
console.log(chalk.gray(` 端点: http://127.0.0.1:${gatewayPort}${testEndpoint}`));
|
|
5551
5576
|
const startTime = Date.now();
|
|
5552
5577
|
let result = await testGatewayApi(gatewayPort, gatewayToken, primary, testEndpoint);
|
|
5553
5578
|
const latency = Date.now() - startTime;
|
|
@@ -5555,26 +5580,17 @@ async function testConnection(paths, args = {}) {
|
|
|
5555
5580
|
// 回退:如果首选端点返回 404/405,尝试另一个
|
|
5556
5581
|
if (!result.success && result.reachable && [404, 405].includes(result.status)) {
|
|
5557
5582
|
const fallbackEndpoint = isAnthropic ? '/v1/chat/completions' : '/v1/responses';
|
|
5558
|
-
console.log(chalk.gray(` ${testEndpoint} 不支持,回退测试 ${fallbackEndpoint}...`));
|
|
5559
5583
|
result = await testGatewayApi(gatewayPort, gatewayToken, primary, fallbackEndpoint);
|
|
5560
5584
|
}
|
|
5561
5585
|
|
|
5562
5586
|
// CLI 对话已成功 + Gateway 可达(404/405)= Dashboard 通过 WebSocket 工作,视为通过
|
|
5563
5587
|
if (!result.success && cliPassed && result.reachable && [404, 405].includes(result.status)) {
|
|
5564
5588
|
console.log(chalk.green(`\n✅ Gateway 测试通过`));
|
|
5565
|
-
console.log(chalk.cyan(` CLI 对话正常,Gateway 可达`));
|
|
5566
|
-
console.log(chalk.gray(` 注: Gateway Dashboard 通过 WebSocket 通信,REST 端点返回 405 属正常现象`));
|
|
5567
5589
|
console.log(chalk.green(`\n🌐 Web Dashboard 访问地址:`));
|
|
5568
5590
|
console.log(chalk.cyan(` http://127.0.0.1:${gatewayPort}/#token=${gatewayToken}`));
|
|
5569
5591
|
} else if (result.success) {
|
|
5570
|
-
console.log(chalk.green(`\n✅ Gateway
|
|
5592
|
+
console.log(chalk.green(`\n✅ Gateway 测试通过`));
|
|
5571
5593
|
console.log(chalk.cyan(` 响应时间: ${latency}ms`));
|
|
5572
|
-
const reply = sanitizeModelReply(result.message, {
|
|
5573
|
-
provider: providerName,
|
|
5574
|
-
model: primary.includes('/') ? primary.split('/')[1] : '',
|
|
5575
|
-
modelKey: primary
|
|
5576
|
-
});
|
|
5577
|
-
console.log(chalk.yellow(` 模型回复: ${reply}`));
|
|
5578
5594
|
console.log(chalk.green(`\n🌐 Web Dashboard 访问地址:`));
|
|
5579
5595
|
console.log(chalk.cyan(` http://127.0.0.1:${gatewayPort}/#token=${gatewayToken}`));
|
|
5580
5596
|
} else {
|
|
@@ -5968,7 +5984,7 @@ function testGatewayApi(port, token, model, endpoint = '/v1/chat/completions') {
|
|
|
5968
5984
|
});
|
|
5969
5985
|
}
|
|
5970
5986
|
|
|
5971
|
-
function testGatewayViaAgent(model) {
|
|
5987
|
+
function testGatewayViaAgent(model, agentId = '') {
|
|
5972
5988
|
return new Promise((resolve) => {
|
|
5973
5989
|
const gwEnv = detectGatewayEnv();
|
|
5974
5990
|
const sessionId = `yymaxapi-test-${Date.now()}`;
|
|
@@ -5979,11 +5995,12 @@ function testGatewayViaAgent(model) {
|
|
|
5979
5995
|
if (gwEnv === 'wsl') {
|
|
5980
5996
|
// Gateway 在 WSL 中,agent 也要在 WSL 中执行
|
|
5981
5997
|
const wslCli = getWslCliBinary();
|
|
5998
|
+
const subcommand = buildGatewayAgentSubcommand({ sessionId, agentId });
|
|
5982
5999
|
if (wslCli) {
|
|
5983
|
-
const agentCmd = `${wslCli}
|
|
6000
|
+
const agentCmd = `${wslCli} ${subcommand}`;
|
|
5984
6001
|
cmd = `wsl -- bash -c '${agentCmd.replace(/'/g, "'\\''")}'`;
|
|
5985
6002
|
} else {
|
|
5986
|
-
const agentCmd = `openclaw
|
|
6003
|
+
const agentCmd = `openclaw ${subcommand} 2>/dev/null || clawdbot ${subcommand} 2>/dev/null || moltbot ${subcommand}`;
|
|
5987
6004
|
cmd = `wsl -- bash -lc '${agentCmd.replace(/'/g, "'\\''")}'`;
|
|
5988
6005
|
}
|
|
5989
6006
|
execOpts = { timeout: 120000 };
|
|
@@ -6001,9 +6018,13 @@ function testGatewayViaAgent(model) {
|
|
|
6001
6018
|
delete env.OPENAI_API_KEY;
|
|
6002
6019
|
delete env.OPENCLAW_CODEX_KEY;
|
|
6003
6020
|
const useNode = nodeInfo && isNodeShebang(cliBinary);
|
|
6004
|
-
cmd =
|
|
6005
|
-
|
|
6006
|
-
|
|
6021
|
+
cmd = buildGatewayAgentCliCommand({
|
|
6022
|
+
cliBinary,
|
|
6023
|
+
nodeInfo,
|
|
6024
|
+
useNode,
|
|
6025
|
+
sessionId,
|
|
6026
|
+
agentId
|
|
6027
|
+
});
|
|
6007
6028
|
execOpts = { timeout: 120000, env };
|
|
6008
6029
|
}
|
|
6009
6030
|
|