fix: trim leading blank lines on first emitted chunk only (#5530)#10612
fix: trim leading blank lines on first emitted chunk only (#5530)#106121kuna wants to merge 1 commit intoopenclaw:mainfrom
Conversation
263309d to
a3ea5b5
Compare
Additional Comments (2)
This PR changes several Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! Prompt To Fix With AIThis is a comment left during a code review.
Path: package.json
Line: 113:120
Comment:
**Caret dependency range**
This PR changes several `@mariozechner/pi-*` dependencies from exact `0.52.6` to `^0.52.6`. That makes installs non-reproducible and can pull in newer versions with API/behavior changes, which is particularly risky here since the PR also relies on `setAutoCompactionRetryHook`/internal session fields. If the intent is just to pick up the current version, keep these pinned to an exact version instead of a caret range.
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/attempt.ts
Line: 523:534
Comment:
**Restoring internal session fields**
`downgradeSystemPromptOneShot()` captures `previousBasePrompt`/`previousRebuild` from `mutableSession._baseSystemPrompt` and later restores them, but those fields are not guaranteed to exist. When they were originally `undefined`, the restore callback sets them back to `undefined` (explicitly), which can change session behavior vs leaving the properties unset (and may break `_rebuildSystemPrompt` lookups if the library expects absence vs undefined). Since this code is intentionally poking internal/private fields, the restore should avoid writing the properties back when they were not present originally (or use the session’s public API only).
How can I resolve this? If you propose a fix, please make it concise. |
a3ea5b5 to
6f5f4ee
Compare
6f5f4ee to
24635ee
Compare
LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths.
LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths.
) * fix: strip leading whitespace from sanitizeUserFacingText output LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as #8052 and #10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths. * Changelog: note sanitizeUserFacingText whitespace normalization Co-authored-by: Tak Hoffman <[email protected]> --------- Co-authored-by: Tak Hoffman <[email protected]>
…nclaw#16158) * fix: strip leading whitespace from sanitizeUserFacingText output LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths. * Changelog: note sanitizeUserFacingText whitespace normalization Co-authored-by: Tak Hoffman <[email protected]> --------- Co-authored-by: Tak Hoffman <[email protected]>
…nclaw#16158) * fix: strip leading whitespace from sanitizeUserFacingText output LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths. * Changelog: note sanitizeUserFacingText whitespace normalization Co-authored-by: Tak Hoffman <[email protected]> --------- Co-authored-by: Tak Hoffman <[email protected]>
…nclaw#16158) * fix: strip leading whitespace from sanitizeUserFacingText output LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths. * Changelog: note sanitizeUserFacingText whitespace normalization Co-authored-by: Tak Hoffman <[email protected]> --------- Co-authored-by: Tak Hoffman <[email protected]>
bfc1ccb to
f92900f
Compare
|
This pull request has been automatically marked as stale due to inactivity. |
|
Closing as AI-assisted stale-fix triage. Linked issue #5530 ("iMessage: leading blank lines in streamed messages") is currently CLOSED and was closed on 2026-02-13T03:32:44Z with state reason NOT_PLANNED. If the underlying bug is still reproducible on current main, please reopen this PR (or open a new focused fix PR) and reference both #5530 and #10612 for fast re-triage. |
|
Closed after AI-assisted stale-fix triage (closed issue duplicate/stale fix). |
…nclaw#16158) * fix: strip leading whitespace from sanitizeUserFacingText output LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths. * Changelog: note sanitizeUserFacingText whitespace normalization Co-authored-by: Tak Hoffman <[email protected]> --------- Co-authored-by: Tak Hoffman <[email protected]> (cherry picked from commit 3881af5) # Conflicts: # CHANGELOG.md
…nclaw#16158) * fix: strip leading whitespace from sanitizeUserFacingText output LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths. * Changelog: note sanitizeUserFacingText whitespace normalization Co-authored-by: Tak Hoffman <[email protected]> --------- Co-authored-by: Tak Hoffman <[email protected]> (cherry picked from commit 3881af5) # Conflicts: # CHANGELOG.md # src/agents/pi-embedded-helpers/errors.ts
…nclaw#16158) * fix: strip leading whitespace from sanitizeUserFacingText output LLM responses frequently begin with \n\n, which survives through sanitizeUserFacingText and reaches the channel as visible blank lines. Root cause: the function used trimmed text for empty-checks but returned the untrimmed 'stripped' variable. Two one-line fixes: 1. Return empty string (not whitespace-only 'stripped') for blank input 2. Apply trimStart() to the final return value Fixes the same issue as openclaw#8052 and openclaw#10612 but at the root cause (sanitizeUserFacingText) rather than scattering trimStart across multiple delivery paths. * Changelog: note sanitizeUserFacingText whitespace normalization Co-authored-by: Tak Hoffman <[email protected]> --------- Co-authored-by: Tak Hoffman <[email protected]>
Problem
Anthropic models emit a
"\n\n"text block before thinking blocks. The existing.trimEnd()inemitBlockChunkonly strips trailing whitespace, so leading newlines pass through to iMessage output as blank lines before the agent's response.Root Cause
emitBlockChunk):stripBlockTags(text, state.blockState).trimEnd()preserves leading\n\n.sanitizeUserFacingText):collapseConsecutiveDuplicateBlocks()returnstext(untrimmed) whenblocks.length < 2.Fix
Targeted first-chunk-only trim instead of the broader
.trim()on every chunk (which risks stripping meaningful indentation at chunk boundaries):emitBlockChunk(streaming path)Only the first emitted chunk (when
lastBlockReplyTextis stillundefined) gets leading blank lines stripped. Subsequent chunks use.trimEnd()as before, preserving indentation in code blocks.sanitizeUserFacingText(final text path)Strips leading blank lines after removing
<final>tags but before error detection and collapse logic.Why
/^(?:[ \t]*\n)+/instead of.trim()\n\n indented code→indented code)Testing
sanitizeUserFacingTextverifying leading blank line strippingSupersedes #9285. Closes #5530.
Greptile Overview
Greptile Summary
\n\nshowing up as empty lines), while keeping.trimEnd()behavior for subsequent chunks.sanitizeUserFacingText()to strip leading blank lines after removing<final>tags and adds a unit test covering this behavior.Confidence Score: 3/5