yymaxapi 1.0.55 → 1.0.56

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.
Files changed (2) hide show
  1. package/bin/yymaxapi.js +79 -39
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -3397,62 +3397,77 @@ async function switchModel(paths) {
3397
3397
  return;
3398
3398
  }
3399
3399
 
3400
- const claudeApiConfig = API_CONFIG.claude;
3401
- const codexApiConfig = API_CONFIG.codex;
3402
- const claudeProviderName = claudeApiConfig.providerName;
3403
- const codexProviderName = codexApiConfig.providerName;
3400
+ const PROVIDER_LABELS = {
3401
+ 'claude-yunyi': '云翼 Claude (包月)',
3402
+ 'yunyi': '云翼 Codex (包月)',
3403
+ 'heibai': 'MAXAPI (按量)',
3404
+ };
3405
+
3406
+ const claudeProviderName = API_CONFIG.claude.providerName;
3407
+ const codexProviderName = API_CONFIG.codex.providerName;
3404
3408
 
3405
- // 从预设模型列表构建选项(确保始终展示最新可用模型)
3409
+ // 预设模型列表
3406
3410
  const choices = [];
3407
- const listedKeys = new Set();
3411
+ const presetKeys = new Set();
3408
3412
 
3409
3413
  if (CLAUDE_MODELS.length > 0) {
3410
3414
  choices.push(new inquirer.Separator(' -- Claude --'));
3411
3415
  for (const m of CLAUDE_MODELS) {
3412
- const providerName = providers[claudeProviderName] ? claudeProviderName : Object.keys(providers)[0];
3413
- const modelKey = `${providerName}/${m.id}`;
3416
+ const pName = providers[claudeProviderName] ? claudeProviderName : Object.keys(providers)[0];
3417
+ const modelKey = `${pName}/${m.id}`;
3414
3418
  const isCurrent = modelKey === primary;
3415
3419
  choices.push({
3416
3420
  name: isCurrent ? `${m.name} (当前)` : m.name,
3417
3421
  value: modelKey,
3418
3422
  });
3419
- listedKeys.add(modelKey);
3423
+ presetKeys.add(modelKey);
3420
3424
  }
3421
3425
  }
3422
3426
 
3423
3427
  if (CODEX_MODELS.length > 0) {
3424
3428
  choices.push(new inquirer.Separator(' -- GPT --'));
3425
3429
  for (const m of CODEX_MODELS) {
3426
- const providerName = providers[codexProviderName] ? codexProviderName : Object.keys(providers)[0];
3427
- const modelKey = `${providerName}/${m.id}`;
3430
+ const pName = providers[codexProviderName] ? codexProviderName : Object.keys(providers)[0];
3431
+ const modelKey = `${pName}/${m.id}`;
3428
3432
  const isCurrent = modelKey === primary;
3429
3433
  choices.push({
3430
3434
  name: isCurrent ? `${m.name} (当前)` : m.name,
3431
3435
  value: modelKey,
3432
3436
  });
3433
- listedKeys.add(modelKey);
3437
+ presetKeys.add(modelKey);
3434
3438
  }
3435
3439
  }
3436
3440
 
3437
- // 补上配置文件中已有但不在预设列表里的模型
3441
+ // 收集用户配置中的其他模型(不在预设列表里的)
3442
+ const otherModels = [];
3438
3443
  for (const [providerName, providerConfig] of Object.entries(providers)) {
3439
3444
  for (const m of (providerConfig.models || [])) {
3440
3445
  const modelKey = `${providerName}/${m.id}`;
3441
- if (listedKeys.has(modelKey)) continue;
3442
- const isCurrent = modelKey === primary;
3443
- choices.push({
3444
- name: isCurrent ? `${m.name || m.id} (当前)` : (m.name || m.id),
3445
- value: modelKey,
3446
- });
3447
- listedKeys.add(modelKey);
3446
+ if (!presetKeys.has(modelKey)) {
3447
+ otherModels.push({ modelKey, name: m.name || m.id, providerName });
3448
+ }
3448
3449
  }
3449
3450
  }
3450
-
3451
- if (choices.filter(c => c.value).length === 0) {
3452
- console.log(chalk.yellow('⚠️ 未找到任何可用模型'));
3453
- return;
3451
+ const registeredKeys = Object.keys(config.agents?.defaults?.models || {});
3452
+ for (const modelKey of registeredKeys) {
3453
+ if (presetKeys.has(modelKey) || otherModels.some(o => o.modelKey === modelKey)) continue;
3454
+ const [pName, mId] = modelKey.split('/');
3455
+ if (!pName || !mId) continue;
3456
+ otherModels.push({ modelKey, name: `${PROVIDER_LABELS[pName] || pName} / ${mId}`, providerName: pName });
3454
3457
  }
3455
3458
 
3459
+ // 当前主模型不在预设列表中时,标注在"其他"入口上
3460
+ const primaryInPreset = presetKeys.has(primary);
3461
+ const otherLabel = otherModels.length > 0
3462
+ ? `切换其他模型 (${otherModels.length} 个)`
3463
+ : '切换其他模型';
3464
+
3465
+ choices.push(new inquirer.Separator(''));
3466
+ choices.push({
3467
+ name: !primaryInPreset && primary ? `${otherLabel} ← 当前在此` : otherLabel,
3468
+ value: '__other__',
3469
+ });
3470
+
3456
3471
  const currentProvider = primary.split('/')[0] || '';
3457
3472
  const currentProviderConfig = providers[currentProvider];
3458
3473
  console.log(chalk.gray(`当前模型: ${primary || '未设置'}`));
@@ -3465,25 +3480,51 @@ async function switchModel(paths) {
3465
3480
  type: 'list',
3466
3481
  name: 'selected',
3467
3482
  message: '选择模型:',
3468
- default: primary,
3483
+ default: primaryInPreset ? primary : undefined,
3469
3484
  pageSize: 15,
3470
3485
  choices,
3471
3486
  }]);
3472
3487
 
3473
- if (selected === primary) {
3488
+ let finalSelected = selected;
3489
+
3490
+ if (selected === '__other__') {
3491
+ if (otherModels.length === 0) {
3492
+ console.log(chalk.gray('\n当前配置中没有其他模型,仅有预设模型可用'));
3493
+ return;
3494
+ }
3495
+ const otherChoices = otherModels.map(o => {
3496
+ const label = PROVIDER_LABELS[o.providerName] || o.providerName;
3497
+ const isCurrent = o.modelKey === primary;
3498
+ return {
3499
+ name: isCurrent ? `${o.name} [${label}] (当前)` : `${o.name} [${label}]`,
3500
+ value: o.modelKey,
3501
+ };
3502
+ });
3503
+ const { pickedOther } = await inquirer.prompt([{
3504
+ type: 'list',
3505
+ name: 'pickedOther',
3506
+ message: '选择其他模型:',
3507
+ default: !primaryInPreset ? primary : undefined,
3508
+ pageSize: 15,
3509
+ choices: otherChoices,
3510
+ }]);
3511
+ finalSelected = pickedOther;
3512
+ }
3513
+
3514
+ if (finalSelected === primary) {
3474
3515
  console.log(chalk.gray('\n模型未变更'));
3475
3516
  return;
3476
3517
  }
3477
3518
 
3478
- const selectedProvider = selected.split('/')[0];
3479
- const selectedModelId = selected.split('/')[1];
3480
- config.agents.defaults.model.primary = selected;
3481
- if (!config.agents.defaults.models[selected]) {
3482
- config.agents.defaults.models[selected] = { alias: selectedProvider };
3519
+ const selectedProviderKey = finalSelected.split('/')[0];
3520
+ const selectedModelId = finalSelected.split('/')[1];
3521
+ config.agents.defaults.model.primary = finalSelected;
3522
+ if (!config.agents.defaults.models[finalSelected]) {
3523
+ config.agents.defaults.models[finalSelected] = { alias: selectedProviderKey };
3483
3524
  }
3484
3525
 
3485
- // 同步更新 provider.models,确保 primary 指向的模型在列表中
3486
- const providerConfig = providers[selectedProvider];
3526
+ // 同步更新 provider.models
3527
+ const providerConfig = providers[selectedProviderKey];
3487
3528
  if (providerConfig && selectedModelId) {
3488
3529
  const existingModel = (providerConfig.models || []).find(m => m.id === selectedModelId);
3489
3530
  if (!existingModel) {
@@ -3504,16 +3545,16 @@ async function switchModel(paths) {
3504
3545
  }
3505
3546
  }
3506
3547
 
3507
- config.agents.defaults.model.fallbacks = (config.agents.defaults.model.fallbacks || []).filter(k => k !== selected);
3508
- if (primary && primary !== selected && !config.agents.defaults.model.fallbacks.includes(primary)) {
3548
+ config.agents.defaults.model.fallbacks = (config.agents.defaults.model.fallbacks || []).filter(k => k !== finalSelected);
3549
+ if (primary && primary !== finalSelected && !config.agents.defaults.model.fallbacks.includes(primary)) {
3509
3550
  config.agents.defaults.model.fallbacks.push(primary);
3510
3551
  }
3511
3552
  ensureGatewaySettings(config);
3512
3553
  writeConfigWithSync(paths, config);
3513
3554
 
3514
- const selectedProviderConfig = providers[selectedProvider];
3515
- const selectedLabel = PROVIDER_LABELS[selectedProvider] || selectedProvider;
3516
- console.log(chalk.green(`\n✅ 已切换到 ${selected}`));
3555
+ const selectedProviderConfig = providers[selectedProviderKey];
3556
+ const selectedLabel = PROVIDER_LABELS[selectedProviderKey] || selectedProviderKey;
3557
+ console.log(chalk.green(`\n✅ 已切换到 ${finalSelected}`));
3517
3558
  console.log(chalk.gray(` 来源: ${selectedLabel}`));
3518
3559
  if (selectedProviderConfig) {
3519
3560
  console.log(chalk.gray(` 节点: ${selectedProviderConfig.baseUrl}`));
@@ -3522,7 +3563,6 @@ async function switchModel(paths) {
3522
3563
  const gwPort = config.gateway?.port || 18789;
3523
3564
  const gwToken = config.gateway?.auth?.token;
3524
3565
 
3525
- // 自动重启 Gateway 使切换立即生效
3526
3566
  if (await isPortOpen(gwPort)) {
3527
3567
  const gwSpinner = ora({ text: '重启 Gateway 使模型切换生效...', spinner: 'dots' }).start();
3528
3568
  const ok = await restartGateway({ silent: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.55",
3
+ "version": "1.0.56",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {