Add subagent prompts and implement company workflow orchestration
- Introduced prompts for various subagent roles: architecture reviewer, code quality reviewer, documentation maintainer, implementation team, testing team, and security reviewer. - Implemented the auto-subagent orchestration in `auto.rs` to manage inline and background reviews. - Created a division structure in `division.rs` to define roles and responsibilities for each subagent. - Developed a company workflow orchestrator in `company.rs` to run the complete division pipeline, consolidating findings and generating executive summaries. - Added logic to determine whether to run a full or quick pipeline based on request complexity.
This commit is contained in:
+88
-28
@@ -4,9 +4,8 @@
|
||||
//! rich panel showing agent statuses, findings count, session counters,
|
||||
//! and usage hints.
|
||||
//!
|
||||
//! Why: the panel is useful even without a running session (shows engine
|
||||
//! state and instructions), and only shows non-zero counters to keep it
|
||||
//! compact.
|
||||
//! Division-aware: when the workflow is a company pipeline, shows the
|
||||
//! division pipeline header with visual arrows between stages.
|
||||
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::{Style, Modifier};
|
||||
@@ -16,21 +15,45 @@ use ratatui::Frame;
|
||||
use super::theme::Theme;
|
||||
use crate::app::workflow::engine::AgentState;
|
||||
|
||||
/// Icons for division states in the company pipeline.
|
||||
fn div_icon(state: AgentState) -> &'static str {
|
||||
match state {
|
||||
AgentState::Idle => "○",
|
||||
AgentState::Running => "▶",
|
||||
AgentState::Completed => "✓",
|
||||
AgentState::Failed => "✗",
|
||||
}
|
||||
}
|
||||
|
||||
/// Detect if the current workflow looks like a company pipeline by
|
||||
/// checking agent names for division keywords.
|
||||
fn is_company_pipeline(agents: &[crate::app::workflow::engine::WorkflowAgent]) -> bool {
|
||||
if agents.is_empty() {
|
||||
return false;
|
||||
}
|
||||
// Company pipeline agents have names like "Strategy", "Engineering", etc.
|
||||
let division_keywords = ["Strategy", "Engineering", "Quality", "Security", "Documentation"];
|
||||
agents.iter().any(|a| {
|
||||
division_keywords.iter().any(|k| a.name.contains(k))
|
||||
})
|
||||
}
|
||||
|
||||
/// Render the workflow status panel.
|
||||
///
|
||||
/// Flow: build header lines (title + usage hints) → if agents exist,
|
||||
/// list each with its lifecycle state colour-coded → show findings
|
||||
/// count and session counters → fall back to an instruction paragraph
|
||||
/// when no agents have been spawned yet.
|
||||
///
|
||||
/// Return: nothing; draws directly into `frame` at `area`.
|
||||
pub fn draw_workflow_panel(frame: &mut Frame, area: Rect, state: &crate::app::state::rest::AppStateRest) {
|
||||
use ratatui::layout::{Constraint, Direction, Layout};
|
||||
|
||||
let is_company = is_company_pipeline(&state.workflow_engine.agents);
|
||||
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::default().fg(Theme::PRIMARY))
|
||||
.title(Span::styled(" ⚙ Workflow ", Style::default().fg(Theme::PRIMARY).add_modifier(Modifier::BOLD)));
|
||||
.title({
|
||||
if is_company {
|
||||
Span::styled(" 🏢 Company Pipeline ", Style::default().fg(Theme::PRIMARY).add_modifier(Modifier::BOLD))
|
||||
} else {
|
||||
Span::styled(" ⚙ Workflow ", Style::default().fg(Theme::PRIMARY).add_modifier(Modifier::BOLD))
|
||||
}
|
||||
});
|
||||
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
@@ -44,14 +67,53 @@ pub fn draw_workflow_panel(frame: &mut Frame, area: Rect, state: &crate::app::st
|
||||
])
|
||||
.split(inner);
|
||||
|
||||
// ── Header: usage hints ─────────────────────────────────────────────────
|
||||
let hint_lines = vec![
|
||||
Line::from(vec![
|
||||
// ── Header ─────────────────────────────────────────────────────────
|
||||
let mut header_lines = vec![];
|
||||
|
||||
if is_company {
|
||||
// Show the division pipeline header with visual arrows
|
||||
let agents = &state.workflow_engine.agents;
|
||||
let mut pipeline_spans: Vec<Span> = Vec::new();
|
||||
for (i, agent) in agents.iter().enumerate() {
|
||||
if i > 0 {
|
||||
pipeline_spans.push(Span::styled(" → ", Style::default().fg(Theme::DIM)));
|
||||
}
|
||||
let icon = div_icon(agent.status.state);
|
||||
let (color, modif) = match agent.status.state {
|
||||
AgentState::Idle => (Theme::DIM, Modifier::empty()),
|
||||
AgentState::Running => (Theme::WARNING, Modifier::BOLD),
|
||||
AgentState::Completed => (Theme::SUCCESS, Modifier::BOLD),
|
||||
AgentState::Failed => (Theme::ERROR, Modifier::BOLD),
|
||||
};
|
||||
pipeline_spans.push(Span::styled(
|
||||
format!("{} {} ", icon, agent.name.chars().take(12).collect::<String>()),
|
||||
Style::default().fg(color).add_modifier(modif),
|
||||
));
|
||||
}
|
||||
header_lines.push(Line::from(pipeline_spans));
|
||||
header_lines.push(Line::from(vec![
|
||||
Span::styled("Status: ", Style::default().fg(Theme::DIM)),
|
||||
if state.turn_in_flight() {
|
||||
Span::styled("● Pipeline Running", Style::default().fg(Theme::WARNING).add_modifier(Modifier::BOLD))
|
||||
} else {
|
||||
Span::styled("● Pipeline Complete", Style::default().fg(Theme::SUCCESS))
|
||||
},
|
||||
Span::raw(" "),
|
||||
Span::styled(
|
||||
format!("Divisions: {} Findings: {}",
|
||||
state.workflow_engine.agents.len(),
|
||||
state.workflow_engine.findings.len(),
|
||||
),
|
||||
Style::default().fg(Theme::DIM),
|
||||
),
|
||||
]));
|
||||
} else {
|
||||
header_lines.push(Line::from(vec![
|
||||
Span::styled("/workflow run ", Style::default().fg(Theme::PRIMARY).add_modifier(Modifier::BOLD)),
|
||||
Span::styled("<prompt>", Style::default().fg(Theme::DIM)),
|
||||
Span::styled(" · Esc to close", Style::default().fg(Theme::DIM)),
|
||||
]),
|
||||
Line::from(vec![
|
||||
]));
|
||||
header_lines.push(Line::from(vec![
|
||||
Span::styled("Status: ", Style::default().fg(Theme::DIM)),
|
||||
if state.turn_in_flight() {
|
||||
Span::styled("● Running", Style::default().fg(Theme::WARNING).add_modifier(Modifier::BOLD))
|
||||
@@ -66,25 +128,23 @@ pub fn draw_workflow_panel(frame: &mut Frame, area: Rect, state: &crate::app::st
|
||||
),
|
||||
Style::default().fg(Theme::DIM),
|
||||
),
|
||||
]),
|
||||
];
|
||||
let header = Paragraph::new(hint_lines);
|
||||
]));
|
||||
}
|
||||
let header = Paragraph::new(header_lines);
|
||||
frame.render_widget(header, chunks[0]);
|
||||
|
||||
// ── Body: agent list or placeholder ─────────────────────────────────────
|
||||
// ── Body: agent/division list ──────────────────────────────────────
|
||||
if state.workflow_engine.agents.is_empty() {
|
||||
// No agents yet — show session counters and a welcome message
|
||||
let session_lines = build_session_lines(state);
|
||||
let placeholder = Paragraph::new(session_lines).wrap(Wrap { trim: false });
|
||||
frame.render_widget(placeholder, chunks[1]);
|
||||
} else {
|
||||
// Build agent status list
|
||||
let items: Vec<ListItem> = state.workflow_engine.agents.iter().map(|agent| {
|
||||
let (state_str, state_color) = match agent.status.state {
|
||||
AgentState::Idle => ("Idle", Theme::DIM),
|
||||
AgentState::Running => ("Running…", Theme::WARNING),
|
||||
AgentState::Completed => ("Done ✓", Theme::SUCCESS),
|
||||
AgentState::Failed => ("Failed ✗", Theme::ERROR),
|
||||
AgentState::Idle => ("○ Idle", Theme::DIM),
|
||||
AgentState::Running => ("▶ Running…", Theme::WARNING),
|
||||
AgentState::Completed => ("✓ Done", Theme::SUCCESS),
|
||||
AgentState::Failed => ("✗ Failed", Theme::ERROR),
|
||||
};
|
||||
let duration_str = match (agent.status.started_at, agent.status.completed_at) {
|
||||
(Some(s), Some(e)) => format!(" {}ms", e.saturating_sub(s)),
|
||||
@@ -93,7 +153,7 @@ pub fn draw_workflow_panel(frame: &mut Frame, area: Rect, state: &crate::app::st
|
||||
};
|
||||
ListItem::new(Line::from(vec![
|
||||
Span::styled(
|
||||
format!(" {:8} ", state_str),
|
||||
format!(" {:12} ", state_str),
|
||||
Style::default().fg(state_color).add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
@@ -159,7 +219,7 @@ fn build_session_lines(state: &crate::app::state::rest::AppStateRest) -> Vec<Lin
|
||||
|
||||
lines.push(Line::from(Span::raw("")));
|
||||
lines.push(Line::from(Span::styled(
|
||||
" Run a workflow to see agents here.",
|
||||
" Complex tasks auto-delegate to the company pipeline.",
|
||||
Style::default().fg(Theme::DIM).add_modifier(Modifier::ITALIC),
|
||||
)));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user