mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-10 02:15:02 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbfb0c71ef |
@@ -0,0 +1,86 @@
|
|||||||
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||||
|
import path from "node:path";
|
||||||
|
import { expect, test } from "vitest";
|
||||||
|
import { realClaudeRewindSdk, revertClaudeConversation } from "./rewind.js";
|
||||||
|
|
||||||
|
interface TranscriptEntry {
|
||||||
|
uuid: string;
|
||||||
|
sessionId: string;
|
||||||
|
subtype?: string;
|
||||||
|
forkedFrom?: { messageUuid: string };
|
||||||
|
compactMetadata?: {
|
||||||
|
preservedSegment: {
|
||||||
|
headUuid: string;
|
||||||
|
anchorUuid: string;
|
||||||
|
tailUuid: string;
|
||||||
|
};
|
||||||
|
preservedMessages: {
|
||||||
|
anchorUuid: string;
|
||||||
|
uuids: string[];
|
||||||
|
allUuids: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseEntries(text: string): TranscriptEntry[] {
|
||||||
|
return text
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map((line) => JSON.parse(line) as TranscriptEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixture from PR #3938, commit 374b08f9d56d9dabc62f8e4e01acc73d1c619548.
|
||||||
|
// This proves stale metadata, not the reported model context overflow.
|
||||||
|
test("keeps compaction references attached to forked messages", async () => {
|
||||||
|
const root = await mkdtemp(path.join(process.cwd(), ".compacted-rewind-"));
|
||||||
|
try {
|
||||||
|
const fixture = await readFile(
|
||||||
|
new URL(
|
||||||
|
"./test-fixtures/issue-3837-compacted-session.jsonl",
|
||||||
|
import.meta.url
|
||||||
|
),
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
const entries = parseEntries(fixture);
|
||||||
|
const sourceSessionId = entries[0]!.sessionId;
|
||||||
|
const transcriptPath = path.join(root, `${sourceSessionId}.jsonl`);
|
||||||
|
await writeFile(transcriptPath, fixture);
|
||||||
|
let forkId = sourceSessionId;
|
||||||
|
await revertClaudeConversation({
|
||||||
|
sdk: realClaudeRewindSdk,
|
||||||
|
sessionId: sourceSessionId,
|
||||||
|
transcriptPath,
|
||||||
|
messageId: entries.at(-1)!.uuid,
|
||||||
|
setSessionId: (id) => {
|
||||||
|
forkId = id;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const fork = parseEntries(
|
||||||
|
await readFile(path.join(root, `${forkId}.jsonl`), "utf8")
|
||||||
|
);
|
||||||
|
const ids = new Map(
|
||||||
|
fork.map((entry) => [entry.forkedFrom?.messageUuid, entry.uuid])
|
||||||
|
);
|
||||||
|
const remap = (id: string) => ids.get(id) ?? id;
|
||||||
|
const source = entries.find(
|
||||||
|
(entry) => entry.subtype === "compact_boundary"
|
||||||
|
)!.compactMetadata!;
|
||||||
|
const actual = fork.find((entry) => entry.subtype === "compact_boundary")!
|
||||||
|
.compactMetadata!;
|
||||||
|
expect(actual).toEqual({
|
||||||
|
...source,
|
||||||
|
preservedSegment: {
|
||||||
|
headUuid: remap(source.preservedSegment.headUuid),
|
||||||
|
anchorUuid: remap(source.preservedSegment.anchorUuid),
|
||||||
|
tailUuid: remap(source.preservedSegment.tailUuid),
|
||||||
|
},
|
||||||
|
preservedMessages: {
|
||||||
|
anchorUuid: remap(source.preservedMessages.anchorUuid),
|
||||||
|
uuids: source.preservedMessages.uuids.map(remap),
|
||||||
|
allUuids: source.preservedMessages.allUuids.map(remap),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
await rm(root, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
{"type":"user","uuid":"10000000-0000-4000-8000-000000000002","parentUuid":null,"isSidechain":false,"sessionId":"10000000-0000-4000-8000-000000000001","timestamp":"2026-08-27T08:00:00.000Z","message":{"role":"user","content":"Before compaction"}}
|
||||||
|
{"type":"assistant","uuid":"10000000-0000-4000-8000-000000000003","parentUuid":"10000000-0000-4000-8000-000000000002","isSidechain":false,"sessionId":"10000000-0000-4000-8000-000000000001","timestamp":"2026-08-27T08:00:00.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Done"}]}}
|
||||||
|
{"type":"system","subtype":"stop_hook_summary","uuid":"10000000-0000-4000-8000-000000000004","parentUuid":"10000000-0000-4000-8000-000000000003","isSidechain":false,"sessionId":"10000000-0000-4000-8000-000000000001","timestamp":"2026-08-27T08:00:00.000Z"}
|
||||||
|
{"type":"system","subtype":"compact_boundary","uuid":"10000000-0000-4000-8000-000000000005","parentUuid":null,"logicalParentUuid":"10000000-0000-4000-8000-000000000004","isSidechain":false,"sessionId":"10000000-0000-4000-8000-000000000001","timestamp":"2026-08-27T08:00:00.000Z","compactMetadata":{"trigger":"auto","preTokens":900000,"preservedSegment":{"headUuid":"10000000-0000-4000-8000-000000000003","anchorUuid":"10000000-0000-4000-8000-000000000006","tailUuid":"10000000-0000-4000-8000-000000000004"},"preservedMessages":{"anchorUuid":"10000000-0000-4000-8000-000000000006","uuids":["10000000-0000-4000-8000-000000000003","10000000-0000-4000-8000-000000000004"],"allUuids":["10000000-0000-4000-8000-000000000003","10000000-0000-4000-8000-000000000008","10000000-0000-4000-8000-000000000004"]},"postTokens":10000}}
|
||||||
|
{"type":"user","uuid":"10000000-0000-4000-8000-000000000006","parentUuid":"10000000-0000-4000-8000-000000000005","isSidechain":false,"isCompactSummary":true,"sessionId":"10000000-0000-4000-8000-000000000001","timestamp":"2026-08-27T08:00:00.000Z","message":{"role":"user","content":"Compacted summary"}}
|
||||||
|
{"type":"user","uuid":"10000000-0000-4000-8000-000000000007","parentUuid":"10000000-0000-4000-8000-000000000006","isSidechain":false,"sessionId":"10000000-0000-4000-8000-000000000001","timestamp":"2026-08-27T08:00:00.000Z","message":{"role":"user","content":"Continue after compaction"}}
|
||||||
Reference in New Issue
Block a user