From 862b10aa05ef66af5a88f307e6209ce10185bbcf Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Fri, 12 Dec 2025 21:45:53 -0500 Subject: fix: prompt for text response when agent returns empty after tool calls When the LLM returned empty content after executing tools, the agent would complete with an empty message. Now both agent loops (LLM-based and Provider-based) detect this case and inject a prompt asking the LLM to provide a response to the user. --- Omni/Agent/Engine.hs | 60 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 24 deletions(-) (limited to 'Omni') diff --git a/Omni/Agent/Engine.hs b/Omni/Agent/Engine.hs index fe3b3d5..dab1329 100644 --- a/Omni/Agent/Engine.hs +++ b/Omni/Agent/Engine.hs @@ -667,18 +667,24 @@ runAgent engineCfg agentCfg userPrompt = do unless (Text.null assistantText) <| engineOnAssistant engineCfg assistantText case msgToolCalls msg of - Nothing -> do - engineOnActivity engineCfg "Agent completed" - engineOnComplete engineCfg - pure - <| Right - <| AgentResult - { resultFinalMessage = msgContent msg, - resultToolCallCount = totalCalls, - resultIterations = iteration + 1, - resultTotalCost = newCost, - resultTotalTokens = newTokens - } + Nothing + | Text.null (msgContent msg) && totalCalls > 0 -> do + engineOnActivity engineCfg "Empty response after tools, prompting for text" + let promptMsg = Message ToolRole "Please provide a response to the user." Nothing Nothing + newMsgs = msgs <> [msg, promptMsg] + loop llm tools' toolMap newMsgs (iteration + 1) totalCalls newTokens newCost toolCallCounts testFailures editFailures + | otherwise -> do + engineOnActivity engineCfg "Agent completed" + engineOnComplete engineCfg + pure + <| Right + <| AgentResult + { resultFinalMessage = msgContent msg, + resultToolCallCount = totalCalls, + resultIterations = iteration + 1, + resultTotalCost = newCost, + resultTotalTokens = newTokens + } Just [] -> do engineOnActivity engineCfg "Agent completed (empty tool calls)" engineOnComplete engineCfg @@ -886,18 +892,24 @@ runAgentWithProvider engineCfg provider agentCfg userPrompt = do unless (Text.null assistantText) <| engineOnAssistant engineCfg assistantText case Provider.msgToolCalls msg of - Nothing -> do - engineOnActivity engineCfg "Agent completed" - engineOnComplete engineCfg - pure - <| Right - <| AgentResult - { resultFinalMessage = Provider.msgContent msg, - resultToolCallCount = totalCalls, - resultIterations = iteration + 1, - resultTotalCost = newCost, - resultTotalTokens = newTokens - } + Nothing + | Text.null (Provider.msgContent msg) && totalCalls > 0 -> do + engineOnActivity engineCfg "Empty response after tools, prompting for text" + let promptMsg = Provider.Message Provider.ToolRole "Please provide a response to the user." Nothing Nothing + newMsgs = msgs <> [msg, promptMsg] + loopProvider prov toolApis' toolMap newMsgs (iteration + 1) totalCalls newTokens newCost toolCallCounts testFailures editFailures + | otherwise -> do + engineOnActivity engineCfg "Agent completed" + engineOnComplete engineCfg + pure + <| Right + <| AgentResult + { resultFinalMessage = Provider.msgContent msg, + resultToolCallCount = totalCalls, + resultIterations = iteration + 1, + resultTotalCost = newCost, + resultTotalTokens = newTokens + } Just [] -> do engineOnActivity engineCfg "Agent completed (empty tool calls)" engineOnComplete engineCfg -- cgit v1.2.3