// scenarios/replay.mjs — reconnect handshake: welcome.lastSeq reflects // persisted events; seq continuation; message_update streamed but never // persisted. import { agentClient, agentEvent, agentHello, rest, sid, waitUntil } from "../lib.mjs"; export async function run(ctx) { const { r, base, token, agentUrl, state } = ctx; const life = state.lifecycle; // set by agent-lifecycle (seq 1..4 persisted) const id = life.id; const agent = await agentClient(agentUrl, token); const welcome = await agentHello(agent, life.snapshot); r.check( `reconnect welcome lastSeq=${life.lastSeq} (persisted high-water)`, welcome?.lastSeq === life.lastSeq, `got ${welcome?.lastSeq}, want ${life.lastSeq}`, ); agentEvent(agent, id, 5, "message_update", { delta: "streaming text that must not persist" }); agentEvent(agent, id, 6, "message_end", { message: { role: "assistant", id: "m2", text: "assistant final", thinking: null, toolCalls: [], toolCallId: null }, }); agentEvent(agent, id, 7, "agent_settled", {}); const settled = await waitUntil( async () => (await rest(base, token, `/api/sessions/${id}/events?after=6`)).json?.length === 1, ); r.check("seq 6..7 persisted (message_update skipped)", settled); agent.close(); const after1 = (await rest(base, token, `/api/sessions/${id}/events?after=1`)).json ?? []; r.check( "events?after=1 returns only seq≥2", JSON.stringify(after1.map((e) => e.seq)) === "[2,3,4,6,7]", JSON.stringify(after1.map((e) => e.seq)), ); r.check( "message_update (seq 5) NOT persisted", !after1.some((e) => e.type === "message_update" || e.seq === 5), JSON.stringify(after1.map((e) => `${e.seq}:${e.type}`)), ); r.check( "REST events unaffected by skipped message_update", after1.some((e) => e.type === "message_end" && e.message?.text === "assistant final"), ); // Fresh reconnect: lastSeq must now cover everything persisted. const agent2 = await agentClient(agentUrl, token); const welcome2 = await agentHello(agent2, life.snapshot); r.check("welcome lastSeq advanced to 7", welcome2?.lastSeq === 7, `got ${welcome2?.lastSeq}`); agent2.close(); state.replay = { id }; }