mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-04 10:01:57 +08:00
fix(openclaw): address code review findings for robustness
- Fix EnvPanel visibleKeys using entry key name instead of array index to prevent visibility state corruption after deletion - Add NaN guard in AgentsDefaultsPanel numeric field parsing - Validate provider id and models before importing from live config - Upgrade import failure log level from debug to warn for OpenCode/OpenClaw
This commit is contained in:
@@ -501,7 +501,7 @@ pub fn run() {
|
|||||||
log::info!("✓ Imported {count} OpenCode provider(s) from live config");
|
log::info!("✓ Imported {count} OpenCode provider(s) from live config");
|
||||||
}
|
}
|
||||||
Ok(_) => log::debug!("○ No OpenCode providers found to import"),
|
Ok(_) => log::debug!("○ No OpenCode providers found to import"),
|
||||||
Err(e) => log::debug!("○ Failed to import OpenCode providers: {e}"),
|
Err(e) => log::warn!("○ Failed to import OpenCode providers: {e}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.2 OMO 配置导入(当数据库中无 OMO provider 时,从本地文件导入)
|
// 2.2 OMO 配置导入(当数据库中无 OMO provider 时,从本地文件导入)
|
||||||
@@ -534,7 +534,7 @@ pub fn run() {
|
|||||||
log::info!("✓ Imported {count} OpenClaw provider(s) from live config");
|
log::info!("✓ Imported {count} OpenClaw provider(s) from live config");
|
||||||
}
|
}
|
||||||
Ok(_) => log::debug!("○ No OpenClaw providers found to import"),
|
Ok(_) => log::debug!("○ No OpenClaw providers found to import"),
|
||||||
Err(e) => log::debug!("○ Failed to import OpenClaw providers: {e}"),
|
Err(e) => log::warn!("○ Failed to import OpenClaw providers: {e}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 导入 MCP 服务器配置(表空时触发)
|
// 3. 导入 MCP 服务器配置(表空时触发)
|
||||||
|
|||||||
@@ -707,6 +707,16 @@ pub fn import_openclaw_providers_from_live(state: &AppState) -> Result<usize, Ap
|
|||||||
let existing = state.db.get_all_providers("openclaw")?;
|
let existing = state.db.get_all_providers("openclaw")?;
|
||||||
|
|
||||||
for (id, config) in providers {
|
for (id, config) in providers {
|
||||||
|
// Validate: skip entries with empty id or no models
|
||||||
|
if id.trim().is_empty() {
|
||||||
|
log::warn!("Skipping OpenClaw provider with empty id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if config.models.is_empty() {
|
||||||
|
log::warn!("Skipping OpenClaw provider '{id}': no models defined");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip if already exists in database
|
// Skip if already exists in database
|
||||||
if existing.contains_key(&id) {
|
if existing.contains_key(&id) {
|
||||||
log::debug!("OpenClaw provider '{id}' already exists in database, skipping");
|
log::debug!("OpenClaw provider '{id}' already exists in database, skipping");
|
||||||
|
|||||||
@@ -70,17 +70,28 @@ const AgentsDefaultsPanel: React.FC = () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional numeric fields
|
// Optional fields
|
||||||
if (workspace.trim()) updated.workspace = workspace.trim();
|
if (workspace.trim()) updated.workspace = workspace.trim();
|
||||||
else delete updated.workspace;
|
else delete updated.workspace;
|
||||||
|
|
||||||
if (timeout.trim()) updated.timeout = Number(timeout);
|
// Numeric fields: validate before saving to avoid NaN
|
||||||
|
const parseNum = (v: string) => {
|
||||||
|
const n = Number(v);
|
||||||
|
return !isNaN(n) && isFinite(n) ? n : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const timeoutNum = timeout.trim() ? parseNum(timeout) : undefined;
|
||||||
|
if (timeoutNum !== undefined) updated.timeout = timeoutNum;
|
||||||
else delete updated.timeout;
|
else delete updated.timeout;
|
||||||
|
|
||||||
if (contextTokens.trim()) updated.contextTokens = Number(contextTokens);
|
const ctxNum = contextTokens.trim() ? parseNum(contextTokens) : undefined;
|
||||||
|
if (ctxNum !== undefined) updated.contextTokens = ctxNum;
|
||||||
else delete updated.contextTokens;
|
else delete updated.contextTokens;
|
||||||
|
|
||||||
if (maxConcurrent.trim()) updated.maxConcurrent = Number(maxConcurrent);
|
const concNum = maxConcurrent.trim()
|
||||||
|
? parseNum(maxConcurrent)
|
||||||
|
: undefined;
|
||||||
|
if (concNum !== undefined) updated.maxConcurrent = concNum;
|
||||||
else delete updated.maxConcurrent;
|
else delete updated.maxConcurrent;
|
||||||
|
|
||||||
await openclawApi.setAgentsDefaults(updated);
|
await openclawApi.setAgentsDefaults(updated);
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ const EnvPanel: React.FC = () => {
|
|||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{entries.map((entry, index) => {
|
{entries.map((entry, index) => {
|
||||||
const sensitive = isApiKey(entry.key);
|
const sensitive = isApiKey(entry.key);
|
||||||
const visible = visibleKeys.has(`${index}`);
|
const visibilityId = entry.key || `__new_${index}`;
|
||||||
|
const visible = visibleKeys.has(visibilityId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={index} className="flex items-center gap-2">
|
<div key={index} className="flex items-center gap-2">
|
||||||
@@ -138,7 +139,7 @@ const EnvPanel: React.FC = () => {
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="flex-shrink-0 h-9 w-9 text-muted-foreground"
|
className="flex-shrink-0 h-9 w-9 text-muted-foreground"
|
||||||
onClick={() => toggleVisibility(`${index}`)}
|
onClick={() => toggleVisibility(visibilityId)}
|
||||||
>
|
>
|
||||||
{visible ? (
|
{visible ? (
|
||||||
<EyeOff className="w-4 h-4" />
|
<EyeOff className="w-4 h-4" />
|
||||||
|
|||||||
Reference in New Issue
Block a user