Detailed changes
@@ -11,7 +11,7 @@ use http_client::{AsyncBody, HttpClient};
use serde::Deserialize;
use settings::Settings;
-use crate::agent_server_store::{AllAgentServersSettings, CustomAgentServerSettings};
+use crate::agent_server_store::AllAgentServersSettings;
const REGISTRY_URL: &str = "https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json";
const REFRESH_THROTTLE_DURATION: Duration = Duration::from_secs(60 * 60);
@@ -117,23 +117,19 @@ impl AgentRegistryStore {
/// are registry agents configured in settings, it will trigger a network fetch.
/// Otherwise, call `refresh()` explicitly when you need fresh data
/// (e.g., when opening the Agent Registry page).
- pub fn init_global(cx: &mut App) -> Entity<Self> {
+ pub fn init_global(
+ cx: &mut App,
+ fs: Arc<dyn Fs>,
+ http_client: Arc<dyn HttpClient>,
+ ) -> Entity<Self> {
if let Some(store) = Self::try_global(cx) {
return store;
}
- let fs = <dyn Fs>::global(cx);
- let http_client: Arc<dyn HttpClient> = cx.http_client();
-
let store = cx.new(|cx| Self::new(fs, http_client, cx));
cx.set_global(GlobalAgentRegistryStore(store.clone()));
- let has_registry_agents_in_settings = AllAgentServersSettings::get_global(cx)
- .custom
- .values()
- .any(|s| matches!(s, CustomAgentServerSettings::Registry { .. }));
-
- if has_registry_agents_in_settings {
+ if AllAgentServersSettings::get_global(cx).has_registry_agents() {
store.update(cx, |store, cx| {
if store.agents.is_empty() {
store.refresh(cx);
@@ -191,7 +187,10 @@ impl AgentRegistryStore {
build_registry_agents(fs.clone(), http_client, data.index, data.raw_body, true)
.await
}
- Err(error) => Err(error),
+ Err(error) => {
+ log::error!("AgentRegistryStore::refresh: fetch failed: {error:#}");
+ Err(error)
+ }
};
this.update(cx, |this, cx| {
@@ -408,6 +408,14 @@ impl AgentServerStore {
.get::<AllAgentServersSettings>(None)
.clone();
+ // If we don't have agents from the registry loaded yet, trigger a
+ // refresh, which will cause this function to be called again
+ if new_settings.has_registry_agents()
+ && let Some(registry) = AgentRegistryStore::try_global(cx)
+ {
+ registry.update(cx, |registry, cx| registry.refresh_if_stale(cx));
+ }
+
self.external_agents.clear();
self.external_agents.insert(
GEMINI_NAME.into(),
@@ -554,7 +562,7 @@ impl AgentServerStore {
CustomAgentServerSettings::Registry { env, .. } => {
let Some(agent) = registry_agents_by_id.get(name) else {
if registry_store.is_some() {
- log::warn!("Registry agent '{}' not found in ACP registry", name);
+ log::debug!("Registry agent '{}' not found in ACP registry", name);
}
continue;
};
@@ -914,10 +922,20 @@ impl AgentServerStore {
} else {
ExternalAgentSource::Custom
};
- let (icon, display_name, source) =
- metadata
- .remove(&agent_name)
- .unwrap_or((None, None, fallback_source));
+ let (icon, display_name, source) = metadata
+ .remove(&agent_name)
+ .or_else(|| {
+ AgentRegistryStore::try_global(cx)
+ .and_then(|store| store.read(cx).agent(&agent_name.0))
+ .map(|s| {
+ (
+ s.icon_path().cloned(),
+ Some(s.name().clone()),
+ ExternalAgentSource::Registry,
+ )
+ })
+ })
+ .unwrap_or((None, None, fallback_source));
let source = if fallback_source == ExternalAgentSource::Builtin {
ExternalAgentSource::Builtin
} else {
@@ -2239,6 +2257,15 @@ pub struct AllAgentServersSettings {
pub codex: Option<BuiltinAgentServerSettings>,
pub custom: HashMap<String, CustomAgentServerSettings>,
}
+
+impl AllAgentServersSettings {
+ pub fn has_registry_agents(&self) -> bool {
+ self.custom
+ .values()
+ .any(|s| matches!(s, CustomAgentServerSettings::Registry { .. }))
+ }
+}
+
#[derive(Default, Clone, JsonSchema, Debug, PartialEq)]
pub struct BuiltinAgentServerSettings {
pub path: Option<PathBuf>,
@@ -12,8 +12,8 @@ use http_client::HttpClient;
use language::{Buffer, BufferEvent, LanguageRegistry, proto::serialize_operation};
use node_runtime::NodeRuntime;
use project::{
- LspStore, LspStoreEvent, ManifestTree, PrettierStore, ProjectEnvironment, ProjectPath,
- ToolchainStore, WorktreeId,
+ AgentRegistryStore, LspStore, LspStoreEvent, ManifestTree, PrettierStore, ProjectEnvironment,
+ ProjectPath, ToolchainStore, WorktreeId,
agent_server_store::AgentServerStore,
buffer_store::{BufferStore, BufferStoreEvent},
context_server_store::ContextServerStore,
@@ -223,6 +223,8 @@ impl HeadlessProject {
lsp_store
});
+ AgentRegistryStore::init_global(cx, fs.clone(), http_client.clone());
+
let agent_server_store = cx.new(|cx| {
let mut agent_server_store = AgentServerStore::local(
node_runtime.clone(),
@@ -621,7 +621,11 @@ fn main() {
snippet_provider::init(cx);
edit_prediction_registry::init(app_state.client.clone(), app_state.user_store.clone(), cx);
let prompt_builder = PromptBuilder::load(app_state.fs.clone(), stdout_is_a_pty(), cx);
- project::AgentRegistryStore::init_global(cx);
+ project::AgentRegistryStore::init_global(
+ cx,
+ app_state.fs.clone(),
+ app_state.client.http_client(),
+ );
agent_ui::init(
app_state.fs.clone(),
app_state.client.clone(),
@@ -201,7 +201,11 @@ fn run_visual_tests(project_path: PathBuf, update_baseline: bool) -> Result<()>
language_model::init(app_state.client.clone(), cx);
language_models::init(app_state.user_store.clone(), app_state.client.clone(), cx);
git_ui::init(cx);
- project::AgentRegistryStore::init_global(cx);
+ project::AgentRegistryStore::init_global(
+ cx,
+ app_state.fs.clone(),
+ app_state.client.http_client(),
+ );
agent_ui::init(
app_state.fs.clone(),
app_state.client.clone(),
@@ -5058,7 +5058,11 @@ mod tests {
git_graph::init(cx);
web_search_providers::init(app_state.client.clone(), cx);
let prompt_builder = PromptBuilder::load(app_state.fs.clone(), false, cx);
- project::AgentRegistryStore::init_global(cx);
+ project::AgentRegistryStore::init_global(
+ cx,
+ app_state.fs.clone(),
+ app_state.client.http_client(),
+ );
agent_ui::init(
app_state.fs.clone(),
app_state.client.clone(),