Description
When a heartbeat agent runs on a non-Anthropic model (e.g. Grok 4.1 Fast via OpenRouter) and produces an alert that gets delivered to the parent session channel, the heartbeat's tool_use blocks leak into the parent session's transcript without their corresponding tool_result blocks. The next Anthropic API call for that session then fails with:
messages.N: tool_use ids were found without tool_result blocks immediately after: callXXXXXXXX, ...
This creates a permanent corruption loop — every subsequent message to the session fails with the same error until /new or /reset is used.
Root Cause (Hypothesis)
The heartbeat runs as an embedded session and makes tool calls (e.g. sessions_list, exec) to perform monitoring. When the heartbeat produces a non-HEARTBEAT_OK response (an alert), the delivery mechanism appears to serialize the heartbeat's assistant turn — including its tool_use content blocks — into the parent session's JSONL transcript, but without the corresponding tool_result entries.
The existing repairToolUseResultPairing in transcript hygiene should synthesize missing results for Anthropic sessions, but it does not appear to catch tool calls injected via heartbeat delivery.
Additional factor: When the heartbeat model is non-Anthropic (OpenRouter/Grok), that model's transcript hygiene path has NO tool result pairing repair (only image sanitization). If the heartbeat's own session cleanup is model-dependent, orphaned tool calls may be persisted before they reach the parent session.
Steps to Reproduce
- Configure an agent with a heartbeat using a non-Anthropic model (e.g.
openrouter/x-ai/grok-4.1-fast)
- Configure the heartbeat with
target: "last" to deliver alerts to the active channel
- Have a heartbeat prompt that requires tool calls (e.g.
sessions_list for context pressure monitoring)
- Wait for the heartbeat to fire and produce an alert (not HEARTBEAT_OK)
- Send any message to the parent session
- Anthropic rejects with
tool_use ids found without tool_result blocks
- Session is permanently corrupted — every subsequent message fails
Environment
- OpenClaw 2026.3.8
- Parent session model:
anthropic/claude-opus-4-6
- Heartbeat model:
openrouter/x-ai/grok-4.1-fast
- Heartbeat config:
every: 30m, target: last, lightContext: true
- Heartbeat prompt includes
sessions_list, exec, and other tool-calling checks
Workaround
Switching the heartbeat model to an Anthropic model (e.g. anthropic/claude-haiku-4-5) appears to resolve the issue, likely because Anthropic's transcript hygiene includes tool result pairing repair.
Expected Behavior
Heartbeat tool calls should never leak into the parent session's transcript. The heartbeat's internal tool_use/tool_result pairs should be contained within its own embedded session context, with only the final text output (the alert message) delivered to the parent session.
Related Issues
Description
When a heartbeat agent runs on a non-Anthropic model (e.g. Grok 4.1 Fast via OpenRouter) and produces an alert that gets delivered to the parent session channel, the heartbeat's
tool_useblocks leak into the parent session's transcript without their correspondingtool_resultblocks. The next Anthropic API call for that session then fails with:This creates a permanent corruption loop — every subsequent message to the session fails with the same error until
/newor/resetis used.Root Cause (Hypothesis)
The heartbeat runs as an embedded session and makes tool calls (e.g.
sessions_list,exec) to perform monitoring. When the heartbeat produces a non-HEARTBEAT_OK response (an alert), the delivery mechanism appears to serialize the heartbeat's assistant turn — including itstool_usecontent blocks — into the parent session's JSONL transcript, but without the correspondingtool_resultentries.The existing
repairToolUseResultPairingin transcript hygiene should synthesize missing results for Anthropic sessions, but it does not appear to catch tool calls injected via heartbeat delivery.Additional factor: When the heartbeat model is non-Anthropic (OpenRouter/Grok), that model's transcript hygiene path has NO tool result pairing repair (only image sanitization). If the heartbeat's own session cleanup is model-dependent, orphaned tool calls may be persisted before they reach the parent session.
Steps to Reproduce
openrouter/x-ai/grok-4.1-fast)target: "last"to deliver alerts to the active channelsessions_listfor context pressure monitoring)tool_use ids found without tool_result blocksEnvironment
anthropic/claude-opus-4-6openrouter/x-ai/grok-4.1-fastevery: 30m,target: last,lightContext: truesessions_list,exec, and other tool-calling checksWorkaround
Switching the heartbeat model to an Anthropic model (e.g.
anthropic/claude-haiku-4-5) appears to resolve the issue, likely because Anthropic's transcript hygiene includes tool result pairing repair.Expected Behavior
Heartbeat tool calls should never leak into the parent session's transcript. The heartbeat's internal tool_use/tool_result pairs should be contained within its own embedded session context, with only the final text output (the alert message) delivered to the parent session.
Related Issues