import { describe, expect, it } from "bun:test"; import { OpencodeRuntimeAdapter } from "../../src/runtime/opencode.js"; const createRuntimeAdapter = ( messages: unknown[], calls: { reverted: string[]; removed: string[]; } = { reverted: [], removed: [] }, ) => Object.assign(Object.create(OpencodeRuntimeAdapter.prototype), { messages: async () => messages, revertMessage: async (_sessionId: string, messageId: string) => { calls.reverted.push(messageId); }, removeMessage: async (_sessionId: string, messageId: string) => { calls.removed.push(messageId); }, }) as OpencodeRuntimeAdapter; describe("OpencodeRuntimeAdapter.revertToUserMessage", () => { it("skips reverting the first user message when the runtime session is empty", async () => { const calls = { reverted: [] as string[], removed: [] as string[] }; const runtime = createRuntimeAdapter([], calls); await runtime.revertToUserMessage("session-1", { userOrdinal: 1 }); expect(calls).toEqual({ reverted: [], removed: [] }); }); it("keeps ordinal mismatches visible when runtime messages exist", async () => { const runtime = createRuntimeAdapter([ { info: { id: "user-1", role: "user" } }, { info: { id: "assistant-1", role: "assistant" } }, ]); await expect( runtime.revertToUserMessage("session-1", { userOrdinal: 2 }), ).rejects.toThrow("target user message not found to revert"); }); it("reverts and removes messages from the target user message onward", async () => { const calls = { reverted: [] as string[], removed: [] as string[] }; const runtime = createRuntimeAdapter( [ { info: { id: "user-1", role: "user" } }, { info: { id: "assistant-1", role: "assistant" } }, { info: { id: "user-2", role: "user" } }, { info: { id: "assistant-2", role: "assistant" } }, ], calls, ); await runtime.revertToUserMessage("session-1", { userOrdinal: 2 }); expect(calls).toEqual({ reverted: ["user-2"], removed: ["assistant-2", "user-2"], }); }); });