fix: remove auto-proceed fake user message injection from agent loop (#255)

The agentic loop injected fake user messages ("Please proceed and use
the available tools to complete this task.") when the LLM responded
with text instead of tool calls. This caused hallucinated conversations
during casual chat, 3x wasted LLM calls, and trust issues.

Remove the `resume_after_tool` parameter and `tools_executed` tracking
entirely. Text responses now return immediately, trusting the LLM to
decide when tools are needed (consistent with ZeroClaw and OpenClaw).

Closes #145

Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
firat.sertgoz
2026-02-20 08:09:52 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 140f29decf
commit 8a4f3b6f88
2 changed files with 2 additions and 26 deletions
-24
View File
@@ -33,16 +33,12 @@ impl Agent {
/// Returns `AgenticLoopResult::Response` on completion, or
/// `AgenticLoopResult::NeedApproval` if a tool requires user approval.
///
/// When `resume_after_tool` is true the loop already knows a tool was
/// executed earlier in this turn (e.g. an approved tool), so it won't
/// force the LLM to use tools if it responds with text.
pub(super) async fn run_agentic_loop(
&self,
message: &IncomingMessage,
session: Arc<Mutex<Session>>,
thread_id: Uuid,
initial_messages: Vec<ChatMessage>,
resume_after_tool: bool,
) -> Result<AgenticLoopResult, Error> {
// Load workspace system prompt (identity files: AGENTS.md, SOUL.md, etc.)
let system_prompt = if let Some(ws) = self.workspace() {
@@ -114,8 +110,6 @@ impl Agent {
const MAX_TOOL_ITERATIONS: usize = 10;
let mut iteration = 0;
let mut tools_executed = resume_after_tool;
loop {
iteration += 1;
if iteration > MAX_TOOL_ITERATIONS {
@@ -199,30 +193,12 @@ impl Agent {
match output.result {
RespondResult::Text(text) => {
// If no tools have been executed yet, prompt the LLM to use tools
// This handles the case where the model explains what it will do
// instead of actually calling tools
if !tools_executed && iteration < 3 {
tracing::debug!(
"No tools executed yet (iteration {}), prompting for tool use",
iteration
);
context_messages.push(ChatMessage::assistant(&text));
context_messages.push(ChatMessage::user(
"Please proceed and use the available tools to complete this task.",
));
continue;
}
// Tools have been executed or we've tried multiple times, return response
return Ok(AgenticLoopResult::Response(text));
}
RespondResult::ToolCalls {
tool_calls,
content,
} => {
tools_executed = true;
// Add the assistant message with tool_calls to context.
// OpenAI protocol requires this before tool-result messages.
context_messages.push(ChatMessage::assistant_with_tool_calls(
+2 -2
View File
@@ -278,7 +278,7 @@ impl Agent {
// Run the agentic tool execution loop
let result = self
.run_agentic_loop(message, session.clone(), thread_id, turn_messages, false)
.run_agentic_loop(message, session.clone(), thread_id, turn_messages)
.await;
// Re-acquire lock and check if interrupted
@@ -1057,7 +1057,7 @@ impl Agent {
// Continue the agentic loop (a tool was already executed this turn)
let result = self
.run_agentic_loop(message, session.clone(), thread_id, context_messages, true)
.run_agentic_loop(message, session.clone(), thread_id, context_messages)
.await;
// Handle the result