mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Add an agents overview dashboard to the TUI (#39094)
## What changed - Add `/agents` to open a full-screen dashboard of loaded root sessions from the shared app server, with subagent status reflected in each root session. - Support search, navigation, and grouping sessions by project or status. - Refresh the dashboard when relevant thread notifications arrive, while preserving its selection and view preferences. - Show a clear message when the dashboard is unavailable with the embedded app server. ## Testing - Add coverage for dashboard rendering, status grouping, persisted view state, and restoring the conversation viewport after closing the dashboard. - Cover `/agents` command discovery and dispatch from parent-owned threads. GitOrigin-RevId: 6651f4c47358116e1809da3ac8844a5842026a95
This commit is contained in:
1 parent
83d015375e
commit
4617d4d21d
19 files changed
+949
-4
No files matched your search
@@ -384,6 +384,7 @@ fn parent_owned_command_is_allowed(command: SlashCommand, args: &str) -> bool {
|
||||
| SlashCommand::App
|
||||
| SlashCommand::Side
|
||||
| SlashCommand::Btw
|
||||
| SlashCommand::Agents
|
||||
| SlashCommand::MultiAgents
|
||||
| SlashCommand::Vim
|
||||
| SlashCommand::Keymap
|
||||
@@ -4976,6 +4977,7 @@ mod tests {
|
||||
#[test]
|
||||
fn parent_owned_thread_allows_bare_navigation_commands() {
|
||||
for (command, expected) in [
|
||||
("/agents", SlashCommand::Agents),
|
||||
("/subagents", SlashCommand::MultiAgents),
|
||||
("/side", SlashCommand::Side),
|
||||
("/btw", SlashCommand::Btw),
|
||||
@@ -4996,13 +4998,13 @@ mod tests {
|
||||
fn parent_owned_thread_allows_safe_command_selected_from_prefix() {
|
||||
let (mut composer, _rx) = new_test_composer();
|
||||
composer.set_parent_owned_thread();
|
||||
type_chars_humanlike(&mut composer, &['/', 's', 'u', 'b']);
|
||||
type_chars_humanlike(&mut composer, &['/', 'a', 'g']);
|
||||
|
||||
let result = composer
|
||||
.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE))
|
||||
.0;
|
||||
|
||||
assert_eq!(result, InputResult::Command(SlashCommand::MultiAgents));
|
||||
assert_eq!(result, InputResult::Command(SlashCommand::Agents));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1222,6 +1222,21 @@ impl BottomPane {
|
||||
popup_consts::standard_popup_hint_line_for_keymap(&self.keymap.list)
|
||||
}
|
||||
|
||||
pub(crate) fn replace_view_if_present(
|
||||
&mut self,
|
||||
view_id: &'static str,
|
||||
view: Box<dyn BottomPaneView>,
|
||||
) {
|
||||
if let Some(index) = self
|
||||
.view_stack
|
||||
.iter()
|
||||
.rposition(|existing| existing.view_id() == Some(view_id))
|
||||
{
|
||||
self.view_stack[index] = view;
|
||||
self.request_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn list_keymap(&self) -> crate::keymap::ListKeymap {
|
||||
self.keymap.list.clone()
|
||||
}
|
||||
@@ -1383,7 +1398,7 @@ impl BottomPane {
|
||||
.lines()
|
||||
.next()
|
||||
.and_then(parse_slash_name)
|
||||
.is_some_and(|(name, _, _)| name == "subagents");
|
||||
.is_some_and(|(name, _, _)| matches!(name, "agents" | "subagents"));
|
||||
|
||||
self.keymap.chat.interrupt_turn.is_pressed(key_event)
|
||||
&& self.is_task_running
|
||||
|
||||
@@ -303,6 +303,7 @@ mod tests {
|
||||
commands,
|
||||
vec![
|
||||
SlashCommand::Ide,
|
||||
SlashCommand::Agents,
|
||||
SlashCommand::Copy,
|
||||
SlashCommand::Export,
|
||||
SlashCommand::Raw,
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ expression: commands
|
||||
/app - continue this session in the Desktop app
|
||||
/init - create an AGENTS.md file with instructions for Codex
|
||||
/compact - summarize conversation to prevent hitting the context limit
|
||||
/agents - view and switch between all active agent sessions
|
||||
/side - start a side conversation in an ephemeral fork
|
||||
/copy - copy last response as markdown
|
||||
/export - export the conversation as markdown
|
||||
|
||||
Reference in new issue
Block a user