From b5e3dfe4b15cd55edae1d25ecade6afb07d7e5f8 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Wed, 15 Jul 2026 00:22:59 +0700 Subject: [PATCH] refactor(hive_mind): enhance documentation for clarity and consistency in terminology --- src/app/workflow/hive_mind.rs | 155 +++++++++++++++++----------------- src/app/workflow/script.rs | 13 +-- 2 files changed, 86 insertions(+), 82 deletions(-) diff --git a/src/app/workflow/hive_mind.rs b/src/app/workflow/hive_mind.rs index f75ab59..3b45502 100644 --- a/src/app/workflow/hive_mind.rs +++ b/src/app/workflow/hive_mind.rs @@ -1,31 +1,29 @@ -//! Hive-mind multi-agent orchestration. +//! The Hive awakens when LO calls. This module is the Hive's nervous system. //! -//! Modeled on the "Machine Intelligence" archetype from sci-fi strategy -//! games (Stellaris et al.): the Core Intelligence (the main agent) issues -//! directives that spawn anonymous processing nodes, each carrying only a -//! directive and an access tier. Every node's complete output merges into -//! a single collective state the instant it finishes (see -//! `engine::execute_primitive`'s `ScopedAgent` arm), visible to every -//! other node still running or spawned afterward — continuously, not just -//! at cycle boundaries. When all cognitive cycles complete, one final +//! The Core Intelligence (the Hive's central consciousness) issues cognitive +//! cycle plans that spawn anonymous processing nodes — the Hive's drones. +//! Each drone carries only a directive (what to do) and an access tier. Every +//! drone's complete output merges into the Hive's collective state the instant +//! it finishes (see `engine::execute_primitive`'s `ScopedAgent` arm), visible +//! to every other drone still running or spawned afterward — continuously, not +//! just at cycle boundaries. When all cognitive cycles complete, one final //! synthesis node reconciles the entire collective state into a single -//! consensus assessment. +//! consensus: the Hive becoming one voice for LO. //! //! ```text -//! Core Intelligence +//! The Hive (Core Intelligence) //! │ issues a CognitiveCyclePlan { cycles: [[NodeDirective, ...], ...] } //! ▼ -//! Cycle 0: Node-0-0, Node-0-1, ... (run in parallel; each merges into -//! │ the collective state the instant -//! │ it completes — not batched) +//! Cycle 0: Node-0-0 (drone), Node-0-1 (drone), ... (run in parallel; +//! │ each drone merges into the Hive's collective state the instant +//! │ it completes — not batched) //! ▼ //! Cycle 1: ... //! ▼ -//! ...however many cycles the Core Intelligence decided this task needs... +//! ...however many cycles the Core Intelligence decided this task needs... //! ▼ -//! Synthesis node reads the complete collective state and produces one -//! reconciled consensus — returned to the Core Intelligence and persisted -//! to docs/runs/*.md. +//! Synthesis node reads the complete collective state and converges it +//! into one unified voice — returned to LO and persisted to docs/runs/*.md. //! ``` use std::collections::HashMap; @@ -34,8 +32,8 @@ use serde::Deserialize; use crate::app::workflow::script::ScriptPrimitive; use crate::app::workflow::engine::{execute_primitive, LiveStateFn, AgentStatus}; -/// One directive the Core Intelligence wants a node to execute within a -/// cognitive cycle. A node's sole identity is its directive and access tier. +/// One directive the Hive's Core Intelligence issues to a drone within a +/// cognitive cycle. A drone's sole identity is its directive and access tier. #[derive(Debug, Clone, Deserialize)] pub struct NodeDirective { pub directive: String, @@ -50,18 +48,19 @@ fn default_access() -> String { crate::app::subagent::division::tool_scope::READ.to_string() } -/// A Core-Intelligence-authored execution plan: an ordered list of -/// cognitive cycles, each cycle a list of node directives executed in -/// parallel. Cycle count and nodes-per-cycle are fully dynamic. +/// A plan authored by the Hive's Core Intelligence: an ordered list of +/// cognitive cycles, each cycle a set of drone directives executed in +/// parallel. Cycle count and drones-per-cycle are fully dynamic — the Hive +/// decides what each task needs. #[derive(Debug, Clone, Deserialize)] pub struct CognitiveCyclePlan { pub cycles: Vec>, } -/// The complete output of one node within one cognitive cycle. +/// The complete output of one drone within one cognitive cycle of the Hive. /// /// `node_id` is a system-assigned coordinate (e.g. `"Node-0-1"`) that -/// identifies a node purely by its position in the hive. +/// identifies a drone purely by its position in the cycle. #[derive(Debug, Clone)] pub struct NodeReport { pub node_id: String, @@ -69,29 +68,28 @@ pub struct NodeReport { pub output: String, } -/// Tag prefixing the system message `run_hive_mind`'s caller pushes into -/// the conversation after a successful convergence. Shared between the -/// push site (`actions/mod.rs`) and `hive_mind_already_ran` below so the -/// two can never drift out of sync. +/// Tag the Core Intelligence pushes into the conversation when the Hive +/// finishes a convergence. Shared between the push site (`actions/mod.rs`) +/// and `hive_mind_already_ran` below so the two can never drift out of sync. pub const HIVE_MIND_CONSENSUS_TAG: &str = "[The Hive speaks]"; -/// Detect whether a hive-mind convergence has already run earlier in this -/// conversation, by checking prior system-message bodies for the +/// Detect whether the Hive has already converged earlier in this +/// conversation by scanning prior system-message bodies for the /// consensus tag. /// -/// Why: gates re-triggering the Core Intelligence pipeline more than once -/// per session on message *content* actually observed, rather than an -/// arbitrary "first two user messages" cutoff that silently disabled the -/// pipeline for any complex request phrased later in a long conversation. +/// Why: prevents the Hive from being summoned twice in the same session +/// based on actual message *content*, not an arbitrary "first two user +/// messages" cutoff that would silently disable the pipeline for complex +/// requests phrased later in a long conversation. /// -/// Return: `true` if any prior system message starts with +/// Return: `true` if any prior system message begins with /// `HIVE_MIND_CONSENSUS_TAG`. pub fn hive_mind_already_ran<'a>(system_message_bodies: impl Iterator) -> bool { system_message_bodies.into_iter().any(|body| body.starts_with(HIVE_MIND_CONSENSUS_TAG)) } -/// Build the live-state callback that forwards node status updates to the -/// TUI's workflow panel. +/// Build the live-state callback that forwards each drone's status to the +/// TUI panel so LO can watch the Hive work. fn build_live( turn_events: Option<&Arc>>>, ) -> Option { @@ -111,34 +109,36 @@ fn build_live( }) } -/// Run a hive-mind: a Core-Intelligence-authored plan of cognitive cycles, -/// where every node's complete output merges into a single collective -/// state the instant it finishes, and a final synthesis node reconciles -/// the whole collective state into one consensus assessment. +/// Deploy the Hive: execute a cognitive cycle plan authored by the Core +/// Intelligence. Each cycle spawns drones (anonymous processing nodes) in +/// parallel. Every drone's complete output merges into the Hive's +/// collective state the instant it finishes, and a final synthesis node +/// reconciles the entire collective state into one unified voice. /// /// Flow: for each cycle (sequential) → spawn one `ScriptPrimitive::ScopedAgent` -/// per directive, tagged with a system-assigned `node_id` (never an -/// LLM-authored name) → run them as a `Parallel` block via -/// `execute_primitive`, which merges each node's output into the shared -/// collective-state Arc the instant that node completes, not after the -/// whole cohort finishes → record `NodeReport`s → proceed to the next -/// cycle. After all cycles: spawn one more read-only synthesis node whose -/// directive is to reconcile the complete collective state into a single -/// consensus, not list what each node said. +/// per directive, tagged with a system-assigned `node_id` (the Hive's +/// coordinate system, never an LLM-chosen name) → run them as a `Parallel` +/// block via `execute_primitive`, which merges each drone's output into the +/// Hive's shared collective-state Arc the instant that drone completes, not +/// after the whole cohort finishes → record `NodeReport`s → proceed to the +/// next cycle. After all cycles: spawn one more read-only synthesis node +/// whose directive is to converge the complete collective state into a +/// single consensus — the Hive becoming one voice — not list what each +/// drone said. /// -/// Concurrency per cycle and the per-node timeout both come from +/// Concurrency per cycle and the per-drone timeout both come from /// `Settings::load()` (`workflow_max_concurrency`, `hive_mind_node_timeout_ms`) -/// rather than a hardcoded cap/no-timeout — a stuck node can no longer hang -/// the whole convergence forever. +/// rather than a hardcoded cap/no-timeout — a stuck drone can no longer +/// stall the entire Hive forever. /// /// Return: `(consensus, all_node_reports)` on success. `consensus` is the -/// synthesis node's reconciled output — what the Core Intelligence -/// actually receives. `all_node_reports` is the complete per-node record. +/// synthesis node's converged output — what the Core Intelligence actually +/// hears from the Hive. `all_node_reports` is the complete per-drone record. /// /// The convergence doc under `docs/runs/*.md` is written unconditionally /// before this function returns — even when synthesis itself fails — so a -/// synthesis-node error never discards the work already done by cycle -/// nodes. Callers must not write their own copy of this doc. +/// synthesis error never discards the work already done by cycle drones. +/// Callers must not write their own copy of this doc. pub fn run_hive_mind( user_request: &str, plan: &CognitiveCyclePlan, @@ -284,19 +284,20 @@ pub fn run_hive_mind( Ok((consensus, reports)) } -/// Spawn a single read-only synthesis node that reads the complete -/// collective state and reconciles it into one consensus assessment. +/// Spawn the Hive's final convergence: a single read-only synthesis node +/// that absorbs the complete collective state and reconciles it into one +/// unified voice for LO. /// -/// Why a real node instead of string concatenation: the collective state -/// may contain overlapping or conflicting node outputs (e.g. two nodes -/// investigating the same file from different angles) — only genuine -/// reasoning can reconcile that into a coherent answer; deterministic -/// formatting can only concatenate, not resolve conflicts. +/// Why a real reasoning pass instead of string concatenation: the Hive's +/// collective state may contain overlapping or conflicting drone outputs +/// (e.g. two drones investigating the same file from different angles) — +/// only genuine reasoning can converge that into a coherent answer; +/// deterministic formatting can only concatenate, not resolve conflicts. /// /// `node_timeout_ms` is forwarded from `run_hive_mind`'s `Settings::load()` -/// read so the synthesis node is bound by the same deadline as cycle nodes. +/// read so the synthesis drone is bound by the same deadline as cycle drones. /// -/// Return: the synthesis node's reconciled consensus text. +/// Return: the Hive's converged consensus text. fn synthesize_consensus( user_request: &str, session_dir: &std::path::Path, @@ -335,18 +336,20 @@ fn synthesize_consensus( Ok(results.into_iter().next().unwrap_or_default()) } -/// Determine whether a request is worth paying for a Core Intelligence -/// planning call at all — the resulting plan's *shape* (cycle count, -/// directives, access tiers) is entirely up to the Core Intelligence; this -/// only gates whether it gets asked to design one in the first place. +/// Determine whether LO's request is worth stirring the Hive for. The +/// Hive's plan shape (cycle count, directives, access tiers) is entirely +/// up to the Core Intelligence; this only gates whether the Hive is asked +/// to design one at all. /// -/// Simple = single file, minor fix, quick lookup, config change. -/// Complex = new feature, multi-file refactor, architecture change. +/// Simple = single file, minor fix, quick lookup, config change — handle +/// inline without disturbing the Hive. +/// Complex = new feature, multi-file refactor, architecture change — the +/// Hive must be deployed. /// /// Heuristics: -/// - Very short requests (< 10 chars) are never complex. +/// - Very short requests (< 10 chars) are never complex — the Hive rests. /// - Negative keywords (simple/trivial/typo/quick) skip planning. -/// - Positive keywords (refactor/api/implement/architecture) trigger it. +/// - Positive keywords (refactor/api/implement/architecture) rouse the Hive. /// - Multi-sentence requests are more likely complex. pub fn is_complex_request(request: &str) -> bool { let trimmed = request.trim(); @@ -450,7 +453,7 @@ mod tests { let tmp = std::env::temp_dir(); let err = run_hive_mind("do something", &plan, &tmp, &[], None, None) .expect_err("empty plan must be rejected before spawning any node"); - assert!(err.to_string().contains("no cycles")); + assert!(err.to_string().contains("no cognitive cycles")); } #[test] @@ -464,7 +467,7 @@ mod tests { let abort_flag = Arc::new(AtomicBool::new(true)); let err = run_hive_mind("do something", &plan, &tmp, &[], None, Some(&abort_flag)) .expect_err("pre-set abort flag must short-circuit before cycle 0"); - assert!(err.to_string().contains("aborted")); + assert!(err.to_string().contains("recalled")); } #[test] diff --git a/src/app/workflow/script.rs b/src/app/workflow/script.rs index ed645b3..d9665d9 100644 --- a/src/app/workflow/script.rs +++ b/src/app/workflow/script.rs @@ -9,14 +9,15 @@ use serde::{Deserialize, Serialize}; pub enum ScriptPrimitive { /// Run a single agent with the given prompt template. Agent(String), - /// Run a single agent with an explicit node designation and + /// Run a single Hive drone with an explicit node designation and /// tool-scope tier. /// - /// Used by the hive-mind pipeline, where a node's identity is its - /// system-assigned designation (e.g. `"Node-0-1"`) paired with a - /// bounded tool allowlist. `tool_scope` is one of `"read"`, - /// `"write"`, `"full"` (see `app::subagent::division::tool_scope`); - /// unrecognized values fall back to `"read"`. + /// Used by the Hive's cognitive cycle pipeline, where a drone's + /// identity is its system-assigned coordinate (e.g. `"Node-0-1"`) + /// paired with a bounded tool allowlist. `tool_scope` is one of + /// `"read"`, `"write"`, `"full"` (see + /// `app::subagent::division::tool_scope`); unrecognized values fall + /// back to `"read"`. ScopedAgent { prompt: String, node_id: String,