use ratatui::style::Style;
use ratatui::text::{Line, Span};
use crate::palette;
use super::{
GenericToolCell, render_tool_header_with_family_and_summary, tool_status_label, truncate_text,
};
pub(super) fn render_agent_compact(cell: &GenericToolCell, low_motion: bool) -> Vec<Line<'static>> {
let family = crate::tui::widgets::tool_card::ToolFamily::Delegate;
let agent_id = cell
.output
.as_deref()
.and_then(extract_agent_id)
.map(str::to_string)
.unwrap_or_else(|| delegate_identity_fallback(cell));
let state_label = match agent_inspection_action(cell) {
Some(AgentCompactAction::Check) => match cell.status {
super::ToolStatus::Running => "checking",
_ => "checked",
},
Some(AgentCompactAction::Wait) => match cell.status {
super::ToolStatus::Running => "waiting",
_ => "waited",
},
None => tool_status_label(cell.status),
};
vec![render_tool_header_with_family_and_summary(
family,
Some(agent_id.as_str()),
state_label,
cell.status,
None,
low_motion,
)]
}
enum AgentCompactAction {
Check,
Wait,
}
pub(super) fn is_agent_inspection(cell: &GenericToolCell) -> bool {
agent_inspection_action(cell).is_some()
}
fn agent_inspection_action(cell: &GenericToolCell) -> Option<AgentCompactAction> {
let summary = cell.input_summary.as_deref()?;
let action = summary.strip_prefix("action:")?.trim_start();
let action = action.split_whitespace().next().unwrap_or("");
match action.trim_end_matches(',') {
"peek" | "progress" | "status" | "list" | "inspect" => Some(AgentCompactAction::Check),
"wait" | "join" | "await" | "block" => Some(AgentCompactAction::Wait),
_ => None,
}
}
pub(super) fn render_activity_group(cell: &GenericToolCell, width: u16) -> Vec<Line<'static>> {
let summary = cell.input_summary.as_deref().unwrap_or("Updated metadata");
let budget = usize::from(width).max(1);
vec![Line::from(Span::styled(
truncate_text(summary, budget),
Style::default().fg(palette::TEXT_MUTED),
))]
}
fn delegate_identity_fallback(cell: &GenericToolCell) -> String {
if let Some(summary) = cell.input_summary.as_deref() {
let summary = summary.trim();
if let Some(rest) = summary.strip_prefix("role:") {
let role = rest.split_whitespace().next().unwrap_or(rest).trim();
if !role.is_empty() {
return role.to_string();
}
}
if let Some(rest) = summary.strip_prefix("prompt:") {
let title = rest.trim();
if !title.is_empty() {
let slug: String = title
.chars()
.take(24)
.map(|ch| {
if ch.is_ascii_alphanumeric() {
ch.to_ascii_lowercase()
} else {
'-'
}
})
.collect();
let slug = slug.trim_matches('-');
if !slug.is_empty() {
return slug.to_string();
}
}
}
}
"subagent".to_string()
}
pub(super) fn extract_agent_id(output: &str) -> Option<&str> {
let key = "\"agent_id\"";
let key_idx = output.find(key)?;
let rest = &output[key_idx + key.len()..];
let colon = rest.find(':')?;
let after_colon = rest[colon + 1..].trim_start();
let after_colon = after_colon.strip_prefix('"')?;
let end = after_colon.find('"')?;
let id = &after_colon[..end];
(!id.is_empty()).then_some(id)
}