test(pi-claude-bridge): cover protocol and session recovery

This commit is contained in:
Rasyidan Akbar F. 2026-10-05 16:59:26 +07:00
commit 08f82a7b57
4 changed files with 333 additions and 0 deletions

View file

@ -0,0 +1,56 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { extendsTranscript, restoredContent, transcriptKeys, type TranscriptMessage } from "../transcript.ts";
const user = { role: "user", content: "Remember MEMORY_73921" };
const assistant = { role: "assistant", content: [{ type: "text", text: "ACK", index: 0 }], timestamp: 1 };
test("fingerprints ignore runtime fields but detect branch and content changes", () => {
const previous = transcriptKeys([user, assistant]);
const current = transcriptKeys([
{ role: "system", content: "Changed prompt" }, user,
{ ...assistant, timestamp: 2, usage: { input: 10 }, content: [{ type: "text", text: "ACK" }] },
{ role: "user", content: "Next" },
]);
assert.ok(extendsTranscript(previous, current));
assert.ok(!extendsTranscript(previous, transcriptKeys([user])));
assert.ok(!extendsTranscript(previous, transcriptKeys([user, { ...assistant, content: "Different" }])));
});
test("tool argument key order does not force a restart", () => {
const message = (args: unknown): TranscriptMessage => ({ role: "assistant", content: [{ type: "toolCall", id: "id", name: "read", arguments: args }] });
assert.deepEqual(transcriptKeys([message({ a: 1, b: 2 })]), transcriptKeys([message({ b: 2, a: 1 })]));
});
test("restoration includes prior messages, tool results, and current input without native calls", () => {
const blocks = restoredContent([
{ role: "system", content: "SYSTEM_PROMPT_NOT_REPLAYED" }, user, assistant,
{ role: "toolResult", toolCallId: "old-id", toolName: "read", content: "ERROR_73921", isError: true },
{ role: "user", content: "Current request" },
]);
const text = blocks.filter((block) => block.type === "text").map((block) => block.text).join("\n");
assert.match(text, /MEMORY_73921/);
assert.match(text, /ERROR_73921/);
assert.match(text, /"isError":true/);
assert.ok(!text.includes("SYSTEM_PROMPT_NOT_REPLAYED"));
assert.equal(blocks.at(-1)?.type, "text");
assert.equal((blocks.at(-1) as { text: string }).text, "Current request");
assert.ok(blocks.every((block) => block.type === "text" || block.type === "image"));
});
test("historical images stay image blocks; thinking signatures are not replayed", () => {
const blocks = restoredContent([
{ role: "user", content: [{ type: "image", data: "aW1hZ2U=", mimeType: "image/png" }] },
{ role: "assistant", content: [{ type: "thinking", thinking: "private", thinkingSignature: "secret-signature" }] },
{ role: "user", content: "Next" },
]);
assert.equal(blocks.filter((block) => block.type === "image").length, 1);
const text = JSON.stringify(blocks);
assert.ok(!text.includes("secret-signature"));
assert.ok(!text.includes("private"));
});
test("tool-result tail gets a continuation request instead of replaying tool calls", () => {
const blocks = restoredContent([{ role: "toolResult", toolCallId: "id", content: "DONE" }]);
assert.match((blocks.at(-1) as { text: string }).text, /Continue the latest user request/);
});