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