yymaxapi 1.0.99 → 1.0.101
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 +306 -100
- package/package.json +1 -1
package/bin/yymaxapi.js
CHANGED
|
@@ -254,6 +254,34 @@ function getDefaultCodexModel() {
|
|
|
254
254
|
return CODEX_MODELS[0] || { id: 'gpt-5.4', name: 'GPT 5.4' };
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
function getExternalClaudeProviderKey() {
|
|
258
|
+
return String(API_CONFIG?.claude?.providerName || 'yunyi-claude').trim() || 'yunyi-claude';
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function getExternalCodexProviderKey() {
|
|
262
|
+
const providerKey = String(API_CONFIG?.codex?.providerName || '').trim();
|
|
263
|
+
if (!providerKey) return 'yunyi-codex';
|
|
264
|
+
return providerKey === 'yunyi' ? 'yunyi-codex' : providerKey;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function getExternalModelKey(type, modelId) {
|
|
268
|
+
const providerKey = type === 'codex' ? getExternalCodexProviderKey() : getExternalClaudeProviderKey();
|
|
269
|
+
return `${providerKey}/${modelId}`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function getProviderBrandPrefix() {
|
|
273
|
+
const providerKeys = [getExternalClaudeProviderKey(), getExternalCodexProviderKey()];
|
|
274
|
+
if (providerKeys.some(key => key.startsWith('maxapi'))) return 'MAXAPI';
|
|
275
|
+
if (providerKeys.some(key => key.startsWith('yunyi'))) return '云翼';
|
|
276
|
+
return 'OpenClaw';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function isUnifiedSingleModelMode() {
|
|
280
|
+
return CLAUDE_MODELS.length === 1
|
|
281
|
+
&& CODEX_MODELS.length === 1
|
|
282
|
+
&& CLAUDE_MODELS[0].id === CODEX_MODELS[0].id;
|
|
283
|
+
}
|
|
284
|
+
|
|
257
285
|
function buildProviderModelMap(models) {
|
|
258
286
|
const mapped = {};
|
|
259
287
|
for (const model of models || []) {
|
|
@@ -268,7 +296,7 @@ function getClaudeSwitchHint() {
|
|
|
268
296
|
}
|
|
269
297
|
|
|
270
298
|
function getOpencodeSwitchHint() {
|
|
271
|
-
return [...CLAUDE_MODELS, ...CODEX_MODELS].map(model => model.name).join(' / ');
|
|
299
|
+
return [...new Set([...CLAUDE_MODELS, ...CODEX_MODELS].map(model => model.name))].join(' / ');
|
|
272
300
|
}
|
|
273
301
|
|
|
274
302
|
async function promptClaudeModelSelection(args = {}, message = '选择 Claude 模型:') {
|
|
@@ -297,16 +325,29 @@ async function promptOpencodeDefaultModelSelection(args = {}, message = '选择
|
|
|
297
325
|
const fallbackClaude = getDefaultClaudeModel();
|
|
298
326
|
const fallbackCodex = getDefaultCodexModel();
|
|
299
327
|
const requested = (args['default-model'] || args.model || args['claude-model'] || args['codex-model'] || '').toString().trim();
|
|
328
|
+
const claudeProviderKey = getExternalClaudeProviderKey();
|
|
329
|
+
const codexProviderKey = getExternalCodexProviderKey();
|
|
330
|
+
|
|
331
|
+
if (isUnifiedSingleModelMode()) {
|
|
332
|
+
const unifiedModel = CLAUDE_MODELS[0] || CODEX_MODELS[0] || fallbackClaude;
|
|
333
|
+
return {
|
|
334
|
+
type: 'claude',
|
|
335
|
+
providerKey: claudeProviderKey,
|
|
336
|
+
modelId: unifiedModel.id,
|
|
337
|
+
modelName: unifiedModel.name,
|
|
338
|
+
modelKey: getExternalModelKey('claude', unifiedModel.id)
|
|
339
|
+
};
|
|
340
|
+
}
|
|
300
341
|
|
|
301
342
|
if (requested) {
|
|
302
343
|
const inClaude = CLAUDE_MODELS.find(model => model.id === requested);
|
|
303
344
|
if (inClaude) {
|
|
304
345
|
return {
|
|
305
346
|
type: 'claude',
|
|
306
|
-
providerKey:
|
|
347
|
+
providerKey: claudeProviderKey,
|
|
307
348
|
modelId: inClaude.id,
|
|
308
349
|
modelName: inClaude.name,
|
|
309
|
-
modelKey:
|
|
350
|
+
modelKey: getExternalModelKey('claude', inClaude.id)
|
|
310
351
|
};
|
|
311
352
|
}
|
|
312
353
|
|
|
@@ -314,10 +355,10 @@ async function promptOpencodeDefaultModelSelection(args = {}, message = '选择
|
|
|
314
355
|
if (inCodex) {
|
|
315
356
|
return {
|
|
316
357
|
type: 'codex',
|
|
317
|
-
providerKey:
|
|
358
|
+
providerKey: codexProviderKey,
|
|
318
359
|
modelId: inCodex.id,
|
|
319
360
|
modelName: inCodex.name,
|
|
320
|
-
modelKey:
|
|
361
|
+
modelKey: getExternalModelKey('codex', inCodex.id)
|
|
321
362
|
};
|
|
322
363
|
}
|
|
323
364
|
}
|
|
@@ -350,20 +391,20 @@ async function promptOpencodeDefaultModelSelection(args = {}, message = '选择
|
|
|
350
391
|
const model = CODEX_MODELS.find(item => item.id === pickedId) || fallbackCodex;
|
|
351
392
|
return {
|
|
352
393
|
type: 'codex',
|
|
353
|
-
providerKey:
|
|
394
|
+
providerKey: codexProviderKey,
|
|
354
395
|
modelId: model.id,
|
|
355
396
|
modelName: model.name,
|
|
356
|
-
modelKey:
|
|
397
|
+
modelKey: getExternalModelKey('codex', model.id)
|
|
357
398
|
};
|
|
358
399
|
}
|
|
359
400
|
|
|
360
401
|
const model = CLAUDE_MODELS.find(item => item.id === pickedId) || fallbackClaude;
|
|
361
402
|
return {
|
|
362
403
|
type: 'claude',
|
|
363
|
-
providerKey:
|
|
404
|
+
providerKey: claudeProviderKey,
|
|
364
405
|
modelId: model.id,
|
|
365
406
|
modelName: model.name,
|
|
366
|
-
modelKey:
|
|
407
|
+
modelKey: getExternalModelKey('claude', model.id)
|
|
367
408
|
};
|
|
368
409
|
}
|
|
369
410
|
|
|
@@ -864,13 +905,14 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
864
905
|
const markerEnd = '# <<< maxapi codex <<<';
|
|
865
906
|
const topMarker = '# >>> maxapi codex top >>>';
|
|
866
907
|
const topMarkerEnd = '# <<< maxapi codex top <<<';
|
|
867
|
-
const providerKey =
|
|
908
|
+
const providerKey = getExternalCodexProviderKey();
|
|
909
|
+
const providerLabel = `${getProviderBrandPrefix()} Codex`;
|
|
910
|
+
const removableProviderKeys = [...new Set([providerKey, 'yunyi-codex', 'maxapi-codex'])];
|
|
868
911
|
// 确保 base_url 以 /v1 结尾(Codex CLI 要求)
|
|
869
912
|
let normalizedUrl = baseUrl.replace(/\/+$/, '');
|
|
870
913
|
if (!normalizedUrl.endsWith('/v1')) normalizedUrl += '/v1';
|
|
871
914
|
try {
|
|
872
915
|
let existing = '';
|
|
873
|
-
const escapedProviderKey = providerKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
874
916
|
if (fs.existsSync(configPath)) {
|
|
875
917
|
existing = fs.readFileSync(configPath, 'utf8');
|
|
876
918
|
// 移除旧的 maxapi section(provider block)
|
|
@@ -879,8 +921,11 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
879
921
|
// 移除旧的 maxapi top-level block
|
|
880
922
|
const topRe = new RegExp(`${topMarker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${topMarkerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`, 'g');
|
|
881
923
|
existing = existing.replace(topRe, '');
|
|
882
|
-
//
|
|
883
|
-
|
|
924
|
+
// 兼容旧版:移除历史遗留的 provider block、旧 openclaw-relay、旧 yunyi opencode 标记块
|
|
925
|
+
for (const removableProviderKey of removableProviderKeys) {
|
|
926
|
+
const escapedProviderKey = removableProviderKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
927
|
+
existing = existing.replace(new RegExp(`\\[model_providers\\.${escapedProviderKey}\\]\\n(?:(?!\\[)[^\\n]*\\n?)*`, 'g'), '');
|
|
928
|
+
}
|
|
884
929
|
existing = existing.replace(/\[model_providers\.openclaw-relay\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
|
|
885
930
|
existing = existing.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
|
|
886
931
|
existing = existing.replace(/\n{3,}/g, '\n\n').trim();
|
|
@@ -900,7 +945,7 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
900
945
|
const providerBlock = [
|
|
901
946
|
marker,
|
|
902
947
|
`[model_providers.${providerKey}]`,
|
|
903
|
-
`name = "
|
|
948
|
+
`name = "${providerLabel}"`,
|
|
904
949
|
`base_url = "${normalizedUrl}"`,
|
|
905
950
|
`wire_api = "responses"`,
|
|
906
951
|
`experimental_bearer_token = "${apiKey}"`,
|
|
@@ -931,10 +976,13 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
931
976
|
} catch { /* 非关键,静默失败 */ }
|
|
932
977
|
}
|
|
933
978
|
|
|
934
|
-
function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, defaultModelKey =
|
|
979
|
+
function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, defaultModelKey = getExternalModelKey('claude', getDefaultClaudeModel().id)) {
|
|
935
980
|
const home = os.homedir();
|
|
936
981
|
const claudeUrl = claudeBaseUrl.replace(/\/+$/, '');
|
|
937
982
|
const codexUrl = (codexBaseUrl || '').replace(/\/+$/, '');
|
|
983
|
+
const claudeProviderKey = getExternalClaudeProviderKey();
|
|
984
|
+
const codexProviderKey = getExternalCodexProviderKey();
|
|
985
|
+
const brandPrefix = getProviderBrandPrefix();
|
|
938
986
|
|
|
939
987
|
// ---- 1. opencode.json (CLI + 桌面版) ----
|
|
940
988
|
const configDir = process.platform === 'win32'
|
|
@@ -950,8 +998,8 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, defaultModelKe
|
|
|
950
998
|
if (!existing.provider) existing.provider = {};
|
|
951
999
|
|
|
952
1000
|
// Claude provider (@ai-sdk/anthropic)
|
|
953
|
-
existing.provider[
|
|
954
|
-
name:
|
|
1001
|
+
existing.provider[claudeProviderKey] = {
|
|
1002
|
+
name: `${brandPrefix} Claude`,
|
|
955
1003
|
npm: '@ai-sdk/anthropic',
|
|
956
1004
|
models: buildProviderModelMap(CLAUDE_MODELS),
|
|
957
1005
|
options: { apiKey, baseURL: `${claudeUrl}/v1` }
|
|
@@ -959,8 +1007,8 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, defaultModelKe
|
|
|
959
1007
|
|
|
960
1008
|
// Codex provider (@ai-sdk/openai)
|
|
961
1009
|
if (codexUrl) {
|
|
962
|
-
existing.provider[
|
|
963
|
-
name:
|
|
1010
|
+
existing.provider[codexProviderKey] = {
|
|
1011
|
+
name: `${brandPrefix} Codex`,
|
|
964
1012
|
npm: '@ai-sdk/openai',
|
|
965
1013
|
models: buildProviderModelMap(CODEX_MODELS),
|
|
966
1014
|
options: { apiKey, baseURL: codexUrl }
|
|
@@ -978,7 +1026,8 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, defaultModelKe
|
|
|
978
1026
|
|
|
979
1027
|
// 从 disabled_providers 中移除我们的 provider
|
|
980
1028
|
if (Array.isArray(existing.disabled_providers)) {
|
|
981
|
-
|
|
1029
|
+
const enabledProviders = new Set([claudeProviderKey, codexProviderKey, 'yunyi-claude', 'yunyi-codex', 'maxapi', 'maxapi-codex']);
|
|
1030
|
+
existing.disabled_providers = existing.disabled_providers.filter(p => !enabledProviders.has(p));
|
|
982
1031
|
if (existing.disabled_providers.length === 0) delete existing.disabled_providers;
|
|
983
1032
|
}
|
|
984
1033
|
|
|
@@ -1036,7 +1085,7 @@ function syncExternalTools(type, baseUrl, apiKey, extra = {}) {
|
|
|
1036
1085
|
synced.push('Codex CLI config');
|
|
1037
1086
|
}
|
|
1038
1087
|
if (type === 'claude' && extra.codexBaseUrl) {
|
|
1039
|
-
writeOpencodeConfig(baseUrl, extra.codexBaseUrl, apiKey, extra.opencodeDefaultModelKey ||
|
|
1088
|
+
writeOpencodeConfig(baseUrl, extra.codexBaseUrl, apiKey, extra.opencodeDefaultModelKey || getExternalModelKey('claude', extra.claudeModelId || getDefaultClaudeModel().id));
|
|
1040
1089
|
synced.push('Opencode config');
|
|
1041
1090
|
}
|
|
1042
1091
|
} catch { /* ignore */ }
|
|
@@ -2115,9 +2164,146 @@ function getManagedClaudeAgentId(config) {
|
|
|
2115
2164
|
return mainAgent ? YYMAXAPI_OPENCLAW_MAIN_AGENT_ID : (sideAgent ? YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID : null);
|
|
2116
2165
|
}
|
|
2117
2166
|
|
|
2167
|
+
function getManagedYunyiActiveType(config) {
|
|
2168
|
+
const defaultsPrimary = canonicalizeManagedYunyiModelKey(String(config?.agents?.defaults?.model?.primary || '').trim());
|
|
2169
|
+
if (isManagedYunyiClaudeModelKey(defaultsPrimary)) return 'claude';
|
|
2170
|
+
if (isManagedYunyiGptModelKey(defaultsPrimary)) return 'codex';
|
|
2171
|
+
|
|
2172
|
+
const mainState = getAgentModelState(findAgentById(config, YYMAXAPI_OPENCLAW_MAIN_AGENT_ID));
|
|
2173
|
+
const mainPrimary = canonicalizeManagedYunyiModelKey(mainState.primary || '');
|
|
2174
|
+
if (isManagedYunyiClaudeModelKey(mainPrimary)) return 'claude';
|
|
2175
|
+
if (isManagedYunyiGptModelKey(mainPrimary)) return 'codex';
|
|
2176
|
+
|
|
2177
|
+
return 'claude';
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
function findManagedYunyiAgentState(config, type) {
|
|
2181
|
+
const candidateIds = type === 'claude'
|
|
2182
|
+
? [YYMAXAPI_OPENCLAW_MAIN_AGENT_ID, YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID]
|
|
2183
|
+
: [YYMAXAPI_OPENCLAW_MAIN_AGENT_ID, YYMAXAPI_OPENCLAW_GPT_AGENT_ID, ...YYMAXAPI_OPENCLAW_LEGACY_GPT_AGENT_IDS];
|
|
2184
|
+
|
|
2185
|
+
const matcher = type === 'claude' ? isManagedYunyiClaudeModelKey : isManagedYunyiGptModelKey;
|
|
2186
|
+
|
|
2187
|
+
for (const agentId of candidateIds) {
|
|
2188
|
+
const state = getAgentModelState(findAgentById(config, agentId));
|
|
2189
|
+
const primary = canonicalizeManagedYunyiModelKey(state.primary || '', type);
|
|
2190
|
+
if (matcher(primary)) return state;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
return {};
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
function getManagedYunyiDesiredPrimaryModelKey(config, type, explicitModelKey = '') {
|
|
2197
|
+
const explicitPrimary = canonicalizeManagedYunyiModelKey(explicitModelKey, type);
|
|
2198
|
+
if (type === 'claude' ? isManagedYunyiClaudeModelKey(explicitPrimary) : isManagedYunyiGptModelKey(explicitPrimary)) {
|
|
2199
|
+
return explicitPrimary;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
const defaultsPrimary = canonicalizeManagedYunyiModelKey(String(config?.agents?.defaults?.model?.primary || '').trim(), type);
|
|
2203
|
+
if (type === 'claude' ? isManagedYunyiClaudeModelKey(defaultsPrimary) : isManagedYunyiGptModelKey(defaultsPrimary)) {
|
|
2204
|
+
return defaultsPrimary;
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
return '';
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
function resolveManagedYunyiAgentAssignments(config, preferredType = '') {
|
|
2211
|
+
const mainAgent = findAgentById(config, YYMAXAPI_OPENCLAW_MAIN_AGENT_ID);
|
|
2212
|
+
const preservedMain = Boolean(mainAgent) && !isManagedMainAgent(mainAgent);
|
|
2213
|
+
const activeType = preferredType || getManagedYunyiActiveType(config);
|
|
2214
|
+
|
|
2215
|
+
if (preservedMain) {
|
|
2216
|
+
return {
|
|
2217
|
+
preservedMain: true,
|
|
2218
|
+
activeType,
|
|
2219
|
+
mainAgentType: '',
|
|
2220
|
+
claudeAgentId: YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID,
|
|
2221
|
+
gptAgentId: YYMAXAPI_OPENCLAW_GPT_AGENT_ID
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
return activeType === 'codex'
|
|
2226
|
+
? {
|
|
2227
|
+
preservedMain: false,
|
|
2228
|
+
activeType,
|
|
2229
|
+
mainAgentType: 'codex',
|
|
2230
|
+
claudeAgentId: YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID,
|
|
2231
|
+
gptAgentId: YYMAXAPI_OPENCLAW_MAIN_AGENT_ID
|
|
2232
|
+
}
|
|
2233
|
+
: {
|
|
2234
|
+
preservedMain: false,
|
|
2235
|
+
activeType: 'claude',
|
|
2236
|
+
mainAgentType: 'claude',
|
|
2237
|
+
claudeAgentId: YYMAXAPI_OPENCLAW_MAIN_AGENT_ID,
|
|
2238
|
+
gptAgentId: YYMAXAPI_OPENCLAW_GPT_AGENT_ID
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
function syncManagedYunyiAgents(config, options = {}) {
|
|
2243
|
+
ensureConfigStructure(config);
|
|
2244
|
+
|
|
2245
|
+
const assignments = resolveManagedYunyiAgentAssignments(config, options.preferredType);
|
|
2246
|
+
const agentList = ensureAgentList(config);
|
|
2247
|
+
const claudeDesiredPrimary = getManagedYunyiDesiredPrimaryModelKey(config, 'claude', options.selectedModelKey);
|
|
2248
|
+
const gptDesiredPrimary = getManagedYunyiDesiredPrimaryModelKey(config, 'codex', options.selectedModelKey);
|
|
2249
|
+
const claudeState = normalizeManagedYunyiModelState('claude', {
|
|
2250
|
+
...findManagedYunyiAgentState(config, 'claude'),
|
|
2251
|
+
...(claudeDesiredPrimary ? { primary: claudeDesiredPrimary } : {})
|
|
2252
|
+
}, options);
|
|
2253
|
+
const gptState = normalizeManagedYunyiModelState('codex', {
|
|
2254
|
+
...findManagedYunyiAgentState(config, 'codex'),
|
|
2255
|
+
...(gptDesiredPrimary ? { primary: gptDesiredPrimary } : {})
|
|
2256
|
+
}, options);
|
|
2257
|
+
let changed = false;
|
|
2258
|
+
|
|
2259
|
+
if (!assignments.preservedMain) {
|
|
2260
|
+
const mainType = assignments.mainAgentType === 'codex' ? 'codex' : 'claude';
|
|
2261
|
+
const mainState = mainType === 'codex' ? gptState : claudeState;
|
|
2262
|
+
const mainResult = upsertManagedAgent(agentList, {
|
|
2263
|
+
id: YYMAXAPI_OPENCLAW_MAIN_AGENT_ID,
|
|
2264
|
+
default: true,
|
|
2265
|
+
name: mainType === 'codex' ? 'yunyi-gpt' : 'yunyi-claude',
|
|
2266
|
+
model: mainState
|
|
2267
|
+
}, isManagedMainAgent);
|
|
2268
|
+
if (mainResult.changed) changed = true;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
if (assignments.claudeAgentId === YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID) {
|
|
2272
|
+
const sideClaudeResult = upsertManagedAgent(agentList, {
|
|
2273
|
+
id: YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID,
|
|
2274
|
+
default: false,
|
|
2275
|
+
name: 'yunyi-claude',
|
|
2276
|
+
model: claudeState
|
|
2277
|
+
}, isManagedClaudeSideAgent);
|
|
2278
|
+
if (sideClaudeResult.changed) changed = true;
|
|
2279
|
+
} else if (removeManagedAgent(agentList, YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID, isManagedClaudeSideAgent)) {
|
|
2280
|
+
changed = true;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
if (assignments.gptAgentId === YYMAXAPI_OPENCLAW_GPT_AGENT_ID) {
|
|
2284
|
+
const gptResult = upsertManagedAgent(agentList, {
|
|
2285
|
+
id: YYMAXAPI_OPENCLAW_GPT_AGENT_ID,
|
|
2286
|
+
default: false,
|
|
2287
|
+
name: 'yunyi-gpt',
|
|
2288
|
+
model: gptState
|
|
2289
|
+
}, isManagedGptAgent);
|
|
2290
|
+
if (gptResult.changed) changed = true;
|
|
2291
|
+
} else if (removeManagedAgent(agentList, YYMAXAPI_OPENCLAW_GPT_AGENT_ID, isManagedGptAgent)) {
|
|
2292
|
+
changed = true;
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
for (const legacyAgentId of YYMAXAPI_OPENCLAW_LEGACY_GPT_AGENT_IDS) {
|
|
2296
|
+
if (legacyAgentId === YYMAXAPI_OPENCLAW_GPT_AGENT_ID) continue;
|
|
2297
|
+
if (removeManagedAgent(agentList, legacyAgentId, isManagedGptAgent)) changed = true;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
return { changed, ...assignments };
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2118
2303
|
function inferManagedYunyiAgentIdForModelKey(config, modelKey) {
|
|
2119
|
-
|
|
2120
|
-
if (
|
|
2304
|
+
const assignments = resolveManagedYunyiAgentAssignments(config);
|
|
2305
|
+
if (isManagedYunyiGptModelKey(modelKey)) return assignments.gptAgentId;
|
|
2306
|
+
if (isManagedYunyiClaudeModelKey(modelKey)) return assignments.claudeAgentId || getManagedClaudeAgentId(config);
|
|
2121
2307
|
return null;
|
|
2122
2308
|
}
|
|
2123
2309
|
|
|
@@ -2157,20 +2343,15 @@ function applyManagedYunyiModelSelection(config, selectedModelKey) {
|
|
|
2157
2343
|
}
|
|
2158
2344
|
}
|
|
2159
2345
|
|
|
2160
|
-
const
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
const shouldManage = selectedType === 'codex'
|
|
2170
|
-
? isManagedGptAgent
|
|
2171
|
-
: (agentId === YYMAXAPI_OPENCLAW_MAIN_AGENT_ID ? isManagedMainAgent : isManagedClaudeSideAgent);
|
|
2172
|
-
const updateResult = upsertManagedAgent(agentList, nextAgent, shouldManage);
|
|
2173
|
-
if (updateResult.changed) changed = true;
|
|
2346
|
+
const syncResult = syncManagedYunyiAgents(config, {
|
|
2347
|
+
preferredType: selectedType,
|
|
2348
|
+
selectedModelKey: normalizedSelected
|
|
2349
|
+
});
|
|
2350
|
+
if (syncResult.changed) changed = true;
|
|
2351
|
+
|
|
2352
|
+
const agentId = selectedType === 'codex'
|
|
2353
|
+
? syncResult.gptAgentId
|
|
2354
|
+
: syncResult.claudeAgentId;
|
|
2174
2355
|
|
|
2175
2356
|
return { changed, selectedModelKey: normalizedSelected, agentId };
|
|
2176
2357
|
}
|
|
@@ -2544,45 +2725,6 @@ function applyManagedYunyiOpenClawLayout(config, options = {}) {
|
|
|
2544
2725
|
}
|
|
2545
2726
|
}
|
|
2546
2727
|
|
|
2547
|
-
const agentList = ensureAgentList(config);
|
|
2548
|
-
const currentMainAgentState = getAgentModelState(findAgentById(config, YYMAXAPI_OPENCLAW_MAIN_AGENT_ID));
|
|
2549
|
-
const mainAgentResult = upsertManagedAgent(agentList, {
|
|
2550
|
-
id: YYMAXAPI_OPENCLAW_MAIN_AGENT_ID,
|
|
2551
|
-
default: true,
|
|
2552
|
-
name: 'yunyi-claude',
|
|
2553
|
-
model: normalizeManagedYunyiModelState('claude', currentMainAgentState, options)
|
|
2554
|
-
}, isManagedMainAgent);
|
|
2555
|
-
if (mainAgentResult.changed) changed = true;
|
|
2556
|
-
|
|
2557
|
-
let claudeAgentId = YYMAXAPI_OPENCLAW_MAIN_AGENT_ID;
|
|
2558
|
-
let preservedMain = !mainAgentResult.managed;
|
|
2559
|
-
if (!mainAgentResult.managed) {
|
|
2560
|
-
const currentClaudeSideState = getAgentModelState(findAgentById(config, YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID));
|
|
2561
|
-
const fallbackClaudeAgentResult = upsertManagedAgent(agentList, {
|
|
2562
|
-
id: YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID,
|
|
2563
|
-
default: false,
|
|
2564
|
-
name: 'yunyi-claude',
|
|
2565
|
-
model: normalizeManagedYunyiModelState('claude', currentClaudeSideState, options)
|
|
2566
|
-
}, isManagedClaudeSideAgent);
|
|
2567
|
-
if (fallbackClaudeAgentResult.changed) changed = true;
|
|
2568
|
-
claudeAgentId = fallbackClaudeAgentResult.managed ? YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID : null;
|
|
2569
|
-
} else if (removeManagedAgent(agentList, YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID, isManagedClaudeSideAgent)) {
|
|
2570
|
-
changed = true;
|
|
2571
|
-
}
|
|
2572
|
-
|
|
2573
|
-
const currentGptAgentState = getAgentModelState(findAgentById(config, YYMAXAPI_OPENCLAW_GPT_AGENT_ID));
|
|
2574
|
-
const gptAgentResult = upsertManagedAgent(agentList, {
|
|
2575
|
-
id: YYMAXAPI_OPENCLAW_GPT_AGENT_ID,
|
|
2576
|
-
default: false,
|
|
2577
|
-
name: 'yunyi-gpt',
|
|
2578
|
-
model: normalizeManagedYunyiModelState('codex', currentGptAgentState, options)
|
|
2579
|
-
}, isManagedGptAgent);
|
|
2580
|
-
if (gptAgentResult.changed) changed = true;
|
|
2581
|
-
for (const legacyAgentId of YYMAXAPI_OPENCLAW_LEGACY_GPT_AGENT_IDS) {
|
|
2582
|
-
if (legacyAgentId === YYMAXAPI_OPENCLAW_GPT_AGENT_ID) continue;
|
|
2583
|
-
if (removeManagedAgent(agentList, legacyAgentId, isManagedGptAgent)) changed = true;
|
|
2584
|
-
}
|
|
2585
|
-
|
|
2586
2728
|
if (shouldManageYunyiDefaults(config)) {
|
|
2587
2729
|
const nextDefaultsModel = normalizeManagedYunyiDefaultsModel(config.agents.defaults.model, options);
|
|
2588
2730
|
if (JSON.stringify(config.agents.defaults.model) !== JSON.stringify(nextDefaultsModel)) {
|
|
@@ -2604,14 +2746,26 @@ function applyManagedYunyiOpenClawLayout(config, options = {}) {
|
|
|
2604
2746
|
changed = true;
|
|
2605
2747
|
}
|
|
2606
2748
|
|
|
2607
|
-
|
|
2749
|
+
const syncResult = syncManagedYunyiAgents(config, options);
|
|
2750
|
+
if (syncResult.changed) changed = true;
|
|
2751
|
+
|
|
2752
|
+
return {
|
|
2753
|
+
changed,
|
|
2754
|
+
applied: true,
|
|
2755
|
+
claudeAgentId: syncResult.claudeAgentId,
|
|
2756
|
+
gptAgentId: syncResult.gptAgentId,
|
|
2757
|
+
preservedMain: syncResult.preservedMain,
|
|
2758
|
+
mainAgentType: syncResult.mainAgentType
|
|
2759
|
+
};
|
|
2608
2760
|
}
|
|
2609
2761
|
|
|
2610
2762
|
function printYunyiOpenClawSwitchHint(result = {}) {
|
|
2611
2763
|
if (!result?.applied) return;
|
|
2612
2764
|
const summary = result.preservedMain && result.claudeAgentId === YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID
|
|
2613
2765
|
? 'OpenClaw: main 已保留, Claude=yunyi-claude, GPT=yunyi-gpt'
|
|
2614
|
-
:
|
|
2766
|
+
: (result.mainAgentType === 'codex'
|
|
2767
|
+
? 'OpenClaw: main=yunyi-gpt, Claude=yunyi-claude'
|
|
2768
|
+
: 'OpenClaw: main=yunyi-claude, GPT=yunyi-gpt');
|
|
2615
2769
|
console.log(chalk.cyan(` ${summary}`));
|
|
2616
2770
|
}
|
|
2617
2771
|
|
|
@@ -3294,7 +3448,7 @@ function readOpencodeCliConfig() {
|
|
|
3294
3448
|
const config = readJsonIfExists(configPath) || {};
|
|
3295
3449
|
return {
|
|
3296
3450
|
configPath,
|
|
3297
|
-
modelKey: config.model ||
|
|
3451
|
+
modelKey: config.model || getExternalModelKey('claude', getDefaultClaudeModel().id),
|
|
3298
3452
|
configured: fs.existsSync(configPath),
|
|
3299
3453
|
config
|
|
3300
3454
|
};
|
|
@@ -3305,7 +3459,7 @@ function readCodexCliConfig() {
|
|
|
3305
3459
|
const configRaw = fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf8') : '';
|
|
3306
3460
|
const auth = readJsonIfExists(authPath) || {};
|
|
3307
3461
|
const model = (configRaw.match(/^model\s*=\s*"([^"]+)"\s*$/m) || [])[1] || getDefaultCodexModel().id;
|
|
3308
|
-
const provider = (configRaw.match(/^model_provider\s*=\s*"([^"]+)"\s*$/m) || [])[1] ||
|
|
3462
|
+
const provider = (configRaw.match(/^model_provider\s*=\s*"([^"]+)"\s*$/m) || [])[1] || getExternalCodexProviderKey();
|
|
3309
3463
|
const providerBlockRegex = new RegExp(`\\[model_providers\\.${escapeRegExp(provider)}\\]([\\s\\S]*?)(?=\\n\\[|$)`, 'm');
|
|
3310
3464
|
const providerBlock = (configRaw.match(providerBlockRegex) || [])[1] || '';
|
|
3311
3465
|
const baseUrl = (providerBlock.match(/base_url\s*=\s*"([^"]+)"/) || [])[1] || '';
|
|
@@ -3815,6 +3969,22 @@ async function tryAutoStartGateway(port, allowAutoDaemon) {
|
|
|
3815
3969
|
}
|
|
3816
3970
|
}
|
|
3817
3971
|
|
|
3972
|
+
if (process.platform !== 'win32') {
|
|
3973
|
+
for (const sh of ['/bin/zsh', '/bin/bash']) {
|
|
3974
|
+
if (!fs.existsSync(sh)) continue;
|
|
3975
|
+
for (const name of ['openclaw', 'clawdbot', 'moltbot']) {
|
|
3976
|
+
const loginShellCmd = `${sh} -lc '${name} gateway'`;
|
|
3977
|
+
console.log(chalk.yellow(`⚠️ 尝试启动 Gateway: ${loginShellCmd}`));
|
|
3978
|
+
if (spawnDetached(loginShellCmd, env)) {
|
|
3979
|
+
if (await waitForGateway(port, '127.0.0.1', 15000)) {
|
|
3980
|
+
console.log(chalk.green('✅ Gateway 已通过 login shell 启动'));
|
|
3981
|
+
return { started: true, method: 'cli-login-shell', cmd: loginShellCmd };
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
|
|
3818
3988
|
return { started: false };
|
|
3819
3989
|
}
|
|
3820
3990
|
|
|
@@ -4264,7 +4434,7 @@ async function presetClaude(paths, args = {}) {
|
|
|
4264
4434
|
if (yunyiLayoutResult.applied) {
|
|
4265
4435
|
syncManagedYunyiAuthProfiles(paths, config);
|
|
4266
4436
|
}
|
|
4267
|
-
syncExternalTools('claude', baseUrl, apiKey, { claudeModelId: modelId, opencodeDefaultModelKey:
|
|
4437
|
+
syncExternalTools('claude', baseUrl, apiKey, { claudeModelId: modelId, opencodeDefaultModelKey: getExternalModelKey('claude', modelId) });
|
|
4268
4438
|
writeSpinner.succeed('配置写入完成');
|
|
4269
4439
|
|
|
4270
4440
|
console.log(chalk.green('\n✅ Claude 节点配置完成!'));
|
|
@@ -4516,15 +4686,14 @@ async function autoActivate(paths, args = {}) {
|
|
|
4516
4686
|
}
|
|
4517
4687
|
|
|
4518
4688
|
// ---- 选模型(Claude + GPT 合并展示) ----
|
|
4519
|
-
const isSingleMode =
|
|
4520
|
-
&& CLAUDE_MODELS[0].id === CODEX_MODELS[0].id;
|
|
4689
|
+
const isSingleMode = isUnifiedSingleModelMode();
|
|
4521
4690
|
|
|
4522
4691
|
let selectedModelId;
|
|
4523
4692
|
let selectedType; // 'claude' or 'codex'
|
|
4524
4693
|
|
|
4525
4694
|
if (isSingleMode) {
|
|
4526
4695
|
selectedModelId = CLAUDE_MODELS[0].id;
|
|
4527
|
-
selectedType = 'claude';
|
|
4696
|
+
selectedType = String(args.primary || '').trim() === 'codex' ? 'codex' : 'claude';
|
|
4528
4697
|
} else {
|
|
4529
4698
|
const modelArg = (args.model || args['claude-model'] || args['codex-model'] || '').toString().trim();
|
|
4530
4699
|
if (modelArg) {
|
|
@@ -4620,15 +4789,18 @@ async function autoActivate(paths, args = {}) {
|
|
|
4620
4789
|
|
|
4621
4790
|
// 主模型 = 用户选的,备选 = 另一个
|
|
4622
4791
|
const primaryModelKey = isClaudePrimary ? claudeModelKey : codexModelKey;
|
|
4623
|
-
const fallbackModelKey = isClaudePrimary ? codexModelKey : claudeModelKey;
|
|
4792
|
+
const fallbackModelKey = isSingleMode ? '' : (isClaudePrimary ? codexModelKey : claudeModelKey);
|
|
4624
4793
|
config.agents.defaults.model.primary = primaryModelKey;
|
|
4625
|
-
config.agents.defaults.model.fallbacks = [fallbackModelKey];
|
|
4794
|
+
config.agents.defaults.model.fallbacks = fallbackModelKey ? [fallbackModelKey] : [];
|
|
4626
4795
|
const yunyiLayoutResult = applyManagedYunyiOpenClawLayout(config, {
|
|
4627
4796
|
force: true,
|
|
4628
4797
|
endpointUrl: selectedEndpoint.url,
|
|
4629
4798
|
apiKey
|
|
4630
4799
|
});
|
|
4631
|
-
applyManagedYunyiModelSelection(config, primaryModelKey);
|
|
4800
|
+
const selectionResult = applyManagedYunyiModelSelection(config, primaryModelKey);
|
|
4801
|
+
const finalYunyiLayoutResult = yunyiLayoutResult.applied
|
|
4802
|
+
? { ...yunyiLayoutResult, ...resolveManagedYunyiAgentAssignments(config, selectedType), applied: true }
|
|
4803
|
+
: yunyiLayoutResult;
|
|
4632
4804
|
|
|
4633
4805
|
// ---- 写入配置 ----
|
|
4634
4806
|
const writeSpinner = ora({ text: '正在写入配置...', spinner: 'dots' }).start();
|
|
@@ -4641,13 +4813,13 @@ async function autoActivate(paths, args = {}) {
|
|
|
4641
4813
|
if (yunyiLayoutResult.applied) {
|
|
4642
4814
|
syncManagedYunyiAuthProfiles(paths, config);
|
|
4643
4815
|
}
|
|
4644
|
-
if (
|
|
4645
|
-
const resetResult = resetManagedAgentSessionsWithSync(paths,
|
|
4816
|
+
if (selectionResult.agentId) {
|
|
4817
|
+
const resetResult = resetManagedAgentSessionsWithSync(paths, selectionResult.agentId);
|
|
4646
4818
|
if (resetResult.changed) {
|
|
4647
|
-
console.log(chalk.gray(` 已重置 ${
|
|
4819
|
+
console.log(chalk.gray(` 已重置 ${selectionResult.agentId} 的活动会话映射`));
|
|
4648
4820
|
}
|
|
4649
4821
|
}
|
|
4650
|
-
const opencodeDefaultModelKey = isClaudePrimary ?
|
|
4822
|
+
const opencodeDefaultModelKey = isClaudePrimary ? getExternalModelKey('claude', claudeModelId) : getExternalModelKey('codex', codexModelId);
|
|
4651
4823
|
try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl, claudeModelId, opencodeDefaultModelKey }); } catch { /* ignore */ }
|
|
4652
4824
|
try { syncExternalTools('codex', codexBaseUrl, apiKey, { modelId: codexModelId }); } catch { /* ignore */ }
|
|
4653
4825
|
writeSpinner.succeed('配置写入完成');
|
|
@@ -4656,7 +4828,7 @@ async function autoActivate(paths, args = {}) {
|
|
|
4656
4828
|
const selectedModel = isClaudePrimary ? claudeModel : codexModel;
|
|
4657
4829
|
console.log(chalk.green('\n✅ 配置完成!'));
|
|
4658
4830
|
console.log(chalk.cyan(` 外部工具默认: ${selectedModel.name}`));
|
|
4659
|
-
printYunyiOpenClawSwitchHint(
|
|
4831
|
+
printYunyiOpenClawSwitchHint(finalYunyiLayoutResult);
|
|
4660
4832
|
|
|
4661
4833
|
const gwPort = config.gateway?.port || 18789;
|
|
4662
4834
|
const gwToken = config.gateway?.auth?.token;
|
|
@@ -4677,9 +4849,10 @@ async function autoActivate(paths, args = {}) {
|
|
|
4677
4849
|
}]);
|
|
4678
4850
|
|
|
4679
4851
|
if (nextAction === 'test') {
|
|
4680
|
-
const selectedOpenClawAgentId =
|
|
4681
|
-
|
|
4682
|
-
|
|
4852
|
+
const selectedOpenClawAgentId = selectionResult.agentId
|
|
4853
|
+
|| (isClaudePrimary
|
|
4854
|
+
? (finalYunyiLayoutResult.claudeAgentId || YYMAXAPI_OPENCLAW_MAIN_AGENT_ID)
|
|
4855
|
+
: (finalYunyiLayoutResult.gptAgentId || YYMAXAPI_OPENCLAW_GPT_AGENT_ID));
|
|
4683
4856
|
await testConnection(paths, { ...args, agent: selectedOpenClawAgentId });
|
|
4684
4857
|
} else {
|
|
4685
4858
|
console.log(chalk.cyan('👋 再见!\n'));
|
|
@@ -5096,7 +5269,7 @@ async function yycodeQuickSetup(paths) {
|
|
|
5096
5269
|
if (yunyiLayoutResult.applied) {
|
|
5097
5270
|
syncManagedYunyiAuthProfiles(paths, config);
|
|
5098
5271
|
}
|
|
5099
|
-
try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl, claudeModelId, opencodeDefaultModelKey:
|
|
5272
|
+
try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl, claudeModelId, opencodeDefaultModelKey: getExternalModelKey('codex', codexModelId) }); } catch { /* ignore */ }
|
|
5100
5273
|
try { syncExternalTools('codex', codexBaseUrl, apiKey, { modelId: codexModelId }); } catch { /* ignore */ }
|
|
5101
5274
|
writeSpinner.succeed('配置写入完成');
|
|
5102
5275
|
|
|
@@ -5250,6 +5423,8 @@ function getConfigStatusLine(paths) {
|
|
|
5250
5423
|
'claude-yunyi': 'Claude(包月)',
|
|
5251
5424
|
'yunyi': 'Codex(包月)',
|
|
5252
5425
|
'heibai': 'MAXAPI(按量)',
|
|
5426
|
+
'maxapi': 'MAXAPI(按量)',
|
|
5427
|
+
'maxapi-codex': 'MAXAPI(按量)',
|
|
5253
5428
|
};
|
|
5254
5429
|
|
|
5255
5430
|
const parts = [];
|
|
@@ -5460,6 +5635,8 @@ async function switchModel(paths) {
|
|
|
5460
5635
|
'claude-yunyi': '云翼 Claude (包月)',
|
|
5461
5636
|
'yunyi': '云翼 Codex (包月)',
|
|
5462
5637
|
'heibai': 'MAXAPI (按量)',
|
|
5638
|
+
'maxapi': 'MAXAPI (按量)',
|
|
5639
|
+
'maxapi-codex': 'MAXAPI (按量)',
|
|
5463
5640
|
};
|
|
5464
5641
|
|
|
5465
5642
|
const claudeProviderName = API_CONFIG.claude.providerName;
|
|
@@ -5468,8 +5645,25 @@ async function switchModel(paths) {
|
|
|
5468
5645
|
// 预设模型列表
|
|
5469
5646
|
const choices = [];
|
|
5470
5647
|
const presetKeys = new Set();
|
|
5471
|
-
|
|
5472
|
-
|
|
5648
|
+
const unifiedSingleMode = isUnifiedSingleModelMode();
|
|
5649
|
+
const unifiedModel = unifiedSingleMode ? (CLAUDE_MODELS[0] || CODEX_MODELS[0] || null) : null;
|
|
5650
|
+
|
|
5651
|
+
if (unifiedSingleMode && unifiedModel) {
|
|
5652
|
+
const preferredProviders = [
|
|
5653
|
+
primary.split('/')[0],
|
|
5654
|
+
providers[claudeProviderName] ? claudeProviderName : '',
|
|
5655
|
+
providers[codexProviderName] ? codexProviderName : '',
|
|
5656
|
+
Object.keys(providers)[0] || ''
|
|
5657
|
+
].filter(Boolean);
|
|
5658
|
+
const unifiedProviderName = preferredProviders[0];
|
|
5659
|
+
const modelKey = `${unifiedProviderName}/${unifiedModel.id}`;
|
|
5660
|
+
const isCurrent = modelKey === primary;
|
|
5661
|
+
choices.push({
|
|
5662
|
+
name: isCurrent ? `${unifiedModel.name} (当前)` : unifiedModel.name,
|
|
5663
|
+
value: modelKey,
|
|
5664
|
+
});
|
|
5665
|
+
presetKeys.add(modelKey);
|
|
5666
|
+
} else if (CLAUDE_MODELS.length > 0) {
|
|
5473
5667
|
choices.push(new inquirer.Separator(' -- Claude --'));
|
|
5474
5668
|
for (const m of CLAUDE_MODELS) {
|
|
5475
5669
|
const pName = providers[claudeProviderName] ? claudeProviderName : Object.keys(providers)[0];
|
|
@@ -5483,7 +5677,7 @@ async function switchModel(paths) {
|
|
|
5483
5677
|
}
|
|
5484
5678
|
}
|
|
5485
5679
|
|
|
5486
|
-
if (CODEX_MODELS.length > 0) {
|
|
5680
|
+
if (!unifiedSingleMode && CODEX_MODELS.length > 0) {
|
|
5487
5681
|
choices.push(new inquirer.Separator(' -- GPT --'));
|
|
5488
5682
|
for (const m of CODEX_MODELS) {
|
|
5489
5683
|
const pName = providers[codexProviderName] ? codexProviderName : Object.keys(providers)[0];
|
|
@@ -5501,6 +5695,12 @@ async function switchModel(paths) {
|
|
|
5501
5695
|
const otherModels = [];
|
|
5502
5696
|
for (const [providerName, providerConfig] of Object.entries(providers)) {
|
|
5503
5697
|
for (const m of (providerConfig.models || [])) {
|
|
5698
|
+
if (unifiedSingleMode
|
|
5699
|
+
&& unifiedModel
|
|
5700
|
+
&& m.id === unifiedModel.id
|
|
5701
|
+
&& (providerName === claudeProviderName || providerName === codexProviderName)) {
|
|
5702
|
+
continue;
|
|
5703
|
+
}
|
|
5504
5704
|
const modelKey = `${providerName}/${m.id}`;
|
|
5505
5705
|
if (!presetKeys.has(modelKey)) {
|
|
5506
5706
|
otherModels.push({ modelKey, name: m.name || m.id, providerName });
|
|
@@ -5509,6 +5709,12 @@ async function switchModel(paths) {
|
|
|
5509
5709
|
}
|
|
5510
5710
|
const registeredKeys = Object.keys(config.agents?.defaults?.models || {});
|
|
5511
5711
|
for (const modelKey of registeredKeys) {
|
|
5712
|
+
if (unifiedSingleMode && unifiedModel) {
|
|
5713
|
+
const [providerName, modelId] = modelKey.split('/');
|
|
5714
|
+
if (modelId === unifiedModel.id && (providerName === claudeProviderName || providerName === codexProviderName)) {
|
|
5715
|
+
continue;
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5512
5718
|
if (presetKeys.has(modelKey) || otherModels.some(o => o.modelKey === modelKey)) continue;
|
|
5513
5719
|
const [pName, mId] = modelKey.split('/');
|
|
5514
5720
|
if (!pName || !mId) continue;
|
|
@@ -5619,7 +5825,7 @@ async function switchModel(paths) {
|
|
|
5619
5825
|
primary = finalSelected;
|
|
5620
5826
|
ensureGatewaySettings(config);
|
|
5621
5827
|
writeConfigWithSync(paths, config);
|
|
5622
|
-
if (selectedAgentId
|
|
5828
|
+
if (selectedAgentId && [YYMAXAPI_OPENCLAW_MAIN_AGENT_ID, YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID, YYMAXAPI_OPENCLAW_GPT_AGENT_ID].includes(selectedAgentId)) {
|
|
5623
5829
|
const resetResult = resetManagedAgentSessionsWithSync(paths, selectedAgentId);
|
|
5624
5830
|
if (resetResult.changed) {
|
|
5625
5831
|
console.log(chalk.gray(` 已重置 ${selectedAgentId} 的活动会话映射`));
|