fix(agent): subagent patuhi tool-calling contract + truncation char-safe
Hasil audit alur AI agent round 3 (fokus correctness & latent crash). - fix(subagent): engine.rs sebelumnya mengeksekusi tool lalu push ChatMessage::tool hasil TANPA mendahuluinya dengan pesan assistant yang mendeklarasikan tool_calls → history malformed ([..., tool, tool, assistant(text)]). Kontrak OpenAI/Anthropic mensyaratkan pesan assistant (berisi tool_calls) sebelum hasil tool. Kini push response_msg (assistant + tool_calls + content) sebelum eksekusi, dan hapus push assistant content-only di akhir (agar tidak duplikat). Loop utama sudah benar; subagent kini selaras. - fix(utils): &content[..1500] / &content[..1000] di build_rich_context dan &diff[..5000] di auto/engine.rs bisa panic saat indeks byte jatuh di tengah karakter multi-byte UTF-8 (emoji/CJK/panah). Tambah helper truncate_chars() yang memotong per karakter (char-safe) dan pakai di 3 titik tersebut. - test: +4 unit test truncate_chars (ASCII, potong, multibyte no-panic, emoji). Catatan audit: subagent/auto (auto-review) & build_rich_context adalah dead code (spawn_background_review & build_rich_context tidak pernah dipanggil). Auto-review jangan diaktifkan asal (parser format teks rapuh + tanpa verifikasi pasca-fix) — dilaporkan, bukan dicolokkan.
This commit is contained in:
@@ -220,7 +220,7 @@ pub async fn run_agent(
|
||||
.await?;
|
||||
|
||||
let content = response_msg.content.clone().unwrap_or_default();
|
||||
let tool_calls = response_msg.tool_calls.unwrap_or_default();
|
||||
let tool_calls = response_msg.tool_calls.clone().unwrap_or_default();
|
||||
|
||||
// If no tool calls, we're done — return content
|
||||
if tool_calls.is_empty() {
|
||||
@@ -229,6 +229,12 @@ pub async fn run_agent(
|
||||
return Ok(content);
|
||||
}
|
||||
|
||||
// Push the assistant message (with its tool_calls) BEFORE executing
|
||||
// so the tool-calling contract is honoured: tool results reference
|
||||
// the calls declared in the preceding assistant message. Without
|
||||
// this, the history is malformed (`[...tool, tool, assistant]`).
|
||||
messages.push(response_msg);
|
||||
|
||||
// Execute tool calls — read-only batches run concurrently (bounded,
|
||||
// order preserved); any mutating tool forces the safe sequential path.
|
||||
let results = execute_tool_batch(&tools, &tool_ctx, &tool_calls);
|
||||
@@ -266,11 +272,6 @@ pub async fn run_agent(
|
||||
|
||||
messages.push(ChatMessage::tool(id, truncate_tool_output(result)));
|
||||
}
|
||||
|
||||
// Add assistant response if there was text content
|
||||
if !content.is_empty() {
|
||||
messages.push(ChatMessage::assistant(Some(content)));
|
||||
}
|
||||
}
|
||||
|
||||
info!("Subagent reached iteration limit ({MAX_ITERATIONS})");
|
||||
|
||||
Reference in New Issue
Block a user