Summary
OpenClaw can leak internal truncation sentinel text into the final user-facing assistant reply, especially strings like:
...(truncated)...
[... N more characters truncated]
These appear to come from tool/transcript truncation or UI/log truncation, but they are not consistently removed before the final assistant text is shown to the user.
Observed behavior
In some conversations, final assistant replies include raw truncation markers such as:
...(truncated)...
[... N more characters truncated]
These markers look like internal tool/runtime/UI placeholders rather than user-intended content.
This is especially confusing because the assistant reply chain can end up treating those placeholders as if they were part of the semantic conversation.
Relevant code facts
1. Tool transcript truncation explicitly injects ...(truncated)...
In dist/run-attempt-DValQTsj.js:
TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 12e3
truncateToolTranscriptText(text) returns:
- original text if short enough
- otherwise:
`${text.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)}
...(truncated)...`
```
Also in the same file, createToolResultMessage(params) writes that text into the transcript-facing tool result message:
const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
...
content: text,
text
So the transcript/message layer can contain the literal sentinel ...(truncated)....
2. Final user-facing sanitization already strips some internal placeholders, but not truncation sentinels
In dist/sanitize-user-facing-text-BPNxpMKx.js, sanitizeUserFacingText() already strips several internal-only artifacts, including:
- final tags
- internal runtime context
- inbound metadata
- tool-call XML / legacy tool-call blocks
[tool calls omitted] placeholder lines
However, there is no equivalent stripping rule for:
...(truncated)...
[... N more characters truncated]
- similar truncation placeholder lines
This suggests the final sanitization layer is missing a guard for truncation sentinels.
Suspected root cause
There seems to be a mismatch between:
- producer-side truncation behavior
- tool transcript generation appends
...(truncated)...
- some UI/log/tool outputs may produce
[... N more characters truncated]
and
- consumer-side final text sanitization
- current sanitization removes several internal placeholders
- but does not remove truncation sentinels before user-visible final text is emitted
As a result, truncation placeholders can travel through the transcript/reply chain and show up in the final assistant message.
Impact
- Degrades reply quality and professionalism
- Exposes internal implementation details to end users
- Can pollute downstream reasoning/context if later turns treat those markers as normal text
- May affect more than one source path:
- Codex tool transcript truncation
- UI/log truncation placeholders
- possibly other text aggregation paths
Suggested fix direction
Recommended minimal hotfix
Add truncation-sentinel stripping to sanitizeUserFacingText() in dist/sanitize-user-facing-text-BPNxpMKx.js, similar to the existing [tool calls omitted] handling.
Recommended behavior:
- remove truncation placeholders only when they appear as:
- a standalone line, or
- a trailing standalone block at the end of the message
Target patterns:
...(truncated)...
[... N more characters truncated]
- optionally
...<truncated>
This keeps the fix narrow and reduces false positives, because it will not remove normal prose ellipses.
Narrower alternative
Instead of (or in addition to) final sanitization, remove the sentinel at the producer side in run-attempt-DValQTsj.js, for example by:
- changing
truncateToolTranscriptText() to truncate without appending ...(truncated)..., or
- stripping that sentinel inside
createToolResultMessage() before storing transcript-visible tool result text
However, this would only fix one source path and would not catch other truncation placeholders like [... N more characters truncated].
Why this is likely the right minimal fix
The final sanitization layer is already the central place where internal-only artifacts are removed from user-visible text. Truncation sentinels are the same category of artifact, so adding them there is consistent with the existing architecture and provides a broader safety net.
Repro hints
A likely repro path is:
- Trigger a tool result large enough to exceed tool transcript limits
- Let the tool transcript contain
...(truncated)...
- Continue the conversation or generate a final assistant reply that aggregates or reflects transcript text
- Observe the truncation marker appear in the final user-facing reply
A second repro path may involve any UI/log/tool path that injects:
[... N more characters truncated]
and then lets that text flow into assistant-visible content without final sanitization.
Summary
OpenClaw can leak internal truncation sentinel text into the final user-facing assistant reply, especially strings like:
...(truncated)...[... N more characters truncated]These appear to come from tool/transcript truncation or UI/log truncation, but they are not consistently removed before the final assistant text is shown to the user.
Observed behavior
In some conversations, final assistant replies include raw truncation markers such as:
...(truncated)...[... N more characters truncated]These markers look like internal tool/runtime/UI placeholders rather than user-intended content.
This is especially confusing because the assistant reply chain can end up treating those placeholders as if they were part of the semantic conversation.
Relevant code facts
1. Tool transcript truncation explicitly injects
...(truncated)...In
dist/run-attempt-DValQTsj.js:TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 12e3truncateToolTranscriptText(text)returns:`${text.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)}...(truncated)...`
```
Also in the same file,
createToolResultMessage(params)writes that text into the transcript-facing tool result message:So the transcript/message layer can contain the literal sentinel
...(truncated)....2. Final user-facing sanitization already strips some internal placeholders, but not truncation sentinels
In
dist/sanitize-user-facing-text-BPNxpMKx.js,sanitizeUserFacingText()already strips several internal-only artifacts, including:[tool calls omitted]placeholder linesHowever, there is no equivalent stripping rule for:
...(truncated)...[... N more characters truncated]This suggests the final sanitization layer is missing a guard for truncation sentinels.
Suspected root cause
There seems to be a mismatch between:
...(truncated)...[... N more characters truncated]and
As a result, truncation placeholders can travel through the transcript/reply chain and show up in the final assistant message.
Impact
Suggested fix direction
Recommended minimal hotfix
Add truncation-sentinel stripping to
sanitizeUserFacingText()indist/sanitize-user-facing-text-BPNxpMKx.js, similar to the existing[tool calls omitted]handling.Recommended behavior:
Target patterns:
...(truncated)...[... N more characters truncated]...<truncated>This keeps the fix narrow and reduces false positives, because it will not remove normal prose ellipses.
Narrower alternative
Instead of (or in addition to) final sanitization, remove the sentinel at the producer side in
run-attempt-DValQTsj.js, for example by:truncateToolTranscriptText()to truncate without appending...(truncated)..., orcreateToolResultMessage()before storing transcript-visible tool result textHowever, this would only fix one source path and would not catch other truncation placeholders like
[... N more characters truncated].Why this is likely the right minimal fix
The final sanitization layer is already the central place where internal-only artifacts are removed from user-visible text. Truncation sentinels are the same category of artifact, so adding them there is consistent with the existing architecture and provides a broader safety net.
Repro hints
A likely repro path is:
...(truncated)...A second repro path may involve any UI/log/tool path that injects:
[... N more characters truncated]and then lets that text flow into assistant-visible content without final sanitization.