Skip to content

Leaked truncation sentinels (...(truncated)... / [..., N more characters truncated]) can appear in final assistant replies #82121

@xiao398008

Description

@xiao398008

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:

  1. producer-side truncation behavior
    • tool transcript generation appends ...(truncated)...
    • some UI/log/tool outputs may produce [... N more characters truncated]

and

  1. 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:

  1. Trigger a tool result large enough to exceed tool transcript limits
  2. Let the tool transcript contain ...(truncated)...
  3. Continue the conversation or generate a final assistant reply that aggregates or reflects transcript text
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions