Skip to content

fix(discord): propagate blockquote context across chunk boundaries#63412

Open
extrasmall0 wants to merge 2 commits intoopenclaw:mainfrom
extrasmall0:raymond/fix-discord-blockquote-chunking
Open

fix(discord): propagate blockquote context across chunk boundaries#63412
extrasmall0 wants to merge 2 commits intoopenclaw:mainfrom
extrasmall0:raymond/fix-discord-blockquote-chunking

Conversation

@extrasmall0
Copy link
Copy Markdown
Contributor

Summary

Fixes #63409

When chunkDiscordText() flushed a chunk in the middle of a blockquote, the next chunk started without the leading > prefix. Discord renders each message independently, so continuation lines appeared as plain text outside the quote block.

Root cause

The chunker already tracks fenced code block state (openFence) and re-seeds the next chunk with the opening fence line on flush. The same treatment was never applied to blockquote prefixes.

Fix

Track the current blockquote prefix (openBlockquote) using the same pattern:

// On flush, re-seed the next chunk with the blockquote prefix
if (openBlockquote && !openFence) {
  current = openBlockquote;
  currentLines = 1;
}

A BLOCKQUOTE_RE helper extracts the prefix including nested levels (> , >> , etc.). The prefix is updated on each line and cleared when a non-blockquote line is encountered.

Behaviour

Case Before After
Multi-line > blockquote split at chunk boundary Continuation lines render as plain text All lines render inside the quote block
Nested >> blockquote split at boundary Same problem Nested level preserved
Fenced code block inside blockquote Unchanged Unchanged
Non-blockquote content Unchanged Unchanged

When chunkDiscordText() flushed a chunk mid-blockquote, the next chunk
started without the leading '>' prefix. Discord renders each message
independently, so continuation lines appeared as plain text outside the
quote block — broken visually.

Fix: track the current blockquote prefix (openBlockquote) in the same
way fenced code blocks are tracked. On flush(), if a blockquote context
is open and we are not inside a fenced block, seed the next chunk's
current buffer with the blockquote prefix so continuation lines render
correctly.

Also add BLOCKQUOTE_RE + getBlockquotePrefix() helpers to support
nested blockquotes ('>>', '>>>', etc.).

Fixes openclaw#63409
@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord size: M labels Apr 8, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 8, 2026

Greptile Summary

This PR introduces chunk.ts for the Discord extension and adds blockquote-context propagation across chunk boundaries — mirroring the existing fenced-code-block re-seeding pattern. The character-split case (long single-line blockquote split by maxChars) is fixed correctly.

However, the unconditional current = openBlockquote re-seeding in flush() also fires for line-count splits, where each continuation line already carries its own > prefix. This inserts a spurious empty blockquote line (> ) at the start of every line-limit-triggered continuation chunk — a regression that did not exist before. No test file was added alongside the new module.

Confidence Score: 4/5

Safe to merge after addressing the line-limit flush regression; no security or data concerns.

The character-split fix is correct, but the unconditional re-seeding in flush() introduces an empty blockquote line artefact for every maxLines-triggered split — a verifiable regression on the changed code path. No tests were added to catch either the original bug or this new edge case.

extensions/discord/src/chunk.ts — specifically the flush() re-seeding block (lines 154-159) and the absence of a companion chunk.test.ts.

Vulnerabilities

No security concerns identified. The chunker operates on plain text strings and performs no I/O, authentication, or credential handling.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/discord/src/chunk.ts
Line: 154-159

Comment:
**Extra empty blockquote line inserted on line-limit splits**

When `flush()` fires because adding the next full line would exceed `maxLines` (rather than `maxChars` mid-line), `current` is seeded to `"> "` and then the next line (which already carries its own `>` prefix) is appended with a `"\n"` delimiter — producing `"> \n> actual content"`. Discord renders that leading `> ` as a separate, visually empty blockquote paragraph before the real content.

The re-seeding is only necessary for *character-split* continuations (`isLineContinuation = true`), where the tail segment has no `>` of its own. For line-boundary splits every continuation line already carries the correct prefix, so re-seeding just adds an artefact.

One way to scope the fix to the case that needs it:

```ts
// Only re-seed when the split happens mid-line (character overrun);
// line-boundary splits naturally carry their own > prefix.
if (openBlockquote && !openFence && isLineContinuation) {
  current = openBlockquote;
  currentLines = 1;
}
```

This would require threading an `isLineContinuation` flag into `flush()` (or inlining the re-seed after the call). The current unconditional seeding is a regression for the `maxLines`-triggered split path.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/discord/src/chunk.ts
Line: 1

Comment:
**No tests for the new chunking logic**

`chunk.ts` is a new file with non-trivial state-machine logic (fenced code blocks, blockquote tracking, long-line splitting, italics rebalancing), but no `chunk.test.ts` was added. The PR description lists specific cases that should be covered (split within a `>` blockquote, nested `>>`, unchanged non-blockquote content). Given the repo's Vitest + V8 coverage threshold of 70%, adding at least the described table-driven cases would prevent future regressions.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(discord): propagate blockquote conte..." | Re-trigger Greptile

Comment on lines +154 to +159
// Re-open blockquote context on next chunk so Discord keeps rendering
// continuation lines inside the quote block.
if (openBlockquote && !openFence) {
current = openBlockquote;
currentLines = 1;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Extra empty blockquote line inserted on line-limit splits

When flush() fires because adding the next full line would exceed maxLines (rather than maxChars mid-line), current is seeded to "> " and then the next line (which already carries its own > prefix) is appended with a "\n" delimiter — producing "> \n> actual content". Discord renders that leading > as a separate, visually empty blockquote paragraph before the real content.

The re-seeding is only necessary for character-split continuations (isLineContinuation = true), where the tail segment has no > of its own. For line-boundary splits every continuation line already carries the correct prefix, so re-seeding just adds an artefact.

One way to scope the fix to the case that needs it:

// Only re-seed when the split happens mid-line (character overrun);
// line-boundary splits naturally carry their own > prefix.
if (openBlockquote && !openFence && isLineContinuation) {
  current = openBlockquote;
  currentLines = 1;
}

This would require threading an isLineContinuation flag into flush() (or inlining the re-seed after the call). The current unconditional seeding is a regression for the maxLines-triggered split path.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/discord/src/chunk.ts
Line: 154-159

Comment:
**Extra empty blockquote line inserted on line-limit splits**

When `flush()` fires because adding the next full line would exceed `maxLines` (rather than `maxChars` mid-line), `current` is seeded to `"> "` and then the next line (which already carries its own `>` prefix) is appended with a `"\n"` delimiter — producing `"> \n> actual content"`. Discord renders that leading `> ` as a separate, visually empty blockquote paragraph before the real content.

The re-seeding is only necessary for *character-split* continuations (`isLineContinuation = true`), where the tail segment has no `>` of its own. For line-boundary splits every continuation line already carries the correct prefix, so re-seeding just adds an artefact.

One way to scope the fix to the case that needs it:

```ts
// Only re-seed when the split happens mid-line (character overrun);
// line-boundary splits naturally carry their own > prefix.
if (openBlockquote && !openFence && isLineContinuation) {
  current = openBlockquote;
  currentLines = 1;
}
```

This would require threading an `isLineContinuation` flag into `flush()` (or inlining the re-seed after the call). The current unconditional seeding is a regression for the `maxLines`-triggered split path.

How can I resolve this? If you propose a fix, please make it concise.

@@ -0,0 +1,302 @@
import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-chunking";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No tests for the new chunking logic

chunk.ts is a new file with non-trivial state-machine logic (fenced code blocks, blockquote tracking, long-line splitting, italics rebalancing), but no chunk.test.ts was added. The PR description lists specific cases that should be covered (split within a > blockquote, nested >>, unchanged non-blockquote content). Given the repo's Vitest + V8 coverage threshold of 70%, adding at least the described table-driven cases would prevent future regressions.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/discord/src/chunk.ts
Line: 1

Comment:
**No tests for the new chunking logic**

`chunk.ts` is a new file with non-trivial state-machine logic (fenced code blocks, blockquote tracking, long-line splitting, italics rebalancing), but no `chunk.test.ts` was added. The PR description lists specific cases that should be covered (split within a `>` blockquote, nested `>>`, unchanged non-blockquote content). Given the repo's Vitest + V8 coverage threshold of 70%, adding at least the described table-driven cases would prevent future regressions.

How can I resolve this? If you propose a fix, please make it concise.

@extrasmall0
Copy link
Copy Markdown
Contributor Author

Follow-up here: I addressed Greptile's main regression note in 8879f7b by limiting the blockquote re-seed to continuation splits, so line-boundary flushes no longer produce an empty quoted paragraph at the start of the next chunk. The change now only preserves quote context for the mid-line split case that originally broke rendering. If maintainers want it, I can add a narrow regression test for the line-limit and char-split cases in a follow-up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discord: streaming chunks break markdown formatting when split occurs inside structured elements

1 participant