fix: use prior assistant text when LLM returns empty after tool execution

When the LLM returns both text content and tool calls in the same response,
the follow-up LLM call after tool execution sometimes returns an empty response
(the model considers the turn complete since it already provided its answer).
Track the last non-empty assistant text content and use it as a fallback
instead of the generic "model returned an empty response" error message.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mikhail Andreev (adw0rd) 2026-03-27 23:41:08 +03:00
parent ee03d1247d
commit 0041f38920

View file

@ -1689,6 +1689,7 @@ func (al *AgentLoop) runTurn(ctx context.Context, ts *turnState) (turnResult, er
activeCandidates, activeModel := al.selectCandidates(ts.agent, ts.userMessage, messages) activeCandidates, activeModel := al.selectCandidates(ts.agent, ts.userMessage, messages)
pendingMessages := append([]providers.Message(nil), ts.opts.InitialSteeringMessages...) pendingMessages := append([]providers.Message(nil), ts.opts.InitialSteeringMessages...)
var finalContent string var finalContent string
var lastAssistantTextContent string // text from last response that also had tool calls
turnLoop: turnLoop:
for ts.currentIteration() < ts.agent.MaxIterations || len(pendingMessages) > 0 || func() bool { for ts.currentIteration() < ts.agent.MaxIterations || len(pendingMessages) > 0 || func() bool {
@ -2169,6 +2170,9 @@ turnLoop:
}) })
allResponsesHandled := len(normalizedToolCalls) > 0 allResponsesHandled := len(normalizedToolCalls) > 0
if response.Content != "" {
lastAssistantTextContent = response.Content
}
assistantMsg := providers.Message{ assistantMsg := providers.Message{
Role: "assistant", Role: "assistant",
Content: response.Content, Content: response.Content,
@ -2668,6 +2672,9 @@ turnLoop:
if finalContent == "" { if finalContent == "" {
if ts.currentIteration() >= ts.agent.MaxIterations && ts.agent.MaxIterations > 0 { if ts.currentIteration() >= ts.agent.MaxIterations && ts.agent.MaxIterations > 0 {
finalContent = toolLimitResponse finalContent = toolLimitResponse
} else if lastAssistantTextContent != "" {
// LLM returned empty after tool execution but already provided text in the tool-call response
finalContent = lastAssistantTextContent
} else { } else {
finalContent = ts.opts.DefaultResponse finalContent = ts.opts.DefaultResponse
} }