daemon: add distill agent to consolidation plan
Add distill_count to ConsolidationPlan, daemon health metrics, and TUI display. Distill agent now participates in the consolidation budget alongside replay, linker, separator, transfer, organize, and connector. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f555fa3c8e
commit
e049d4437f
3 changed files with 40 additions and 13 deletions
|
|
@ -480,6 +480,7 @@ fn compute_graph_health(store: &crate::store::Store) -> GraphHealth {
|
||||||
plan_transfer: plan.transfer_count,
|
plan_transfer: plan.transfer_count,
|
||||||
plan_organize: plan.organize_count,
|
plan_organize: plan.organize_count,
|
||||||
plan_connector: plan.connector_count,
|
plan_connector: plan.connector_count,
|
||||||
|
plan_distill: plan.distill_count,
|
||||||
plan_rationale: plan.rationale,
|
plan_rationale: plan.rationale,
|
||||||
computed_at: crate::store::format_datetime_space(crate::store::now_epoch()),
|
computed_at: crate::store::format_datetime_space(crate::store::now_epoch()),
|
||||||
}
|
}
|
||||||
|
|
@ -607,6 +608,8 @@ pub struct GraphHealth {
|
||||||
pub plan_transfer: usize,
|
pub plan_transfer: usize,
|
||||||
pub plan_organize: usize,
|
pub plan_organize: usize,
|
||||||
pub plan_connector: usize,
|
pub plan_connector: usize,
|
||||||
|
#[serde(default)]
|
||||||
|
pub plan_distill: usize,
|
||||||
pub plan_rationale: Vec<String>,
|
pub plan_rationale: Vec<String>,
|
||||||
pub computed_at: String,
|
pub computed_at: String,
|
||||||
}
|
}
|
||||||
|
|
@ -995,15 +998,16 @@ pub fn run_daemon() -> Result<(), String> {
|
||||||
transfer_count: h.plan_transfer,
|
transfer_count: h.plan_transfer,
|
||||||
organize_count: h.plan_organize,
|
organize_count: h.plan_organize,
|
||||||
connector_count: h.plan_connector,
|
connector_count: h.plan_connector,
|
||||||
|
distill_count: h.plan_distill,
|
||||||
run_health: true,
|
run_health: true,
|
||||||
rationale: Vec::new(),
|
rationale: Vec::new(),
|
||||||
};
|
};
|
||||||
let runs = plan.to_agent_runs(5);
|
let runs = plan.to_agent_runs(5);
|
||||||
|
|
||||||
log_event("scheduler", "consolidation-plan",
|
log_event("scheduler", "consolidation-plan",
|
||||||
&format!("{} agents ({}r {}l {}s {}t)",
|
&format!("{} agents ({}r {}l {}s {}t {}d)",
|
||||||
runs.len(), h.plan_replay, h.plan_linker,
|
runs.len(), h.plan_replay, h.plan_linker,
|
||||||
h.plan_separator, h.plan_transfer));
|
h.plan_separator, h.plan_transfer, h.plan_distill));
|
||||||
|
|
||||||
// Phase 1: Agent runs — sequential within type, parallel across types.
|
// Phase 1: Agent runs — sequential within type, parallel across types.
|
||||||
// Same-type agents chain (they may touch overlapping graph regions),
|
// Same-type agents chain (they may touch overlapping graph regions),
|
||||||
|
|
@ -1400,9 +1404,9 @@ pub fn show_status() -> Result<(), String> {
|
||||||
indicator(gh.episodic_ratio, 0.4, false), gh.episodic_ratio * 100.0,
|
indicator(gh.episodic_ratio, 0.4, false), gh.episodic_ratio * 100.0,
|
||||||
gh.sigma);
|
gh.sigma);
|
||||||
|
|
||||||
let total = gh.plan_replay + gh.plan_linker + gh.plan_separator + gh.plan_transfer + 1;
|
let total = gh.plan_replay + gh.plan_linker + gh.plan_separator + gh.plan_transfer + gh.plan_distill + 1;
|
||||||
eprintln!(" consolidation plan: {} agents ({}r {}l {}s {}t +health)",
|
eprintln!(" consolidation plan: {} agents ({}r {}l {}s {}t {}d +health)",
|
||||||
total, gh.plan_replay, gh.plan_linker, gh.plan_separator, gh.plan_transfer);
|
total, gh.plan_replay, gh.plan_linker, gh.plan_separator, gh.plan_transfer, gh.plan_distill);
|
||||||
}
|
}
|
||||||
eprintln!();
|
eprintln!();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,7 @@ pub struct ConsolidationPlan {
|
||||||
pub transfer_count: usize,
|
pub transfer_count: usize,
|
||||||
pub organize_count: usize,
|
pub organize_count: usize,
|
||||||
pub connector_count: usize,
|
pub connector_count: usize,
|
||||||
|
pub distill_count: usize,
|
||||||
pub run_health: bool,
|
pub run_health: bool,
|
||||||
pub rationale: Vec<String>,
|
pub rationale: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -185,9 +186,10 @@ impl ConsolidationPlan {
|
||||||
}
|
}
|
||||||
// Build per-type batch lists, then interleave so different agent
|
// Build per-type batch lists, then interleave so different agent
|
||||||
// types alternate rather than running all-replay-then-all-linker.
|
// types alternate rather than running all-replay-then-all-linker.
|
||||||
let types: [(&str, usize); 6] = [
|
let types: [(&str, usize); 7] = [
|
||||||
("linker", self.linker_count),
|
("linker", self.linker_count),
|
||||||
("organize", self.organize_count),
|
("organize", self.organize_count),
|
||||||
|
("distill", self.distill_count),
|
||||||
("replay", self.replay_count),
|
("replay", self.replay_count),
|
||||||
("connector", self.connector_count),
|
("connector", self.connector_count),
|
||||||
("separator", self.separator_count),
|
("separator", self.separator_count),
|
||||||
|
|
@ -257,6 +259,7 @@ fn consolidation_plan_inner(store: &Store, detect_interf: bool) -> Consolidation
|
||||||
transfer_count: 0,
|
transfer_count: 0,
|
||||||
organize_count: 0,
|
organize_count: 0,
|
||||||
connector_count: 0,
|
connector_count: 0,
|
||||||
|
distill_count: 0,
|
||||||
run_health: true,
|
run_health: true,
|
||||||
rationale: Vec::new(),
|
rationale: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
@ -341,6 +344,18 @@ fn consolidation_plan_inner(store: &Store, detect_interf: bool) -> Consolidation
|
||||||
plan.rationale.push(format!(
|
plan.rationale.push(format!(
|
||||||
"Organize: {} (half of linker count)", plan.organize_count));
|
"Organize: {} (half of linker count)", plan.organize_count));
|
||||||
|
|
||||||
|
// Distill: core concept maintenance — at least as much as organize
|
||||||
|
// High gini means hubs need refinement; low alpha means hubs are overloaded
|
||||||
|
plan.distill_count = plan.organize_count;
|
||||||
|
if gini > 0.4 {
|
||||||
|
plan.distill_count += 20;
|
||||||
|
}
|
||||||
|
if alpha < 2.0 {
|
||||||
|
plan.distill_count += 20;
|
||||||
|
}
|
||||||
|
plan.rationale.push(format!(
|
||||||
|
"Distill: {} (synthesize hub content)", plan.distill_count));
|
||||||
|
|
||||||
// Connector: bridges fragmented communities
|
// Connector: bridges fragmented communities
|
||||||
let community_count = graph.community_count();
|
let community_count = graph.community_count();
|
||||||
let nodes_per_community = if community_count > 0 {
|
let nodes_per_community = if community_count > 0 {
|
||||||
|
|
@ -365,7 +380,7 @@ fn consolidation_plan_inner(store: &Store, detect_interf: bool) -> Consolidation
|
||||||
if let Ok(ratings) = serde_json::from_str::<std::collections::HashMap<String, f64>>(&elo_json) {
|
if let Ok(ratings) = serde_json::from_str::<std::collections::HashMap<String, f64>>(&elo_json) {
|
||||||
let types = [
|
let types = [
|
||||||
"replay", "linker", "separator", "transfer",
|
"replay", "linker", "separator", "transfer",
|
||||||
"organize", "connector",
|
"organize", "connector", "distill",
|
||||||
];
|
];
|
||||||
let elos: Vec<f64> = types.iter()
|
let elos: Vec<f64> = types.iter()
|
||||||
.map(|t| ratings.get(*t).copied().unwrap_or(1000.0))
|
.map(|t| ratings.get(*t).copied().unwrap_or(1000.0))
|
||||||
|
|
@ -392,22 +407,24 @@ fn consolidation_plan_inner(store: &Store, detect_interf: bool) -> Consolidation
|
||||||
plan.transfer_count = allocate(weights[3]);
|
plan.transfer_count = allocate(weights[3]);
|
||||||
plan.organize_count = allocate(weights[4]);
|
plan.organize_count = allocate(weights[4]);
|
||||||
plan.connector_count = allocate(weights[5]);
|
plan.connector_count = allocate(weights[5]);
|
||||||
|
plan.distill_count = allocate(weights[6]);
|
||||||
|
|
||||||
plan.rationale.push(format!(
|
plan.rationale.push(format!(
|
||||||
"Elo allocation (budget={}): replay={} linker={} separator={} transfer={} organize={} connector={}",
|
"Elo allocation (budget={}): replay={} linker={} separator={} transfer={} organize={} connector={} distill={}",
|
||||||
budget,
|
budget,
|
||||||
plan.replay_count, plan.linker_count, plan.separator_count,
|
plan.replay_count, plan.linker_count, plan.separator_count,
|
||||||
plan.transfer_count, plan.organize_count, plan.connector_count));
|
plan.transfer_count, plan.organize_count, plan.connector_count, plan.distill_count));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No Elo file — use budget with equal distribution
|
// No Elo file — use budget with equal distribution
|
||||||
let per_type = budget / 6;
|
let per_type = budget / 7;
|
||||||
plan.replay_count = per_type;
|
plan.replay_count = per_type;
|
||||||
plan.linker_count = per_type;
|
plan.linker_count = per_type;
|
||||||
plan.separator_count = per_type;
|
plan.separator_count = per_type;
|
||||||
plan.transfer_count = per_type;
|
plan.transfer_count = per_type;
|
||||||
plan.organize_count = per_type;
|
plan.organize_count = per_type;
|
||||||
plan.connector_count = per_type;
|
plan.connector_count = per_type;
|
||||||
|
plan.distill_count = per_type;
|
||||||
plan.rationale.push(format!(
|
plan.rationale.push(format!(
|
||||||
"No Elo ratings — equal distribution ({} each, budget={})", per_type, budget));
|
"No Elo ratings — equal distribution ({} each, budget={})", per_type, budget));
|
||||||
}
|
}
|
||||||
|
|
@ -457,11 +474,17 @@ pub fn format_plan(plan: &ConsolidationPlan) -> String {
|
||||||
if plan.connector_count > 0 {
|
if plan.connector_count > 0 {
|
||||||
out.push_str(&format!(" {}. connector ×{} — cross-cluster bridging\n",
|
out.push_str(&format!(" {}. connector ×{} — cross-cluster bridging\n",
|
||||||
step, plan.connector_count));
|
step, plan.connector_count));
|
||||||
|
step += 1;
|
||||||
|
}
|
||||||
|
if plan.distill_count > 0 {
|
||||||
|
out.push_str(&format!(" {}. distill ×{:2} — hub content synthesis + refinement\n",
|
||||||
|
step, plan.distill_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
let total = plan.replay_count + plan.linker_count
|
let total = plan.replay_count + plan.linker_count
|
||||||
+ plan.separator_count + plan.transfer_count
|
+ plan.separator_count + plan.transfer_count
|
||||||
+ plan.organize_count + plan.connector_count
|
+ plan.organize_count + plan.connector_count
|
||||||
|
+ plan.distill_count
|
||||||
+ if plan.run_health { 1 } else { 0 };
|
+ if plan.run_health { 1 } else { 0 };
|
||||||
out.push_str(&format!("\nTotal agent runs: {}\n", total));
|
out.push_str(&format!("\nTotal agent runs: {}\n", total));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -539,7 +539,7 @@ fn render_health(frame: &mut Frame, gh: &GraphHealth, area: Rect) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Plan
|
// Plan
|
||||||
let total = gh.plan_replay + gh.plan_linker + gh.plan_separator + gh.plan_transfer + 1;
|
let total = gh.plan_replay + gh.plan_linker + gh.plan_separator + gh.plan_transfer + gh.plan_distill + 1;
|
||||||
let plan_line = Line::from(vec![
|
let plan_line = Line::from(vec![
|
||||||
Span::raw(" plan: "),
|
Span::raw(" plan: "),
|
||||||
Span::styled(
|
Span::styled(
|
||||||
|
|
@ -547,8 +547,8 @@ fn render_health(frame: &mut Frame, gh: &GraphHealth, area: Rect) {
|
||||||
Style::default().add_modifier(Modifier::BOLD),
|
Style::default().add_modifier(Modifier::BOLD),
|
||||||
),
|
),
|
||||||
Span::raw(format!(
|
Span::raw(format!(
|
||||||
" agents ({}r {}l {}s {}t +health)",
|
" agents ({}r {}l {}s {}t {}d +health)",
|
||||||
gh.plan_replay, gh.plan_linker, gh.plan_separator, gh.plan_transfer
|
gh.plan_replay, gh.plan_linker, gh.plan_separator, gh.plan_transfer, gh.plan_distill
|
||||||
)),
|
)),
|
||||||
]);
|
]);
|
||||||
frame.render_widget(Paragraph::new(plan_line), plan_area);
|
frame.render_widget(Paragraph::new(plan_line), plan_area);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue