From 2fc9b05833e06efdbca2a16de72b1f6f201b4e63 Mon Sep 17 00:00:00 2001 From: dj-oyu <68707227+dj-oyu@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:12:08 +0900 Subject: [PATCH] fix(agent): force final LLM response when max iterations exhausted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the agent hits max_tool_iterations with tool calls still pending, make one additional LLM call without tools to force a text response instead of returning the empty default message. Also remove the user-facing "Memory threshold reached" notification from chat channels — this is an internal optimization that should only appear in logs, not in Telegram/Discord/etc. Co-Authored-By: Claude Opus 4.6 --- pkg/agent/loop.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 8b9e5c9bc..20c788627 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -761,6 +761,23 @@ func (al *AgentLoop) runLLMIteration(ctx context.Context, agent *AgentInstance, } } + // If max iterations exhausted with tool calls still pending, + // make one final LLM call without tools to force a text response. + if finalContent == "" && iteration >= agent.MaxIterations { + logger.WarnCF("agent", "Max iterations reached, forcing final response without tools", + map[string]interface{}{ + "agent_id": agent.ID, + "iteration": iteration, + }) + forceResp, forceErr := agent.Provider.Chat(ctx, messages, nil, agent.Model, map[string]interface{}{ + "max_tokens": 8192, + "temperature": 0.7, + }) + if forceErr == nil && forceResp.Content != "" { + finalContent = forceResp.Content + } + } + return finalContent, iteration, nil } @@ -795,13 +812,12 @@ func (al *AgentLoop) maybeSummarize(agent *AgentInstance, sessionKey, channel, c if _, loading := al.summarizing.LoadOrStore(summarizeKey, true); !loading { go func() { defer al.summarizing.Delete(summarizeKey) - if !constants.IsInternalChannel(channel) { - al.bus.PublishOutbound(bus.OutboundMessage{ - Channel: channel, - ChatID: chatID, - Content: "Memory threshold reached. Optimizing conversation history...", + logger.InfoCF("agent", "Memory threshold reached, optimizing conversation history", + map[string]interface{}{ + "session_key": sessionKey, + "history_len": len(newHistory), + "token_estimate": tokenEstimate, }) - } al.summarizeSession(agent, sessionKey) }() }