fix: flush block streaming on paragraph boundaries for chunkMode=newline (#7014)

* feat: Implement paragraph boundary flushing in block streaming

- Added `flushOnParagraph` option to `BlockReplyChunking` for immediate flushing on paragraph breaks.
- Updated `EmbeddedBlockChunker` to handle paragraph boundaries during chunking.
- Enhanced `createBlockReplyCoalescer` to support flushing on enqueue.
- Added tests to verify behavior of flushing with and without `flushOnEnqueue` set.
- Updated relevant types and interfaces to include `flushOnParagraph` and `flushOnEnqueue` options.

* fix: Improve streaming behavior and enhance block chunking logic

- Resolved issue with stuck typing indicator after streamed BlueBubbles replies.
- Refactored `EmbeddedBlockChunker` to streamline fence-split handling and ensure maxChars fallback for newline chunking.
- Added tests to validate new chunking behavior, including handling of paragraph breaks and fence scenarios.
- Updated changelog to reflect these changes.

* test: Add test for clamping long paragraphs in EmbeddedBlockChunker

- Introduced a new test case to verify that long paragraphs are correctly clamped to maxChars when flushOnParagraph is enabled.
- Updated logic in EmbeddedBlockChunker to handle cases where the next paragraph break exceeds maxChars, ensuring proper chunking behavior.

* refactor: streamline logging and improve error handling in message processing

- Removed verbose logging statements from the `processMessage` function to reduce clutter.
- Enhanced error handling by using `runtime.error` for typing restart failures.
- Updated the `applySystemPromptOverrideToSession` function to accept a string directly instead of a function, simplifying the prompt application process.
- Adjusted the `runEmbeddedAttempt` function to directly use the system prompt override without invoking it as a function.
This commit is contained in:
Tyler Yust
2026-02-02 01:22:41 -08:00
committed by GitHub
parent 85cd55e22b
commit 9ef24fd400
14 changed files with 377 additions and 73 deletions

View File

@@ -18,6 +18,7 @@ export function createBlockReplyCoalescer(params: {
const maxChars = Math.max(minChars, Math.floor(config.maxChars));
const idleMs = Math.max(0, Math.floor(config.idleMs));
const joiner = config.joiner ?? "";
const flushOnEnqueue = config.flushOnEnqueue === true;
let bufferText = "";
let bufferReplyToId: ReplyPayload["replyToId"];
@@ -57,7 +58,7 @@ export function createBlockReplyCoalescer(params: {
if (!bufferText) {
return;
}
if (!options?.force && bufferText.length < minChars) {
if (!options?.force && !flushOnEnqueue && bufferText.length < minChars) {
scheduleIdleFlush();
return;
}
@@ -86,6 +87,19 @@ export function createBlockReplyCoalescer(params: {
return;
}
// When flushOnEnqueue is set (chunkMode="newline"), each enqueued payload is treated
// as a separate paragraph and flushed immediately so delivery matches streaming boundaries.
if (flushOnEnqueue) {
if (bufferText) {
void flush({ force: true });
}
bufferReplyToId = payload.replyToId;
bufferAudioAsVoice = payload.audioAsVoice;
bufferText = text;
void flush({ force: true });
return;
}
if (
bufferText &&
(bufferReplyToId !== payload.replyToId || bufferAudioAsVoice !== payload.audioAsVoice)