fix: hot-reload opencode settings in active agents#302
Conversation
WalkthroughAdds immediate post-write config reloads in the settings API, makes OpenCode defaults and server-pool rebuilds part of runtime config reloads, switches opencode server pool storage to ArcSwap, derives equality for OpenCode config/permissions, and clarifies OpenCode worker guidance in templates and spawn_worker descriptions/schema. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/api/settings.rs (1)
340-351: Consider extracting the reload logic into a helper function.This reload block is duplicated nearly verbatim at lines 461–489 in
update_raw_config. Extracting it into a shared helper (e.g.,reload_runtime_configs) would reduce duplication and centralize the reload behavior.♻️ Suggested helper extraction
async fn reload_runtime_configs( state: &ApiState, config_path: &std::path::Path, ) { match crate::config::Config::load_from_path(config_path) { Ok(new_config) => { let runtime_configs = state.runtime_configs.load(); let mcp_managers = state.mcp_managers.load(); let reload_targets = runtime_configs .iter() .filter_map(|(agent_id, runtime_config)| { mcp_managers.get(agent_id).map(|mcp_manager| { ( agent_id.clone(), runtime_config.clone(), mcp_manager.clone(), ) }) }) .collect::<Vec<_>>(); drop(runtime_configs); drop(mcp_managers); for (agent_id, runtime_config, mcp_manager) in reload_targets { runtime_config .reload_config(&new_config, &agent_id, &mcp_manager) .await; } } Err(error) => { tracing::warn!(%error, "config written but failed to reload immediately"); } } }Then both call sites simplify to:
reload_runtime_configs(&state, &config_path).await;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/api/settings.rs` around lines 340 - 351, The duplicated reload logic that builds reload_targets from runtime_configs and mcp_managers appears twice (once here and again in update_raw_config); extract it into a shared async helper named e.g. reload_runtime_configs(state: &ApiState, config_path: &Path) that loads the new Config, captures state.runtime_configs.load() and state.mcp_managers.load(), builds the same reload_targets (using agent_id.clone(), runtime_config.clone(), mcp_manager.clone()), drops the guards, iterates and calls runtime_config.reload_config(&new_config, &agent_id, &mcp_manager).await for each target, and logs on Err; then replace both inline blocks with a single await call to reload_runtime_configs(&state, &config_path).await to remove duplication and centralize behavior (references: runtime_configs, mcp_managers, runtime_config.reload_config, update_raw_config).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/api/settings.rs`:
- Around line 340-351: The duplicated reload logic that builds reload_targets
from runtime_configs and mcp_managers appears twice (once here and again in
update_raw_config); extract it into a shared async helper named e.g.
reload_runtime_configs(state: &ApiState, config_path: &Path) that loads the new
Config, captures state.runtime_configs.load() and state.mcp_managers.load(),
builds the same reload_targets (using agent_id.clone(), runtime_config.clone(),
mcp_manager.clone()), drops the guards, iterates and calls
runtime_config.reload_config(&new_config, &agent_id, &mcp_manager).await for
each target, and logs on Err; then replace both inline blocks with a single
await call to reload_runtime_configs(&state, &config_path).await to remove
duplication and centralize behavior (references: runtime_configs, mcp_managers,
runtime_config.reload_config, update_raw_config).
| drop(runtime_configs); | ||
| drop(mcp_managers); | ||
|
|
||
| for (agent_id, runtime_config, mcp_manager) in reload_targets { |
There was a problem hiding this comment.
Minor perf thing: this is a serial .await loop. If reload_targets can get large, bounded concurrency (or join_all) might keep this endpoint snappy.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/config.rs (1)
5644-5645: Align pool initialization comment with actual behavior.The field comment says lazy init, but
RuntimeConfig::neweagerly constructsOpenCodeServerPool. Please either update the comment or defer creation to first use.Also applies to: 5672-5677, 5706-5706
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/agent/channel_dispatch.rssrc/api/settings.rssrc/config.rssrc/opencode/types.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- src/api/settings.rs
Summary
update_global_settingswritesconfig.toml, so settings changes apply to live agents without waiting on file-watcher timing.defaults.opencodeinRuntimeConfig::reload_config, soopencode.enabledtoggles update channel prompts/tool definitions and worker dispatch behavior without a restart.spawn_workermust includeworker_type: \"opencode\"plusdirectory, and coding-heavy tasks default to OpenCode when enabled.