yymaxapi 1.0.88 → 1.0.90
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
CHANGED
|
@@ -134,7 +134,7 @@ const DEFAULT_API_CONFIG = {
|
|
|
134
134
|
"codex": {
|
|
135
135
|
"urlSuffix": "/codex",
|
|
136
136
|
"api": "openai-completions",
|
|
137
|
-
"contextWindow":
|
|
137
|
+
"contextWindow": 1000000,
|
|
138
138
|
"maxTokens": 128000,
|
|
139
139
|
"providerName": "yunyi"
|
|
140
140
|
}
|
|
@@ -881,6 +881,7 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
881
881
|
if (!normalizedUrl.endsWith('/v1')) normalizedUrl += '/v1';
|
|
882
882
|
try {
|
|
883
883
|
let existing = '';
|
|
884
|
+
const escapedProviderKey = providerKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
884
885
|
if (fs.existsSync(configPath)) {
|
|
885
886
|
existing = fs.readFileSync(configPath, 'utf8');
|
|
886
887
|
// 移除旧的 maxapi section(provider block)
|
|
@@ -889,13 +890,14 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
889
890
|
// 移除旧的 maxapi top-level block
|
|
890
891
|
const topRe = new RegExp(`${topMarker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${topMarkerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`, 'g');
|
|
891
892
|
existing = existing.replace(topRe, '');
|
|
892
|
-
//
|
|
893
|
-
existing = existing.replace(
|
|
894
|
-
existing = existing.replace(/^model_provider\s*=\s*"[^"]*"\s*$/gm, '');
|
|
893
|
+
// 兼容旧版:移除历史遗留的未标记 yunyi-codex provider、旧 openclaw-relay、旧 yunyi opencode 标记块
|
|
894
|
+
existing = existing.replace(new RegExp(`\\[model_providers\\.${escapedProviderKey}\\]\\n(?:(?!\\[)[^\\n]*\\n?)*`, 'g'), '');
|
|
895
895
|
existing = existing.replace(/\[model_providers\.openclaw-relay\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
|
|
896
896
|
existing = existing.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
|
|
897
897
|
existing = existing.replace(/\n{3,}/g, '\n\n').trim();
|
|
898
898
|
}
|
|
899
|
+
const hasExistingTopLevelModelConfig = /^model\s*=\s*"[^"]*"\s*$/m.test(existing)
|
|
900
|
+
|| /^model_provider\s*=\s*"[^"]*"\s*$/m.test(existing);
|
|
899
901
|
|
|
900
902
|
// 顶层设置(MUST 在所有 [section] 之前)
|
|
901
903
|
const topBlock = [
|
|
@@ -919,7 +921,9 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
919
921
|
// 组装:顶层设置 → 原有内容 → provider section
|
|
920
922
|
let content;
|
|
921
923
|
if (existing) {
|
|
922
|
-
content =
|
|
924
|
+
content = hasExistingTopLevelModelConfig
|
|
925
|
+
? `${existing}\n\n${providerBlock}\n`
|
|
926
|
+
: `${topBlock}\n\n${existing}\n\n${providerBlock}\n`;
|
|
923
927
|
} else {
|
|
924
928
|
content = `${topBlock}\n\n${providerBlock}\n`;
|
|
925
929
|
}
|
|
@@ -1933,6 +1937,10 @@ const YYMAXAPI_OPENCLAW_GPT_PRIMARY = `${YYMAXAPI_OPENCLAW_GPT_PROVIDER}/gpt-5.4
|
|
|
1933
1937
|
const YYMAXAPI_OPENCLAW_GPT_FALLBACK = `${YYMAXAPI_OPENCLAW_GPT_PROVIDER}/gpt-5.3-codex`;
|
|
1934
1938
|
const YYMAXAPI_MANAGED_MAIN_NAMES = new Set(['Claude', 'claude', 'yunyi-claude', 'claude-yunyi']);
|
|
1935
1939
|
const YYMAXAPI_MANAGED_GPT_NAMES = new Set(['GPT', 'Codex', 'gpt', 'yunyi-gpt', 'yunyi-codex']);
|
|
1940
|
+
const YYMAXAPI_MANAGED_MULTIMODAL_MODELS = {
|
|
1941
|
+
claude: new Set(['claude-sonnet-4-6', 'claude-opus-4-6']),
|
|
1942
|
+
codex: new Set(['gpt-5.4'])
|
|
1943
|
+
};
|
|
1936
1944
|
|
|
1937
1945
|
function isYymaxapiOpenClawBuild() {
|
|
1938
1946
|
return isLikelyYunyiBaseUrl(ENDPOINTS[0]?.url || '')
|
|
@@ -1982,14 +1990,21 @@ function resolveManagedYunyiModelName(type, modelId, fallbackName) {
|
|
|
1982
1990
|
return catalog.find(model => model.id === modelId)?.name || fallbackName;
|
|
1983
1991
|
}
|
|
1984
1992
|
|
|
1993
|
+
function getManagedYunyiModelInput(type, modelId) {
|
|
1994
|
+
return YYMAXAPI_MANAGED_MULTIMODAL_MODELS[type]?.has(modelId)
|
|
1995
|
+
? ['text', 'image']
|
|
1996
|
+
: ['text'];
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1985
1999
|
function getManagedYunyiProviderModels(type) {
|
|
1986
2000
|
const apiConfig = type === 'claude'
|
|
1987
2001
|
? { contextWindow: API_CONFIG.claude?.contextWindow || 200000, maxTokens: API_CONFIG.claude?.maxTokens || 8192 }
|
|
1988
|
-
: { contextWindow: API_CONFIG.codex?.contextWindow ||
|
|
2002
|
+
: { contextWindow: API_CONFIG.codex?.contextWindow || 1000000, maxTokens: API_CONFIG.codex?.maxTokens || 128000 };
|
|
1989
2003
|
|
|
1990
2004
|
return getManagedYunyiModelCatalog(type).map(model => ({
|
|
1991
2005
|
id: model.id,
|
|
1992
2006
|
name: resolveManagedYunyiModelName(type, model.id, model.name),
|
|
2007
|
+
input: getManagedYunyiModelInput(type, model.id),
|
|
1993
2008
|
contextWindow: apiConfig.contextWindow,
|
|
1994
2009
|
maxTokens: apiConfig.maxTokens
|
|
1995
2010
|
}));
|
|
@@ -2011,6 +2026,150 @@ function findAgentById(config, agentId) {
|
|
|
2011
2026
|
return config.agents.list.find(agent => agent && typeof agent === 'object' && agent.id === agentId) || null;
|
|
2012
2027
|
}
|
|
2013
2028
|
|
|
2029
|
+
function canonicalizeManagedYunyiModelKey(modelKey, preferredType = '') {
|
|
2030
|
+
const text = String(modelKey || '').trim();
|
|
2031
|
+
if (!text.includes('/')) return text;
|
|
2032
|
+
const [, modelId = ''] = text.split('/');
|
|
2033
|
+
if (!modelId) return text;
|
|
2034
|
+
if (preferredType === 'claude' || (!preferredType && isManagedYunyiClaudeModelKey(text))) {
|
|
2035
|
+
return `${YYMAXAPI_OPENCLAW_CLAUDE_PROVIDER}/${modelId}`;
|
|
2036
|
+
}
|
|
2037
|
+
if (preferredType === 'codex' || preferredType === 'gpt' || (!preferredType && isManagedYunyiGptModelKey(text))) {
|
|
2038
|
+
return `${YYMAXAPI_OPENCLAW_GPT_PROVIDER}/${modelId}`;
|
|
2039
|
+
}
|
|
2040
|
+
return text;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
function getManagedYunyiKnownModelKeys(type) {
|
|
2044
|
+
return type === 'claude'
|
|
2045
|
+
? [YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY, YYMAXAPI_OPENCLAW_CLAUDE_FALLBACK]
|
|
2046
|
+
: [YYMAXAPI_OPENCLAW_GPT_PRIMARY, YYMAXAPI_OPENCLAW_GPT_FALLBACK];
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
function normalizeManagedYunyiModelState(type, modelState = {}, options = {}) {
|
|
2050
|
+
const knownKeys = getManagedYunyiKnownModelKeys(type);
|
|
2051
|
+
const fallbackPrimary = knownKeys[0];
|
|
2052
|
+
const currentPrimary = canonicalizeManagedYunyiModelKey(modelState.primary || '', type);
|
|
2053
|
+
const canPreserve = !options.force && currentPrimary && knownKeys.includes(currentPrimary);
|
|
2054
|
+
const primary = canPreserve ? currentPrimary : fallbackPrimary;
|
|
2055
|
+
|
|
2056
|
+
let fallbacks = Array.isArray(modelState.fallbacks) ? modelState.fallbacks : [];
|
|
2057
|
+
fallbacks = [...new Set(
|
|
2058
|
+
fallbacks
|
|
2059
|
+
.map(item => canonicalizeManagedYunyiModelKey(item, type))
|
|
2060
|
+
.filter(item => item && item !== primary && knownKeys.includes(item))
|
|
2061
|
+
)];
|
|
2062
|
+
|
|
2063
|
+
if (fallbacks.length === 0) {
|
|
2064
|
+
fallbacks = knownKeys.filter(item => item !== primary);
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
return { primary, fallbacks };
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
function normalizeManagedYunyiDefaultsModel(modelState = {}, options = {}) {
|
|
2071
|
+
const currentPrimary = String(modelState.primary || '').trim();
|
|
2072
|
+
const canPreserve = !options.force && currentPrimary && isManagedYunyiModelKey(currentPrimary);
|
|
2073
|
+
const primary = canPreserve
|
|
2074
|
+
? canonicalizeManagedYunyiModelKey(currentPrimary)
|
|
2075
|
+
: YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY;
|
|
2076
|
+
|
|
2077
|
+
let fallbacks = Array.isArray(modelState.fallbacks) ? modelState.fallbacks : [];
|
|
2078
|
+
fallbacks = [...new Set(
|
|
2079
|
+
fallbacks
|
|
2080
|
+
.map(item => {
|
|
2081
|
+
const text = String(item || '').trim();
|
|
2082
|
+
return isManagedYunyiModelKey(text) ? canonicalizeManagedYunyiModelKey(text) : text;
|
|
2083
|
+
})
|
|
2084
|
+
.filter(item => item && item !== primary)
|
|
2085
|
+
)];
|
|
2086
|
+
|
|
2087
|
+
if (fallbacks.length === 0) {
|
|
2088
|
+
fallbacks = [isManagedYunyiClaudeModelKey(primary) ? YYMAXAPI_OPENCLAW_GPT_PRIMARY : YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY];
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
return { primary, fallbacks };
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
function getManagedClaudeAgentId(config) {
|
|
2095
|
+
const mainAgent = findAgentById(config, YYMAXAPI_OPENCLAW_MAIN_AGENT_ID);
|
|
2096
|
+
if (mainAgent && isManagedMainAgent(mainAgent)) {
|
|
2097
|
+
return YYMAXAPI_OPENCLAW_MAIN_AGENT_ID;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
const sideAgent = findAgentById(config, YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID);
|
|
2101
|
+
if (sideAgent && isManagedClaudeSideAgent(sideAgent)) {
|
|
2102
|
+
return YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
return mainAgent ? YYMAXAPI_OPENCLAW_MAIN_AGENT_ID : (sideAgent ? YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID : null);
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
function inferManagedYunyiAgentIdForModelKey(config, modelKey) {
|
|
2109
|
+
if (isManagedYunyiGptModelKey(modelKey)) return YYMAXAPI_OPENCLAW_GPT_AGENT_ID;
|
|
2110
|
+
if (isManagedYunyiClaudeModelKey(modelKey)) return getManagedClaudeAgentId(config);
|
|
2111
|
+
return null;
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
function applyManagedYunyiModelSelection(config, selectedModelKey) {
|
|
2115
|
+
ensureConfigStructure(config);
|
|
2116
|
+
|
|
2117
|
+
const normalizedSelected = canonicalizeManagedYunyiModelKey(selectedModelKey);
|
|
2118
|
+
const selectedType = isManagedYunyiClaudeModelKey(normalizedSelected)
|
|
2119
|
+
? 'claude'
|
|
2120
|
+
: (isManagedYunyiGptModelKey(normalizedSelected) ? 'codex' : '');
|
|
2121
|
+
|
|
2122
|
+
if (!selectedType) {
|
|
2123
|
+
return { changed: false, selectedModelKey: normalizedSelected, agentId: null };
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
let changed = false;
|
|
2127
|
+
const previousPrimary = String(config.agents?.defaults?.model?.primary || '').trim();
|
|
2128
|
+
const previousCanonical = isManagedYunyiModelKey(previousPrimary)
|
|
2129
|
+
? canonicalizeManagedYunyiModelKey(previousPrimary)
|
|
2130
|
+
: previousPrimary;
|
|
2131
|
+
const nextDefaultsModel = {
|
|
2132
|
+
primary: normalizedSelected,
|
|
2133
|
+
fallbacks: previousCanonical && previousCanonical !== normalizedSelected ? [previousCanonical] : []
|
|
2134
|
+
};
|
|
2135
|
+
|
|
2136
|
+
if (JSON.stringify(config.agents.defaults.model) !== JSON.stringify(nextDefaultsModel)) {
|
|
2137
|
+
config.agents.defaults.model = nextDefaultsModel;
|
|
2138
|
+
changed = true;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
const managedModelAliases = {
|
|
2142
|
+
[YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY]: YYMAXAPI_OPENCLAW_CLAUDE_PROVIDER,
|
|
2143
|
+
[YYMAXAPI_OPENCLAW_CLAUDE_FALLBACK]: YYMAXAPI_OPENCLAW_CLAUDE_PROVIDER,
|
|
2144
|
+
[YYMAXAPI_OPENCLAW_GPT_PRIMARY]: YYMAXAPI_OPENCLAW_GPT_PROVIDER,
|
|
2145
|
+
[YYMAXAPI_OPENCLAW_GPT_FALLBACK]: YYMAXAPI_OPENCLAW_GPT_PROVIDER
|
|
2146
|
+
};
|
|
2147
|
+
for (const [modelKey, alias] of Object.entries(managedModelAliases)) {
|
|
2148
|
+
const nextEntry = { alias };
|
|
2149
|
+
if (JSON.stringify(config.agents.defaults.models[modelKey] || {}) !== JSON.stringify(nextEntry)) {
|
|
2150
|
+
config.agents.defaults.models[modelKey] = nextEntry;
|
|
2151
|
+
changed = true;
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
const agentId = inferManagedYunyiAgentIdForModelKey(config, normalizedSelected)
|
|
2156
|
+
|| (selectedType === 'codex' ? YYMAXAPI_OPENCLAW_GPT_AGENT_ID : YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID);
|
|
2157
|
+
const agentList = ensureAgentList(config);
|
|
2158
|
+
const nextAgent = {
|
|
2159
|
+
id: agentId,
|
|
2160
|
+
default: agentId === YYMAXAPI_OPENCLAW_MAIN_AGENT_ID,
|
|
2161
|
+
name: selectedType === 'codex' ? 'yunyi-gpt' : 'yunyi-claude',
|
|
2162
|
+
model: normalizeManagedYunyiModelState(selectedType, { primary: normalizedSelected })
|
|
2163
|
+
};
|
|
2164
|
+
const shouldManage = selectedType === 'codex'
|
|
2165
|
+
? isManagedGptAgent
|
|
2166
|
+
: (agentId === YYMAXAPI_OPENCLAW_MAIN_AGENT_ID ? isManagedMainAgent : isManagedClaudeSideAgent);
|
|
2167
|
+
const updateResult = upsertManagedAgent(agentList, nextAgent, shouldManage);
|
|
2168
|
+
if (updateResult.changed) changed = true;
|
|
2169
|
+
|
|
2170
|
+
return { changed, selectedModelKey: normalizedSelected, agentId };
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2014
2173
|
function resolveOpenClawTestTarget(config, args = {}) {
|
|
2015
2174
|
const requestedAgentId = String(args.agent || args['agent-id'] || '').trim();
|
|
2016
2175
|
const requestedAgent = requestedAgentId ? findAgentById(config, requestedAgentId) : null;
|
|
@@ -2027,11 +2186,23 @@ function resolveOpenClawTestTarget(config, args = {}) {
|
|
|
2027
2186
|
if (requestedAgent) {
|
|
2028
2187
|
const agentState = getAgentModelState(requestedAgent);
|
|
2029
2188
|
if (agentState.primary) {
|
|
2030
|
-
primary = agentState.primary;
|
|
2189
|
+
primary = canonicalizeManagedYunyiModelKey(agentState.primary);
|
|
2031
2190
|
fallbacks = agentState.fallbacks;
|
|
2032
2191
|
agentId = requestedAgent.id;
|
|
2033
2192
|
agentName = String(requestedAgent.name || '').trim();
|
|
2034
2193
|
}
|
|
2194
|
+
} else {
|
|
2195
|
+
const inferredAgentId = inferManagedYunyiAgentIdForModelKey(config, primary);
|
|
2196
|
+
const inferredAgent = inferredAgentId ? findAgentById(config, inferredAgentId) : null;
|
|
2197
|
+
if (inferredAgent) {
|
|
2198
|
+
const agentState = getAgentModelState(inferredAgent);
|
|
2199
|
+
if (agentState.primary) {
|
|
2200
|
+
primary = canonicalizeManagedYunyiModelKey(agentState.primary);
|
|
2201
|
+
fallbacks = agentState.fallbacks.map(item => isManagedYunyiModelKey(item) ? canonicalizeManagedYunyiModelKey(item) : item);
|
|
2202
|
+
}
|
|
2203
|
+
agentId = inferredAgent.id;
|
|
2204
|
+
agentName = String(inferredAgent.name || '').trim();
|
|
2205
|
+
}
|
|
2035
2206
|
}
|
|
2036
2207
|
|
|
2037
2208
|
const providerName = primary.includes('/') ? primary.split('/')[0] : '';
|
|
@@ -2233,6 +2404,39 @@ function shouldManageYunyiDefaults(config) {
|
|
|
2233
2404
|
return fallbacks.some(isManagedYunyiModelKey);
|
|
2234
2405
|
}
|
|
2235
2406
|
|
|
2407
|
+
function shouldManageYunyiImageDefaults(config) {
|
|
2408
|
+
const imageModelState = normalizeDefaultModelSelection(config?.agents?.defaults?.imageModel, config);
|
|
2409
|
+
const primary = typeof imageModelState.primary === 'string' ? imageModelState.primary.trim() : '';
|
|
2410
|
+
const fallbacks = Array.isArray(imageModelState.fallbacks) ? imageModelState.fallbacks : [];
|
|
2411
|
+
if (!primary) return true;
|
|
2412
|
+
if (isManagedYunyiModelKey(primary)) return true;
|
|
2413
|
+
return fallbacks.some(isManagedYunyiModelKey);
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
function normalizeManagedYunyiImageModel(modelState = {}, options = {}) {
|
|
2417
|
+
const currentPrimary = String(modelState.primary || '').trim();
|
|
2418
|
+
const canPreserve = !options.force && currentPrimary && isManagedYunyiModelKey(currentPrimary);
|
|
2419
|
+
const primary = canPreserve
|
|
2420
|
+
? canonicalizeManagedYunyiModelKey(currentPrimary)
|
|
2421
|
+
: YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY;
|
|
2422
|
+
|
|
2423
|
+
let fallbacks = Array.isArray(modelState.fallbacks) ? modelState.fallbacks : [];
|
|
2424
|
+
fallbacks = [...new Set(
|
|
2425
|
+
fallbacks
|
|
2426
|
+
.map(item => {
|
|
2427
|
+
const text = String(item || '').trim();
|
|
2428
|
+
return isManagedYunyiModelKey(text) ? canonicalizeManagedYunyiModelKey(text) : text;
|
|
2429
|
+
})
|
|
2430
|
+
.filter(item => item && item !== primary)
|
|
2431
|
+
)];
|
|
2432
|
+
|
|
2433
|
+
if (fallbacks.length === 0) {
|
|
2434
|
+
fallbacks = [isManagedYunyiClaudeModelKey(primary) ? YYMAXAPI_OPENCLAW_GPT_PRIMARY : YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY];
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
return { primary, fallbacks };
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2236
2440
|
function applyManagedYunyiOpenClawLayout(config, options = {}) {
|
|
2237
2441
|
if (!isYymaxapiOpenClawBuild()) {
|
|
2238
2442
|
return { changed: false, applied: false, claudeAgentId: null, preservedMain: false };
|
|
@@ -2293,28 +2497,24 @@ function applyManagedYunyiOpenClawLayout(config, options = {}) {
|
|
|
2293
2497
|
}
|
|
2294
2498
|
|
|
2295
2499
|
const agentList = ensureAgentList(config);
|
|
2500
|
+
const currentMainAgentState = getAgentModelState(findAgentById(config, YYMAXAPI_OPENCLAW_MAIN_AGENT_ID));
|
|
2296
2501
|
const mainAgentResult = upsertManagedAgent(agentList, {
|
|
2297
2502
|
id: YYMAXAPI_OPENCLAW_MAIN_AGENT_ID,
|
|
2298
2503
|
default: true,
|
|
2299
2504
|
name: 'yunyi-claude',
|
|
2300
|
-
model:
|
|
2301
|
-
primary: YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY,
|
|
2302
|
-
fallbacks: [YYMAXAPI_OPENCLAW_CLAUDE_FALLBACK]
|
|
2303
|
-
}
|
|
2505
|
+
model: normalizeManagedYunyiModelState('claude', currentMainAgentState, options)
|
|
2304
2506
|
}, isManagedMainAgent);
|
|
2305
2507
|
if (mainAgentResult.changed) changed = true;
|
|
2306
2508
|
|
|
2307
2509
|
let claudeAgentId = YYMAXAPI_OPENCLAW_MAIN_AGENT_ID;
|
|
2308
2510
|
let preservedMain = !mainAgentResult.managed;
|
|
2309
2511
|
if (!mainAgentResult.managed) {
|
|
2512
|
+
const currentClaudeSideState = getAgentModelState(findAgentById(config, YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID));
|
|
2310
2513
|
const fallbackClaudeAgentResult = upsertManagedAgent(agentList, {
|
|
2311
2514
|
id: YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID,
|
|
2312
2515
|
default: false,
|
|
2313
2516
|
name: 'yunyi-claude',
|
|
2314
|
-
model:
|
|
2315
|
-
primary: YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY,
|
|
2316
|
-
fallbacks: [YYMAXAPI_OPENCLAW_CLAUDE_FALLBACK]
|
|
2317
|
-
}
|
|
2517
|
+
model: normalizeManagedYunyiModelState('claude', currentClaudeSideState, options)
|
|
2318
2518
|
}, isManagedClaudeSideAgent);
|
|
2319
2519
|
if (fallbackClaudeAgentResult.changed) changed = true;
|
|
2320
2520
|
claudeAgentId = fallbackClaudeAgentResult.managed ? YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID : null;
|
|
@@ -2322,28 +2522,32 @@ function applyManagedYunyiOpenClawLayout(config, options = {}) {
|
|
|
2322
2522
|
changed = true;
|
|
2323
2523
|
}
|
|
2324
2524
|
|
|
2525
|
+
const currentGptAgentState = getAgentModelState(findAgentById(config, YYMAXAPI_OPENCLAW_GPT_AGENT_ID));
|
|
2325
2526
|
const gptAgentResult = upsertManagedAgent(agentList, {
|
|
2326
2527
|
id: YYMAXAPI_OPENCLAW_GPT_AGENT_ID,
|
|
2327
2528
|
default: false,
|
|
2328
2529
|
name: 'yunyi-gpt',
|
|
2329
|
-
model:
|
|
2330
|
-
primary: YYMAXAPI_OPENCLAW_GPT_PRIMARY,
|
|
2331
|
-
fallbacks: [YYMAXAPI_OPENCLAW_GPT_FALLBACK]
|
|
2332
|
-
}
|
|
2530
|
+
model: normalizeManagedYunyiModelState('codex', currentGptAgentState, options)
|
|
2333
2531
|
}, isManagedGptAgent);
|
|
2334
2532
|
if (gptAgentResult.changed) changed = true;
|
|
2335
2533
|
|
|
2336
2534
|
if (shouldManageYunyiDefaults(config)) {
|
|
2337
|
-
const nextDefaultsModel =
|
|
2338
|
-
primary: YYMAXAPI_OPENCLAW_CLAUDE_PRIMARY,
|
|
2339
|
-
fallbacks: [YYMAXAPI_OPENCLAW_GPT_PRIMARY]
|
|
2340
|
-
};
|
|
2535
|
+
const nextDefaultsModel = normalizeManagedYunyiDefaultsModel(config.agents.defaults.model, options);
|
|
2341
2536
|
if (JSON.stringify(config.agents.defaults.model) !== JSON.stringify(nextDefaultsModel)) {
|
|
2342
2537
|
config.agents.defaults.model = nextDefaultsModel;
|
|
2343
2538
|
changed = true;
|
|
2344
2539
|
}
|
|
2345
2540
|
}
|
|
2346
2541
|
|
|
2542
|
+
if (shouldManageYunyiImageDefaults(config)) {
|
|
2543
|
+
const currentImageModel = normalizeDefaultModelSelection(config.agents.defaults.imageModel, config);
|
|
2544
|
+
const nextImageModel = normalizeManagedYunyiImageModel(currentImageModel, options);
|
|
2545
|
+
if (JSON.stringify(currentImageModel) !== JSON.stringify(nextImageModel)) {
|
|
2546
|
+
config.agents.defaults.imageModel = nextImageModel;
|
|
2547
|
+
changed = true;
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2347
2551
|
return { changed, applied: true, claudeAgentId, preservedMain };
|
|
2348
2552
|
}
|
|
2349
2553
|
|
|
@@ -5097,7 +5301,8 @@ async function switchModel(paths) {
|
|
|
5097
5301
|
|
|
5098
5302
|
const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
|
|
5099
5303
|
applyConfigRepairsWithSync(config, paths);
|
|
5100
|
-
|
|
5304
|
+
applyManagedYunyiOpenClawLayout(config);
|
|
5305
|
+
let primary = config.agents?.defaults?.model?.primary || '';
|
|
5101
5306
|
const providers = config.models?.providers || {};
|
|
5102
5307
|
|
|
5103
5308
|
if (Object.keys(providers).length === 0) {
|
|
@@ -5195,6 +5400,7 @@ async function switchModel(paths) {
|
|
|
5195
5400
|
}]);
|
|
5196
5401
|
|
|
5197
5402
|
let finalSelected = selected;
|
|
5403
|
+
let selectedAgentId = '';
|
|
5198
5404
|
|
|
5199
5405
|
if (selected === '__other__') {
|
|
5200
5406
|
if (otherModels.length === 0) {
|
|
@@ -5225,42 +5431,51 @@ async function switchModel(paths) {
|
|
|
5225
5431
|
return;
|
|
5226
5432
|
}
|
|
5227
5433
|
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
const
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
contextWindow:
|
|
5250
|
-
maxTokens:
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5434
|
+
if (isManagedYunyiModelKey(finalSelected)) {
|
|
5435
|
+
const selectionResult = applyManagedYunyiModelSelection(config, finalSelected);
|
|
5436
|
+
finalSelected = selectionResult.selectedModelKey;
|
|
5437
|
+
selectedAgentId = selectionResult.agentId || '';
|
|
5438
|
+
} else {
|
|
5439
|
+
const selectedProviderKey = finalSelected.split('/')[0];
|
|
5440
|
+
const selectedModelId = finalSelected.split('/')[1];
|
|
5441
|
+
config.agents.defaults.model.primary = finalSelected;
|
|
5442
|
+
if (!config.agents.defaults.models[finalSelected]) {
|
|
5443
|
+
config.agents.defaults.models[finalSelected] = { alias: selectedProviderKey };
|
|
5444
|
+
}
|
|
5445
|
+
|
|
5446
|
+
// 同步更新 provider.models
|
|
5447
|
+
const providerConfig = providers[selectedProviderKey];
|
|
5448
|
+
if (providerConfig && selectedModelId) {
|
|
5449
|
+
const existingModel = (providerConfig.models || []).find(m => m.id === selectedModelId);
|
|
5450
|
+
if (!existingModel) {
|
|
5451
|
+
const allModels = [...CLAUDE_MODELS, ...CODEX_MODELS];
|
|
5452
|
+
const knownModel = allModels.find(m => m.id === selectedModelId);
|
|
5453
|
+
const apiType = providerConfig.api || '';
|
|
5454
|
+
const isAnthropic = apiType.startsWith('anthropic');
|
|
5455
|
+
const defaultCtx = isAnthropic ? (API_CONFIG.claude?.contextWindow || 200000) : (API_CONFIG.codex?.contextWindow || 200000);
|
|
5456
|
+
const defaultMax = isAnthropic ? (API_CONFIG.claude?.maxTokens || 8192) : (API_CONFIG.codex?.maxTokens || 8192);
|
|
5457
|
+
providerConfig.models = [{
|
|
5458
|
+
id: selectedModelId,
|
|
5459
|
+
name: knownModel ? knownModel.name : selectedModelId,
|
|
5460
|
+
contextWindow: defaultCtx,
|
|
5461
|
+
maxTokens: defaultMax
|
|
5462
|
+
}];
|
|
5463
|
+
} else {
|
|
5464
|
+
providerConfig.models = [existingModel];
|
|
5465
|
+
}
|
|
5254
5466
|
}
|
|
5255
|
-
}
|
|
5256
5467
|
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5468
|
+
config.agents.defaults.model.fallbacks = (config.agents.defaults.model.fallbacks || []).filter(k => k !== finalSelected);
|
|
5469
|
+
if (primary && primary !== finalSelected && !config.agents.defaults.model.fallbacks.includes(primary)) {
|
|
5470
|
+
config.agents.defaults.model.fallbacks.push(primary);
|
|
5471
|
+
}
|
|
5260
5472
|
}
|
|
5473
|
+
|
|
5474
|
+
primary = finalSelected;
|
|
5261
5475
|
ensureGatewaySettings(config);
|
|
5262
5476
|
writeConfigWithSync(paths, config);
|
|
5263
5477
|
|
|
5478
|
+
const selectedProviderKey = finalSelected.split('/')[0];
|
|
5264
5479
|
const selectedProviderConfig = providers[selectedProviderKey];
|
|
5265
5480
|
const selectedLabel = PROVIDER_LABELS[selectedProviderKey] || selectedProviderKey;
|
|
5266
5481
|
console.log(chalk.green(`\n✅ 已切换到 ${finalSelected}`));
|
|
@@ -5286,7 +5501,7 @@ async function switchModel(paths) {
|
|
|
5286
5501
|
|
|
5287
5502
|
// 重启后直接测试连接
|
|
5288
5503
|
console.log('');
|
|
5289
|
-
await testConnection(paths, {});
|
|
5504
|
+
await testConnection(paths, selectedAgentId ? { agent: selectedAgentId } : {});
|
|
5290
5505
|
}
|
|
5291
5506
|
// ============ 权限管理 (tools.profile) ============
|
|
5292
5507
|
const TOOLS_PROFILES = [
|