feat(agent): subagent tool paralel + auto-load AGENTS.md + verify cek setelah edit
Lanjutan audit alur AI agent (round 2), mengisi celah yang tersisa dari
perpbaikan paralel tool di loop utama (74b1ad4) agar lebih mirip Claude Code.
- feat(subagent): eksekusi batch tool read-only paralel di subagent engine
(engine.rs). Tool::run sinkron, jadi pakai scoped OS thread (bounded
window 8); hasil dipertahankan dalam urutan panggilan asli. Batch dengan
tool mutating jatuh balik ke jalur sequential aman.
- feat(agent): auto-load AGENTS.md/CLAUDE.md/.cursorrules ke system prompt
tiap turn (seperti Claude Code load AGENTS.md saat startup). Fungsi
main_agent_prompt_with_project_context menempel blok PROJECT CONTEXT;
dibaca dari workspace root pertama & dibatasi 12k char.
- feat(prompt): arahan VERIFY AFTER EDIT — setelah edit/write, agent wajib
jalankan cargo check/clippy/test (atau lint/test sesuai stack) via bash
sebelum mengakhiri turn; perbaiki error yang terlihat, jangan klaim
'compiles/works' tanpa hasil nyata.
- feat(infra): build_rich_context kini membaca AGENTS.md & CLAUDE.md juga
(untuk explore_codebase/scout).
- test: +3 subagent engine (order paralel, kecepatan konkuren, fallback
mutating), +2 domain prompt (konteks proyek & fallback kosong).
This commit is contained in:
@@ -5,7 +5,7 @@ use tracing::{debug, info, warn};
|
||||
|
||||
use zesdex_domain::agent::{AgentTurnParams, TurnEvent};
|
||||
use zesdex_domain::core::{ChatMessage, StreamEvent, ToolDef};
|
||||
use zesdex_domain::main_agent_prompt;
|
||||
use zesdex_domain::main_agent_prompt_with_project_context;
|
||||
|
||||
use super::ToolExecutor;
|
||||
use crate::ports::ProviderService;
|
||||
@@ -111,6 +111,46 @@ fn conversation_chars(messages: &[ChatMessage]) -> usize {
|
||||
.sum()
|
||||
}
|
||||
|
||||
/// The maximum combined size (characters) of project-rule files injected into
|
||||
/// the system prompt, so a huge AGENTS.md cannot blow the context window.
|
||||
const PROJECT_CONTEXT_MAX_CHARS: usize = 12_000;
|
||||
|
||||
/// Case-insensitive rule filenames auto-loaded from the workspace root into
|
||||
/// the system prompt, matching the Claude-Code/AGENTS.md convention.
|
||||
const RULE_FILENAMES: [&str; 6] = [
|
||||
"AGENTS.md",
|
||||
"agent.md",
|
||||
"CLAUDE.md",
|
||||
"claude.md",
|
||||
".cursorrules",
|
||||
".zesdexrules",
|
||||
];
|
||||
|
||||
/// Build a compact "project context" block from the repo's convention files
|
||||
/// (AGENTS.md, CLAUDE.md, .cursorrules, …) found at the workspace root.
|
||||
///
|
||||
/// Follows the Claude-Code convention of loading AGENTS.md at startup so the
|
||||
/// model starts each turn with the repo's rules. Reads are best-effort and
|
||||
/// capped at [`PROJECT_CONTEXT_MAX_CHARS`] total; missing files are skipped.
|
||||
fn build_project_context(root: &std::path::Path) -> String {
|
||||
let mut ctx = String::new();
|
||||
for file in RULE_FILENAMES {
|
||||
let full = root.join(file);
|
||||
if let Ok(content) = std::fs::read_to_string(&full) {
|
||||
ctx.push_str(&format!("\n### {file}\n```\n{}\n```", content.trim()));
|
||||
}
|
||||
}
|
||||
let context = ctx.trim().to_string();
|
||||
if context.len() <= PROJECT_CONTEXT_MAX_CHARS {
|
||||
return context;
|
||||
}
|
||||
context
|
||||
.chars()
|
||||
.take(PROJECT_CONTEXT_MAX_CHARS)
|
||||
.collect::<String>()
|
||||
+ "\n...[project context truncated]"
|
||||
}
|
||||
|
||||
/// Track repeated tool-call errors so the loop can recover instead of
|
||||
/// burning iterations retrying the same failing tool.
|
||||
#[derive(Default)]
|
||||
@@ -341,9 +381,17 @@ impl<P: ProviderService, T: ToolExecutor> super::AgentTurnService for AgentTurnS
|
||||
|
||||
// Insert system prompt at position 0 once and keep it there for the
|
||||
// entire turn, avoiding per-iteration clones of the full message list.
|
||||
// Auto-load repo conventions (AGENTS.md / CLAUDE.md / .cursorrules)
|
||||
// from the first workspace root, like Claude Code does at startup.
|
||||
let project_context = params
|
||||
.workspace_roots
|
||||
.first()
|
||||
.map(|root| build_project_context(root))
|
||||
.unwrap_or_default();
|
||||
let system_prompt = main_agent_prompt_with_project_context(&project_context);
|
||||
params
|
||||
.messages
|
||||
.insert(0, ChatMessage::system(main_agent_prompt()));
|
||||
.insert(0, ChatMessage::system(system_prompt));
|
||||
let original_count = params.messages.len();
|
||||
|
||||
// Estimate request complexity from the last user message.
|
||||
|
||||
Reference in New Issue
Block a user