yymaxapi 1.0.51 → 1.0.53

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 +74 -160
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -88,36 +88,24 @@ const FALLBACK_ENDPOINTS = [
88
88
  ];
89
89
 
90
90
  const DEFAULT_CLAUDE_MODELS = [
91
- {
92
- "id": "claude-opus-4-6",
93
- "name": "Claude Opus 4.6"
94
- },
95
- {
96
- "id": "claude-opus-4-6-Thinking",
97
- "name": "Claude Opus 4.6 Thinking"
98
- },
99
91
  {
100
92
  "id": "claude-sonnet-4-6",
101
93
  "name": "Claude Sonnet 4.6"
102
94
  },
103
95
  {
104
- "id": "claude-sonnet-4-6-Thinking",
105
- "name": "Claude Sonnet 4.6 Thinking"
106
- },
107
- {
108
- "id": "claude-haiku-4-5",
109
- "name": "Claude Haiku 4.5"
96
+ "id": "claude-opus-4-6",
97
+ "name": "Claude Opus 4.6 (待恢复)"
110
98
  }
111
99
  ];
112
100
 
113
101
  const DEFAULT_CODEX_MODELS = [
114
102
  {
115
- "id": "gpt-5.3-codex",
116
- "name": "GPT 5.3 Codex"
103
+ "id": "gpt-5.4",
104
+ "name": "GPT 5.4"
117
105
  },
118
106
  {
119
- "id": "gpt-5.2",
120
- "name": "GPT 5.2"
107
+ "id": "gpt-5.4-pro",
108
+ "name": "GPT 5.4 Pro (待支持)"
121
109
  }
122
110
  ];
123
111
 
@@ -132,8 +120,8 @@ const DEFAULT_API_CONFIG = {
132
120
  "codex": {
133
121
  "urlSuffix": "/codex",
134
122
  "api": "openai-responses",
135
- "contextWindow": 128000,
136
- "maxTokens": 32768,
123
+ "contextWindow": 1050000,
124
+ "maxTokens": 128000,
137
125
  "providerName": "yunyi"
138
126
  }
139
127
  };
@@ -702,7 +690,7 @@ function writeCodexConfig(baseUrl, apiKey) {
702
690
  }
703
691
  const section = [
704
692
  marker,
705
- `model = "gpt-5.3-codex"`,
693
+ `model = "gpt-5.4"`,
706
694
  `model_provider = "${providerKey}"`,
707
695
  ``,
708
696
  `[model_providers.${providerKey}]`,
@@ -1182,17 +1170,11 @@ function coerceModelsRecord(value) {
1182
1170
  return record;
1183
1171
  }
1184
1172
 
1185
- const OPENCLAW_KNOWN_ROOT_KEYS = new Set([
1186
- 'models', 'agents', 'auth', 'gateway', 'tools',
1187
- 'channels', 'mcpServers', 'globalShortcut', 'customModes',
1188
- 'permissions', 'proxy', 'env', 'hooks', 'storage',
1189
- ]);
1173
+ const OPENCLAW_INVALID_ROOT_KEYS = ['model'];
1190
1174
 
1191
1175
  function sanitizeRootKeys(config) {
1192
- for (const key of Object.keys(config)) {
1193
- if (!OPENCLAW_KNOWN_ROOT_KEYS.has(key)) {
1194
- delete config[key];
1195
- }
1176
+ for (const key of OPENCLAW_INVALID_ROOT_KEYS) {
1177
+ if (key in config) delete config[key];
1196
1178
  }
1197
1179
  }
1198
1180
 
@@ -2604,50 +2586,13 @@ async function presetCodex(paths, args = {}) {
2604
2586
 
2605
2587
  // ============ 一键激活(同时配置 Claude Code + Codex) ============
2606
2588
  async function autoActivate(paths, args = {}) {
2607
- console.log(chalk.cyan.bold('\n🚀 一键激活(同时配置 Claude Code + Codex)\n'));
2589
+ console.log(chalk.cyan.bold('\n🚀 一键激活\n'));
2608
2590
 
2609
2591
  const claudeApiConfig = API_CONFIG.claude;
2610
2592
  const codexApiConfig = API_CONFIG.codex;
2611
2593
  const claudeProviderName = claudeApiConfig.providerName;
2612
2594
  const codexProviderName = codexApiConfig.providerName;
2613
-
2614
- // ---- 测速选节点 ----
2615
- const shouldTest = !(args['no-test'] || args.noTest);
2616
- let selectedEndpoint = ENDPOINTS[0];
2617
-
2618
- if (shouldTest) {
2619
- console.log(chalk.cyan('📡 开始测速节点...\n'));
2620
- const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
2621
-
2622
- const sorted = speedResult.ranked || [];
2623
- if (sorted.length > 0) {
2624
- const defaultEp = ENDPOINTS[0];
2625
- const { selectedIndex } = await inquirer.prompt([{
2626
- type: 'list',
2627
- name: 'selectedIndex',
2628
- message: '选择节点:',
2629
- choices: [
2630
- { name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
2631
- new inquirer.Separator(' ---- 或按测速结果选择 ----'),
2632
- ...sorted.map((e, i) => ({
2633
- name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
2634
- value: i
2635
- }))
2636
- ]
2637
- }]);
2638
- selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
2639
- if (speedResult.usedFallback) {
2640
- console.log(chalk.yellow(`\n⚠ 当前使用备用节点\n`));
2641
- }
2642
- } else {
2643
- console.log(chalk.red('\n⚠️ 所有节点(含备用)均不可达'));
2644
- const { proceed } = await inquirer.prompt([{
2645
- type: 'confirm', name: 'proceed',
2646
- message: '仍要写入默认节点配置吗?', default: false
2647
- }]);
2648
- if (!proceed) { console.log(chalk.gray('已取消')); return; }
2649
- }
2650
- }
2595
+ const selectedEndpoint = ENDPOINTS[0];
2651
2596
 
2652
2597
  // ---- API Key ----
2653
2598
  const apiKeyEnvFallbacks = [
@@ -2663,7 +2608,7 @@ async function autoActivate(paths, args = {}) {
2663
2608
  apiKey = directKey;
2664
2609
  } else {
2665
2610
  const envKey = getApiKeyFromArgs({}, apiKeyEnvFallbacks);
2666
- apiKey = await promptApiKey('请输入 API Key(同时用于 Claude Code 和 Codex):', envKey || '');
2611
+ apiKey = await promptApiKey('请输入 API Key:', envKey || '');
2667
2612
  }
2668
2613
  if (!apiKey) { console.log(chalk.gray('已取消')); return; }
2669
2614
 
@@ -2678,51 +2623,67 @@ async function autoActivate(paths, args = {}) {
2678
2623
  if (!continueAnyway) { console.log(chalk.gray('已取消')); return; }
2679
2624
  }
2680
2625
 
2681
- // ---- 构建配置 ----
2682
- const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
2683
-
2684
- const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
2685
- const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
2686
-
2687
- // 检测单一模式:Claude 和 Codex 只有一个模型且 id 相同(如 maxapi 的 heibai)
2626
+ // ---- 选模型(Claude + GPT 合并展示) ----
2688
2627
  const isSingleMode = CLAUDE_MODELS.length === 1 && CODEX_MODELS.length === 1
2689
2628
  && CLAUDE_MODELS[0].id === CODEX_MODELS[0].id;
2690
2629
 
2691
- let claudeModelId, codexModelId;
2630
+ let selectedModelId;
2631
+ let selectedType; // 'claude' or 'codex'
2692
2632
 
2693
2633
  if (isSingleMode) {
2694
- // 单一模式:固定模型,不选择,不分 Claude/Codex
2695
- claudeModelId = CLAUDE_MODELS[0].id;
2696
- codexModelId = CODEX_MODELS[0].id;
2634
+ selectedModelId = CLAUDE_MODELS[0].id;
2635
+ selectedType = 'claude';
2697
2636
  } else {
2698
- // 多模型模式:让用户选模型
2699
- claudeModelId = (args['claude-model'] || '').toString().trim();
2700
- if (!claudeModelId && CLAUDE_MODELS.length > 1) {
2637
+ const modelArg = (args.model || args['claude-model'] || args['codex-model'] || '').toString().trim();
2638
+ if (modelArg) {
2639
+ const inClaude = CLAUDE_MODELS.find(m => m.id === modelArg);
2640
+ const inCodex = CODEX_MODELS.find(m => m.id === modelArg);
2641
+ selectedModelId = modelArg;
2642
+ selectedType = inClaude ? 'claude' : inCodex ? 'codex' : 'claude';
2643
+ } else {
2644
+ const allChoices = [];
2645
+ if (CLAUDE_MODELS.length > 0) {
2646
+ allChoices.push(new inquirer.Separator(' -- Claude --'));
2647
+ for (const m of CLAUDE_MODELS) {
2648
+ allChoices.push({ name: m.name, value: `claude:${m.id}` });
2649
+ }
2650
+ }
2651
+ if (CODEX_MODELS.length > 0) {
2652
+ allChoices.push(new inquirer.Separator(' -- GPT --'));
2653
+ for (const m of CODEX_MODELS) {
2654
+ allChoices.push({ name: m.name, value: `codex:${m.id}` });
2655
+ }
2656
+ }
2657
+
2701
2658
  const { picked } = await inquirer.prompt([{
2702
2659
  type: 'list',
2703
2660
  name: 'picked',
2704
- message: '选择 Claude 模型:',
2705
- choices: CLAUDE_MODELS.map(m => ({ name: m.name, value: m.id })),
2706
- default: CLAUDE_MODELS[0].id
2661
+ message: '选择模型:',
2662
+ choices: allChoices,
2663
+ default: `claude:${CLAUDE_MODELS[0].id}`
2707
2664
  }]);
2708
- claudeModelId = picked;
2709
- }
2710
- if (!claudeModelId) claudeModelId = CLAUDE_MODELS[0]?.id || 'claude-sonnet-4-6';
2711
2665
 
2712
- codexModelId = (args['codex-model'] || '').toString().trim();
2713
- if (!codexModelId && CODEX_MODELS.length > 1) {
2714
- const { pickedCodex } = await inquirer.prompt([{
2715
- type: 'list',
2716
- name: 'pickedCodex',
2717
- message: '选择 Codex 模型:',
2718
- choices: CODEX_MODELS.map(m => ({ name: m.name, value: m.id })),
2719
- default: CODEX_MODELS[0].id
2720
- }]);
2721
- codexModelId = pickedCodex;
2666
+ const [pickedType, pickedId] = picked.split(':');
2667
+ selectedType = pickedType;
2668
+ selectedModelId = pickedId;
2722
2669
  }
2723
- if (!codexModelId) codexModelId = CODEX_MODELS[0]?.id || 'gpt-5.3-codex';
2724
2670
  }
2725
2671
 
2672
+ // ---- 构建配置 ----
2673
+ const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
2674
+
2675
+ const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
2676
+ const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
2677
+
2678
+ // 根据用户选择确定主模型
2679
+ const isClaudePrimary = selectedType === 'claude';
2680
+ const claudeModelId = isClaudePrimary
2681
+ ? selectedModelId
2682
+ : CLAUDE_MODELS[0]?.id || 'claude-sonnet-4-6';
2683
+ const codexModelId = !isClaudePrimary
2684
+ ? selectedModelId
2685
+ : CODEX_MODELS[0]?.id || 'gpt-5.4';
2686
+
2726
2687
  const claudeModel = CLAUDE_MODELS.find(m => m.id === claudeModelId) || { id: claudeModelId, name: claudeModelId };
2727
2688
  const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: codexModelId };
2728
2689
  const claudeModelKey = `${claudeProviderName}/${claudeModelId}`;
@@ -2746,7 +2707,7 @@ async function autoActivate(paths, args = {}) {
2746
2707
  config.auth.profiles[`${claudeProviderName}:default`] = { provider: claudeProviderName, mode: 'api_key' };
2747
2708
  config.agents.defaults.models[claudeModelKey] = { alias: claudeProviderName };
2748
2709
 
2749
- // 写入 Codex provider(单一模式下仍写入,保证配置完整)
2710
+ // 写入 Codex provider
2750
2711
  config.models.providers[codexProviderName] = {
2751
2712
  baseUrl: codexBaseUrl,
2752
2713
  auth: DEFAULT_AUTH_MODE,
@@ -2764,34 +2725,9 @@ async function autoActivate(paths, args = {}) {
2764
2725
  config.auth.profiles[`${codexProviderName}:default`] = { provider: codexProviderName, mode: 'api_key' };
2765
2726
  config.agents.defaults.models[codexModelKey] = { alias: codexProviderName };
2766
2727
 
2767
- // ---- 选择主力 ----
2768
- let primaryModelKey, fallbackModelKey;
2769
- if (isSingleMode) {
2770
- // 单一模式:直接用 Claude provider 作为 primary,不需要用户选
2771
- primaryModelKey = claudeModelKey;
2772
- fallbackModelKey = codexModelKey;
2773
- } else {
2774
- let primaryType = 'claude';
2775
- if (args.primary === 'claude') {
2776
- primaryType = 'claude';
2777
- } else if (args.primary === 'codex') {
2778
- primaryType = 'codex';
2779
- } else {
2780
- const { picked } = await inquirer.prompt([{
2781
- type: 'list',
2782
- name: 'picked',
2783
- message: '选择主力工具(默认启动哪个):',
2784
- choices: [
2785
- { name: 'Claude Code', value: 'claude' },
2786
- { name: 'Codex (GPT)', value: 'codex' }
2787
- ]
2788
- }]);
2789
- primaryType = picked;
2790
- }
2791
- primaryModelKey = primaryType === 'claude' ? claudeModelKey : codexModelKey;
2792
- fallbackModelKey = primaryType === 'claude' ? codexModelKey : claudeModelKey;
2793
- }
2794
-
2728
+ // 主模型 = 用户选的,备选 = 另一个
2729
+ const primaryModelKey = isClaudePrimary ? claudeModelKey : codexModelKey;
2730
+ const fallbackModelKey = isClaudePrimary ? codexModelKey : claudeModelKey;
2795
2731
  config.agents.defaults.model.primary = primaryModelKey;
2796
2732
  config.agents.defaults.model.fallbacks = [fallbackModelKey];
2797
2733
 
@@ -2808,19 +2744,11 @@ async function autoActivate(paths, args = {}) {
2808
2744
  writeSpinner.succeed('配置写入完成');
2809
2745
 
2810
2746
  // ---- 输出结果 ----
2811
- console.log(chalk.green('\n✅ 一键激活完成!'));
2812
- if (isSingleMode) {
2813
- console.log(chalk.cyan(` 节点: ${selectedEndpoint.url}`));
2814
- console.log(chalk.gray(` 模型: ${claudeModel.name}`));
2815
- } else {
2816
- const primaryType = primaryModelKey === claudeModelKey ? 'claude' : 'codex';
2817
- const primaryTag = primaryType === 'claude' ? ' (主)' : '';
2818
- const codexTag = primaryType === 'codex' ? ' (主)' : '';
2819
- console.log(chalk.cyan(` Claude Code${primaryTag}: ${claudeBaseUrl}`));
2820
- console.log(chalk.gray(` 模型: ${claudeModel.name}`));
2821
- console.log(chalk.cyan(` Codex${codexTag}: ${codexBaseUrl}`));
2822
- console.log(chalk.gray(` 模型: ${codexModel.name}`));
2823
- }
2747
+ const primaryLabel = isClaudePrimary ? 'Claude' : 'GPT';
2748
+ const selectedModel = isClaudePrimary ? claudeModel : codexModel;
2749
+ console.log(chalk.green('\n✅ 配置完成!'));
2750
+ console.log(chalk.cyan(` 模型: ${selectedModel.name} (${primaryLabel})`));
2751
+ console.log(chalk.gray(` 节点: ${selectedEndpoint.url} (${selectedEndpoint.name})`));
2824
2752
  console.log(chalk.gray(' API Key: 已设置'));
2825
2753
  if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
2826
2754
 
@@ -2830,20 +2758,6 @@ async function autoActivate(paths, args = {}) {
2830
2758
  console.log(chalk.green(`\n🌐 Web Dashboard:`));
2831
2759
  console.log(chalk.cyan(` http://127.0.0.1:${gwPort}/?token=${gwToken}`));
2832
2760
  }
2833
-
2834
- // ---- 测试连接 ----
2835
- const shouldTestGateway = args.test !== undefined
2836
- ? !['false', '0', 'no'].includes(String(args.test).toLowerCase())
2837
- : await inquirer.prompt([{
2838
- type: 'confirm',
2839
- name: 'testGateway',
2840
- message: '是否立即通过 OpenClaw Gateway 测试?',
2841
- default: true
2842
- }]).then(r => r.testGateway);
2843
-
2844
- if (shouldTestGateway) {
2845
- await testConnection(paths, args);
2846
- }
2847
2761
  }
2848
2762
 
2849
2763
  // ============ 单独配置 Claude Code CLI ============
@@ -3118,8 +3032,8 @@ async function yycodeQuickSetup(paths) {
3118
3032
 
3119
3033
  // Codex 侧
3120
3034
  const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
3121
- const codexModelId = 'gpt-5.3-codex';
3122
- const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: 'GPT 5.3 Codex' };
3035
+ const codexModelId = CODEX_MODELS[0]?.id || 'gpt-5.4';
3036
+ const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: 'GPT 5.4' };
3123
3037
  const codexModelKey = `${codexProviderName}/${codexModelId}`;
3124
3038
 
3125
3039
  config.models.providers[codexProviderName] = {
@@ -4503,7 +4417,7 @@ function testCodexApi(baseUrl, apiKey, model) {
4503
4417
  const protocol = urlObj.protocol === 'https:' ? https : http;
4504
4418
 
4505
4419
  const postData = JSON.stringify({
4506
- model: model || 'gpt-5.2',
4420
+ model: model || 'gpt-5.4',
4507
4421
  input: '你是哪个模型?请用一句话回答你的模型名称和版本。'
4508
4422
  });
4509
4423
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.51",
3
+ "version": "1.0.53",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {