Preserve live markdown block newlines
This commit is contained in:
@@ -955,6 +955,38 @@ describe("processAgentStreamEvents", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves a live block trailing newline after promoting completed markdown blocks", () => {
|
||||||
|
const result = processAgentStreamEvents({
|
||||||
|
events: [
|
||||||
|
makeStreamReducerEvent(
|
||||||
|
makeTimelineEvent(
|
||||||
|
"Done. I added `[TimelineMerge] ...` logging around the suspicious merge",
|
||||||
|
),
|
||||||
|
238,
|
||||||
|
),
|
||||||
|
makeStreamReducerEvent(makeTimelineEvent("/reconcile paths.\n\nChanged:\n"), 239),
|
||||||
|
makeStreamReducerEvent(makeTimelineEvent("- [timeline-debug.ts]"), 240),
|
||||||
|
],
|
||||||
|
currentTail: [],
|
||||||
|
currentHead: [],
|
||||||
|
currentCursor: undefined,
|
||||||
|
currentAgent: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.changedTail).toBe(true);
|
||||||
|
expect(result.changedHead).toBe(true);
|
||||||
|
expect(result.tail).toHaveLength(1);
|
||||||
|
expect(result.tail[0]).toMatchObject({
|
||||||
|
kind: "assistant_message",
|
||||||
|
text: "Done. I added `[TimelineMerge] ...` logging around the suspicious merge/reconcile paths.",
|
||||||
|
});
|
||||||
|
expect(result.head).toHaveLength(1);
|
||||||
|
expect(result.head[0]).toMatchObject({
|
||||||
|
kind: "assistant_message",
|
||||||
|
text: "Changed:\n- [timeline-debug.ts]",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("does not promote a markdown block that is still inside an open code fence", () => {
|
it("does not promote a markdown block that is still inside an open code fence", () => {
|
||||||
const result = processAgentStreamEvents({
|
const result = processAgentStreamEvents({
|
||||||
events: [
|
events: [
|
||||||
|
|||||||
@@ -793,6 +793,10 @@ function createAssistantBlockId(params: { groupId: string; blockIndex: number })
|
|||||||
return `${params.groupId}:block:${params.blockIndex}`;
|
return `${params.groupId}:block:${params.blockIndex}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTrailingNewlineSuffix(text: string): string {
|
||||||
|
return /\n+$/.exec(text)?.[0] ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
function getActiveAssistantHeadIndex(head: StreamItem[]): number {
|
function getActiveAssistantHeadIndex(head: StreamItem[]): number {
|
||||||
for (let index = head.length - 1; index >= 0; index -= 1) {
|
for (let index = head.length - 1; index >= 0; index -= 1) {
|
||||||
if (head[index]?.kind === "assistant_message") {
|
if (head[index]?.kind === "assistant_message") {
|
||||||
@@ -832,7 +836,7 @@ function promoteCompletedAssistantBlocks(params: { tail: StreamItem[]; head: Str
|
|||||||
const blockGroupId = activeItem.blockGroupId ?? activeItem.id;
|
const blockGroupId = activeItem.blockGroupId ?? activeItem.id;
|
||||||
const firstBlockIndex = activeItem.blockIndex ?? 0;
|
const firstBlockIndex = activeItem.blockIndex ?? 0;
|
||||||
const completedBlocks = blocks.slice(0, -1);
|
const completedBlocks = blocks.slice(0, -1);
|
||||||
const liveBlock = blocks[blocks.length - 1] ?? "";
|
const liveBlock = `${blocks[blocks.length - 1] ?? ""}${getTrailingNewlineSuffix(activeItem.text)}`;
|
||||||
const promotedItems = completedBlocks.map<AssistantMessageItem>((block, offset) => ({
|
const promotedItems = completedBlocks.map<AssistantMessageItem>((block, offset) => ({
|
||||||
kind: "assistant_message",
|
kind: "assistant_message",
|
||||||
id: createAssistantBlockId({
|
id: createAssistantBlockId({
|
||||||
|
|||||||
Reference in New Issue
Block a user