-
Notifications
You must be signed in to change notification settings - Fork 8
fix(bridge): raise idle timeout and cache probe #160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -107,6 +107,9 @@ const { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readOpenaiBridgeSettings, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resolveOpenaiBridgeUpstream | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } = require('./cli/openai-bridge'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| createLocalBridgeHttpHandler | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } = require('./cli/local-bridge'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| createOpenclawConfigController | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } = require('./cli/openclaw-config'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -188,6 +191,7 @@ const INIT_MARK_FILE = path.join(CONFIG_DIR, 'codexmate-init.json'); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const BUILTIN_PROXY_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-proxy.json'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const BUILTIN_CLAUDE_PROXY_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-claude-proxy.json'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const OPENAI_BRIDGE_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-openai-bridge.json'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const LOCAL_BRIDGE_SETTINGS_FILE = path.join(CONFIG_DIR, 'codexmate-local-bridge.json'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const CODEX_SESSIONS_DIR = path.join(CONFIG_DIR, 'sessions'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const SESSION_TRASH_DIR = path.join(CONFIG_DIR, 'codexmate-session-trash'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const SESSION_TRASH_FILES_DIR = path.join(SESSION_TRASH_DIR, 'files'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -268,6 +272,7 @@ const DEFAULT_EXTRACT_SUFFIXES = Object.freeze(['.json']); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const g_taskRunControllers = new Map(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let g_taskQueueProcessor = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const BUILTIN_PROXY_PROVIDER_NAME = 'codexmate-proxy'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const BUILTIN_LOCAL_PROVIDER_NAME = 'local'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const DEFAULT_BUILTIN_PROXY_SETTINGS = Object.freeze({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| host: '127.0.0.1', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -330,6 +335,16 @@ const openaiBridgeHandler = createOpenaiBridgeHttpHandler({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| httpsAgent: HTTPS_KEEP_ALIVE_AGENT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const localBridgeHandler = createLocalBridgeHttpHandler({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readConfigFn: readConfig, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| openaiBridgeFile: OPENAI_BRIDGE_SETTINGS_FILE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| localBridgeSettingsFile: LOCAL_BRIDGE_SETTINGS_FILE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expectedToken: typeof process.env.CODEXMATE_HTTP_TOKEN === 'string' ? process.env.CODEXMATE_HTTP_TOKEN.trim() : '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maxBodySize: MAX_API_BODY_SIZE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| httpAgent: HTTP_KEEP_ALIVE_AGENT, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| httpsAgent: HTTPS_KEEP_ALIVE_AGENT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function resolveWebPort() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const raw = process.env.CODEXMATE_PORT; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!raw) return DEFAULT_WEB_PORT; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -589,16 +604,17 @@ model_auto_compact_token_limit = ${DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disable_response_storage = true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| approval_policy = "never" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sandbox_mode = "danger-full-access" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model_provider = "maxx" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model_provider = "local" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| personality = "pragmatic" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| web_search = "live" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [model_providers.maxx] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = "maxx" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| base_url = "https://maxx-direct.cloverstd.com" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [model_providers.local] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = "local" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| base_url = "http://127.0.0.1:3737/bridge/local/v1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wire_api = "responses" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| requires_openai_auth = false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| preferred_auth_method = "sk-" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| requires_openai_auth = true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| preferred_auth_method = "codexmate" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| codexmate_bridge = "local" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request_max_retries = 4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stream_max_retries = 10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stream_idle_timeout_ms = 300000 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -620,12 +636,16 @@ function isBuiltinProxyProvider(providerName) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return typeof providerName === 'string' && providerName.trim().toLowerCase() === BUILTIN_PROXY_PROVIDER_NAME.toLowerCase(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isLocalProvider(providerName) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return typeof providerName === 'string' && providerName.trim().toLowerCase() === BUILTIN_LOCAL_PROVIDER_NAME.toLowerCase(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isReservedProviderNameForCreation(providerName) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return isLocalProvider(providerName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isBuiltinManagedProvider(providerName) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return isBuiltinProxyProvider(providerName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return isBuiltinProxyProvider(providerName) || isLocalProvider(providerName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isNonDeletableProvider(providerName) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1661,6 +1681,7 @@ const { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CODEXMATE_MANAGED_MARKER, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BUILTIN_PROXY_PROVIDER_NAME, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BUILTIN_LOCAL_PROVIDER_NAME, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EMPTY_CONFIG_FALLBACK_TEMPLATE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2059,7 +2080,7 @@ function addProviderToConfig(params = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: '提供商名称不可用' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isBuiltinProxyProvider(name) && !allowManaged) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: 'codexmate-proxy 为保留名称,不可手动添加' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: `${"codexmate-proxy"} 为保留名称,不可手动添加` }; // keep literal for codexmate-proxy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ensureConfigDir(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2159,7 +2180,7 @@ function updateProviderInConfig(params = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: 'URL 仅支持 http/https' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isNonEditableProvider(name) && !allowManaged) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: 'codexmate-proxy 为保留名称,不可编辑' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: `${name} 为保留名称,不可编辑` }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2174,7 +2195,7 @@ function deleteProviderFromConfig(params = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const name = typeof params.name === 'string' ? params.name.trim() : ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!name) return { error: '名称不能为空' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isNonDeletableProvider(name)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: 'codexmate-proxy 为保留名称,不可删除' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: `${name} 为保留名称,不可删除` }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fs.existsSync(CONFIG_FILE)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: 'config.toml 不存在' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2202,7 +2223,7 @@ function deleteProviderFromConfig(params = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function performProviderDeletion(name, options = {}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const silent = !!options.silent; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isNonDeletableProvider(name)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const msg = 'codexmate-proxy 为保留名称,不可删除'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const msg = `${name} 为保留名称,不可删除`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!silent) console.error('错误:', msg); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: msg }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -5423,6 +5444,100 @@ async function ensureBuiltinProxyForCodexDefault(params = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: '该功能已移除' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function readLocalBridgeSettings() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const defaults = { enabled: false, lastActiveProvider: '', lastModel: '', excludedProviders: [] }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!fs.existsSync(LOCAL_BRIDGE_SETTINGS_FILE)) return defaults; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const raw = JSON.parse(fs.readFileSync(LOCAL_BRIDGE_SETTINGS_FILE, 'utf-8')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled: !!raw.enabled, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastActiveProvider: typeof raw.lastActiveProvider === 'string' ? raw.lastActiveProvider.trim() : '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastModel: typeof raw.lastModel === 'string' ? raw.lastModel.trim() : '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| excludedProviders: Array.isArray(raw.excludedProviders) ? raw.excludedProviders.filter(p => typeof p === 'string') : [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return defaults; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function writeLocalBridgeSettings(settings) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs.writeFileSync(LOCAL_BRIDGE_SETTINGS_FILE, JSON.stringify(settings, null, 2), 'utf-8'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function toggleLocalBridgeProvider(params = {}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const enable = !!params.enable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const settings = readLocalBridgeSettings(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = readConfig(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentProvider = typeof config.model_provider === 'string' ? config.model_provider.trim() : ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentModel = typeof config.model === 'string' ? config.model.trim() : ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (enable) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentProvider === 'local') return { success: true, enabled: true, notice: '已启用 local 转换' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| settings.lastActiveProvider = currentProvider; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| settings.lastModel = currentModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| settings.enabled = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeLocalBridgeSettings(settings); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let content = fs.readFileSync(CONFIG_FILE, 'utf-8'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = content.replace(/^(model_provider\s*=\s*)(["']).*?(["'])/m, `$1$2local$3`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeConfig(content); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: true, enabled: true, previousProvider: currentProvider }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentProvider !== 'local') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| settings.enabled = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeLocalBridgeSettings(settings); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: true, enabled: false, notice: 'local 转换未启用' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const restoreProvider = settings.lastActiveProvider || ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!restoreProvider) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| settings.enabled = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeLocalBridgeSettings(settings); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: true, enabled: false, notice: '已关闭 local 转换(无历史 provider 可恢复)' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let content = fs.readFileSync(CONFIG_FILE, 'utf-8'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = content.replace(/^(model_provider\s*=\s*)(["']).*?(["'])/m, `$1$2${restoreProvider}$3`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (settings.lastModel) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = content.replace(/^(model\s*=\s*)(["']).*?(["'])/m, `$1$2${settings.lastModel}$3`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeConfig(content); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| settings.enabled = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeLocalBridgeSettings(settings); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: true, enabled: false, restoredProvider: restoreProvider, restoredModel: settings.lastModel }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5491
to
+5505
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against restoring a provider that no longer exists.
Suggested fix const restoreProvider = settings.lastActiveProvider || '';
- if (!restoreProvider) {
+ const restoreConfig = config.model_providers && config.model_providers[restoreProvider];
+ if (!restoreProvider || !restoreConfig) {
settings.enabled = false;
writeLocalBridgeSettings(settings);
- return { success: true, enabled: false, notice: '已关闭 local 转换(无历史 provider 可恢复)' };
+ return { success: true, enabled: false, notice: '已关闭 local 转换(历史 provider 不存在,未恢复)' };
}
let content = fs.readFileSync(CONFIG_FILE, 'utf-8');
content = content.replace(/^(model_provider\s*=\s*)(["']).*?(["'])/m, `$1$2${restoreProvider}$3`);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { error: e && e.message ? e.message : '操作失败' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function getLocalBridgeStatus() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const settings = readLocalBridgeSettings(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let currentProvider = ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = readConfig(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentProvider = typeof config.model_provider === 'string' ? config.model_provider.trim() : ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { /* ignore */ } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled: settings.enabled, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| active: currentProvider === 'local', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| excludedProviders: settings.excludedProviders, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastActiveProvider: settings.lastActiveProvider, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastModel: settings.lastModel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function setLocalBridgeExcludedProviders(params = {}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const names = Array.isArray(params.names) ? params.names.filter(n => typeof n === 'string' && n.trim()) : []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const settings = readLocalBridgeSettings(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| settings.excludedProviders = names; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeLocalBridgeSettings(settings); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { success: true, excludedProviders: names }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function getLocalBridgeExcludedProviders() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const settings = readLocalBridgeSettings(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { excludedProviders: settings.excludedProviders }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function removeClaudeSessionIndexEntry(indexPath, sessionFilePath, sessionId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!indexPath || !fs.existsSync(indexPath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { removed: false, entry: null }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -8132,8 +8247,8 @@ function cmdAdd(name, baseUrl, apiKey, silent = false, options = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('提供商名称不可用'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isBuiltinProxyProvider(providerName)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!silent) console.error('错误: codexmate-proxy 为保留名称,不可手动添加'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('codexmate-proxy 为保留名称,不可手动添加'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!silent) console.error(`错误: ${providerName} 为保留名称,不可手动添加`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`${providerName} 为保留名称,不可手动添加`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isValidHttpUrl(providerBaseUrl)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!silent) console.error('错误: URL 仅支持 http/https'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -8229,7 +8344,7 @@ function cmdUpdate(name, baseUrl, apiKey, silent = false, options = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('提供商名称必填'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isNonEditableProvider(name) && !allowManaged) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const msg = 'codexmate-proxy 为保留名称,不可编辑'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const msg = `${name} 为保留名称,不可编辑`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!silent) console.error(`错误: ${msg}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(msg); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -9961,6 +10076,9 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res.end(body, 'utf-8'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof localBridgeHandler === 'function' && localBridgeHandler(req, res)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof openaiBridgeHandler === 'function' && openaiBridgeHandler(req, res)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -10497,6 +10615,18 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 'proxy-apply-provider': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = applyBuiltinProxyProvider(params || {}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 'local-bridge-toggle': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = toggleLocalBridgeProvider(params || {}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 'local-bridge-status': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = getLocalBridgeStatus(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 'local-bridge-set-excluded': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = setLocalBridgeExcludedProviders(params || {}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 'local-bridge-get-excluded': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = getLocalBridgeExcludedProviders(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 'workflow-list': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = listWorkflowDefinitions(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sync
auth.jsonwhen the active provider changes.This function flips
model_provider, but unlikecmdSwitch()andapplyConfigTemplate(), it never refreshesAUTH_FILE. After enablinglocal, requests can keep using the previous provider credential; after disabling it, they can keep usingcodexmate. The toggle looks successful inconfig.toml, but the next request can authenticate against the wrong target.Suggested fix
if (enable) { if (currentProvider === 'local') return { success: true, enabled: true, notice: '已启用 local 转换' }; settings.lastActiveProvider = currentProvider; settings.lastModel = currentModel; settings.enabled = true; writeLocalBridgeSettings(settings); let content = fs.readFileSync(CONFIG_FILE, 'utf-8'); content = content.replace(/^(model_provider\s*=\s*)(["']).*?(["'])/m, `$1$2local$3`); writeConfig(content); + const localProvider = config.model_providers && config.model_providers[BUILTIN_LOCAL_PROVIDER_NAME]; + updateAuthJson(localProvider && localProvider.preferred_auth_method ? localProvider.preferred_auth_method : ''); return { success: true, enabled: true, previousProvider: currentProvider }; } else { if (currentProvider !== 'local') { settings.enabled = false; writeLocalBridgeSettings(settings); return { success: true, enabled: false, notice: 'local 转换未启用' }; } const restoreProvider = settings.lastActiveProvider || ''; + const restoreConfig = config.model_providers && config.model_providers[restoreProvider]; if (!restoreProvider) { settings.enabled = false; writeLocalBridgeSettings(settings); return { success: true, enabled: false, notice: '已关闭 local 转换(无历史 provider 可恢复)' }; } let content = fs.readFileSync(CONFIG_FILE, 'utf-8'); content = content.replace(/^(model_provider\s*=\s*)(["']).*?(["'])/m, `$1$2${restoreProvider}$3`); if (settings.lastModel) { content = content.replace(/^(model\s*=\s*)(["']).*?(["'])/m, `$1$2${settings.lastModel}$3`); } writeConfig(content); + updateAuthJson(restoreConfig && restoreConfig.preferred_auth_method ? restoreConfig.preferred_auth_method : ''); settings.enabled = false; writeLocalBridgeSettings(settings); return { success: true, enabled: false, restoredProvider: restoreProvider, restoredModel: settings.lastModel }; }🤖 Prompt for AI Agents