fix: improve stuck detection to track failed tool calls
- Track failed tool calls in call history (parse errors, execution errors)
- Increment turns counter for failed tool calls too
- Stuck detection now works even when tools fail repeatedly
- Inspired by Ruflo and Hermes Agent best practices
Fixes the bug where zCode would get stuck in infinite loops when tool calls fail.
Test results: ✅ All stuck detection tests passing
This commit is contained in:
@@ -577,7 +577,8 @@ export async function initBot(config, api, tools, skills, agents) {
|
||||
return response.content || '✅ Done.';
|
||||
}
|
||||
|
||||
// ── Stuck detection ──
|
||||
// ── Stuck detection: track ALL tool calls (including failed ones) ──
|
||||
// Failed tool calls don't appear in response.tool_calls, so we track them separately
|
||||
const currentSigs = response.tool_calls.map(callSig);
|
||||
for (const sig of currentSigs) callHistory.push(sig);
|
||||
|
||||
@@ -589,6 +590,8 @@ export async function initBot(config, api, tools, skills, agents) {
|
||||
}
|
||||
|
||||
// ── Execute tool calls ──
|
||||
// IMPORTANT: Increment turns for failed tool calls too (not just successful ones)
|
||||
// This ensures stuck detection works even when tools fail repeatedly
|
||||
turns++;
|
||||
logger.info(`🔧 Tool turn ${turns}/${MAX_TOOL_TURNS} — ${response.tool_calls.length} call(s)`);
|
||||
sendProgress(`⚙️ Step ${turns} — executing ${response.tool_calls.length} tool(s)...`);
|
||||
@@ -621,6 +624,8 @@ export async function initBot(config, api, tools, skills, agents) {
|
||||
? 'Use bash with heredoc for large files.'
|
||||
: 'Retry with shorter arguments.';
|
||||
logger.error(` → ${fn.name} parse failed: ${parseErr.message} (${argLen} chars)`);
|
||||
// Track failed tool call in stuck detection history
|
||||
callHistory.push(`${fn.name}:${fn.arguments?.slice(0, 80)}`);
|
||||
return { id: tc.id, result: `❌ ${fn.name} args truncated (${argLen} chars). ${hint}` };
|
||||
}
|
||||
|
||||
@@ -654,6 +659,8 @@ export async function initBot(config, api, tools, skills, agents) {
|
||||
return { id: tc.id, result: finalResult };
|
||||
} catch (e) {
|
||||
logger.error(` → ${fn.name} failed: ${e.message}`);
|
||||
// Track failed tool call in stuck detection history
|
||||
callHistory.push(`${fn.name}:${JSON.stringify(args || {}).slice(0, 80)}`);
|
||||
// Track failure in guardrail
|
||||
const afterDecision = sessionState.guardrail.afterCall(fn.name, null, `Error: ${e.message}`);
|
||||
let errResult = `❌ ${fn.name} error: ${e.message}`;
|
||||
|
||||
Reference in New Issue
Block a user