mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-08 18:33:28 +08:00
feat: preview ecc2 routing decisions
This commit is contained in:
@@ -41,6 +41,7 @@ pub struct Dashboard {
|
|||||||
selected_parent_session: Option<String>,
|
selected_parent_session: Option<String>,
|
||||||
selected_child_sessions: Vec<DelegatedChildSummary>,
|
selected_child_sessions: Vec<DelegatedChildSummary>,
|
||||||
selected_team_summary: Option<TeamSummary>,
|
selected_team_summary: Option<TeamSummary>,
|
||||||
|
selected_route_preview: Option<String>,
|
||||||
logs: Vec<ToolLogEntry>,
|
logs: Vec<ToolLogEntry>,
|
||||||
selected_diff_summary: Option<String>,
|
selected_diff_summary: Option<String>,
|
||||||
selected_pane: Pane,
|
selected_pane: Pane,
|
||||||
@@ -140,6 +141,7 @@ impl Dashboard {
|
|||||||
selected_parent_session: None,
|
selected_parent_session: None,
|
||||||
selected_child_sessions: Vec::new(),
|
selected_child_sessions: Vec::new(),
|
||||||
selected_team_summary: None,
|
selected_team_summary: None,
|
||||||
|
selected_route_preview: None,
|
||||||
logs: Vec::new(),
|
logs: Vec::new(),
|
||||||
selected_diff_summary: None,
|
selected_diff_summary: None,
|
||||||
selected_pane: Pane::Sessions,
|
selected_pane: Pane::Sessions,
|
||||||
@@ -995,6 +997,7 @@ impl Dashboard {
|
|||||||
self.selected_parent_session = None;
|
self.selected_parent_session = None;
|
||||||
self.selected_child_sessions.clear();
|
self.selected_child_sessions.clear();
|
||||||
self.selected_team_summary = None;
|
self.selected_team_summary = None;
|
||||||
|
self.selected_route_preview = None;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1010,12 +1013,19 @@ impl Dashboard {
|
|||||||
Ok(children) => {
|
Ok(children) => {
|
||||||
let mut delegated = Vec::new();
|
let mut delegated = Vec::new();
|
||||||
let mut team = TeamSummary::default();
|
let mut team = TeamSummary::default();
|
||||||
|
let mut route_candidates = Vec::new();
|
||||||
|
|
||||||
for child_id in children {
|
for child_id in children {
|
||||||
match self.db.get_session(&child_id) {
|
match self.db.get_session(&child_id) {
|
||||||
Ok(Some(session)) => {
|
Ok(Some(session)) => {
|
||||||
team.total += 1;
|
team.total += 1;
|
||||||
match session.state {
|
let unread_messages = self
|
||||||
|
.unread_message_counts
|
||||||
|
.get(&child_id)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(0);
|
||||||
|
let state = session.state.clone();
|
||||||
|
match state {
|
||||||
SessionState::Idle => team.idle += 1,
|
SessionState::Idle => team.idle += 1,
|
||||||
SessionState::Running => team.running += 1,
|
SessionState::Running => team.running += 1,
|
||||||
SessionState::Pending => team.pending += 1,
|
SessionState::Pending => team.pending += 1,
|
||||||
@@ -1024,13 +1034,14 @@ impl Dashboard {
|
|||||||
SessionState::Completed => {}
|
SessionState::Completed => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
route_candidates.push(DelegatedChildSummary {
|
||||||
|
unread_messages,
|
||||||
|
state: state.clone(),
|
||||||
|
session_id: child_id.clone(),
|
||||||
|
});
|
||||||
delegated.push(DelegatedChildSummary {
|
delegated.push(DelegatedChildSummary {
|
||||||
unread_messages: self
|
unread_messages,
|
||||||
.unread_message_counts
|
state,
|
||||||
.get(&child_id)
|
|
||||||
.copied()
|
|
||||||
.unwrap_or(0),
|
|
||||||
state: session.state,
|
|
||||||
session_id: child_id,
|
session_id: child_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1045,17 +1056,71 @@ impl Dashboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.selected_team_summary = if team.total > 0 { Some(team) } else { None };
|
self.selected_team_summary = if team.total > 0 { Some(team) } else { None };
|
||||||
|
self.selected_route_preview =
|
||||||
|
self.build_route_preview(team.total, &route_candidates);
|
||||||
delegated.truncate(3);
|
delegated.truncate(3);
|
||||||
delegated
|
delegated
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::warn!("Failed to load delegated child sessions: {error}");
|
tracing::warn!("Failed to load delegated child sessions: {error}");
|
||||||
self.selected_team_summary = None;
|
self.selected_team_summary = None;
|
||||||
|
self.selected_route_preview = None;
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_route_preview(
|
||||||
|
&self,
|
||||||
|
delegate_count: usize,
|
||||||
|
delegates: &[DelegatedChildSummary],
|
||||||
|
) -> Option<String> {
|
||||||
|
if let Some(idle_clear) = delegates
|
||||||
|
.iter()
|
||||||
|
.filter(|delegate| delegate.state == SessionState::Idle && delegate.unread_messages == 0)
|
||||||
|
.min_by_key(|delegate| delegate.session_id.as_str())
|
||||||
|
{
|
||||||
|
return Some(format!(
|
||||||
|
"reuse idle {}",
|
||||||
|
format_session_id(&idle_clear.session_id)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if delegate_count < self.cfg.max_parallel_sessions {
|
||||||
|
return Some("spawn new delegate".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(idle_backed_up) = delegates
|
||||||
|
.iter()
|
||||||
|
.filter(|delegate| delegate.state == SessionState::Idle)
|
||||||
|
.min_by_key(|delegate| (delegate.unread_messages, delegate.session_id.as_str()))
|
||||||
|
{
|
||||||
|
return Some(format!(
|
||||||
|
"reuse idle {} with inbox {}",
|
||||||
|
format_session_id(&idle_backed_up.session_id),
|
||||||
|
idle_backed_up.unread_messages
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(active_delegate) = delegates
|
||||||
|
.iter()
|
||||||
|
.filter(|delegate| matches!(delegate.state, SessionState::Running | SessionState::Pending))
|
||||||
|
.min_by_key(|delegate| (delegate.unread_messages, delegate.session_id.as_str()))
|
||||||
|
{
|
||||||
|
return Some(format!(
|
||||||
|
"reuse active {} with inbox {}",
|
||||||
|
format_session_id(&active_delegate.session_id),
|
||||||
|
active_delegate.unread_messages
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if delegate_count == 0 {
|
||||||
|
Some("spawn new delegate".to_string())
|
||||||
|
} else {
|
||||||
|
Some("spawn fallback delegate".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn selected_session_id(&self) -> Option<&str> {
|
fn selected_session_id(&self) -> Option<&str> {
|
||||||
self.sessions
|
self.sessions
|
||||||
.get(self.selected_session)
|
.get(self.selected_session)
|
||||||
@@ -1165,6 +1230,10 @@ impl Dashboard {
|
|||||||
if self.cfg.auto_dispatch_unread_handoffs { "on" } else { "off" }
|
if self.cfg.auto_dispatch_unread_handoffs { "on" } else { "off" }
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if let Some(route_preview) = self.selected_route_preview.as_ref() {
|
||||||
|
lines.push(format!("Next route {route_preview}"));
|
||||||
|
}
|
||||||
|
|
||||||
if !self.selected_child_sessions.is_empty() {
|
if !self.selected_child_sessions.is_empty() {
|
||||||
lines.push("Delegates".to_string());
|
lines.push("Delegates".to_string());
|
||||||
for child in &self.selected_child_sessions {
|
for child in &self.selected_child_sessions {
|
||||||
@@ -1752,10 +1821,12 @@ mod tests {
|
|||||||
});
|
});
|
||||||
dashboard.global_handoff_backlog_leads = 2;
|
dashboard.global_handoff_backlog_leads = 2;
|
||||||
dashboard.global_handoff_backlog_messages = 5;
|
dashboard.global_handoff_backlog_messages = 5;
|
||||||
|
dashboard.selected_route_preview = Some("reuse idle worker-1".to_string());
|
||||||
|
|
||||||
let text = dashboard.selected_session_metrics_text();
|
let text = dashboard.selected_session_metrics_text();
|
||||||
assert!(text.contains("Team 3/8 | idle 1 | running 1 | pending 1 | failed 0 | stopped 0"));
|
assert!(text.contains("Team 3/8 | idle 1 | running 1 | pending 1 | failed 0 | stopped 0"));
|
||||||
assert!(text.contains("Global handoff backlog 2 lead(s) / 5 handoff(s) | Auto-dispatch off"));
|
assert!(text.contains("Global handoff backlog 2 lead(s) / 5 handoff(s) | Auto-dispatch off"));
|
||||||
|
assert!(text.contains("Next route reuse idle worker-1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2171,6 +2242,7 @@ mod tests {
|
|||||||
selected_parent_session: None,
|
selected_parent_session: None,
|
||||||
selected_child_sessions: Vec::new(),
|
selected_child_sessions: Vec::new(),
|
||||||
selected_team_summary: None,
|
selected_team_summary: None,
|
||||||
|
selected_route_preview: None,
|
||||||
logs: Vec::new(),
|
logs: Vec::new(),
|
||||||
selected_diff_summary: None,
|
selected_diff_summary: None,
|
||||||
selected_pane: Pane::Sessions,
|
selected_pane: Pane::Sessions,
|
||||||
|
|||||||
Reference in New Issue
Block a user