feat: Delivery mirroring - let agents remember what they sent#1031
feat: Delivery mirroring - let agents remember what they sent#1031TSavo wants to merge 3 commits intoopenclaw:mainfrom
Conversation
…ript Adds messages.deliveryMirror.enabled config option that mirrors delivered messages back into the session transcript as assistant messages, so the agent can 'remember' what it sent without fetching channel history. Mirroring hooks added to: - routeReply (normal agent replies) - message tool (agent tool sends) - gateway send API (with sessionKey param) Also adds cron isolation.postToMainMode='full' option for isolated cron runs to post full output (not just summary) back to main session. Includes unit tests for appendAssistantMessageToSessionTranscript helper.
There was a problem hiding this comment.
💡 Codex Review
https://github.com/clawdbot/clawdbot/blob/1713455dd7c5ccd27d3892a12b1caaf658dc0e03/src/cli/cron-cli/register.cron-add.ts#L180-L184
Wire post-mode/max-chars into cron add payload
The CLI adds --post-mode and --post-max-chars, but the isolation object only sets postToMainPrefix before calling cron.add. As a result, postToMainMode and postToMainMaxChars are never sent to the gateway, so users who pass --post-mode=full (or change max chars) will still get the default summary behavior with no warning. This makes the new flags silently ineffective for isolated jobs.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…yload Addresses Codex review feedback - the CLI options were defined but not actually passed through to the isolation object when calling cron.add.
|
Thanks! Taking over. Slopus missed some stuff :) Findings
|
|
Squashed and landed on main: 6c79964bc6c68edefc4311f05c9e50dfce814c0b. Tests: pnpm lint, pnpm build, pnpm test. |
Co-authored-by: T Savo <TSavo@users.noreply.github.com>
|
Rebased main + re-landed squash: fdaeada3e3c72ef9b4c5a2f38cf6d31a1844f765. Tests: pnpm lint, pnpm build, pnpm test. |
Heartbeat-initiated outbound messages were not being mirrored back into the session transcript, causing context confusion when users replied to heartbeat messages. The agent had no memory of what it sent. This adds the 'mirror' parameter to the deliverOutboundPayloads call in runHeartbeatOnce, matching the pattern established by openclaw#1031 for other delivery paths (routeReply, message tool, gateway send API). Fixes the case where: 1. Heartbeat triggers agent to send a message (e.g., "was machst du grad?") 2. User receives and replies to that message 3. Agent has no context about the original message it sent 4. Agent is confused about what the user is replying to Now the outbound heartbeat text/media is recorded in the session transcript, giving the agent the context it needs.
Co-authored-by: T Savo <TSavo@users.noreply.github.com>
🦞 The Problem
When Clawdbot sends a message to Discord/Slack/etc., that delivery is a side-effect that never enters the session transcript. On the next turn, the agent has no memory of what it sent — unless it fetches channel history or reads a log file.
This is particularly painful for cron jobs:
postToMainsummary is just a truncated line, not the full outputThe agent literally cannot answer "what did I just say?" without extra tooling.
💡 The Solution: Delivery Mirroring
Add a first-class
messages.deliveryMirrorconfig option that mirrors delivered messages back into the session transcript as assistant messages.{ "messages": { "deliveryMirror": { "enabled": true } } }When enabled, every successful outbound send also appends an
assistantmessage to the session transcript with the exact text that was delivered. Future turns naturally include "what I said" in context.🔧 Implementation
Mirroring hooks added at three layers (covers all send paths):
routeReply— normal agent replies after a turnmessagetool — when agents use the message tool to sendsendAPI — raw gateway sends (with optionalsessionKeyparam)Also adds
isolation.postToMainMode: "full"for cron jobs — isolated runs can now post full output (not just summary) back to the main session.Files Changed
src/config/sessions/transcript.ts— newappendAssistantMessageToSessionTranscript()helpersrc/auto-reply/reply/route-reply.ts— mirroring for normal repliessrc/agents/tools/message-tool.ts— mirroring for message toolsrc/gateway/server-methods/send.ts— mirroring for gateway APIsrc/cron/*—postToMainModeoption for isolated cron runs✅ Testing
appendAssistantMessageToSessionTranscript(5 tests, all passing)🤖 AI-Assisted
This PR was built with Claude (Opus). The implementation was tested in a Docker container with an isolated config before committing. I understand what the code does and have verified it works end-to-end.
Why this matters: Agents that can't remember what they said aren't really agents — they're stateless responders. This makes Clawdbot's cron jobs, scheduled digests, and multi-turn workflows actually coherent.