Crate renames: - zesdex-entities::seaorm → domain (misleading name, no SeaORM used) - zesdex-dto → merged into zesdex-entities (100% re-exports) - zesdex-libs → zesdex-infra (vague name) Module renames: - app/harness → guard (misleading: safety gatekeeper, not test harness) - runtime/commands → action_dispatch (name clashed with controller/command) - resources → prompts (embedded prompt text, not general resources) - tool/seqthink → sequential_think (unreadable abbreviation) - msglog/query → insert (module only inserts, never queries) Dead code removal: - app/mode/help.rs (orphaned — not declared in mod.rs) - app/mode/loading.rs (orphaned — not declared in mod.rs) File splitting (71 new files, avg ~115 lines/file): - app/runtime/actions/: 1→8 files (was 2030 lines) - view/overlays/: 1→16 files (was 1167 lines) - tool/lsp/: 1→8 per-tool files (was 909 lines) - main.rs: 1→5 files (session, daemon, attach, event_loop) - workflow/engine + hive_mind: 2→10 files - subagent/engine + auto: 2→9 files - lsp/provisioner: 1→5 files - review/: 1→6 files - guard/: 1→2 files (extracted patterns) - state/misc: 1→3 files (input, scroll) - mcp/: 1→3 files (transport, adapter) - stream/json_repair extracted from turn.rs DRY: - Pattern constants (STUB_PATTERNS etc) in guard/patterns shared with subagent - 3 near-identical background spawners → 1 generic + thin wrappers - Shared spawn_subagent_with_drain() extracted - Shared create_session() in main - write_osc52 deduplicated Bug fixes: - archive_message(): sess.db → db (wrong variable name) - execute_one_tool(): wrong parameter name - check_credential_read() function was missing (restored from test expectations)
104 lines
3.3 KiB
Rust
104 lines
3.3 KiB
Rust
//! `AgentDefinition` -- declarative specification for instantiating a
|
|
//! subagent from workflow scripts or programmatic calls.
|
|
//!
|
|
//! Also provides a shared [`spawn_subagent_with_drain`] helper that
|
|
//! eliminates the channel-creation + drain-thread boilerplate duplicated
|
|
//! across `auto/mod.rs`, `review/mod.rs`, and `workflow/engine/mod.rs`.
|
|
|
|
use super::event::SubagentEvent;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Declarative specification for instantiating a subagent: name, role,
|
|
/// optional system prompt, allowed tools, step budget, and temperature.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AgentDefinition {
|
|
pub name: String,
|
|
pub role: String,
|
|
pub system_prompt: Option<String>,
|
|
pub allowed_tools: Option<Vec<String>>,
|
|
pub max_steps: Option<usize>,
|
|
pub temperature: Option<f32>,
|
|
}
|
|
|
|
impl AgentDefinition {
|
|
/// Create an agent definition with the required name and role; all
|
|
/// optional fields start as `None`.
|
|
pub fn new(name: String, role: String) -> Self {
|
|
AgentDefinition {
|
|
name,
|
|
role,
|
|
system_prompt: None,
|
|
allowed_tools: None,
|
|
max_steps: None,
|
|
temperature: None,
|
|
}
|
|
}
|
|
|
|
/// Builder method: set the system prompt for this agent.
|
|
pub fn with_system_prompt(mut self, prompt: String) -> Self {
|
|
self.system_prompt = Some(prompt);
|
|
self
|
|
}
|
|
|
|
/// Builder method: set the allowed tool list for this agent.
|
|
pub fn with_allowed_tools(mut self, tools: Vec<String>) -> Self {
|
|
self.allowed_tools = Some(tools);
|
|
self
|
|
}
|
|
|
|
/// Builder method: set the maximum step count for this agent.
|
|
pub fn with_max_steps(mut self, steps: usize) -> Self {
|
|
self.max_steps = Some(steps);
|
|
self
|
|
}
|
|
|
|
}
|
|
|
|
/// Shared subagent spawning utility: creates an mpsc channel and spawns a
|
|
/// drain thread that forwards every [`SubagentEvent`] to `on_event`.
|
|
///
|
|
/// Returns the sender half (for passing to [`run_subagent`](super::engine::run_subagent))
|
|
/// and the drain thread's join handle so the caller can keep it alive for
|
|
/// the duration of the subagent run.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```ignore
|
|
/// let (tx, _drain) = spawn_subagent_with_drain(|event| {
|
|
/// match &event {
|
|
/// SubagentEvent::ToolCall { tool, .. } => tracing::debug!("tool: {tool}"),
|
|
/// SubagentEvent::Completed => tracing::debug!("done"),
|
|
/// _ => {}
|
|
/// }
|
|
/// });
|
|
/// let verdict = run_subagent(&ctx, &tx)?;
|
|
/// ```
|
|
///
|
|
/// # Duplication eliminated
|
|
///
|
|
/// Previously every subagent caller inlined the same 5-line pattern:
|
|
///
|
|
/// ```ignore
|
|
/// let (tx, mut rx) = tokio::sync::mpsc::channel(32);
|
|
/// let _drain = std::thread::spawn(move || {
|
|
/// while let Some(event) = rx.blocking_recv() { ... }
|
|
/// });
|
|
/// ```
|
|
///
|
|
/// Callers that need a larger buffer (e.g. workflow engine uses 64) should
|
|
/// create the channel manually instead of using this helper.
|
|
pub fn spawn_subagent_with_drain<F>(
|
|
on_event: F,
|
|
) -> (tokio::sync::mpsc::Sender<SubagentEvent>, std::thread::JoinHandle<()>)
|
|
where
|
|
F: Fn(SubagentEvent) + Send + 'static,
|
|
{
|
|
let (tx, mut rx) = tokio::sync::mpsc::channel(32);
|
|
let drain = std::thread::spawn(move || {
|
|
while let Some(event) = rx.blocking_recv() {
|
|
on_event(event);
|
|
}
|
|
});
|
|
(tx, drain)
|
|
}
|