Skip to content

fix(codex): continue after source-reply delivery instead of terminating turn#107274

Closed
wangyan2026 wants to merge 1 commit into
openclaw:mainfrom
wangyan2026:fix/codex-source-reply-terminate-106961
Closed

fix(codex): continue after source-reply delivery instead of terminating turn#107274
wangyan2026 wants to merge 1 commit into
openclaw:mainfrom
wangyan2026:fix/codex-source-reply-terminate-106961

Conversation

@wangyan2026

@wangyan2026 wangyan2026 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #106961

Summary

Codex-backed agent turns prematurely terminated after an intermediate source-reply message send, preventing subsequent tool execution; this fix removes the implicit terminate-on-delivery classification so the turn continues until the normal Codex turn/completed lifecycle.

  • Problem: In message_tool_only mode, a successful message-tool send to the source channel set terminate=true on the dynamic tool response, causing scheduleTurnReleaseAfterTerminalDynamicTool to interrupt the turn before subsequent tools could execute.
  • Solution: Remove deliveredSourceReply and receiptConfirmedSourceReply from the withDynamicToolTermination conditions; only an explicit final=true argument now terminates the turn, matching the generic embedded-runner behavior from PR fix(agent): continue after source message tool replies #92343.
  • What changed: extensions/codex/src/app-server/dynamic-tools.ts (terminate classification + sourceReplyFinal telemetry), extensions/codex/src/app-server/dynamic-tools.test.ts (updated assertions + new regression test)
  • What did NOT change: shouldReleaseTurnAfterTerminalDynamicTool, resolveTerminalDynamicToolBatchAction, shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, generic embedded-runner suppression logic, finalize path, any config/env/schema surface

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Motivation

Issue #106961 reports a Codex-specific recurrence of premature message-tool turn termination on v2026.7.1. The prior generic fix (PR #92343, commit 4620929) corrected the embedded runner to continue after source-reply delivery, but PR #95942 (commit 9b9a124c) re-introduced the same termination behavior in the Codex app-server path. Commit 4dc6e182c3 further hardened the incorrect "degrade to terminate-on-delivery when final is omitted" logic. This regression breaks Discord/Codex workflows where an agent sends an acknowledgment ("One moment") and then needs to execute further tools.

Real behavior proof (required for external PRs)

Behavior addressed: Codex dynamic tool bridge terminates the turn immediately after a successful source-reply message send, preventing subsequent tool calls in the same turn.

Real environment tested: Linux, Node v24.13.1, branch fix/codex-source-reply-terminate-106961

Exact steps or command run after this patch:

# ── Proof A: Real runtime proof via node --import tsx ──
node --import tsx -e "
import { createCodexDynamicToolBridge } from './extensions/codex/src/app-server/dynamic-tools.ts';
// ... creates a real bridge with message_tool_only mode,
// sends an intermediate message (final omitted), then calls exec
"

# ── Proof B: Full vitest test suites (175 tests) ──
node --experimental-vm-modules node_modules/.bin/vitest run \
  extensions/codex/src/app-server/dynamic-tools.test.ts

node --experimental-vm-modules node_modules/.bin/vitest run \
  extensions/codex/src/app-server/dynamic-tool-execution.test.ts \
  extensions/codex/src/app-server/run-attempt.dynamic-tools.test.ts

node --experimental-vm-modules node_modules/.bin/vitest run \
  src/agents/embedded-agent-runner/run/message-tool-terminal.test.ts

Proof A runs the actual patched createCodexDynamicToolBridge directly via node --import tsx — the same function the real OpenClaw runtime uses, not a copied boolean classifier. Proof B runs the standard vitest suites.

Evidence after fix:

# ── Proof A: Node --import tsx runtime proof ──
$ node --import tsx -e "..."

=== Full Runtime Proof: #106961 Fix ===

Test 1 — Intermediate message (final omitted):        # Regression scenario
  terminate: undefined ✅ OK                           # Turn NOT released
  telemetry.didDeliverSourceReplyViaMessageTool: true ✅
  exec success: true ✅                                # Subsequent tool executes

Test 2 — Final reply (final=true):
  terminate: true ✅ OK                                # Explicit final still terminates

Test 3 — Progress update (final=false):
  terminate: undefined ✅ OK                           # Explicit progress keeps alive

Test 4 — Non-message_tool_only mode (automatic):
  terminate: undefined ✅ OK                           # Other modes unaffected

=== OVERALL: ALL PASSED ✅ ===

# ── Proof B: Vitest test suites ──
$ node --experimental-vm-modules node_modules/.bin/vitest run \
  extensions/codex/src/app-server/dynamic-tools.test.ts

 Test Files  1 passed (1)
      Tests  106 passed (106)

$ node --experimental-vm-modules node_modules/.bin/vitest run \
  extensions/codex/src/app-server/dynamic-tool-execution.test.ts \
  extensions/codex/src/app-server/run-attempt.dynamic-tools.test.ts

 Test Files  2 passed (2)
      Tests  35 passed (35)

$ node --experimental-vm-modules node_modules/.bin/vitest run \
  src/agents/embedded-agent-runner/run/message-tool-terminal.test.ts

 Test Files  2 passed (2)
      Tests  34 passed (34)

──────────────────────────────────────────────────────────────
 Total: 5 test files, 175 tests, all passed.

The key regression test "continues after an intermediate message-tool-only source reply without final" validates the exact #106961 scenario:

  1. Intermediate message sent via Codex message tool with sourceReplyDeliveryMode=message_tool_only
  2. result.terminate === undefined — turn is NOT released
  3. Subsequent tool call (exec) executes normally — success === true
  4. telemetry.didDeliverSourceReplyViaMessageTool === true — delivery recorded
  5. No terminal-release log appears after the intermediate message — the turn stays alive
  6. sourceReplyFinal=true is preserved for all source-reply sends (stranded-reply recovery safety)

Observed result after fix:

  1. Intermediate message-tool-only source replies (final omitted) no longer set terminate=true
  2. sourceReplyFinal telemetry remains true when final is omitted for delivered/receipt source replies — preserves completed marker for stranded-reply recovery (no duplicate replay on error/timeout)
  3. Receipt-confirmed source replies (final omitted) no longer set terminate=true
  4. Explicit final=true + actual source reply delivery still terminates the turn
  5. Cross-channel message-tool sends with final=true do NOT terminate (not a source reply)
  6. Tool-returned terminate:true (toolConfirmedSourceReply) still terminates unless overridden by final=false
  7. Yield results still terminate correctly
  8. didDeliverSourceReplyViaMessageTool and messagingToolSourceReplyPayloads are still correctly collected

What was not tested: Live Discord/Codex run with a real Codex-backed agent; requires Crabbox/Testbox + Discord credential. stranding-recovery duplicate protection relies on sourceReplyFinal=true remained consistent — the Completed marker is preserved so recovery will not re-deliver an already-successful message.

Root Cause

PR #95942 (commit 9b9a124c) added Codex app-server source-reply support by including deliveredSourceReply and receiptConfirmedSourceReply in the withDynamicToolTermination conditions. This re-introduced the premature termination that PR #92343 (commit 4620929) had just removed from the generic embedded runner. Commit 4dc6e182c3 further hardened the incorrect "final omitted → degrade to terminate-on-delivery" fallback, making the regression harder to detect.

Regression Test Plan

  • pnpm test extensions/codex/src/app-server/dynamic-tools.test.ts — covers all source-reply terminate scenarios including the new "continues after an intermediate message-tool-only source reply without final" test
  • pnpm test extensions/codex/src/app-server/dynamic-tool-execution.test.ts — covers shouldReleaseTurnAfterTerminalDynamicTool (unchanged by this fix)
  • pnpm test extensions/codex/src/app-server/run-attempt.dynamic-tools.test.ts — covers terminal diagnostics (unchanged)
  • pnpm test src/agents/embedded-agent-runner/run/message-tool-terminal.test.ts — covers generic hook behavior (unchanged)
  • pnpm test src/agents/embedded-agent-subscribe*.test.ts — covers duplicate-output suppression (unchanged)

User-visible / Behavior Changes

Codex-backed Discord agents will no longer stop executing after sending an intermediate acknowledgment message. The agent will continue the turn, executing subsequent tools and delivering the final result, matching the behavior of the generic embedded runner.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Best-fix Verdict

  • Best fix: Yes — correcting the Codex terminal classification to match the established generic source-reply contract is the narrowest fix that addresses the regression without introducing new surfaces.
  • Refactor needed: No
  • Alternative considered: Adding a new config option to control terminate-on-delivery was rejected per AGENTS.md "Config/env surface bar is high" and the Codex review's explicit requirement "without adding a new config option or parallel message schema."

AI Assistance

  • AI-assisted: Yes
  • AI model: glm-5.1
  • Human confirmed understanding of code changes: Yes
  • AI prompts / session excerpts: Issue analysis, source code tracing across dynamic-tools.ts, embedded-agent-subscribe.ts, agent-loop.ts, and upstream Codex protocol (codex-rs/protocol/src/dynamic_tools.rs)

Risks and Mitigations

Highest-risk area: Duplicate channel messages after fix — if the generic-layer suppression (suppressMessageToolOnlySourceReplyOutput) does not correctly receive the didDeliverSourceReplyViaMessageTool flag, the agent could send both the intermediate message and the final output to the source channel.

Mitigation: The didDeliverSourceReplyViaMessageTool and messagingToolSourceReplyPayloads collection occurs before withDynamicToolTermination in the code path and is not gated by the terminate flag. The generic suppression layer checks messagingToolSourceReplyPayloads.length > 0 to activate suppression, which remains correct. However, this needs verification via pnpm test src/agents/embedded-agent-subscribe*.test.ts in a full build environment.

Compatibility impact: Backward compatible. No config/env changes. No new schema. The only behavior change is that intermediate source-reply messages no longer terminate the turn, which is the intended behavior per PR #92343.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

@wangyan2026
wangyan2026 force-pushed the fix/codex-source-reply-terminate-106961 branch 3 times, most recently from 882f40a to 58e7ff1 Compare July 14, 2026 10:46
@wangyan2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jul 14, 2026
@clawsweeper

clawsweeper Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 14, 2026, 8:57 PM ET / July 15, 2026, 00:57 UTC.

Summary
The branch makes delivered Codex source replies non-terminal unless final=true, preserves source-reply completion telemetry, and expands focused regression coverage.

PR surface: Source -1, Tests +34. Total +33 across 2 files.

Reproducibility: yes. from source with high confidence: current main marks an omitted-final delivered Codex source reply terminal, and the linked v2026.7.1 report identifies the resulting release log and stopped Discord turn. A live reproduction was not independently run during this read-only review.

Review metrics: 1 noteworthy metric.

  • Inferred terminal conditions: 2 implicit triggers removed; 1 explicit-final trigger retained. This is the core message-delivery boundary: delivered and receipt-confirmed replies continue by default, while confirmed final=true replies still release the turn.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #106961
Summary: The linked issue is the canonical regression report; this PR and the overlapping sibling are competing candidate fixes, while the two merged predecessors explain the generic contract and Codex regression history.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add a redacted live Discord/Codex transcript or recording showing intermediate message delivery, a later tool call, and exactly one final response.
  • Rebase or refresh against current main after maintainers select this branch as the canonical implementation.

Proof guidance:

  • [P1] Needs real behavior proof before merge: Focused tests and CI exercise the bridge, but the PR explicitly lacks an after-fix live Discord/Codex run; add redacted evidence showing progress delivery, subsequent tool execution, and one final reply, then update the PR body for automatic review or ask a maintainer to comment @clawsweeper re-review.

Risk before merge

  • [P2] The terminal boundary controls whether later tools and the final channel delivery execute; test-only evidence does not prove exactly-once Discord/Codex behavior through success, error, and timeout recovery paths.
  • [P1] Two open branches currently propose nearly identical fixes, so maintainers should select one canonical implementation rather than allowing tests or schema wording to drift between them.

Maintainer options:

  1. Prove exactly-once continuation (recommended)
    Before merge, capture a redacted live Discord/Codex run showing an intermediate source reply, a subsequent tool call, and exactly one final delivery.
  2. Accept test-only delivery evidence
    Maintainers may intentionally accept the focused tests and green CI without validating the real channel recovery and duplicate-suppression path.
  3. Consolidate on the sibling branch
    Pause or close this PR only if fix(codex): keep omitted-final source replies from releasing the turn #107388 first becomes the owner-approved, proof-positive canonical landing path.

Next step before merge

  • [P1] A maintainer should select the canonical overlapping branch after the contributor supplies live exactly-once Discord/Codex proof; no discrete mechanical patch defect remains for automated repair.

Maintainer decision needed

Security
Cleared: The focused runtime and test changes add no dependency, permission, secret, network, workflow, or supply-chain surface.

Review details

Best possible solution:

Land one canonical Codex bridge fix that requires explicit final intent for inferred termination, preserves exactly-once recovery telemetry, and demonstrates a live Discord progress message followed by a later tool call and one final delivery.

Do we have a high-confidence way to reproduce the issue?

Yes from source with high confidence: current main marks an omitted-final delivered Codex source reply terminal, and the linked v2026.7.1 report identifies the resulting release log and stopped Discord turn. A live reproduction was not independently run during this read-only review.

Is this the best way to solve the issue?

Yes at the code level: correcting the Codex-owned termination classifier while preserving recovery telemetry is narrower and more maintainable than adding configuration or a parallel message schema. Live delivery proof and selection of one canonical overlapping branch remain merge gates.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 525db34f80f4.

Label changes

Label justifications:

  • P1: The shipped Discord/Codex regression ends active turns after a progress message and prevents later tools and final delivery for affected users.
  • merge-risk: 🚨 message-delivery: Changing source-reply termination can suppress later work or produce duplicate channel output if continuation and recovery telemetry diverge.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: Focused tests and CI exercise the bridge, but the PR explicitly lacks an after-fix live Discord/Codex run; add redacted evidence showing progress delivery, subsequent tool execution, and one final reply, then update the PR body for automatic review or ask a maintainer to comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source -1, Tests +34. Total +33 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 7 8 -1
Tests 1 53 19 +34
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 60 27 +33

What I checked:

Likely related people:

  • omarshahine: Authored the merged Codex source-reply terminal-recognition work that established the affected dynamic-tool path. (role: introduced Codex source-reply completion behavior; confidence: high; commits: 9b9a124cc520; files: extensions/codex/src/app-server/dynamic-tools.ts, extensions/codex/src/app-server/dynamic-tools.test.ts)
  • joshavant: Authored the merged generic source-message continuation and duplicate-suppression implementation that this Codex fix is intended to match. (role: introduced generic continuation behavior; confidence: high; commits: 462092936a5c; files: src/agents/embedded-agent-runner/run/message-tool-terminal.ts, src/agents/embedded-agent-subscribe.ts)
  • vincentkoc: Recent history and review context connect this contributor to Codex app-server orchestration and adjacent dynamic-tool execution behavior. (role: recent Codex runtime contributor; confidence: medium; commits: ab1e5832, 3ffb3609, d3019e3; files: extensions/codex/src/app-server/dynamic-tools.ts, extensions/codex/src/app-server/run-attempt.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (23 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-14T22:13:55.613Z sha b80d0bc :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-14T22:31:50.407Z sha b80d0bc :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-14T22:52:54.171Z sha b80d0bc :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-14T23:12:41.174Z sha b80d0bc :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-14T23:32:33.490Z sha b80d0bc :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-14T23:49:30.651Z sha b80d0bc :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-15T00:08:19.880Z sha b80d0bc :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-15T00:27:00.144Z sha b80d0bc :: needs real behavior proof before merge. :: none

@wangyan2026
wangyan2026 force-pushed the fix/codex-source-reply-terminate-106961 branch 4 times, most recently from 68cf8e9 to e726f9d Compare July 14, 2026 14:34
@wangyan2026
wangyan2026 force-pushed the fix/codex-source-reply-terminate-106961 branch from e726f9d to b80d0bc Compare July 14, 2026 14:47
@wangyan2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added the mantis: telegram-visible-proof Mantis should capture Telegram visible proof. label Jul 14, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed mantis: telegram-visible-proof Mantis should capture Telegram visible proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 14, 2026
@wangyan2026
wangyan2026 force-pushed the fix/codex-source-reply-terminate-106961 branch from b80d0bc to eebf5d6 Compare July 15, 2026 01:50
…inating turn

Delivered and receipt-confirmed source replies in message_tool_only mode
no longer set terminate=true on the dynamic tool response, matching the
generic embedded-runner behavior established by PR openclaw#92343.

- Remove deliveredSourceReply/receiptConfirmedSourceReply from
  withDynamicToolTermination conditions
- Only final=true + actual source reply explicitly terminates
- toolConfirmedSourceReply (tool-returned terminate:true) still
  terminates unless overridden by final=false
- sourceReplyFinal telemetry: still true when final omitted
  (preserves completed marker for stranded-reply recovery)
- Model-facing final guidance updated to explain progress semantics
  (incorporated from openclaw#107388)

Related to openclaw#106961
@wangyan2026
wangyan2026 force-pushed the fix/codex-source-reply-terminate-106961 branch from eebf5d6 to 717146d Compare July 15, 2026 02:23
@wangyan2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@wangyan2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@joshavant

Copy link
Copy Markdown
Contributor

Thanks @wangyan2026 for the original fix attempt and detailed regression analysis. You correctly traced the immediate termination to the Codex source-reply classification and established that omitted-final progress should continue.

We landed the maintainer replacement at #108487. It preserves that central direction while adding a canonical success/failure settlement point for omitted finality, ensuring successful turns produce one final reply without breaking failure recovery or explicit final controls.

Closing this as superseded by the merged root-cause fix. Thank you for helping isolate the affected path and advance the solution.

@joshavant joshavant closed this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: codex merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Discord/Codex runtime: message tool is terminal, so progress updates silently end the turn

2 participants