Bug Summary
When a Codex-backed agent (e.g. GPT-5.5) calls the OpenClaw message(action=send) tool to deliver a progress update mid-turn, the Codex app-server treats the tool result as sufficient to release the turn. The agent announces intent, sends a progress message, and then goes completely silent — no further tool calls, no final response, no artifact written.
Reproduction
- Agent receives a task from user via Telegram
- Agent runs some bash commands (works fine)
- Agent calls
message(action=send) to send a progress update to Telegram: {"ok": true, "messageId": "9805"}
- Turn ends. No further tool calls. No final response.
- User asks "Did you complete?" → same cycle repeats
Observed in transcript (stopReason: "toolUse" on the assistant message — the model wanted to continue, but the app-server ended the turn).
Environment
- OpenClaw:
2026.7.1-beta.1 (4eb1d33)
- Agent: Stark (gpt-5.5, Codex app-server, yolo mode)
- Channel: Telegram
- Config:
turnCompletionIdleTimeoutMs: 60000 (default), postToolRawAssistantCompletionIdleTimeoutMs: 300000
Root Cause Analysis
In run-attempt (dist), the message tool is handled as a dynamic tool with a 120s timeout (CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 12e4). After the tool returns successfully:
shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response) checks response.asyncStarted !== true
- For the
message tool, the response is synchronous (ok: true, messageId: ...), so asyncStarted is not set
- This means
shouldBlockTerminalReleaseForNonTerminalDynamicToolResult returns true → sets currentTurnHadNonTerminalDynamicToolResult = true
- But then
shouldReleaseTurnAfterTerminalDynamicTool checks !state.currentTurnHadNonTerminalDynamicToolResult — which is now false
- The turn is released
The logic appears to be: synchronous dynamic tool results block the terminal-release shortcut, but the combination of currentTurnHadNonTerminalDynamicToolResult = true + no pending terminal dynamic tool + no active app-server turn requests results in the turn being released anyway via the idle watch.
The message tool should not be turn-terminal. It's a delivery mechanism, not a completion signal.
Proposed Fixes
1. Runtime fix (structural)
message(action=send) must never be turn-terminal unless the assistant has emitted a final response or an explicit terminal flag is set. The message tool is a delivery mechanism, not a completion signal. Consider either:
- Treating
message results as async for turn-completion purposes (so asyncStarted = true), or
- Adding a
turnTerminal: false flag to the message tool's response, or
- Excluding
message from the terminal-release check entirely
2. Integration test
Add a test: agent sends progress via message, then runs a bash command, writes an artifact, and sends a final message. The test should fail if the bash command or artifact never executes.
3. Stalled-turn watchdog
If a turn sends only a message tool call and then has no further tool activity or final response within 30-60s, mark it as stalled. Either auto-resume the turn or alert the user.
4. Delivery metadata distinction
Distinguish progress_message from final_delivery in OpenClaw tool metadata so Telegram delivery does not collapse the work loop. The message tool could accept an optional kind: "progress" | "final" parameter. Progress messages would be explicitly non-terminal; final messages could optionally be terminal.
Workaround Applied
- Agent-side: Instructed agent via AGENTS.md to never send progress messages mid-turn — do all work first, then send only a final summary. This prevents the bug from triggering but limits agent communication.
- Config-side: Bumped
turnCompletionIdleTimeoutMs from 60s → 300s. This is a shot in the dark — if the app-server is explicitly treating message as terminal, the timeout bump doesn't help.
Impact
This affects all Codex-backed agents that use the message tool mid-turn for progress updates. Stark (gpt-5.5) has been consistently failing on multi-step tasks because of this. Other agents (Donna, Hermione, Jack) may be affected but haven't exhibited the pattern as clearly.
Bug Summary
When a Codex-backed agent (e.g. GPT-5.5) calls the OpenClaw
message(action=send)tool to deliver a progress update mid-turn, the Codex app-server treats the tool result as sufficient to release the turn. The agent announces intent, sends a progress message, and then goes completely silent — no further tool calls, no final response, no artifact written.Reproduction
message(action=send)to send a progress update to Telegram:{"ok": true, "messageId": "9805"}Observed in transcript (
stopReason: "toolUse"on the assistant message — the model wanted to continue, but the app-server ended the turn).Environment
2026.7.1-beta.1(4eb1d33)turnCompletionIdleTimeoutMs: 60000(default),postToolRawAssistantCompletionIdleTimeoutMs: 300000Root Cause Analysis
In
run-attempt(dist), themessagetool is handled as a dynamic tool with a 120s timeout (CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 12e4). After the tool returns successfully:shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response)checksresponse.asyncStarted !== truemessagetool, the response is synchronous (ok: true, messageId: ...), soasyncStartedis not setshouldBlockTerminalReleaseForNonTerminalDynamicToolResultreturnstrue→ setscurrentTurnHadNonTerminalDynamicToolResult = trueshouldReleaseTurnAfterTerminalDynamicToolchecks!state.currentTurnHadNonTerminalDynamicToolResult— which is nowfalseThe logic appears to be: synchronous dynamic tool results block the terminal-release shortcut, but the combination of
currentTurnHadNonTerminalDynamicToolResult = true+ no pending terminal dynamic tool + no active app-server turn requests results in the turn being released anyway via the idle watch.The
messagetool should not be turn-terminal. It's a delivery mechanism, not a completion signal.Proposed Fixes
1. Runtime fix (structural)
message(action=send)must never be turn-terminal unless the assistant has emitted a final response or an explicit terminal flag is set. Themessagetool is a delivery mechanism, not a completion signal. Consider either:messageresults as async for turn-completion purposes (soasyncStarted = true), orturnTerminal: falseflag to themessagetool's response, ormessagefrom the terminal-release check entirely2. Integration test
Add a test: agent sends progress via
message, then runs a bash command, writes an artifact, and sends a final message. The test should fail if the bash command or artifact never executes.3. Stalled-turn watchdog
If a turn sends only a
messagetool call and then has no further tool activity or final response within 30-60s, mark it as stalled. Either auto-resume the turn or alert the user.4. Delivery metadata distinction
Distinguish
progress_messagefromfinal_deliveryin OpenClaw tool metadata so Telegram delivery does not collapse the work loop. Themessagetool could accept an optionalkind: "progress" | "final"parameter. Progress messages would be explicitly non-terminal; final messages could optionally be terminal.Workaround Applied
turnCompletionIdleTimeoutMsfrom 60s → 300s. This is a shot in the dark — if the app-server is explicitly treatingmessageas terminal, the timeout bump doesn't help.Impact
This affects all Codex-backed agents that use the
messagetool mid-turn for progress updates. Stark (gpt-5.5) has been consistently failing on multi-step tasks because of this. Other agents (Donna, Hermione, Jack) may be affected but haven't exhibited the pattern as clearly.