Compare commits

...

1 Commits

Author SHA1 Message Date
Matthew Zeng
baed766154 update 2026-03-20 23:50:21 -07:00
2 changed files with 84 additions and 16 deletions

View File

@@ -720,6 +720,7 @@ pub(crate) struct ChatWidget {
connectors_partial_snapshot: Option<ConnectorsSnapshot>,
connectors_prefetch_in_flight: bool,
connectors_force_refetch_pending: bool,
pending_mcp_output_requests: usize,
plugins_cache: PluginsCacheState,
plugins_fetch_state: PluginListFetchState,
// Queue of interruptive UI events deferred during an active write cycle
@@ -1455,9 +1456,6 @@ impl ChatWidget {
cwds: Vec::new(),
force_reload: true,
});
if self.connectors_enabled() {
self.prefetch_connectors();
}
if let Some(user_message) = self.initial_user_message.take() {
self.submit_user_message(user_message);
}
@@ -2183,6 +2181,7 @@ impl ChatWidget {
}
fn on_mcp_startup_complete(&mut self, ev: McpStartupCompleteEvent) {
let codex_apps_ready = ev.ready.iter().any(|server| server == "codex_apps");
let mut parts = Vec::new();
if !ev.failed.is_empty() {
let failed_servers: Vec<_> = ev.failed.iter().map(|f| f.server.clone()).collect();
@@ -2201,6 +2200,11 @@ impl ChatWidget {
self.mcp_startup_status = None;
self.update_task_running_state();
self.maybe_send_next_queued_input();
if self.connectors_enabled() && codex_apps_ready {
// Populate `$` app mentions from the session's already-started MCP manager
// instead of doing a separate TUI-side connector prefetch.
self.submit_op(Op::ListMcpTools);
}
self.request_redraw();
}
@@ -3664,6 +3668,7 @@ impl ChatWidget {
connectors_partial_snapshot: None,
connectors_prefetch_in_flight: false,
connectors_force_refetch_pending: false,
pending_mcp_output_requests: 0,
plugins_cache: PluginsCacheState::default(),
plugins_fetch_state: PluginListFetchState::default(),
interrupts: InterruptManager::new(),
@@ -3864,6 +3869,7 @@ impl ChatWidget {
connectors_partial_snapshot: None,
connectors_prefetch_in_flight: false,
connectors_force_refetch_pending: false,
pending_mcp_output_requests: 0,
plugins_cache: PluginsCacheState::default(),
plugins_fetch_state: PluginListFetchState::default(),
interrupts: InterruptManager::new(),
@@ -4056,6 +4062,7 @@ impl ChatWidget {
connectors_partial_snapshot: None,
connectors_prefetch_in_flight: false,
connectors_force_refetch_pending: false,
pending_mcp_output_requests: 0,
plugins_cache: PluginsCacheState::default(),
plugins_fetch_state: PluginListFetchState::default(),
interrupts: InterruptManager::new(),
@@ -5939,10 +5946,6 @@ impl ChatWidget {
self.prefetch_connectors_with_options(force_refetch);
}
fn prefetch_connectors(&mut self) {
self.prefetch_connectors_with_options(/*force_refetch*/ false);
}
fn prefetch_connectors_with_options(&mut self, force_refetch: bool) {
if !self.connectors_enabled() {
return;
@@ -8358,8 +8361,8 @@ impl ChatWidget {
.is_empty()
{
self.add_to_history(history_cell::empty_mcp_output());
} else {
self.submit_op(Op::ListMcpTools);
} else if self.submit_op(Op::ListMcpTools) {
self.pending_mcp_output_requests = self.pending_mcp_output_requests.saturating_add(1);
}
}
@@ -8821,13 +8824,77 @@ impl ChatWidget {
}
fn on_list_mcp_tools(&mut self, ev: McpListToolsResponseEvent) {
self.add_to_history(history_cell::new_mcp_tools_output(
&self.config,
ev.tools,
ev.resources,
ev.resource_templates,
&ev.auth_statuses,
));
if self.connectors_enabled() {
let mut connectors_by_id: HashMap<String, connectors::AppInfo> = HashMap::new();
for tool in ev.tools.values() {
let Some(meta) = tool.meta.as_ref().and_then(serde_json::Value::as_object) else {
continue;
};
let Some(connector_id) = meta
.get("connector_id")
.and_then(serde_json::Value::as_str)
.filter(|id| !id.is_empty())
else {
continue;
};
connectors_by_id
.entry(connector_id.to_string())
.or_insert_with(|| {
let name = meta
.get("connector_name")
.or_else(|| meta.get("connector_display_name"))
.and_then(serde_json::Value::as_str)
.filter(|name| !name.trim().is_empty())
.unwrap_or(connector_id)
.to_string();
let description = meta
.get("connector_description")
.or_else(|| meta.get("connectorDescription"))
.and_then(serde_json::Value::as_str)
.map(str::trim)
.filter(|description| !description.is_empty())
.map(ToString::to_string);
connectors::AppInfo {
id: connector_id.to_string(),
name,
description,
logo_url: None,
logo_url_dark: None,
distribution_channel: None,
branding: None,
app_metadata: None,
labels: None,
install_url: None,
is_accessible: true,
is_enabled: true,
plugin_display_names: Vec::new(),
}
});
}
let mut app_connectors = connectors_by_id.into_values().collect::<Vec<_>>();
app_connectors.sort_by(|left, right| {
left.name
.cmp(&right.name)
.then_with(|| left.id.cmp(&right.id))
});
let app_connectors = connectors::with_app_enabled_state(app_connectors, &self.config);
self.bottom_pane
.set_connectors_snapshot(Some(ConnectorsSnapshot {
connectors: app_connectors,
}));
}
if self.pending_mcp_output_requests > 0 {
self.pending_mcp_output_requests -= 1;
self.add_to_history(history_cell::new_mcp_tools_output(
&self.config,
ev.tools,
ev.resources,
ev.resource_templates,
&ev.auth_statuses,
));
}
}
fn on_list_custom_prompts(&mut self, ev: ListCustomPromptsResponseEvent) {

View File

@@ -1895,6 +1895,7 @@ async fn make_chatwidget_manual(
connectors_partial_snapshot: None,
connectors_prefetch_in_flight: false,
connectors_force_refetch_pending: false,
pending_mcp_output_requests: 0,
plugins_cache: PluginsCacheState::default(),
plugins_fetch_state: PluginListFetchState::default(),
interrupts: InterruptManager::new(),