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:
asepharyana
2026-07-12 11:28:39 +07:00
parent 7158d362fd
commit 2efd40ca88
124 changed files with 2379 additions and 19 deletions
+14
View File
@@ -1,8 +1,14 @@
//! Construction of a `SubagentContext` from an `AgentDefinition`,
//! including the default read-only tool set for reviewer agents.
use std::path::PathBuf;
use super::spawn::AgentDefinition;
/// Default read-only tool names granted to `role == "reviewer"` agents.
pub const REVIEWER_ALLOWED: &[&str] = &["read", "grep", "glob", "recall", "remember"];
/// Per-invocation configuration for a subagent: prompt, allowed tools,
/// step budget, and the session directory it should operate against.
pub struct SubagentContext {
pub system_prompt: String,
pub allowed_tools: Vec<String>,
@@ -10,6 +16,14 @@ pub struct SubagentContext {
pub session_dir: PathBuf,
}
/// Build a `SubagentContext` from an `AgentDefinition`.
///
/// Flow: copy optional `allowed_tools` from the def -> fall back to the
/// reviewer-allowlist when the def has none and the role is "reviewer" ->
/// fall back to an empty list (i.e. "all tools allowed") for other roles.
///
/// Return: a context with empty `system_prompt` and `session_dir`,
/// `max_steps = 25`, and the resolved allowed-tool list.
pub fn build_subagent_context(def: AgentDefinition) -> SubagentContext {
let allowed_tools = def.allowed_tools.clone().unwrap_or_else(|| {
if def.role == "reviewer" {
+38 -5
View File
@@ -1,3 +1,7 @@
//! Subagent execution loop: drive an LLM conversation, gate tool calls
//! against the context's allowlist, run tools, and stream progress events
//! to the parent via an mpsc channel.
use tokio::sync::mpsc;
use crate::dto::chat::message::ChatMessage;
use crate::dto::provider::request::ToolDef;
@@ -5,12 +9,20 @@ use crate::tool::{all_tools, tool_defs, tool_is_risky};
use super::context::SubagentContext;
use super::event::SubagentEvent;
/// Upper bound on agent loop steps; effectively unbounded (`usize::MAX`).
#[allow(dead_code)]
pub const MAX_AGENT_STEPS: usize = usize::MAX;
/// Maps a subagent's allowed tool names to concrete Tool trait objects and
/// OpenAI-style tool definitions. When `allowed_tools` is empty every tool is
/// available; otherwise only explicitly allowed ones are included.
/// OpenAI-style tool definitions.
///
/// Flow: load `all_tools()` → if `allowed_tools` is empty, use all; else
/// filter by membership → derive `ToolDef`s for the LLM.
///
/// Why: an empty allowlist means "no restriction" (matches
/// `build_subagent_context`'s default for non-reviewer roles).
///
/// Return: `(tool impls, schema defs)` for the subagent to use.
fn build_subagent_tools(allowed_tools: &[String]) -> (Vec<Box<dyn crate::tool::Tool>>, Vec<ToolDef>) {
let all = all_tools();
let filtered: Vec<Box<dyn crate::tool::Tool>> = if allowed_tools.is_empty() {
@@ -24,9 +36,16 @@ fn build_subagent_tools(allowed_tools: &[String]) -> (Vec<Box<dyn crate::tool::T
(filtered, defs)
}
/// Resolves the API key, model, and base URL from the persisted application
/// configuration rather than environment variables, matching how the main agent
/// resolves its credentials.
/// Resolve the API key, model, and base URL from persisted app config.
///
/// Flow: try the settings key for the active provider → fall back to the
/// provider's `api_key_env` env-var → fall back to the provider's
/// `default_api_key` → fall back to an empty string.
///
/// Why: matches the main agent's credential resolution exactly, so
/// subagents automatically inherit the same provider settings.
///
/// Return: `(api_key, model, optional_base_url)`.
fn resolve_provider_config() -> (String, String, Option<String>) {
let settings = crate::model::settings::Settings::load();
let app_config = crate::model::app_config::AppConfig::load();
@@ -54,6 +73,20 @@ fn resolve_provider_config() -> (String, String, Option<String>) {
(api_key, model, base_url)
}
/// Synchronous subagent entry point: run up to `ctx.max_steps` iterations
/// of the LLM tool loop.
///
/// Flow: inject system prompt → for each step: resolve provider config,
/// build an LLM client, call `chat_with_tools_non_streaming`, process tool
/// calls or collect text output → send `SubagentEvent`s on `tx` → break on
/// first text-only (non-empty) response.
///
/// Why: runs synchronously on a dedicated thread so the main async event
/// loop is not blocked. Tool gating prevents restricted or risky tools from
/// executing unless explicitly allowed.
///
/// Return: the concatenated text output, or an `anyhow::Error` if the LLM
/// call fails at any step.
pub fn run_subagent(ctx: SubagentContext, tx: mpsc::Sender<SubagentEvent>) -> anyhow::Result<String> {
let mut output = String::new();
let mut messages: Vec<ChatMessage> = Vec::new();
+5
View File
@@ -1,5 +1,10 @@
//! Event variants that a running subagent can emit to its parent via the
//! shared mpsc channel.
use serde_json::Value;
/// Progress and outcome events emitted by `run_subagent` as it processes
/// LLM responses and tool calls.
#[derive(Debug, Clone)]
pub enum SubagentEvent {
StepCompleted {
+3
View File
@@ -1,3 +1,6 @@
//! Subagent management: spawning, context building, engine loop, and
//! progress events.
pub mod context;
pub mod engine;
pub mod event;
+8
View File
@@ -1,5 +1,10 @@
//! AgentDefinition -- declarative specification for instantiating a
//! subagent from workflow scripts or programmatic calls.
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,
@@ -11,6 +16,8 @@ pub struct AgentDefinition {
}
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,
@@ -22,6 +29,7 @@ impl AgentDefinition {
}
}
/// Builder method: limit this agent to at most `steps` LLM calls.
pub fn with_max_steps(mut self, steps: usize) -> Self {
self.max_steps = Some(steps);
self