From 2e79dd122e5664353e02e0d33715ae8c1041a379 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Sun, 7 Jun 2026 17:14:40 +0900 Subject: feat(chat): restyle thinking — visible bubble, collapse, title swap, persisted open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thinking renders inside a visible rounded-card bubble (like tool calls), capped to the same max-w-5xl column as assistant text. Uses a DaisyUI checkbox collapse (no arrow/plus icon) with smooth animation. Title reads "Thinking" + loading-dots while the model is actively generating, then flips to "Thoughts" with no dots once done. Open/closed state persists across the generating→completed→sealed transition via stable ordinal keys (per-conversation isolation via {#key} in App). Added optional streaming flag to RenderedChunk (pure selector, only on the accumulating chunk). --- src/core/chunks/reducer.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/core/chunks/reducer.test.ts') diff --git a/src/core/chunks/reducer.test.ts b/src/core/chunks/reducer.test.ts index 7ecc349..f2f1b75 100644 --- a/src/core/chunks/reducer.test.ts +++ b/src/core/chunks/reducer.test.ts @@ -371,6 +371,21 @@ describe("selectChunks", () => { expect(chunks[0]?.provisional).toBe(true); expect(chunks[0]?.chunk).toEqual({ type: "text", text: "building..." }); }); + + it("marks ONLY the actively-accumulating chunk as streaming", () => { + let s = initialState(); + s = foldEvent(s, turnStart("t1")); + // A flushed-but-still-provisional thinking chunk, then a live accumulating one. + s = foldEvent(s, reasoningDelta("t1", "first thought")); + s = foldEvent(s, toolCall("t1", "tc1", "bash", {})); // flushes the thinking + s = foldEvent(s, textDelta("t1", "now writing")); + const chunks = selectChunks(s); + const thinking = chunks.find((c) => c.chunk.type === "thinking"); + const accumulating = chunks.find((c) => c.streaming === true); + expect(thinking?.streaming).toBeFalsy(); // flushed → not streaming + expect(accumulating?.chunk).toEqual({ type: "text", text: "now writing" }); + expect(chunks.filter((c) => c.streaming === true)).toHaveLength(1); + }); }); describe("selectMessages", () => { -- cgit v1.2.3