Summary
The inbound System: system-event preview truncates the user's message body at 160 characters, and in the runtime-context injection path it is emitted without a trailing separator, so the truncated line runs straight into the following Conversation info (untrusted metadata) block. This was reported in #67503 (closed for inactivity) with fix PR #67761 (closed unmerged as superseded). The close note on #67503 asked for a fresh issue if it still reproduces on the latest release. It does, on 2026.6.1, with live evidence below, and the relevant code has moved from the per-extension handlers into a shared module (likely why #67761 was marked superseded).
Still reproduces on 2026.6.1
Captured from the actual model-facing prompt for a Slack DM longer than 160 characters. The body reaches the model up to three times: once in a standalone runtime-context message, and twice in the turn message (truncated header + full body).
(runtime-context message)
OpenClaw runtime context for the immediately preceding user message.
...
System: [2026-06-18 12:05 GMT+3] Slack DM from <user>: Hey, can you pull together a quick summary of the deployment we discussed yesterday and include the rollback steps, the health checks we ran, and the follow-u
(turn message)
Conversation info (untrusted metadata):
```json
{ ... }
```
System: [2026-06-18 12:05 GMT+3] Slack DM from <user>: Hey, can you pull together a quick summary of the deployment we discussed yesterday and include the rollback steps, the health checks we ran, and the follow-u
Hey, can you pull together a quick summary of the deployment we discussed yesterday and include the rollback steps, the health checks we ran, and the follow-up items so I can forward it on?
The first System: line ends at exactly 160 characters (cut mid-word, no ellipsis, no trailing newline), so the runtime-context message abuts Conversation info.
Intended vs defect
The 160-char preview itself is intentional (a short notification snippet). The defects are:
- The runtime-context preview block is emitted with no trailing separator, so the truncated
System: line fuses into the next block. (The in-turn copy is correctly separated, because that path joins with a blank line.)
- The body is echoed two to three times per channel turn. Webchat is unaffected (no envelope or preview).
Current code locations (2026.6.1)
The extensions/slack/.../prepare.ts path cited in #67503 and #67761 has been refactored into a shared module:
- Per-channel preview:
const preview = rawBody.replace(/\s+/g, " ").slice(0, 160) then enqueueSystemEvent(${inboundLabel}: ${preview}, ...) (same shape across the Slack, Teams, and Feishu handlers).
-
drainFormattedSystemEvents builds the System: [ts] <line> entries and returns systemLines.join("\n") with no trailing terminator.
- Consumers:
buildCurrentInboundPrompt joins the block with the prompt using a blank line (in-turn copy separated correctly), whereas buildRuntimeContextMessageContent emits the runtime-context message ending on the unterminated block.
Suggested fix
PR #67761's approach still applies and is the cleanest: drop the message body from the system event, keeping enqueueSystemEvent(inboundLabel, ...) as a notification-only header. That removes the truncation, the fusion, and the redundant echo together. If the preview is kept, it should at minimum be terminated with a separator and cut on a word boundary (the env-value truncator appends an ellipsis; the inbound preview does not).
Related
Environment
- OpenClaw 2026.6.1, Linux, Node 24, host-native
- Observed on Slack DM; the same
enqueueSystemEvent preview pattern exists across channel handlers per source.
Summary
The inbound
System:system-event preview truncates the user's message body at 160 characters, and in the runtime-context injection path it is emitted without a trailing separator, so the truncated line runs straight into the followingConversation info (untrusted metadata)block. This was reported in #67503 (closed for inactivity) with fix PR #67761 (closed unmerged as superseded). The close note on #67503 asked for a fresh issue if it still reproduces on the latest release. It does, on 2026.6.1, with live evidence below, and the relevant code has moved from the per-extension handlers into a shared module (likely why #67761 was marked superseded).Still reproduces on 2026.6.1
Captured from the actual model-facing prompt for a Slack DM longer than 160 characters. The body reaches the model up to three times: once in a standalone runtime-context message, and twice in the turn message (truncated header + full body).
The first
System:line ends at exactly 160 characters (cut mid-word, no ellipsis, no trailing newline), so the runtime-context message abutsConversation info.Intended vs defect
The 160-char preview itself is intentional (a short notification snippet). The defects are:
System:line fuses into the next block. (The in-turn copy is correctly separated, because that path joins with a blank line.)Current code locations (2026.6.1)
The
extensions/slack/.../prepare.tspath cited in #67503 and #67761 has been refactored into a shared module:const preview = rawBody.replace(/\s+/g, " ").slice(0, 160)thenenqueueSystemEvent(${inboundLabel}: ${preview}, ...)(same shape across the Slack, Teams, and Feishu handlers).drainFormattedSystemEventsbuilds theSystem: [ts] <line>entries and returnssystemLines.join("\n")with no trailing terminator.buildCurrentInboundPromptjoins the block with the prompt using a blank line (in-turn copy separated correctly), whereasbuildRuntimeContextMessageContentemits the runtime-context message ending on the unterminated block.Suggested fix
PR #67761's approach still applies and is the cleanest: drop the message body from the system event, keeping
enqueueSystemEvent(inboundLabel, ...)as a notification-only header. That removes the truncation, the fusion, and the redundant echo together. If the preview is kept, it should at minimum be terminated with a separator and cut on a word boundary (the env-value truncator appends an ellipsis; the inbound preview does not).Related
Environment
enqueueSystemEventpreview pattern exists across channel handlers per source.