Enhance tool documentation and add new features
- Added module-level documentation for memory tools (`remember`, `recall`, `forget`) to clarify their purpose. - Improved documentation in `recall.rs` and `remember.rs` to describe the functionality and flow of memory entry operations. - Updated `mod.rs` to include descriptions for the tool trait and execution context. - Enhanced `plan.rs` with detailed comments on plan-mode signaling tools. - Documented text search tools in `search.rs` to explain their functionality. - Improved sequential-thinking tool documentation in `seqthink.rs`. - Added safety filter documentation in `shell_filter` for credential and git operations. - Enhanced utility tools documentation, including `cd`, `dir_cache_update`, and `todowrite`. - Improved rendering documentation in view modules (`chat`, `markdown`, `status`, `workflow`) to clarify rendering flows and purposes.
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
//! Workflow engine: interprets `ScriptPrimitive` values (agent, parallel,
|
||||
//! pipeline, phase) by spawning subagents, collecting results, and
|
||||
//! managing concurrency.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -5,6 +9,7 @@ use super::script::{ScriptPrimitive, WorkflowScript};
|
||||
|
||||
static FINDINGS: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
|
||||
/// The lifecycle state of an agent within a workflow run.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AgentState {
|
||||
Idle,
|
||||
@@ -13,6 +18,7 @@ pub enum AgentState {
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Timestamped status of one workflow agent.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AgentStatus {
|
||||
pub state: AgentState,
|
||||
@@ -21,6 +27,7 @@ pub struct AgentStatus {
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
/// A single agent tracked within a workflow run.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WorkflowAgent {
|
||||
pub id: String,
|
||||
@@ -28,6 +35,8 @@ pub struct WorkflowAgent {
|
||||
pub status: AgentStatus,
|
||||
}
|
||||
|
||||
/// Orchestrator for running workflow scripts: holds agent roster and a
|
||||
/// shared finding accumulator visible to all pipeline stages.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WorkflowEngine {
|
||||
pub agents: Vec<WorkflowAgent>,
|
||||
@@ -35,6 +44,7 @@ pub struct WorkflowEngine {
|
||||
}
|
||||
|
||||
impl WorkflowEngine {
|
||||
/// Create an empty workflow engine with no agents or findings.
|
||||
pub fn new() -> Self {
|
||||
WorkflowEngine {
|
||||
agents: Vec::new(),
|
||||
@@ -43,6 +53,14 @@ impl WorkflowEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn a single synchronous subagent with the given prompt, passing it
|
||||
/// any findings from earlier sibling agents.
|
||||
///
|
||||
/// Flow: build an `AgentDefinition` -> build a `SubagentContext` ->
|
||||
/// inject findings into the system prompt -> call `run_subagent` on a
|
||||
/// dedicated mpsc channel.
|
||||
///
|
||||
/// Return: the agent's text output, or an error on failure.
|
||||
fn spawn_single_agent(prompt: &str, findings_snapshot: Vec<String>) -> anyhow::Result<String> {
|
||||
use crate::app::subagent::context::build_subagent_context;
|
||||
use crate::app::subagent::engine::run_subagent;
|
||||
@@ -74,6 +92,20 @@ fn spawn_single_agent(prompt: &str, findings_snapshot: Vec<String>) -> anyhow::R
|
||||
|
||||
type ParallelResult = (usize, anyhow::Result<Vec<String>>);
|
||||
|
||||
/// Recursively execute a `ScriptPrimitive` tree, respecting an overall
|
||||
/// concurrency cap for parallel branches.
|
||||
///
|
||||
/// Flow: match the primitive ->
|
||||
/// `Agent` -> `spawn_single_agent`
|
||||
/// `Parallel` -> spawn threads up to `concurrency_cap`, join
|
||||
/// `Pipeline` -> spawn threads sequentially, collect in order
|
||||
/// `Phase` -> recurse (pass-through wrapper)
|
||||
///
|
||||
/// Why: parallelism is implemented with `std::thread::spawn` and a
|
||||
/// counting semaphore so the main async event loop remains unblocked.
|
||||
///
|
||||
/// Return: a `Vec<String>` of all agent outputs (or error strings) in
|
||||
/// the order they were submitted.
|
||||
pub fn execute_primitive(
|
||||
primitive: &ScriptPrimitive,
|
||||
args: &HashMap<String, String>,
|
||||
@@ -169,6 +201,14 @@ pub fn execute_primitive(
|
||||
}
|
||||
}
|
||||
|
||||
/// Run a `WorkflowScript` with the given template arguments and produce a
|
||||
/// summary string.
|
||||
///
|
||||
/// Flow: clear the global finding store -> cap concurrency to 5 -> call
|
||||
/// `execute_primitive` on the script's root primitive -> format results
|
||||
/// into a one-line-per-agent summary.
|
||||
///
|
||||
/// Return: a human-readable summary string.
|
||||
pub fn run_workflow(script: &WorkflowScript, args: &HashMap<String, String>) -> anyhow::Result<String> {
|
||||
if let Ok(mut findings) = FINDINGS.lock() {
|
||||
findings.clear();
|
||||
@@ -201,12 +241,19 @@ pub fn run_workflow(script: &WorkflowScript, args: &HashMap<String, String>) ->
|
||||
Ok(summary)
|
||||
}
|
||||
|
||||
/// Add a finding text to the global workflow findings list, making it
|
||||
/// visible to sibling agents spawned later in the same run.
|
||||
pub fn note_finding(text: &str) {
|
||||
if let Ok(mut findings) = FINDINGS.lock() {
|
||||
findings.push(text.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple template engine: replace `{{key}}` placeholders with values
|
||||
/// from `args`.
|
||||
///
|
||||
/// Why: a structed template engine is unnecessary for the limited
|
||||
/// use-case; this is intentionally simple and safe.
|
||||
fn resolve_template(template: &str, args: &HashMap<String, String>) -> String {
|
||||
let mut result = template.to_string();
|
||||
for (key, value) in args {
|
||||
@@ -215,6 +262,9 @@ fn resolve_template(template: &str, args: &HashMap<String, String>) -> String {
|
||||
result
|
||||
}
|
||||
|
||||
/// A counting semaphore built from a `Mutex` + `Condvar`.
|
||||
///
|
||||
/// Used by `execute_primitive` to cap concurrent parallel branches.
|
||||
struct Semaphore {
|
||||
count: Mutex<usize>,
|
||||
condvar: std::sync::Condvar,
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
//! Workflow orchestration: a script interpreter that runs pipeline/parallel
|
||||
//! primitives across multiple subagent instances.
|
||||
|
||||
pub mod engine;
|
||||
pub mod script;
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
//! Script primitives for the workflow engine: agent invocation, parallel
|
||||
//! execution, pipelines, and phases.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A workflow script primitive — can be a single agent, a parallel fan-out,
|
||||
/// a sequential pipeline, or a named phase.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ScriptPrimitive {
|
||||
/// Run a single agent with the given prompt template.
|
||||
Agent(String),
|
||||
/// Execute several primitives concurrently.
|
||||
Parallel(Vec<ScriptPrimitive>),
|
||||
/// Execute several primitives sequentially, each waiting for the
|
||||
/// previous to complete.
|
||||
Pipeline(Vec<ScriptPrimitive>),
|
||||
/// A named wrapper around another primitive (used for display/tracing).
|
||||
Phase {
|
||||
name: String,
|
||||
script: Box<ScriptPrimitive>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Runtime options for a workflow execution.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ScriptOptions {
|
||||
pub max_concurrency: usize,
|
||||
@@ -28,6 +39,7 @@ impl Default for ScriptOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// A named, versioned workflow script with its primitives and options.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WorkflowScript {
|
||||
pub name: String,
|
||||
|
||||
Reference in New Issue
Block a user