Add task mentions to the TUI composer (#40315)

## What changed

- Include matching Codex tasks in the `@` mention popup when the active thread supports task tools, prioritizing tasks from the current working directory.
- Submit selected tasks as bounded live thread references so Codex can load their contents with `read_thread`.
- Preserve task mentions across composer history and thread start, resume, and fork flows.

## Testing

- Add coverage for task search and capability propagation, popup selection and rendering, submission encoding, history round-trips, and reference validation and limits.

GitOrigin-RevId: 17502be91bf6d4b01745668829eb69fb318cb5b9
This commit is contained in:
Eric Traut authored and copyberry committed 2026-08-24 02:46:56 +00:00
1 parent a8468330bb
commit 76d98a771e
30 files changed
+1317 -44

No files matched your search

+42 -1
View File
@@ -102,12 +102,16 @@ impl App {
}
AppEvent::DynamicToolThreadStarted {
thread_id,
task_tools_available,
registered,
} => {
self.agents_overview
.dispatched_requests
.entry(thread_id)
.or_default();
if task_tools_available {
app_server.remember_task_tool_thread(thread_id);
}
let _ = registered.send(());
}
AppEvent::DynamicToolCallCompleted {
@@ -129,6 +133,9 @@ impl App {
}
}
}
AppEvent::TaskToolsAvailable { thread_id } => {
app_server.remember_task_tool_thread(thread_id);
}
AppEvent::RequestOlderScrollbackHistory { thread_id } => {
if self.chat_widget.thread_id() == Some(thread_id)
&& self.overlay.is_none()
@@ -1158,11 +1165,45 @@ impl App {
);
}
AppEvent::StartFileSearch(query) => {
self.file_search.on_user_query(query);
self.file_search.on_user_query(query.clone());
if let Some(thread_id) = self.active_thread_id
&& app_server.task_tools_available(thread_id)
&& self.config.features.enabled(Feature::MentionsV2)
{
let cwd = self
.thread_cwd(thread_id)
.await
.map(|cwd| cwd.to_path_buf())
.or_else(|| {
app_server
.remote_cwd_override()
.map(std::path::Path::to_path_buf)
})
.unwrap_or_else(|| self.config.cwd.to_path_buf());
crate::task_mentions::spawn_search(
app_server.request_handle(),
query,
thread_id,
cwd,
app_server.task_search_generation(),
self.app_event_tx.clone(),
);
}
}
AppEvent::FileSearchResult { query, matches } => {
self.chat_widget.apply_file_search_result(query, matches);
}
AppEvent::TaskSearchResult {
thread_id,
query,
matches,
} => {
if self.active_thread_id == Some(thread_id)
&& app_server.task_tools_available(thread_id)
{
self.chat_widget.on_task_search_result(&query, matches);
}
}
AppEvent::RefreshRateLimits { origin } => {
self.refresh_rate_limits(app_server, origin);
}