TLDR
Codex harness defaults direct source-visible replies to message_tool, which is correct for many external direct-chat routes, but it is wrong for internal WebChat sessions. WebChat is an internal/non-deliverable channel, so a direct WebChat turn can suppress the normal final reply path and steer the model toward message(action=send). The user-visible symptom is a private/tool-send style response such as Sent. instead of the actual answer in the WebChat thread.
Impact
Product impact: P2 if WebChat/direct local OpenClaw sessions are run through Codex by default. Users can lose the visible answer for a normal direct WebChat turn even though the model completed the request.
QA impact: P1 for Codex runtime confidence, because this is exactly the class of first-hour local gateway behavior the runtime parity harness should catch: the wrong delivery layer is selected even though the model/runtime may otherwise be healthy.
What is wrong
extensions/codex/harness.ts sets deliveryDefaults.sourceVisibleReplies = "message_tool" for the Codex harness. dispatch-from-config applies that harness default when direct-chat messages.visibleReplies is unset. For WebChat/internal direct sessions, that default is unsafe because WebChat is not an outbound delivery target for message(action=send).
This is not a request to expose duplicate OpenClaw dynamic workspace tools in Codex. It is a product delivery-policy bug: internal WebChat source replies should stay on the automatic final-reply path.
Evidence
Local beta.5 session logs showed a direct WebChat/Codex turn using message(action=send) and then producing a visible Sent. final reply rather than the substantive answer. Source inspection matches the behavior:
extensions/codex/harness.ts defines the Codex harness default as sourceVisibleReplies: "message_tool".
src/auto-reply/reply/dispatch-from-config.ts applies harness defaults for direct source-visible replies when config is unset.
src/utils/message-channel-constants.ts defines WebChat as the internal message channel.
src/infra/outbound/targets-resolve-shared.ts rejects WebChat as an outbound delivery target.
Reproduction
A focused regression test reproduces the policy mismatch:
- Register a Codex harness with
deliveryDefaults.sourceVisibleReplies = "message_tool".
- Create a direct WebChat context with
Provider, Surface, and OriginatingChannel set to webchat.
- Leave
messages.visibleReplies unset.
- Dispatch a normal reply.
- Expected:
sourceReplyDeliveryMode is automatic and the final reply is queued to WebChat.
- Actual before fix: the harness default can select
message_tool_only, suppressing automatic final delivery.
Proposed fix
Ignore harness sourceVisibleReplies: "message_tool" defaults for internal WebChat source contexts. Keep the Codex harness default for external direct-chat routes where the message tool is the intended visible-reply path.
Validation
Focused local validation on a Lexar-backed checkout:
VITEST_MAX_WORKERS=1 pnpm test src/auto-reply/reply/dispatch-from-config.test.ts -- -t "keeps internal webchat"
VITEST_MAX_WORKERS=1 pnpm test src/auto-reply/reply/dispatch-from-config.test.ts
Both passed locally.
TLDR
Codex harness defaults direct source-visible replies to
message_tool, which is correct for many external direct-chat routes, but it is wrong for internal WebChat sessions. WebChat is an internal/non-deliverable channel, so a direct WebChat turn can suppress the normal final reply path and steer the model towardmessage(action=send). The user-visible symptom is a private/tool-send style response such asSent.instead of the actual answer in the WebChat thread.Impact
Product impact: P2 if WebChat/direct local OpenClaw sessions are run through Codex by default. Users can lose the visible answer for a normal direct WebChat turn even though the model completed the request.
QA impact: P1 for Codex runtime confidence, because this is exactly the class of first-hour local gateway behavior the runtime parity harness should catch: the wrong delivery layer is selected even though the model/runtime may otherwise be healthy.
What is wrong
extensions/codex/harness.tssetsdeliveryDefaults.sourceVisibleReplies = "message_tool"for the Codex harness.dispatch-from-configapplies that harness default when direct-chatmessages.visibleRepliesis unset. For WebChat/internal direct sessions, that default is unsafe because WebChat is not an outbound delivery target formessage(action=send).This is not a request to expose duplicate OpenClaw dynamic workspace tools in Codex. It is a product delivery-policy bug: internal WebChat source replies should stay on the automatic final-reply path.
Evidence
Local beta.5 session logs showed a direct WebChat/Codex turn using
message(action=send)and then producing a visibleSent.final reply rather than the substantive answer. Source inspection matches the behavior:extensions/codex/harness.tsdefines the Codex harness default assourceVisibleReplies: "message_tool".src/auto-reply/reply/dispatch-from-config.tsapplies harness defaults for direct source-visible replies when config is unset.src/utils/message-channel-constants.tsdefines WebChat as the internal message channel.src/infra/outbound/targets-resolve-shared.tsrejects WebChat as an outbound delivery target.Reproduction
A focused regression test reproduces the policy mismatch:
deliveryDefaults.sourceVisibleReplies = "message_tool".Provider,Surface, andOriginatingChannelset towebchat.messages.visibleRepliesunset.sourceReplyDeliveryModeisautomaticand the final reply is queued to WebChat.message_tool_only, suppressing automatic final delivery.Proposed fix
Ignore harness
sourceVisibleReplies: "message_tool"defaults for internal WebChat source contexts. Keep the Codex harness default for external direct-chat routes where themessagetool is the intended visible-reply path.Validation
Focused local validation on a Lexar-backed checkout:
Both passed locally.