← Back to PRs

#21174: fix(bluebubbles): trim leading newlines from message text

by cosmopax open 2026-02-19 19:05 View on GitHub →
channel: bluebubbles size: XS
## Summary Describe the problem and fix in 2–5 bullets: - Problem: iMessage bubbles sent via BlueBubbles often contain unsightly leading newlines, especially when the response follows a tool call or is constructed from multiple blocks. - Why it matters: This creates empty vertical space at the top of messages, degrading the reading experience o iOS/macOS. - What changed: Applied `.trimStart()` in three key locations: 1. The `BlockReplyCoalescer` (to strip artifacts during message assembly). 2. The BlueBubbles `send.ts` adapter (defensive trimming). 3. The BlueBubbles `channel.ts` outbound handler (final safeguard). - What did NOT change (scope boundary): Strictly limits changes to whitespace handling in the BlueBubbles extension and the reply coalescer; no logic changes to message routing. ## Change Type (select all) - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [x] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [ ] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR - Closes #12770 - Related # ## User-visible / Behavior Changes List user-visible changes (including defaults/config). If none, write `None`. - Messages sent via the BlueBubbles channel will no longer have leading blank lines/whitespace, especially when following tool outputs. - Reply blocks will be coalesced more cleanly without redundant newlines. ## Security Impact (required) - New permissions/capabilities? (`Yes/No`) No - Secrets/tokens handling changed? (`Yes/No`) No - New/changed network calls? (`Yes/No`) No - Command/tool execution surface changed? (`Yes/No`)No - Data access scope changed? (`Yes/No`) No - If any `Yes`, explain risk + mitigation: None ## Repro + Verification ### Environment - OS: macOS - Runtime/container: Node.js 22+ - Model/provider: Any LLM, model-agnostic whitespace handling. - Integration/channel (if any): BlueBubbles - Relevant config (redacted): None ### Steps 1. Configure BlueBubbles channel. 2. Trigger a response that includes a tool call followed by text (which often outputs a leading newline). 3. Observe the message bubble in iMessage. ### Expected -- The message text starts immediately at the top of the bubble. ### Actual -The message text starts after one or more blank lines. ## Evidence Attach at least one: - [ ] Failing test/log before + passing after - [x] Trace/log snippets - [ ] Screenshot/recording - [ ] Perf numbers (if relevant) ### "Verified with a reproduction script that mocks the BlockReplyCoalescer. The log shows that the second block (which started with \n\n) was correctly trimmed before being joined." ### ```text Simulating: Block 1 (e.g. tool output) followed by Block 2 (text with leading newlines)... --- FLUSHED PAYLOAD --- Payload Text: "Some tool output...\n\nHere is the result of your request." PASS: Payload joined correctly with standard joiner (\n\n). ----------------------- ``` ## Human Verification (required) What you personally verified (not just CI), and how: - Verified scenarios: Checked that sendMessageBlueBubbles correctly trims input strings. Verified that BlockReplyCoalescer trims text segments before joining. - Edge cases checked: Empty strings, strings with only whitespace (handled by existing logic + new trim), standard text messages. - What you did **not** verify: Full end-to-end BlueBubbles server interaction (mocked/unit tested logic). - ## Compatibility / Migration - Backward compatible? (`Yes/No`) Yes - Config/env changes? (`Yes/No`) No - Migration needed? (`Yes/No`) No - If yes, exact upgrade steps: None ## Failure Recovery (if this breaks) - How to disable/revert this change quickly: Revert the commit. - Files/config to restore: extensions/bluebubbles/src/channel.ts, extensions/bluebubbles/src/send.ts, src/auto-reply/reply/block-reply-coalescer.ts - Known bad symptoms reviewers should watch for: Messages appearing "glued together" if the joiner logic fails (unlikely given testing). ## Risks and Mitigations List only real risks for this PR. Add/remove entries as needed. If none, write `None`. - Risk: None - Mitigation: None <!-- greptile_comment --> <h3>Greptile Summary</h3> Trims leading whitespace (spaces, tabs, newlines) from BlueBubbles message text before sending. The change prevents messages with leading newlines from appearing with unwanted blank lines at the start. - Changed `text` to `text.trimStart()` in `channel.ts:317` when calling `sendMessageBlueBubbles` - Changed `text ?? ""` to `(text ?? "").trimStart()` in `send.ts:325` inside `sendMessageBlueBubbles` - Changed concatenated text to `text.trimStart()` in `block-reply-coalescer.ts:117` when coalescing message chunks The fix is applied consistently across the BlueBubbles channel and shared reply coalescer, matching the pattern used in other channels like iMessage (`src/imessage/send.ts:75`, `src/imessage/send.ts:78`) and Signal (`src/signal/format.ts:329`). <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - The change is straightforward, well-scoped, and follows established patterns in the codebase. `trimStart()` is applied consistently across three related locations. The logic handles empty text correctly (checks `trimmedText.trim()` after trimming), and subsequent markdown stripping ensures messages like "***" don't become empty. The pattern matches existing usage in iMessage and Signal channels. - No files require special attention <sub>Last reviewed commit: 4a2fbe5</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs