mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 11:43:57 +08:00
fix: OpenCode live provider import updates (#4712)
* fix: sync existing opencode providers from live config * fix: preserve OpenCode provider display names * docs: update comments and log messages to reflect new update behavior - fix stale comment in lib.rs that said existing providers are skipped - change log message from 'Imported' to 'Synced' since count now includes both new imports and updates
This commit is contained in:
@@ -672,18 +672,19 @@ pub fn run() {
|
|||||||
|
|
||||||
// 1.6. 自动同步 OpenCode / OpenClaw 的 live providers 到数据库
|
// 1.6. 自动同步 OpenCode / OpenClaw 的 live providers 到数据库
|
||||||
//
|
//
|
||||||
// additive 模式(OpenCode / OpenClaw)的 import 函数本身按 id 幂等,
|
// additive 模式(OpenCode / OpenClaw)的 import 函数按 id 幂等——
|
||||||
// 已有的 provider 会被跳过,所以每次启动都跑是安全的——既保证新装
|
// 新 id 执行导入,已有 id 则更新 settings 和 display name,所以每次
|
||||||
// 用户开箱可见 live 中的供应商,也让外部修改的 live 文件能在重启
|
// 启动都跑是安全的:既保证新装用户开箱可见 live 中的供应商,也让外部
|
||||||
// 后同步到数据库(与之前依赖前端"导入当前配置"按钮手动触发不同)。
|
// 修改的 live 文件能在重启后同步到数据库(与之前依赖前端"导入当前配置"
|
||||||
|
// 按钮手动触发不同)。
|
||||||
//
|
//
|
||||||
// 底层 read_*_config 在文件不存在时返回默认空配置,因此新装且无
|
// 底层 read_*_config 在文件不存在时返回默认空配置,因此新装且无
|
||||||
// live 文件的用户走 Ok(0) 路径,不会产生错误日志噪音。
|
// live 文件的用户走 Ok(0) 路径,不会产生错误日志噪音。
|
||||||
match crate::services::provider::import_opencode_providers_from_live(&app_state) {
|
match crate::services::provider::import_opencode_providers_from_live(&app_state) {
|
||||||
Ok(count) if count > 0 => {
|
Ok(count) if count > 0 => {
|
||||||
log::info!("✓ Imported {count} OpenCode provider(s) from live config");
|
log::info!("✓ Synced {count} OpenCode provider(s) from live config");
|
||||||
}
|
}
|
||||||
Ok(_) => log::debug!("○ No new OpenCode providers to import"),
|
Ok(_) => log::debug!("○ No OpenCode provider changes from live config"),
|
||||||
Err(e) => log::warn!("✗ Failed to import OpenCode providers: {e}"),
|
Err(e) => log::warn!("✗ Failed to import OpenCode providers: {e}"),
|
||||||
}
|
}
|
||||||
match crate::services::provider::import_openclaw_providers_from_live(&app_state) {
|
match crate::services::provider::import_openclaw_providers_from_live(&app_state) {
|
||||||
|
|||||||
@@ -1404,15 +1404,10 @@ pub fn import_opencode_providers_from_live(state: &AppState) -> Result<usize, Ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut imported = 0;
|
let mut imported = 0;
|
||||||
|
let mut updated = 0;
|
||||||
let existing_ids = state.db.get_provider_ids("opencode")?;
|
let existing_ids = state.db.get_provider_ids("opencode")?;
|
||||||
|
|
||||||
for (id, config) in providers {
|
for (id, config) in providers {
|
||||||
// Skip if already exists in database
|
|
||||||
if existing_ids.contains(&id) {
|
|
||||||
log::debug!("OpenCode provider '{id}' already exists in database, skipping");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to Value for settings_config
|
// Convert to Value for settings_config
|
||||||
let settings_config = match serde_json::to_value(&config) {
|
let settings_config = match serde_json::to_value(&config) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
@@ -1422,13 +1417,36 @@ pub fn import_opencode_providers_from_live(state: &AppState) -> Result<usize, Ap
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if existing_ids.contains(&id) {
|
||||||
|
match state.db.get_provider_by_id(&id, "opencode") {
|
||||||
|
Ok(Some(existing)) => {
|
||||||
|
let display_name = config.name.clone().unwrap_or_else(|| existing.name.clone());
|
||||||
|
if existing.settings_config != settings_config || existing.name != display_name
|
||||||
|
{
|
||||||
|
let mut provider = existing;
|
||||||
|
provider.name = display_name;
|
||||||
|
provider.settings_config = settings_config;
|
||||||
|
if let Err(e) = state.db.save_provider("opencode", &provider) {
|
||||||
|
log::warn!(
|
||||||
|
"Failed to update OpenCode provider '{id}' from live config: {e}"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
updated += 1;
|
||||||
|
log::info!("Updated OpenCode provider '{id}' from live config");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
log::warn!("OpenCode provider '{id}' disappeared while importing live config")
|
||||||
|
}
|
||||||
|
Err(e) => log::warn!("Failed to look up OpenCode provider '{id}': {e}"),
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Create provider
|
// Create provider
|
||||||
let mut provider = Provider::with_id(
|
let display_name = config.name.clone().unwrap_or_else(|| id.clone());
|
||||||
id.clone(),
|
let mut provider = Provider::with_id(id.clone(), display_name, settings_config, None);
|
||||||
config.name.clone().unwrap_or_else(|| id.clone()),
|
|
||||||
settings_config,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
provider.meta = Some(crate::provider::ProviderMeta {
|
provider.meta = Some(crate::provider::ProviderMeta {
|
||||||
live_config_managed: Some(true),
|
live_config_managed: Some(true),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1444,7 +1462,7 @@ pub fn import_opencode_providers_from_live(state: &AppState) -> Result<usize, Ap
|
|||||||
log::info!("Imported OpenCode provider '{id}' from live config");
|
log::info!("Imported OpenCode provider '{id}' from live config");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(imported)
|
Ok(imported + updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import all providers from OpenClaw live config to database
|
/// Import all providers from OpenClaw live config to database
|
||||||
|
|||||||
@@ -1294,6 +1294,40 @@ base_url = "http://localhost:8080"
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn import_opencode_providers_from_live_updates_existing_provider_from_live() {
|
||||||
|
with_test_home(|state, _| {
|
||||||
|
let provider = opencode_provider("existing-opencode");
|
||||||
|
state
|
||||||
|
.db
|
||||||
|
.save_provider(AppType::OpenCode.as_str(), &provider)
|
||||||
|
.expect("seed existing opencode provider");
|
||||||
|
|
||||||
|
let mut live_settings = provider.settings_config.clone();
|
||||||
|
live_settings.as_object_mut().unwrap().remove("name");
|
||||||
|
live_settings["npm"] = Value::String("@ai-sdk/anthropic".to_string());
|
||||||
|
live_settings["models"]["gpt-4o"]["name"] = Value::String("Claude Sonnet".to_string());
|
||||||
|
crate::opencode_config::set_provider(&provider.id, live_settings)
|
||||||
|
.expect("seed edited live opencode provider");
|
||||||
|
|
||||||
|
let updated = import_opencode_providers_from_live(state)
|
||||||
|
.expect("import opencode providers from live");
|
||||||
|
assert_eq!(updated, 1);
|
||||||
|
|
||||||
|
let saved = state
|
||||||
|
.db
|
||||||
|
.get_provider_by_id(&provider.id, AppType::OpenCode.as_str())
|
||||||
|
.expect("query updated opencode provider")
|
||||||
|
.expect("opencode provider should exist");
|
||||||
|
assert_eq!(saved.name, provider.name);
|
||||||
|
assert_eq!(saved.settings_config["npm"], json!("@ai-sdk/anthropic"));
|
||||||
|
assert_eq!(
|
||||||
|
saved.settings_config["models"]["gpt-4o"]["name"],
|
||||||
|
json!("Claude Sonnet")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn import_openclaw_providers_from_live_marks_provider_as_live_managed() {
|
fn import_openclaw_providers_from_live_marks_provider_as_live_managed() {
|
||||||
|
|||||||
Reference in New Issue
Block a user