feat: cleaner TUI for sub-agents (#12327)

<img width="760" height="496" alt="Screenshot 2026-02-20 at 14 31 25"
src="https://github.com/user-attachments/assets/1983b825-bb47-417e-9925-6f727af56765"
/>
This commit is contained in:
jif-oai
2026-02-20 15:26:33 +00:00
committed by GitHub
parent 2036a5f5e0
commit 4d60c803ba
26 changed files with 1735 additions and 176 deletions

View File

@@ -2747,6 +2747,32 @@ pub struct CollabAgentSpawnBeginEvent {
pub prompt: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
pub struct CollabAgentRef {
/// Thread ID of the receiver/new agent.
pub thread_id: ThreadId,
/// Optional nickname assigned to an AgentControl-spawned sub-agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub agent_nickname: Option<String>,
/// Optional role (agent_role) assigned to an AgentControl-spawned sub-agent.
#[serde(default, alias = "agent_type", skip_serializing_if = "Option::is_none")]
pub agent_role: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
pub struct CollabAgentStatusEntry {
/// Thread ID of the receiver/new agent.
pub thread_id: ThreadId,
/// Optional nickname assigned to an AgentControl-spawned sub-agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub agent_nickname: Option<String>,
/// Optional role (agent_role) assigned to an AgentControl-spawned sub-agent.
#[serde(default, alias = "agent_type", skip_serializing_if = "Option::is_none")]
pub agent_role: Option<String>,
/// Last known status of the agent.
pub status: AgentStatus,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabAgentSpawnEndEvent {
/// Identifier for the collab tool call.
@@ -2755,6 +2781,12 @@ pub struct CollabAgentSpawnEndEvent {
pub sender_thread_id: ThreadId,
/// Thread ID of the newly spawned agent, if it was created.
pub new_thread_id: Option<ThreadId>,
/// Optional nickname assigned to the new agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub new_agent_nickname: Option<String>,
/// Optional role assigned to the new agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub new_agent_role: Option<String>,
/// Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the
/// beginning.
pub prompt: String,
@@ -2783,6 +2815,12 @@ pub struct CollabAgentInteractionEndEvent {
pub sender_thread_id: ThreadId,
/// Thread ID of the receiver.
pub receiver_thread_id: ThreadId,
/// Optional nickname assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_nickname: Option<String>,
/// Optional role assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_role: Option<String>,
/// Prompt sent from the sender to the receiver. Can be empty to prevent CoT
/// leaking at the beginning.
pub prompt: String,
@@ -2796,6 +2834,9 @@ pub struct CollabWaitingBeginEvent {
pub sender_thread_id: ThreadId,
/// Thread ID of the receivers.
pub receiver_thread_ids: Vec<ThreadId>,
/// Optional nicknames/roles for receivers.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub receiver_agents: Vec<CollabAgentRef>,
/// ID of the waiting call.
pub call_id: String,
}
@@ -2806,6 +2847,9 @@ pub struct CollabWaitingEndEvent {
pub sender_thread_id: ThreadId,
/// ID of the waiting call.
pub call_id: String,
/// Optional receiver metadata paired with final statuses.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub agent_statuses: Vec<CollabAgentStatusEntry>,
/// Last known status of the receiver agents reported to the sender agent.
pub statuses: HashMap<ThreadId, AgentStatus>,
}
@@ -2828,6 +2872,12 @@ pub struct CollabCloseEndEvent {
pub sender_thread_id: ThreadId,
/// Thread ID of the receiver.
pub receiver_thread_id: ThreadId,
/// Optional nickname assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_nickname: Option<String>,
/// Optional role assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_role: Option<String>,
/// Last known status of the receiver agent reported to the sender agent before
/// the close.
pub status: AgentStatus,
@@ -2841,6 +2891,12 @@ pub struct CollabResumeBeginEvent {
pub sender_thread_id: ThreadId,
/// Thread ID of the receiver.
pub receiver_thread_id: ThreadId,
/// Optional nickname assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_nickname: Option<String>,
/// Optional role assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_role: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
@@ -2851,6 +2907,12 @@ pub struct CollabResumeEndEvent {
pub sender_thread_id: ThreadId,
/// Thread ID of the receiver.
pub receiver_thread_id: ThreadId,
/// Optional nickname assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_nickname: Option<String>,
/// Optional role assigned to the receiver agent.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub receiver_agent_role: Option<String>,
/// Last known status of the receiver agent reported to the sender agent after
/// resume.
pub status: AgentStatus,