mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-20 06:02:18 +02:00
feat: make chat-style tasks the default experience (#11101)
This commit is contained in:
1 parent
2da6a248c3
commit
815e49bb7c
80 files changed
+3858
-1497
No files matched your search
@@ -6,7 +6,7 @@ import { parseAcpxStdoutLine } from "@paperclipai/adapter-utils/acpx-engine/ui";
|
||||
import { buildTranscript, type RunLogChunk, type TranscriptEntry } from "../../adapters";
|
||||
import type { ToolRunDecision } from "@paperclipai/shared";
|
||||
import { ThemeProvider } from "../../context/ThemeContext";
|
||||
import { RunTranscriptView, normalizeTranscript } from "./RunTranscriptView";
|
||||
import { RunTranscriptView, keyTranscriptBlocks, normalizeTranscript } from "./RunTranscriptView";
|
||||
|
||||
describe("RunTranscriptView", () => {
|
||||
it("folds repeated tool_call status updates for the same toolUseId into one block", () => {
|
||||
@@ -322,4 +322,48 @@ describe("RunTranscriptView", () => {
|
||||
expect(html).not.toContain("line-250");
|
||||
expect(html).not.toContain("line-499");
|
||||
});
|
||||
|
||||
it("keeps the streaming tail block's key stable as deltas merge in", () => {
|
||||
// A streaming assistant message accumulates deltas; each delta advances the
|
||||
// block's `ts`. The React key must stay anchored to the block's opening
|
||||
// timestamp so the tail does not unmount/remount (restarting its fade).
|
||||
const firstDelta: TranscriptEntry[] = [
|
||||
{ kind: "assistant", ts: "2026-03-12T00:00:00.000Z", text: "Hel", delta: true },
|
||||
];
|
||||
const withMoreDeltas: TranscriptEntry[] = [
|
||||
...firstDelta,
|
||||
{ kind: "assistant", ts: "2026-03-12T00:00:00.400Z", text: "lo the", delta: true },
|
||||
{ kind: "assistant", ts: "2026-03-12T00:00:00.900Z", text: "re", delta: true },
|
||||
];
|
||||
|
||||
const keyOf = (entries: TranscriptEntry[]) => {
|
||||
const keyed = keyTranscriptBlocks(normalizeTranscript(entries, true));
|
||||
return keyed[keyed.length - 1]!.key;
|
||||
};
|
||||
|
||||
// Same opening timestamp → identical key even though `ts` advanced.
|
||||
expect(keyOf(withMoreDeltas)).toBe(keyOf(firstDelta));
|
||||
// And that key is anchored to the opening ts, not the latest one.
|
||||
expect(keyOf(withMoreDeltas)).toContain("2026-03-12T00:00:00.000Z");
|
||||
expect(keyOf(withMoreDeltas)).not.toContain("2026-03-12T00:00:00.900Z");
|
||||
});
|
||||
|
||||
it("assigns unique keys and does not remount earlier blocks when a new tail arrives", () => {
|
||||
const base: TranscriptEntry[] = [
|
||||
{ kind: "assistant", ts: "2026-03-12T00:00:00.000Z", text: "first message", delta: true },
|
||||
{ kind: "thinking", ts: "2026-03-12T00:00:01.000Z", text: "pondering", delta: true },
|
||||
];
|
||||
const withNewTail: TranscriptEntry[] = [
|
||||
...base,
|
||||
{ kind: "assistant", ts: "2026-03-12T00:00:02.000Z", text: "second message", delta: true },
|
||||
];
|
||||
|
||||
const baseKeys = keyTranscriptBlocks(normalizeTranscript(base, true)).map((b) => b.key);
|
||||
const nextKeys = keyTranscriptBlocks(normalizeTranscript(withNewTail, true)).map((b) => b.key);
|
||||
|
||||
// Keys are unique within a render.
|
||||
expect(new Set(nextKeys).size).toBe(nextKeys.length);
|
||||
// Existing blocks keep their identity when a new block appends after them.
|
||||
expect(nextKeys.slice(0, baseKeys.length)).toEqual(baseKeys);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user