yymaxapi 1.0.50 → 1.0.52
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 +90 -58
- package/package.json +1 -1
package/bin/yymaxapi.js
CHANGED
|
@@ -140,8 +140,6 @@ const DEFAULT_API_CONFIG = {
|
|
|
140
140
|
|
|
141
141
|
const SKIP_API_VALIDATION = false;
|
|
142
142
|
|
|
143
|
-
const SKIP_API_VALIDATION = false;
|
|
144
|
-
|
|
145
143
|
function normalizeEndpoints(raw, fallback) {
|
|
146
144
|
if (!Array.isArray(raw)) return fallback;
|
|
147
145
|
const normalized = raw
|
|
@@ -1184,8 +1182,17 @@ function coerceModelsRecord(value) {
|
|
|
1184
1182
|
return record;
|
|
1185
1183
|
}
|
|
1186
1184
|
|
|
1185
|
+
const OPENCLAW_INVALID_ROOT_KEYS = ['model'];
|
|
1186
|
+
|
|
1187
|
+
function sanitizeRootKeys(config) {
|
|
1188
|
+
for (const key of OPENCLAW_INVALID_ROOT_KEYS) {
|
|
1189
|
+
if (key in config) delete config[key];
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1187
1193
|
function ensureConfigStructure(config) {
|
|
1188
1194
|
const next = config || {};
|
|
1195
|
+
sanitizeRootKeys(next);
|
|
1189
1196
|
if (!next.models) next.models = {};
|
|
1190
1197
|
if (!next.models.providers) next.models.providers = {};
|
|
1191
1198
|
if (!next.agents) next.agents = {};
|
|
@@ -2668,25 +2675,54 @@ async function autoActivate(paths, args = {}) {
|
|
|
2668
2675
|
// ---- 构建配置 ----
|
|
2669
2676
|
const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
|
|
2670
2677
|
|
|
2671
|
-
// 增量写入: 只添加/更新云翼 provider,保留其他已有配置
|
|
2672
|
-
|
|
2673
|
-
// Claude 侧 — 让用户选模型
|
|
2674
2678
|
const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2679
|
+
const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
|
|
2680
|
+
|
|
2681
|
+
// 检测单一模式:Claude 和 Codex 只有一个模型且 id 相同(如 maxapi 的 heibai)
|
|
2682
|
+
const isSingleMode = CLAUDE_MODELS.length === 1 && CODEX_MODELS.length === 1
|
|
2683
|
+
&& CLAUDE_MODELS[0].id === CODEX_MODELS[0].id;
|
|
2684
|
+
|
|
2685
|
+
let claudeModelId, codexModelId;
|
|
2686
|
+
|
|
2687
|
+
if (isSingleMode) {
|
|
2688
|
+
// 单一模式:固定模型,不选择,不分 Claude/Codex
|
|
2689
|
+
claudeModelId = CLAUDE_MODELS[0].id;
|
|
2690
|
+
codexModelId = CODEX_MODELS[0].id;
|
|
2691
|
+
} else {
|
|
2692
|
+
// 多模型模式:让用户选模型
|
|
2693
|
+
claudeModelId = (args['claude-model'] || '').toString().trim();
|
|
2694
|
+
if (!claudeModelId && CLAUDE_MODELS.length > 1) {
|
|
2695
|
+
const { picked } = await inquirer.prompt([{
|
|
2696
|
+
type: 'list',
|
|
2697
|
+
name: 'picked',
|
|
2698
|
+
message: '选择 Claude 模型:',
|
|
2699
|
+
choices: CLAUDE_MODELS.map(m => ({ name: m.name, value: m.id })),
|
|
2700
|
+
default: CLAUDE_MODELS[0].id
|
|
2701
|
+
}]);
|
|
2702
|
+
claudeModelId = picked;
|
|
2703
|
+
}
|
|
2704
|
+
if (!claudeModelId) claudeModelId = CLAUDE_MODELS[0]?.id || 'claude-sonnet-4-6';
|
|
2705
|
+
|
|
2706
|
+
codexModelId = (args['codex-model'] || '').toString().trim();
|
|
2707
|
+
if (!codexModelId && CODEX_MODELS.length > 1) {
|
|
2708
|
+
const { pickedCodex } = await inquirer.prompt([{
|
|
2709
|
+
type: 'list',
|
|
2710
|
+
name: 'pickedCodex',
|
|
2711
|
+
message: '选择 Codex 模型:',
|
|
2712
|
+
choices: CODEX_MODELS.map(m => ({ name: m.name, value: m.id })),
|
|
2713
|
+
default: CODEX_MODELS[0].id
|
|
2714
|
+
}]);
|
|
2715
|
+
codexModelId = pickedCodex;
|
|
2716
|
+
}
|
|
2717
|
+
if (!codexModelId) codexModelId = CODEX_MODELS[0]?.id || 'gpt-5.3-codex';
|
|
2685
2718
|
}
|
|
2686
|
-
|
|
2719
|
+
|
|
2687
2720
|
const claudeModel = CLAUDE_MODELS.find(m => m.id === claudeModelId) || { id: claudeModelId, name: claudeModelId };
|
|
2721
|
+
const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: codexModelId };
|
|
2688
2722
|
const claudeModelKey = `${claudeProviderName}/${claudeModelId}`;
|
|
2723
|
+
const codexModelKey = `${codexProviderName}/${codexModelId}`;
|
|
2689
2724
|
|
|
2725
|
+
// 写入 Claude provider
|
|
2690
2726
|
config.models.providers[claudeProviderName] = {
|
|
2691
2727
|
baseUrl: claudeBaseUrl,
|
|
2692
2728
|
auth: DEFAULT_AUTH_MODE,
|
|
@@ -2704,23 +2740,7 @@ async function autoActivate(paths, args = {}) {
|
|
|
2704
2740
|
config.auth.profiles[`${claudeProviderName}:default`] = { provider: claudeProviderName, mode: 'api_key' };
|
|
2705
2741
|
config.agents.defaults.models[claudeModelKey] = { alias: claudeProviderName };
|
|
2706
2742
|
|
|
2707
|
-
// Codex
|
|
2708
|
-
const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
|
|
2709
|
-
let codexModelId = (args['codex-model'] || '').toString().trim();
|
|
2710
|
-
if (!codexModelId && CODEX_MODELS.length > 1) {
|
|
2711
|
-
const { pickedCodex } = await inquirer.prompt([{
|
|
2712
|
-
type: 'list',
|
|
2713
|
-
name: 'pickedCodex',
|
|
2714
|
-
message: '选择 Codex 模型:',
|
|
2715
|
-
choices: CODEX_MODELS.map(m => ({ name: m.name, value: m.id })),
|
|
2716
|
-
default: CODEX_MODELS[0].id
|
|
2717
|
-
}]);
|
|
2718
|
-
codexModelId = pickedCodex;
|
|
2719
|
-
}
|
|
2720
|
-
if (!codexModelId) codexModelId = CODEX_MODELS[0]?.id || 'gpt-5.3-codex';
|
|
2721
|
-
const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: codexModelId };
|
|
2722
|
-
const codexModelKey = `${codexProviderName}/${codexModelId}`;
|
|
2723
|
-
|
|
2743
|
+
// 写入 Codex provider(单一模式下仍写入,保证配置完整)
|
|
2724
2744
|
config.models.providers[codexProviderName] = {
|
|
2725
2745
|
baseUrl: codexBaseUrl,
|
|
2726
2746
|
auth: DEFAULT_AUTH_MODE,
|
|
@@ -2739,27 +2759,34 @@ async function autoActivate(paths, args = {}) {
|
|
|
2739
2759
|
config.agents.defaults.models[codexModelKey] = { alias: codexProviderName };
|
|
2740
2760
|
|
|
2741
2761
|
// ---- 选择主力 ----
|
|
2742
|
-
let
|
|
2743
|
-
if (
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2762
|
+
let primaryModelKey, fallbackModelKey;
|
|
2763
|
+
if (isSingleMode) {
|
|
2764
|
+
// 单一模式:直接用 Claude provider 作为 primary,不需要用户选
|
|
2765
|
+
primaryModelKey = claudeModelKey;
|
|
2766
|
+
fallbackModelKey = codexModelKey;
|
|
2747
2767
|
} else {
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2768
|
+
let primaryType = 'claude';
|
|
2769
|
+
if (args.primary === 'claude') {
|
|
2770
|
+
primaryType = 'claude';
|
|
2771
|
+
} else if (args.primary === 'codex') {
|
|
2772
|
+
primaryType = 'codex';
|
|
2773
|
+
} else {
|
|
2774
|
+
const { picked } = await inquirer.prompt([{
|
|
2775
|
+
type: 'list',
|
|
2776
|
+
name: 'picked',
|
|
2777
|
+
message: '选择主力工具(默认启动哪个):',
|
|
2778
|
+
choices: [
|
|
2779
|
+
{ name: 'Claude Code', value: 'claude' },
|
|
2780
|
+
{ name: 'Codex (GPT)', value: 'codex' }
|
|
2781
|
+
]
|
|
2782
|
+
}]);
|
|
2783
|
+
primaryType = picked;
|
|
2784
|
+
}
|
|
2785
|
+
primaryModelKey = primaryType === 'claude' ? claudeModelKey : codexModelKey;
|
|
2786
|
+
fallbackModelKey = primaryType === 'claude' ? codexModelKey : claudeModelKey;
|
|
2758
2787
|
}
|
|
2759
2788
|
|
|
2760
|
-
const primaryModelKey = primaryType === 'claude' ? claudeModelKey : codexModelKey;
|
|
2761
2789
|
config.agents.defaults.model.primary = primaryModelKey;
|
|
2762
|
-
const fallbackModelKey = primaryType === 'claude' ? codexModelKey : claudeModelKey;
|
|
2763
2790
|
config.agents.defaults.model.fallbacks = [fallbackModelKey];
|
|
2764
2791
|
|
|
2765
2792
|
// ---- 写入配置 ----
|
|
@@ -2775,13 +2802,19 @@ async function autoActivate(paths, args = {}) {
|
|
|
2775
2802
|
writeSpinner.succeed('配置写入完成');
|
|
2776
2803
|
|
|
2777
2804
|
// ---- 输出结果 ----
|
|
2778
|
-
const primaryTag = primaryType === 'claude' ? ' (主)' : '';
|
|
2779
|
-
const codexTag = primaryType === 'codex' ? ' (主)' : '';
|
|
2780
2805
|
console.log(chalk.green('\n✅ 一键激活完成!'));
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2806
|
+
if (isSingleMode) {
|
|
2807
|
+
console.log(chalk.cyan(` 节点: ${selectedEndpoint.url}`));
|
|
2808
|
+
console.log(chalk.gray(` 模型: ${claudeModel.name}`));
|
|
2809
|
+
} else {
|
|
2810
|
+
const primaryType = primaryModelKey === claudeModelKey ? 'claude' : 'codex';
|
|
2811
|
+
const primaryTag = primaryType === 'claude' ? ' (主)' : '';
|
|
2812
|
+
const codexTag = primaryType === 'codex' ? ' (主)' : '';
|
|
2813
|
+
console.log(chalk.cyan(` Claude Code${primaryTag}: ${claudeBaseUrl}`));
|
|
2814
|
+
console.log(chalk.gray(` 模型: ${claudeModel.name}`));
|
|
2815
|
+
console.log(chalk.cyan(` Codex${codexTag}: ${codexBaseUrl}`));
|
|
2816
|
+
console.log(chalk.gray(` 模型: ${codexModel.name}`));
|
|
2817
|
+
}
|
|
2785
2818
|
console.log(chalk.gray(' API Key: 已设置'));
|
|
2786
2819
|
if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
|
|
2787
2820
|
|
|
@@ -3665,8 +3698,7 @@ async function testConnection(paths, args = {}) {
|
|
|
3665
3698
|
console.log(chalk.yellow('⚠️ 请先设置主模型'));
|
|
3666
3699
|
return;
|
|
3667
3700
|
}
|
|
3668
|
-
|
|
3669
|
-
const preferOrder = ['claude-yunyi', 'yunyi', 'heibai'];
|
|
3701
|
+
const preferOrder = ['maxapi', 'heibai', 'claude-yunyi', 'yunyi', 'maxapi-codex'];
|
|
3670
3702
|
const preferred = preferOrder.find(n => providerNames.includes(n));
|
|
3671
3703
|
const firstP = preferred || providerNames.find(n => n.includes('claude')) || providerNames[0];
|
|
3672
3704
|
const firstModels = providers[firstP]?.models || [];
|