feat(hive-mind): implement multi-agent orchestration with cognitive cycles

- Introduced a new hive-mind architecture that allows the Core Intelligence to issue directives to anonymous processing nodes.
- Each node executes its directive and merges output into a collective state, visible to all nodes in real-time.
- Added support for dynamic cognitive cycles, enabling flexible task management.
- Implemented documentation generation for hive-mind runs, ensuring a durable record of decisions and actions.
- Refactored existing company pipeline tools to align with the new hive-mind structure, replacing division-specific prompts with a more generalized approach.
- Updated workflow rendering to accommodate hive-mind nodes and their system-assigned designations.
- Enhanced error handling and validation for cognitive cycle plans.
This commit is contained in:
asepharyana
2026-07-14 08:12:43 +07:00
parent b1e0dcae14
commit 25f084f9db
23 changed files with 895 additions and 1225 deletions
+63 -79
View File
@@ -402,19 +402,21 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
});
state.dirty = true;
} else if kind == "bg-test-gen" {
let escalated = message.starts_with("ESCALATED:");
state.push_toast(Toast {
kind: ToastKind::Info,
kind: if escalated { ToastKind::Error } else { ToastKind::Info },
message: message.clone(),
created_at: chrono::Utc::now().timestamp_millis(),
lifetime_ms: 8000,
lifetime_ms: if escalated { 30000 } else { 8000 },
});
state.dirty = true;
} else if kind == "bg-arch-review" || kind == "bg-security-review" {
let escalated = message.starts_with("ESCALATED:");
state.push_toast(Toast {
kind: ToastKind::Info,
kind: if escalated { ToastKind::Error } else { ToastKind::Info },
message: message.clone(),
created_at: chrono::Utc::now().timestamp_millis(),
lifetime_ms: 10000,
lifetime_ms: if escalated { 30000 } else { 10000 },
});
state.dirty = true;
} else if kind == "workflow_done" {
@@ -1002,7 +1004,7 @@ fn run_agent_turn(
if user_request.is_empty() {
false
} else {
crate::app::workflow::company::is_complex_request(user_request)
crate::app::workflow::hive_mind::is_complex_request(user_request)
}
} else {
false
@@ -1014,58 +1016,46 @@ fn run_agent_turn(
.and_then(|m| m.content.as_deref())
.unwrap_or("");
let use_full = true;
let mode_label = "full";
tracing::info!(
"[ceo] pipeline triggered (mode={}) — dynamically generating planning workflow via LLM",
mode_label
);
tracing::info!("[hive-mind] triggered — Core Intelligence compiling a cognitive cycle plan via LLM");
if let Ok(mut q) = events_q.lock() {
q.push_back(TurnEvent::SystemNote {
kind: "pipeline".to_string(),
message: format!(
"CEO is planning workflow (mode={mode_label})...",
),
message: "Core Intelligence is compiling a cognitive cycle plan...".to_string(),
});
}
let pipeline_abort = Some(tc.abort_flag.clone());
// Ask LLM to dynamically generate the workflow specialists plan
let required_divisions = if use_full {
"all 5 divisions (Strategy, Engineering, Quality, Security, Documentation)"
} else {
"the 3 quick divisions (Strategy, Engineering, Quality)"
};
let example_json = if use_full {
r#"{
"Strategy": [ ["Architect", "Analyze component tree..."] ],
"Engineering": [ ["Developer", "Implement core algorithms..."] ],
"Quality": [ ["Tester", "Write unit tests..."] ],
"Security": [ ["Auditor", "Review dependencies..."] ],
"Documentation": [ ["Writer", "Document API endpoints..."] ]
}"#
} else {
r#"{
"Strategy": [ ["Architect", "Analyze component tree..."] ],
"Engineering": [ ["Developer", "Implement core algorithms..."] ],
"Quality": [ ["Tester", "Write unit tests..."] ]
}"#
};
// Ask the LLM to freely design its own hive: any number of cycles,
// each with any number of nodes, every node carrying only a
// directive and an access tier. Cycle count and shape are decided
// by the Core Intelligence per task.
let system_msg = ChatMessage::system(
"You are a professional software architect and workflow planner. \
Generate a tailored, structured multi-agent workflow specialists plan for the requested task. \
Do not explain. Return ONLY raw JSON matching the requested structure."
"You are the Core Intelligence of a distributed machine, compiling a cognitive \
cycle plan for a specific task. You spawn anonymous processing nodes; each node \
carries only a directive (what to do) and an access tier. Decide how many cycles \
and nodes-per-cycle are actually needed. Simple tasks might need one cycle with \
one node; large tasks might need several cycles with multiple nodes each. Cycles \
run sequentially; every node's complete output merges into the collective state \
the instant it finishes, automatically visible to all later cycles. Nodes within \
a cycle run in parallel. Do not explain. Return ONLY raw JSON matching the requested structure."
);
let user_msg = ChatMessage::user(format!(
"Design a structured multi-agent workflow plan for the following task:\n\n\
"Compile a cognitive cycle plan for the following task:\n\n\
\"{user_request}\"\n\n\
You must output a JSON object representing the 'specialists' configuration for {required_divisions}.\n\
Each division must have a list of custom specialists defined by a pair of [label, focus_description].\n\n\
Return ONLY a JSON object with this exact structure, with no markdown codeblocks and no explanation:\n\
{example_json}"
Return ONLY a JSON object of this exact shape, with no markdown codeblocks and no explanation:\n\
{{\n\
\x20 \"cycles\": [\n\
\x20 [\n\
\x20 {{ \"directive\": \"<what this node does>\", \"access\": \"read|write|full\" }}\n\
\x20 ]\n\
\x20 ]\n\
}}\n\n\
access: 'read' = investigation only, 'write' = read + edit/write/bash, \
'full' = write + delete/git_operator. Pick the narrowest access each node actually needs. \
Each node object has exactly two fields: directive and access, addressed only by \
its system-assigned designation."
));
let planner_result = tc.client.chat_with_tools_non_streaming(&[system_msg, user_msg], None);
@@ -1084,43 +1074,29 @@ fn run_agent_turn(
reply_text.to_string()
};
match serde_json::from_str::<std::collections::HashMap<String, Vec<(String, String)>>>(&clean_json) {
Ok(custom_specialists) => {
let spec_desc = custom_specialists.iter()
.map(|(k, v)| format!("{}: {} agents", k, v.len()))
match serde_json::from_str::<crate::app::workflow::hive_mind::CognitiveCyclePlan>(&clean_json) {
Ok(plan) => {
let cycle_desc = plan.cycles.iter()
.enumerate()
.map(|(i, nodes)| format!("cycle {i}: {} node(s)", nodes.len()))
.collect::<Vec<String>>()
.join(", ");
if let Ok(mut q) = events_q.lock() {
q.push_back(TurnEvent::SystemNote {
kind: "pipeline".to_string(),
message: format!(
"CEO planned: Strategy → Engineering → Quality{}. (Config: {}) Running specialists...",
if use_full { " → Security → Documentation" } else { "" },
spec_desc
),
message: format!("Core Intelligence compiled {} cycle(s) — {cycle_desc}. Deploying nodes...", plan.cycles.len()),
});
}
if use_full {
crate::app::workflow::company::run_company_pipeline(
user_request,
&tc.edit_log_session_dir,
&tc.workspace_roots,
Some(events_q),
&pipeline_abort,
&custom_specialists,
)
} else {
crate::app::workflow::company::run_company_pipeline_quick(
user_request,
&tc.edit_log_session_dir,
&tc.workspace_roots,
Some(events_q),
&pipeline_abort,
&custom_specialists,
)
}
crate::app::workflow::hive_mind::run_hive_mind(
user_request,
&plan,
&tc.edit_log_session_dir,
&tc.workspace_roots,
Some(events_q),
pipeline_abort.as_ref(),
)
}
Err(e) => Err(anyhow::anyhow!("Failed to parse LLM planning JSON: {e}. Cleaned JSON was: {clean_json}")),
}
@@ -1129,10 +1105,18 @@ fn run_agent_turn(
};
match pipeline_result {
Ok(summary) => {
tracing::info!("[ceo] company pipeline completed successfully");
Ok((consensus, reports)) => {
tracing::info!("[hive-mind] convergence completed successfully");
if let Some(workspace_root) = tc.workspace_roots.first() {
match crate::app::workflow::docs::write_hive_mind_convergence(workspace_root, user_request, &reports, &consensus) {
Ok(path) => tracing::info!("[hive-mind] convergence documented at {}", path.display()),
Err(e) => tracing::warn!("[hive-mind] failed to write docs/runs report: {e}"),
}
}
let pipeline_msg = ChatMessage::system(format!(
"[Company Pipeline: {mode_label}]\n{summary}",
"[Hive-Mind Consensus]\n{consensus}",
));
archive_message(tc.db.as_ref(), &tc.session_id, &pipeline_msg);
msgs.push(pipeline_msg);
@@ -1140,14 +1124,14 @@ fn run_agent_turn(
if let Ok(mut q) = events_q.lock() {
q.push_back(TurnEvent::SystemNote {
kind: "pipeline".to_string(),
message: format!("Company pipeline ({mode_label}) complete. CEO reviewing results..."),
message: "Hive-mind convergence complete. Core Intelligence reviewing consensus...".to_string(),
});
}
}
Err(e) => {
tracing::warn!("[ceo] company pipeline failed: {}", e);
tracing::warn!("[hive-mind] convergence failed: {}", e);
let fail_msg = ChatMessage::system(format!(
"[Pipeline Note] The company pipeline encountered issues: {e}.\n\
"[Pipeline Note] The hive-mind encountered issues: {e}.\n\
Proceeding with direct execution as fallback.",
));
msgs.push(fail_msg);