Files
tutti/tools/scripts/run-agent-session-replay.test.mjs
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

4087 lines
115 KiB
JavaScript

import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import { EventEmitter } from "node:events";
import { realpathSync } from "node:fs";
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { createServer } from "node:http";
import { tmpdir } from "node:os";
import { basename, dirname, join, resolve } from "node:path";
import test from "node:test";
import { setTimeout as delay } from "node:timers/promises";
import { fileURLToPath } from "node:url";
import { createAgentSessionReplayControlWriter } from "../../apps/desktop/src/main/agentSessionReplayStatus.ts";
import {
cassettePolicy,
materializeReplayWorkspaceBlobs,
parseActivityEvents,
replayActionFromManifest,
verifyCassette
} from "./agent-session-replay-runner/cassette.mjs";
import {
enableAgentSessionRecordingFeature,
replayListenerInfoPath,
replayWorkbenchSnapshot
} from "./agent-session-replay-runner/runtime.mjs";
import {
resolveAgentSessionReplayProjectRoot,
resolveRecordScenarioProject,
seedRecordingUserProject,
verifyRecordedProjectBindingArtifacts
} from "./agent-session-replay-runner/recording.mjs";
import {
activateRendererReplayWorkspaceCassette,
assertNoDuplicateEngineSends,
bootstrapRendererReplayWorkspace,
bootstrapReplayWorkspace,
bindManagedReplayShutdown,
createRendererActivityDriver,
createReplayActivityClock,
createReplayPlaybackController,
createReplayWorkspaceSurfaceReadyQueue,
createSerialAsyncQueue,
maybeSettleForScreenshot,
validateReplayCheckpointPlan,
assertReplayWorkspaceSucceeded,
checkpointNeedsToolSettle,
checkpointNeedsScreenshotSettle,
checkpointAllowsOptionalScreenshotSettle,
captureCheckpointScreenshot,
captureScreenshot,
hasOpenToolDetailText,
normalizeScreenshotClip,
parseArgs,
resolveDesktopHeadless,
resolveAgentSessionScreenshotClip,
replayCheckpointScreenshotPath,
replayControlRouter,
replayPendingInteraction,
resolveReplayProjectFromExpectedState,
replayObservedTurnId,
replayStimuli,
replayStimulusPrecondition,
replayStimulusRetryableStatus,
replayStimulusRequest,
replayTurnIdentityPlan,
replayWorkspaceTransportRegistrations,
readReplayTotalDurationMs,
replayWorkspaceActivityClockOrigin,
replayWorkspaceInitialTargetCheckpoint,
managedReplayFailure,
loadRecordScenario,
screenshotEvidenceLabel,
submitRequestedRequiresSessionIdle,
validateAction,
validateReplayWorkspaceManifest,
verifyReplayWorkspaceTransports,
replayTransportHardFailureMessage
} from "./run-agent-session-replay.mjs";
const replayCassetteAID = "277377ed-af34-454f-a8b9-1047b4064e74";
const replayCassetteBID = "628c61c4-cbcb-4445-83f7-718bbbd414bd";
const workspaceRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
test("open tool detail accepts short rendered fileChange content", () => {
assert.equal(hasOpenToolDetailText(["R15_TEST"]), true);
});
test("open tool detail rejects missing or empty content", () => {
assert.equal(hasOpenToolDetailText([]), false);
assert.equal(hasOpenToolDetailText([null, undefined, " \n\t "]), false);
});
function respondToCheckpointVerification(request, response) {
const match = request.url?.match(
/\/checkpoints\/(?<checkpointIndex>\d+)\/verify$/u
);
if (request.method !== "POST" || !match?.groups) return false;
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({
canonicalMessageVersion: 1,
canonicalSessionUpdatedAtUnixMs: 1,
checkpointIndex: Number(match.groups.checkpointIndex),
readinessSatisfied: true,
triggerMatched: true
})
);
return true;
}
test("managed Replay failure preserves a structured startup cause", () => {
assert.deepEqual(
managedReplayFailure(
replayCassetteAID,
new Error("tuttid exited before publishing listener info", {
cause: {
code: "managed_process_stderr",
message: "unsupported process cassette schema version 2"
}
})
),
{
cassetteId: replayCassetteAID,
cause: {
code: "managed_process_stderr",
message: "unsupported process cassette schema version 2"
},
error: "tuttid exited before publishing listener info"
}
);
});
test("Replay Turn identity plan excludes restored historical Turns", () => {
const session = (turnIds) => ({
id: "session-1",
turns: turnIds.map((id) => ({ id }))
});
assert.deepEqual(
replayTurnIdentityPlan(
{ agent: { sessions: [session(["turn-old", "turn-new"])] } },
{ agent: { sessions: [session(["turn-old"])] } }
),
{
"session-1": {
initialTurnIds: ["turn-old"],
recordedTurnIds: ["turn-new"]
}
}
);
});
test("Replay Turn identity plan keeps child Session lineage", () => {
assert.deepEqual(
replayTurnIdentityPlan({
agent: {
sessions: [
{
id: "root-recorded",
kind: "root",
turns: [{ id: "root-turn-recorded" }]
},
{
id: "child-recorded",
kind: "child",
rootSessionId: "root-recorded",
rootTurnId: "root-turn-recorded",
parentSessionId: "root-recorded",
parentTurnId: "root-turn-recorded",
parentToolCallId: "call-stable",
turns: [{ id: "child-turn-recorded" }]
}
]
}
}),
{
"root-recorded": {
initialTurnIds: [],
recordedTurnIds: ["root-turn-recorded"]
},
"child-recorded": {
initialTurnIds: [],
recordedTurnIds: ["child-turn-recorded"],
kind: "child",
initialSession: false,
rootSessionId: "root-recorded",
rootTurnId: "root-turn-recorded",
parentSessionId: "root-recorded",
parentTurnId: "root-turn-recorded",
parentToolCallId: "call-stable"
}
}
);
});
test("managed Replay stops its Desktop when the owner process exits", async () => {
const runtime = new EventEmitter();
runtime.stdout = new EventEmitter();
runtime.stderr = new EventEmitter();
let checkParent = null;
let stopCount = 0;
const dispose = bindManagedReplayShutdown(
{},
{
clearInterval() {},
isProcessAlive: () => false,
parentPid: "123",
processRuntime: runtime,
setInterval(check) {
checkParent = check;
return { unref() {} };
},
async stopDesktop() {
stopCount += 1;
}
}
);
checkParent();
runtime.stdout.emit(
"error",
Object.assign(new Error("write EPIPE"), { code: "EPIPE" })
);
await Promise.resolve();
assert.equal(stopCount, 1);
dispose();
assert.equal(runtime.listenerCount("SIGINT"), 0);
assert.equal(runtime.stdout.listenerCount("error"), 0);
});
test("Replay Workspace confirms final Surface readiness serially", async () => {
const events = [];
let releaseFirst;
const firstReady = new Promise((resolve) => {
releaseFirst = resolve;
});
const reportReady = createReplayWorkspaceSurfaceReadyQueue(
async (cassette) => {
events.push(`start:${cassette.cassetteId}`);
if (cassette.cassetteId === "cassette-1") {
await firstReady;
}
events.push(`ready:${cassette.cassetteId}`);
}
);
const first = reportReady({ cassetteId: "cassette-1" });
const second = reportReady({ cassetteId: "cassette-2" });
await Promise.resolve();
assert.deepEqual(events, ["start:cassette-1"]);
releaseFirst();
await Promise.all([first, second]);
assert.deepEqual(events, [
"start:cassette-1",
"ready:cassette-1",
"start:cassette-2",
"ready:cassette-2"
]);
});
test("Replay Workspace continues Surface readiness after one failure", async () => {
const events = [];
const reportReady = createReplayWorkspaceSurfaceReadyQueue(
async (cassette) => {
events.push(cassette.cassetteId);
if (cassette.cassetteId === "cassette-1") {
throw new Error("first Surface failed");
}
}
);
const first = reportReady({ cassetteId: "cassette-1" });
const second = reportReady({ cassetteId: "cassette-2" });
await assert.rejects(first, /first Surface failed/u);
await second;
assert.deepEqual(events, ["cassette-1", "cassette-2"]);
});
test("createSerialAsyncQueue runs Desktop UI tasks one at a time", async () => {
const events = [];
let releaseFirst;
const firstGate = new Promise((resolve) => {
releaseFirst = resolve;
});
const enqueue = createSerialAsyncQueue();
const first = enqueue(async () => {
events.push("start:a");
await firstGate;
events.push("end:a");
});
const second = enqueue(async () => {
events.push("start:b");
events.push("end:b");
});
await Promise.resolve();
assert.deepEqual(events, ["start:a"]);
releaseFirst();
await Promise.all([first, second]);
assert.deepEqual(events, ["start:a", "end:a", "start:b", "end:b"]);
});
test("maybeSettleForScreenshot pins and clears settle agent session id", async () => {
const expressions = [];
const client = {
async send(method, params) {
assert.equal(method, "Runtime.evaluate");
expressions.push(params.expression);
return { result: { value: true } };
}
};
let settleSawPin = false;
await maybeSettleForScreenshot(
{
async settleForScreenshot() {
settleSawPin = expressions.some((expression) =>
expression.includes("__tuttiSettleAgentSessionId = ")
);
}
},
client,
1_000,
{ kind: "tool.completed", tags: ["tool.completed"] },
"session-r03"
);
assert.equal(settleSawPin, true);
assert.ok(
expressions.some((expression) =>
expression.includes('__tuttiSettleAgentSessionId = "session-r03"')
)
);
assert.ok(
expressions.some((expression) =>
expression.includes("delete globalThis.__tuttiSettleAgentSessionId")
)
);
});
test("working checkpoint settle is scenario opt-in", async () => {
const client = {
async send() {
return { result: { value: true } };
}
};
let settles = 0;
const scenario = {
async settleForScreenshot() {
settles += 1;
}
};
const checkpoint = { kind: "turn.working", tags: ["turn.working"] };
await maybeSettleForScreenshot(scenario, client, 1_000, checkpoint);
scenario.settleForWorkingScreenshot = true;
await maybeSettleForScreenshot(scenario, client, 1_000, checkpoint);
assert.equal(settles, 1);
});
test("replayObservedTurnId prefers Protocol v2 turnId after settle", () => {
assert.equal(
replayObservedTurnId({
activeTurnId: null,
latestTurn: { turnId: "turn-settled" }
}),
"turn-settled"
);
assert.equal(
replayObservedTurnId({
activeTurnId: "turn-active",
latestTurn: { turnId: "turn-other" }
}),
"turn-active"
);
assert.equal(
replayObservedTurnId({
activeTurnId: null,
latestTurn: { id: "turn-legacy" }
}),
"turn-legacy"
);
assert.equal(
replayObservedTurnId({
activeTurnId: null,
latestTurn: {}
}),
null
);
});
test("replay rebases cancel Turn id from settled latestTurn.turnId", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-cancel-turnid-"));
const listenerDirectory = join(root, "run");
await mkdir(listenerDirectory, { recursive: true });
const verified = [];
const playbackStartedAt = Date.now();
const server = createServer((request, response) => {
response.setHeader("content-type", "application/json");
if (respondToCheckpointVerification(request, response)) return;
if (
request.method === "GET" &&
request.url ===
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/playback`
) {
response.end(
JSON.stringify({
drained: false,
paused: false,
playbackElapsedMs: Date.now() - playbackStartedAt,
providerConnections: [],
speed: 1,
timingMode: "realtime"
})
);
return;
}
// Settled after early cancel: activeTurnId cleared; Protocol v2 uses turnId.
response.end(
JSON.stringify({
session: {
activeTurnId: null,
latestTurn: { turnId: "turn-live-canceled" },
status: "idle"
}
})
);
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
await writeFile(
join(listenerDirectory, "tuttid.listener.json"),
JSON.stringify({
addr: `127.0.0.1:${address.port}`,
auth: { token: "test-token" }
})
);
const base = {
agentSessionId: "session-1",
workspaceId: "workspace-1"
};
await replayStimuli(
root,
{
...base,
activityEvents: [
{
...base,
kind: "effect",
occurredAtUnixMs: 1,
payload: { outcome: "succeeded" },
sequence: 1,
type: "session/activate"
},
{
...base,
kind: "effect",
occurredAtUnixMs: 2,
payload: {
outcome: "succeeded",
turnId: "turn-recorded-canceled"
},
sequence: 2,
type: "turn/cancel"
}
],
turnIdentityPlan: {
"session-1": {
initialTurnIds: [],
recordedTurnIds: ["turn-recorded-canceled"]
}
}
},
2_000,
{
cassetteId: replayCassetteAID,
rendererDriver: {
async dispatchIntent() {},
async verifyEffect(event) {
verified.push(event);
}
},
checkpoints: [
{
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] },
schemaVersion: cassettePolicy.schemaVersion
}
]
}
);
assert.equal(verified.length, 2);
assert.equal(verified[1].type, "turn/cancel");
assert.equal(verified[1].payload.turnId, "turn-live-canceled");
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("replay rebases recorded Turn identities before Engine intents", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-turn-identity-"));
const listenerDirectory = join(root, "run");
await mkdir(listenerDirectory, { recursive: true });
const requests = [];
const dispatched = [];
let activeTurnId = null;
const playbackStartedAt = Date.now();
const server = createServer((request, response) => {
requests.push(`${request.method} ${request.url}`);
response.setHeader("content-type", "application/json");
if (respondToCheckpointVerification(request, response)) return;
if (
request.method === "GET" &&
request.url ===
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/playback`
) {
response.end(
JSON.stringify({
drained: false,
paused: false,
playbackElapsedMs: Date.now() - playbackStartedAt,
providerConnections: [],
speed: 1,
timingMode: "realtime"
})
);
return;
}
if (
request.method === "POST" &&
request.url ===
"/v1/workspaces/workspace-1/agent-sessions/session-1/input"
) {
activeTurnId = "turn-replay";
response.statusCode = 201;
response.end("{}");
return;
}
response.end(
JSON.stringify({
session: {
activeTurnId,
latestTurn: { id: "turn-replay" },
status: activeTurnId ? "working" : "idle"
}
})
);
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
await writeFile(
join(listenerDirectory, "tuttid.listener.json"),
JSON.stringify({
addr: `127.0.0.1:${address.port}`,
auth: { token: "test-token" }
})
);
const base = {
agentSessionId: "session-1",
workspaceId: "workspace-1"
};
await replayStimuli(
root,
{
...base,
activityEvents: [
{
...base,
kind: "direct-stimulus",
occurredAtUnixMs: 1,
payload: { content: [{ type: "text", text: "start" }] },
sequence: 1,
type: "session.send"
},
{
...base,
kind: "intent",
occurredAtUnixMs: 2,
payload: {
action: "implement",
commandId: "plan-command",
idempotencyKey:
"plan-implementation:workspace-recorded:session-1:turn-recorded",
promptKind: "plan-implementation",
requestId: "turn-recorded",
turnId: "turn-recorded"
},
sequence: 2,
type: "plan/decisionRequested"
}
],
turnIdentityPlan: {
"session-1": {
initialTurnIds: [],
recordedTurnIds: ["turn-recorded"]
}
}
},
2_000,
{
cassetteId: replayCassetteAID,
rendererDriver: {
dispatchIntent(event) {
dispatched.push(event);
activeTurnId = null;
},
async verifyEffect() {}
},
checkpoints: [
{
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] },
schemaVersion: cassettePolicy.schemaVersion
},
{
index: 1,
kind: "after-activity-event",
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 2
},
cursor: { activityEventSequence: 2, providerConnections: [] },
schemaVersion: cassettePolicy.schemaVersion
}
]
}
);
assert.equal(dispatched[0].payload.turnId, "turn-replay");
assert.equal(dispatched[0].payload.requestId, "turn-replay");
assert.equal(
requests.some((request) => request.includes("turn-recorded")),
false
);
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("replay rebases child Session and Turn identities from lineage", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-child-identity-"));
const listenerDirectory = join(root, "run");
await mkdir(listenerDirectory, { recursive: true });
const dispatched = [];
const verified = [];
let rootActiveTurnId = "root-turn-live";
const playbackStartedAt = Date.now();
const server = createServer((request, response) => {
response.setHeader("content-type", "application/json");
if (respondToCheckpointVerification(request, response)) return;
if (
request.method === "GET" &&
request.url ===
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/playback`
) {
response.end(
JSON.stringify({
drained: false,
paused: false,
playbackElapsedMs: Date.now() - playbackStartedAt,
providerConnections: [],
speed: 1,
timingMode: "realtime"
})
);
return;
}
if (
request.method === "GET" &&
request.url ===
"/v1/workspaces/workspace-1/agent-sessions/root-recorded?projection=messageHydration"
) {
response.end(
JSON.stringify({
session: {
id: "root-recorded",
kind: "root",
activeTurnId: rootActiveTurnId,
latestTurn: { id: "root-turn-live" }
},
childSessions: [
{
id: "child-live",
kind: "child",
rootAgentSessionId: "root-recorded",
rootTurnId: "root-turn-live",
parentAgentSessionId: "root-recorded",
parentTurnId: "root-turn-live",
parentToolCallId: "call-stable",
activeTurnId: "child-turn-live",
latestTurn: { id: "child-turn-live" }
}
]
})
);
return;
}
if (
request.method === "GET" &&
request.url === "/v1/workspaces/workspace-1/agent-sessions/root-recorded"
) {
response.end(
JSON.stringify({
session: {
activeTurnId: rootActiveTurnId,
latestTurn: { id: "root-turn-live" },
status: rootActiveTurnId ? "working" : "idle"
}
})
);
return;
}
response.end("{}");
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
await writeFile(
join(listenerDirectory, "tuttid.listener.json"),
JSON.stringify({
addr: `127.0.0.1:${address.port}`,
auth: { token: "test-token" }
})
);
const rootEvent = {
agentSessionId: "root-recorded",
workspaceId: "workspace-1"
};
const childEvent = {
agentSessionId: "child-recorded",
workspaceId: "workspace-1"
};
await replayStimuli(
root,
{
...rootEvent,
activityEvents: [
{
...rootEvent,
kind: "effect",
occurredAtUnixMs: 1,
payload: {},
sequence: 1,
type: "session/activate"
},
{
...childEvent,
kind: "intent",
occurredAtUnixMs: 2,
payload: {
requestId: "request-1",
turnId: "child-turn-recorded"
},
sequence: 2,
type: "interaction/responseRequested"
},
{
...childEvent,
correlationId: "recorded-correlation",
kind: "effect",
occurredAtUnixMs: 3,
payload: {
requestId: "request-1",
turnId: "child-turn-recorded"
},
sequence: 3,
type: "interaction/respond"
}
],
turnIdentityPlan: {
"root-recorded": {
initialTurnIds: [],
recordedTurnIds: ["root-turn-recorded"]
},
"child-recorded": {
initialTurnIds: [],
recordedTurnIds: ["child-turn-recorded"],
kind: "child",
initialSession: false,
rootSessionId: "root-recorded",
rootTurnId: "root-turn-recorded",
parentSessionId: "root-recorded",
parentTurnId: "root-turn-recorded",
parentToolCallId: "call-stable"
}
}
},
2_000,
{
cassetteId: replayCassetteAID,
rendererDriver: {
async dispatchIntent(event) {
dispatched.push(event);
},
async verifyEffect(event) {
verified.push(event);
if (event.type === "interaction/respond") {
rootActiveTurnId = null;
}
}
},
checkpoints: [
{
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] },
schemaVersion: cassettePolicy.schemaVersion
},
{
index: 1,
kind: "after-activity-event",
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 3
},
cursor: { activityEventSequence: 3, providerConnections: [] },
schemaVersion: cassettePolicy.schemaVersion
}
]
}
);
assert.equal(dispatched[0].agentSessionId, "child-live");
assert.equal(dispatched[0].payload.turnId, "child-turn-live");
assert.equal(verified[1].agentSessionId, "child-live");
assert.equal(verified[1].payload.turnId, "child-turn-live");
assert.match(verified[1].correlationId, /^10:child-live/u);
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("resolves the tuttid listener from the daemon run directory", () => {
assert.equal(
replayListenerInfoPath("/tmp/replay-state"),
"/tmp/replay-state/run/tuttid.listener.json"
);
});
test("isolated replay workbench suppresses onboarding without preopening AgentGUI", () => {
const snapshot = replayWorkbenchSnapshot("2026-07-28T00:00:00.000Z");
assert.deepEqual(snapshot.nodes, []);
assert.deepEqual(snapshot.nodeStack, []);
assert.equal(snapshot.activeNodeId, null);
assert.deepEqual(snapshot.metadata.workspaceOnboarding, {
autoOpened: true,
autoOpenedAt: "2026-07-28T00:00:00.000Z",
schemaVersion: 1
});
});
test("replay retries only lifecycle readiness conflicts", () => {
assert.equal(
replayStimulusPrecondition({
type: "session.send",
payload: { guidance: false }
}),
"session-idle"
);
assert.equal(
replayStimulusPrecondition({
type: "session.send",
payload: { guidance: true }
}),
null
);
assert.equal(
replayStimulusPrecondition({ type: "turn.cancel", payload: {} }),
null
);
assert.equal(replayStimulusRetryableStatus("session.create", 502), false);
assert.equal(replayStimulusRetryableStatus("session.create", 503), false);
assert.equal(replayStimulusRetryableStatus("session.send", 409), true);
assert.equal(replayStimulusRetryableStatus("session.send", 502), false);
assert.equal(
replayStimulusRetryableStatus("interactive.response", 404),
false
);
assert.deepEqual(
replayPendingInteraction(
{
pendingInteractions: [
{ requestId: "request-1", status: "pending", turnId: "turn-live" }
]
},
"request-1"
),
{ requestId: "request-1", status: "pending", turnId: "turn-live" }
);
assert.equal(
replayPendingInteraction(
{
pendingInteractions: [
{ requestId: "request-1", status: "answered", turnId: "turn-live" }
]
},
"request-1"
),
null
);
});
test("submit idle wait skips busy-queue submits and honors send causation", () => {
const queuedSubmit = {
kind: "intent",
type: "submit/requested",
eventId: "intent-queued",
correlationId: "submit-queued",
payload: {
routing: "auto",
submitDiagnostics: { queued: false }
}
};
const drainedSubmit = {
kind: "intent",
type: "submit/requested",
eventId: "intent-drained",
correlationId: "submit-drained",
payload: {
routing: "auto",
submitDiagnostics: { queued: false }
}
};
const explicitQueued = {
kind: "intent",
type: "submit/requested",
eventId: "intent-explicit",
payload: {
routing: "auto",
submitDiagnostics: { queued: true }
}
};
const sendNow = {
kind: "intent",
type: "submit/requested",
eventId: "intent-send-now",
payload: {
routing: "send_now",
submitDiagnostics: { queued: false }
}
};
const tape = [
queuedSubmit,
drainedSubmit,
{
kind: "effect",
type: "queue/sendPrompt",
eventId: "effect-1",
causedByEventId: "intent-drained",
correlationId: "submit-drained",
payload: { outcome: "succeeded" }
},
{
kind: "intent",
type: "queue/sendNowRequested",
eventId: "intent-send-now-req",
correlationId: "submit-queued"
},
{
kind: "effect",
type: "queue/sendPrompt",
eventId: "effect-2",
causedByEventId: "intent-send-now-req",
correlationId: "submit-queued",
payload: { outcome: "succeeded" }
}
];
assert.equal(submitRequestedRequiresSessionIdle(queuedSubmit, tape), false);
assert.equal(submitRequestedRequiresSessionIdle(drainedSubmit, tape), true);
assert.equal(submitRequestedRequiresSessionIdle(explicitQueued, tape), false);
assert.equal(submitRequestedRequiresSessionIdle(sendNow, tape), false);
});
test("replay waits for the previous Turn before each queued send", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-order-"));
const listenerDirectory = join(root, "run");
await mkdir(listenerDirectory, { recursive: true });
let active = false;
let activeChecks = 0;
const sent = [];
const accepted = [];
const server = createServer((request, response) => {
if (respondToCheckpointVerification(request, response)) return;
if (
request.method === "GET" &&
request.url ===
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/playback`
) {
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({
drained: false,
paused: false,
playbackElapsedMs: 0,
providerConnections: [],
speed: 1,
timingMode: "realtime"
})
);
return;
}
if (request.method === "GET") {
activeChecks += 1;
if (activeChecks >= 2) active = false;
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({
session: {
activeTurnId: active ? "turn-active" : null,
status: active ? "working" : "idle"
}
})
);
return;
}
if (request.url?.endsWith("/input")) {
if (active) {
response.statusCode = 502;
response.end("agent session already has an active turn");
return;
}
sent.push(request.url);
active = true;
activeChecks = 0;
response.end("{}");
return;
}
active = true;
activeChecks = 0;
response.statusCode = 201;
response.end("{}");
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
await writeFile(
join(listenerDirectory, "tuttid.listener.json"),
JSON.stringify({
addr: `127.0.0.1:${address.port}`,
auth: { token: "test-token" }
})
);
const base = {
workspaceId: "workspace-1",
agentSessionId: "session-1"
};
await replayStimuli(
root,
{
...base,
activityEvents: [
{
...base,
kind: "direct-stimulus",
sequence: 1,
occurredAtUnixMs: 1,
type: "session.send",
payload: { content: [{ type: "text", text: "second" }] }
},
{
...base,
kind: "direct-stimulus",
sequence: 2,
occurredAtUnixMs: 1,
type: "session.send",
payload: { content: [{ type: "text", text: "third" }] }
}
]
},
2_000,
{
checkpoints: [
{
schemaVersion: cassettePolicy.schemaVersion,
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] }
},
{
schemaVersion: cassettePolicy.schemaVersion,
index: 1,
kind: "after-activity-event",
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 2
},
cursor: { activityEventSequence: 2, providerConnections: [] }
}
],
onStimulusAccepted(stimulus) {
accepted.push(stimulus.type);
},
cassetteId: replayCassetteAID
}
);
assert.equal(sent.length, 2);
assert.deepEqual(accepted, ["session.send", "session.send"]);
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("replay diagnoses a 502 through the exact Cassette transport", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-transport-error-"));
const listenerDirectory = join(root, "run");
await mkdir(listenerDirectory, { recursive: true });
const requests = [];
const server = createServer((request, response) => {
if (respondToCheckpointVerification(request, response)) return;
requests.push(`${request.method} ${request.url}`);
if (
request.method === "GET" &&
request.url ===
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/playback`
) {
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({
drained: false,
paused: false,
playbackElapsedMs: 0,
providerConnections: [],
speed: 1,
timingMode: "realtime"
})
);
return;
}
if (
request.method === "POST" &&
request.url ===
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/verify`
) {
response.statusCode = 409;
response.end("recorded outbound frame mismatch");
return;
}
if (request.method === "GET") {
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({
session: { activeTurnId: null, status: "idle" }
})
);
return;
}
response.statusCode = 502;
response.end("provider transport failed");
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
await writeFile(
join(listenerDirectory, "tuttid.listener.json"),
JSON.stringify({
addr: `127.0.0.1:${address.port}`,
auth: { token: "test-token" }
})
);
const base = {
agentSessionId: "session-1",
workspaceId: "workspace-1"
};
await assert.rejects(
replayStimuli(
root,
{
...base,
activityEvents: [
{
...base,
kind: "direct-stimulus",
occurredAtUnixMs: 1,
payload: { content: [{ type: "text", text: "fail" }] },
sequence: 1,
type: "session.send"
}
]
},
2_000,
{
checkpoints: [
{
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] },
schemaVersion: cassettePolicy.schemaVersion
}
],
cassetteId: replayCassetteAID
}
),
/recorded outbound frame mismatch/u
);
assert.equal(
requests.includes(
`POST /v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/verify`
),
true
);
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("replay drives intents and verifies effects without sending HTTP", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-activity-"));
const listenerDirectory = join(root, "run");
await mkdir(listenerDirectory, { recursive: true });
const requests = [];
const playbackStartedAt = Date.now();
const server = createServer((request, response) => {
if (respondToCheckpointVerification(request, response)) return;
if (
request.method === "GET" &&
request.url ===
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/transport/playback`
) {
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({
drained: false,
paused: false,
playbackElapsedMs: Date.now() - playbackStartedAt,
providerConnections: [],
speed: 1,
timingMode: "realtime"
})
);
return;
}
requests.push(`${request.method} ${request.url}`);
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({ session: { activeTurnId: null, status: "idle" } })
);
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
await writeFile(
join(listenerDirectory, "tuttid.listener.json"),
JSON.stringify({
addr: `127.0.0.1:${address.port}`,
auth: { token: "test-token" }
})
);
const base = {
schemaVersion: cassettePolicy.schemaVersion,
scopeId: "workspace-1",
workspaceId: "workspace-1",
agentSessionId: "session-1"
};
const calls = [];
const callTimes = [];
await replayStimuli(
root,
{
workspaceId: base.workspaceId,
agentSessionId: base.agentSessionId,
activityEvents: [
{
...base,
sequence: 1,
occurredAtUnixMs: 1,
kind: "intent",
type: "queue/sendNowRequested",
eventId: "intent-1",
correlationId: "submit-1",
payload: { promptId: "prompt-1" }
},
{
...base,
sequence: 2,
occurredAtUnixMs: 81,
kind: "effect",
type: "session.send",
eventId: "effect-1",
correlationId: "submit-1",
causedByEventId: "intent-1",
payload: { outcome: "succeeded", guidance: true }
}
]
},
2_000,
{
checkpoints: [
{
schemaVersion: cassettePolicy.schemaVersion,
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] }
},
{
schemaVersion: cassettePolicy.schemaVersion,
index: 1,
kind: "after-activity-event",
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 2
},
cursor: { activityEventSequence: 2, providerConnections: [] }
}
],
rendererDriver: {
dispatchIntent(event) {
calls.push(`intent:${event.type}`);
callTimes.push(Date.now());
},
verifyEffect(event) {
calls.push(`effect:${event.payload.outcome}`);
callTimes.push(Date.now());
}
},
cassetteId: replayCassetteAID
}
);
assert.deepEqual(calls, [
"intent:queue/sendNowRequested",
"effect:succeeded"
]);
assert.ok(callTimes[1] - callTimes[0] >= 60);
assert.equal(
requests.some((request) => request.startsWith("POST /v1/workspaces/")),
false
);
assert.equal(
requests.some((request) => request.startsWith("GET /v1/workspaces/")),
true
);
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("renderer activity driver scopes bridge calls to one Replay Cassette", async () => {
const expressions = [];
const driver = createRendererActivityDriver(
{
async send(_method, parameters) {
expressions.push(parameters.expression);
return { result: { value: { accepted: true } } };
}
},
2_000,
replayCassetteAID
);
await driver.dispatchIntent({ type: "submit/requested" });
await driver.verifyEffect({ type: "session.send" });
assert.equal(expressions.length, 2);
assert.match(expressions[0], /dispatchCassetteIntent/u);
assert.match(expressions[0], new RegExp(replayCassetteAID, "u"));
assert.match(expressions[1], /verifyCassetteEffect/u);
assert.match(expressions[1], new RegExp(replayCassetteAID, "u"));
});
test("renderer activity driver resumes an exactly-once invocation after CDP collects its Promise", async () => {
const expressions = [];
let calls = 0;
const driver = createRendererActivityDriver(
{
async send(_method, parameters) {
expressions.push(parameters.expression);
calls += 1;
if (calls === 1) {
throw new Error("Promise was collected (-32000)");
}
return { result: { value: { accepted: true } } };
}
},
2_000,
replayCassetteAID
);
await driver.dispatchIntent({
type: "submit/requested",
eventId: "intent-exactly-once"
});
assert.equal(calls, 2);
assert.equal(expressions[0], expressions[1]);
assert.match(expressions[0], /__tuttiAgentSessionReplayInvocations/u);
assert.match(expressions[0], /intent-exactly-once/u);
});
test("renderer activity driver hard-times out when CDP evaluate never resolves", async () => {
const driver = createRendererActivityDriver(
{
async send() {
return new Promise(() => {
// Simulate a wedged renderer: CDP never settles.
});
}
},
50,
replayCassetteAID
);
await assert.rejects(
() =>
driver.verifyEffect({
type: "session/activate",
eventId: "effect-wedged"
}),
/renderer replay invocation timed out after 1s/u
);
});
test("rejects a direct session.send correlated with a renderer intent", () => {
assert.throws(
() =>
assertNoDuplicateEngineSends([
{
kind: "intent",
type: "submit/requested",
correlationId: "submit-1"
},
{
kind: "direct-stimulus",
type: "session.send",
correlationId: "submit-1"
}
]),
/duplicates renderer intent/u
);
});
test("parses ordered activity events and requires effects to follow intents", () => {
const base = {
schemaVersion: cassettePolicy.schemaVersion,
agentSessionId: "session-1",
occurredAtUnixMs: 1
};
const valid = [
{
...base,
sequence: 1,
kind: "intent",
type: "submit/requested",
eventId: "intent-1",
payload: { content: [] }
},
{
...base,
sequence: 2,
kind: "effect",
type: "session.send",
eventId: "effect-1",
causedByEventId: "intent-1",
payload: { outcome: "succeeded" }
}
];
assert.equal(
parseActivityEvents(valid.map(JSON.stringify).join("\n")).length,
2
);
assert.throws(
() =>
parseActivityEvents(
[
{
...valid[1],
sequence: 1
}
]
.map(JSON.stringify)
.join("\n")
),
/earlier intent/u
);
assert.throws(
() =>
parseActivityEvents(
valid
.map((event, index) =>
JSON.stringify({
...event,
occurredAtUnixMs: index === 0 ? 2 : 1
})
)
.join("\n")
),
/is invalid/u
);
});
test("activity replay clock follows daemon elapsed time and playback state", async () => {
let playback = {
paused: false,
playbackElapsedMs: 0,
providerConnections: [],
speed: 1,
timingMode: "realtime"
};
const waits = [];
let resumeOnNextWait = false;
const clock = createReplayActivityClock({
playbackState: async () => playback,
wait: async (durationMs) => {
waits.push(durationMs);
if (!playback.paused && playback.timingMode === "realtime") {
playback = {
...playback,
playbackElapsedMs:
playback.playbackElapsedMs + durationMs * playback.speed
};
}
if (resumeOnNextWait) {
resumeOnNextWait = false;
playback = { ...playback, paused: false };
}
}
});
await clock.waitUntil(1_000);
playback = { ...playback, playbackElapsedMs: 20 };
await clock.waitUntil(1_100);
assert.equal(
waits.reduce((total, duration) => total + duration, 0),
80
);
playback = { ...playback, speed: 2 };
const speedWaitStart = waits.length;
await clock.waitUntil(1_200);
assert.equal(
waits
.slice(speedWaitStart)
.reduce((total, duration) => total + duration, 0),
50
);
playback = { ...playback, paused: true };
const pauseWaitStart = waits.length;
resumeOnNextWait = true;
await clock.waitUntil(1_300);
assert.equal(
waits
.slice(pauseWaitStart)
.reduce((total, duration) => total + duration, 0),
100
);
playback = { ...playback, timingMode: "fast-forward" };
const fastForwardWaitStart = waits.length;
await clock.waitUntil(2_000);
assert.equal(waits.length, fastForwardWaitStart);
});
test("uses portable checkpoint plan instead of deriving activity boundaries", () => {
const checkpoints = validateReplayCheckpointPlan(
{
schemaVersion: 2,
cassetteSchemaVersion: cassettePolicy.schemaVersion,
observationSchemaVersion: 2,
checkpoints: [
{
id: "checkpoint-0000",
index: 0,
kind: "replay.bootstrap",
tags: ["replay.bootstrap"],
cursor: {
activityEventSequence: 0,
providerConnections: []
},
trigger: { source: "bootstrap" }
},
{
id: "checkpoint-0001",
index: 1,
kind: "submission.accepted",
tags: ["submission.accepted"],
cursor: {
activityEventSequence: 2,
providerConnections: []
},
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 2,
boundaryKind: "intent-effects"
}
}
]
},
[
{ sequence: 1, kind: "intent", eventId: "intent-1" },
{
sequence: 2,
kind: "effect",
eventId: "effect-1",
causedByEventId: "intent-1"
},
{ sequence: 3, kind: "direct-stimulus", eventId: "send-1" }
]
);
assert.deepEqual(
checkpoints.map((checkpoint) => checkpoint.cursor.activityEventSequence),
[0, 2]
);
});
test("rejects checkpoint plan v1 without a compatibility fallback", () => {
assert.throws(
() =>
validateReplayCheckpointPlan(
{
schemaVersion: 1,
cassetteSchemaVersion: cassettePolicy.schemaVersion,
observationSchemaVersion: 1,
checkpoints: []
},
[]
),
/checkpoint_plan_invalid: unsupported plan schema/
);
});
test("next checkpoint fast-forwards without skipping the stable boundary", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-control-"));
const controlPath = join(root, "replay-control.json");
const statusPath = join(root, "replay-status.json");
const commands = [];
const requestPaths = [];
const transportPlayback = {
drained: false,
paused: false,
playbackElapsedMs: 0,
providerConnections: [],
speed: 1,
timingMode: "realtime"
};
const server = createServer(async (request, response) => {
requestPaths.push(request.url);
if (respondToCheckpointVerification(request, response)) return;
if (request.method === "GET") {
response.setHeader("content-type", "application/json");
response.end(JSON.stringify(transportPlayback));
return;
}
let body = "";
for await (const chunk of request) body += chunk;
const command = JSON.parse(body);
commands.push(command);
if (command.command === "pause") transportPlayback.paused = true;
if (command.command === "resume") transportPlayback.paused = false;
if (command.command === "set-timing-mode") {
transportPlayback.timingMode = command.timingMode;
}
response.setHeader("content-type", "application/json");
response.end("{}");
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
const checkpoints = [
{
schemaVersion: cassettePolicy.schemaVersion,
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] }
},
{
schemaVersion: cassettePolicy.schemaVersion,
index: 1,
kind: "after-activity-event",
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 2
},
cursor: { activityEventSequence: 2, providerConnections: [] }
}
];
await writeFile(
controlPath,
JSON.stringify(replayControlRouter(replayCassetteAID, 0, "resume"))
);
const reached = [];
let replacement = null;
const playback = createReplayPlaybackController({
baseURL: `http://127.0.0.1:${address.port}`,
checkpoints,
controlPath,
headers: { "content-type": "application/json" },
onCheckpoint(checkpoint) {
reached.push(checkpoint);
},
onReplacement(value) {
replacement = value;
},
cassetteId: replayCassetteAID,
statusPath,
targetCheckpoint: null,
timeoutMs: 2_000
});
await playback.initialize();
await writeFile(
controlPath,
JSON.stringify(
replayControlRouter(replayCassetteAID, 1, "next-checkpoint")
)
);
await playback.waitUntilRunnable();
assert.equal(playback.checkpointAfter(2).index, 1);
await playback.activityAdvanced(2);
await playback.reach(checkpoints[1]);
assert.deepEqual(reached, [1]);
assert.deepEqual(commands, [
{ command: "set-provider-cursor", providerConnections: [] },
{ command: "set-timing-mode", timingMode: "fast-forward" },
{ command: "resume" },
{ command: "set-timing-mode", timingMode: "realtime" },
{ command: "pause" }
]);
assert.equal(
requestPaths.includes(
`/v1/agent-session-replay/cassettes/${replayCassetteAID}/checkpoints/1/verify`
),
true
);
assert.deepEqual(JSON.parse(await readFile(statusPath, "utf8")), {
currentCheckpoint: 1,
totalCheckpoints: 2,
paused: true,
timingMode: "realtime",
targetCheckpoint: null
});
await writeFile(
controlPath,
JSON.stringify(replayControlRouter(replayCassetteAID, 2, "resume"))
);
await playback.waitUntilRunnable();
assert.deepEqual(commands.at(-1), { command: "resume" });
let slowOperationSettled = false;
let settleSlowOperation;
const slowOperation = new Promise((resolveSlowOperation) => {
settleSlowOperation = resolveSlowOperation;
});
const controlSlowOperation = (async () => {
await writeFile(
controlPath,
JSON.stringify(replayControlRouter(replayCassetteAID, 3, "pause"))
);
for (let attempt = 0; attempt < 20; attempt += 1) {
if (commands.at(-1)?.command === "pause") break;
await delay(25);
}
assert.equal(slowOperationSettled, false);
assert.deepEqual(commands.at(-1), { command: "pause" });
await writeFile(
controlPath,
JSON.stringify(replayControlRouter(replayCassetteAID, 4, "resume"))
);
for (let attempt = 0; attempt < 20; attempt += 1) {
if (commands.at(-1)?.command === "resume") break;
await delay(25);
}
assert.deepEqual(commands.at(-1), { command: "resume" });
settleSlowOperation();
})();
await Promise.all([
playback
.runWhilePolling(() => slowOperation)
.finally(() => {
slowOperationSettled = true;
}),
controlSlowOperation
]);
assert.deepEqual(commands.slice(-3), [
{ command: "pause" },
{ command: "clear-provider-cursor" },
{ command: "resume" }
]);
await writeFile(
controlPath,
JSON.stringify(
replayControlRouter(replayCassetteAID, 5, "switch-cassette", {
cassetteId: "cassette-2"
})
)
);
await assert.rejects(
playback.waitForReplacement(() => true),
/Replay Cassette replacement requested/u
);
assert.deepEqual(replacement, {
command: "switch-cassette",
currentCheckpoint: 1,
cassetteId: "cassette-2"
});
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("manual next holds activity after landing a shared-actSeq checkpoint", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-shared-actseq-"));
const controlPath = join(root, "replay-control.json");
const statusPath = join(root, "replay-status.json");
const commands = [];
const transportPlayback = {
drained: false,
paused: false,
playbackElapsedMs: 0,
providerConnections: [],
speed: 1,
timingMode: "realtime"
};
const server = createServer(async (request, response) => {
if (respondToCheckpointVerification(request, response)) return;
if (request.method === "GET") {
response.setHeader("content-type", "application/json");
response.end(JSON.stringify(transportPlayback));
return;
}
let body = "";
for await (const chunk of request) body += chunk;
const command = JSON.parse(body);
commands.push(command);
if (command.command === "pause") transportPlayback.paused = true;
if (command.command === "resume") transportPlayback.paused = false;
if (command.command === "set-timing-mode") {
transportPlayback.timingMode = command.timingMode;
}
if (command.command === "set-provider-cursor") {
transportPlayback.providerConnections = command.providerConnections ?? [];
}
if (command.command === "clear-provider-cursor") {
transportPlayback.providerConnections = [];
}
response.setHeader("content-type", "application/json");
response.end("{}");
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
const providerAt = (chunkSeq) => [
{ connectionId: "connection-1", chunkSeq, unitIndex: 1 }
];
const checkpoints = [
{
schemaVersion: cassettePolicy.schemaVersion,
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] }
},
{
schemaVersion: cassettePolicy.schemaVersion,
index: 1,
kind: "tool.started",
trigger: {
source: "provider-observation",
type: "call.started"
},
cursor: {
activityEventSequence: 2,
providerConnections: providerAt(54)
}
},
{
schemaVersion: cassettePolicy.schemaVersion,
index: 2,
kind: "interaction.pending",
trigger: {
source: "provider-observation",
type: "interaction.requested"
},
cursor: {
activityEventSequence: 2,
providerConnections: providerAt(55)
}
},
{
schemaVersion: cassettePolicy.schemaVersion,
index: 3,
kind: "interaction.resolved",
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 3
},
cursor: {
activityEventSequence: 3,
providerConnections: providerAt(55)
}
}
];
const reached = [];
const writeControl = createAgentSessionReplayControlWriter(controlPath);
const playback = createReplayPlaybackController({
baseURL: `http://127.0.0.1:${address.port}`,
checkpoints,
controlPath,
headers: { "content-type": "application/json" },
onCheckpoint(checkpoint) {
reached.push(checkpoint);
},
cassetteId: replayCassetteAID,
statusPath,
targetCheckpoint: 1,
timeoutMs: 2_000
});
await playback.initialize();
await playback.activityAdvanced(2);
await playback.runWhilePolling(async () => {
while (!reached.includes(1)) {
await playback.reach(checkpoints[1]);
await delay(10);
}
});
assert.deepEqual(reached, [1]);
const setProviderCountAfterFirstLand = commands.filter(
(command) => command.command === "set-provider-cursor"
).length;
await writeControl({
command: "next-checkpoint",
cassetteId: replayCassetteAID
});
// Duplicate next while seeking must only ack the revision.
await writeControl({
command: "next-checkpoint",
cassetteId: replayCassetteAID
});
await playback.runWhilePolling(async () => {
while (!reached.includes(2)) {
await playback.reach(checkpoints[2]);
await delay(10);
}
});
assert.deepEqual(reached, [1, 2]);
assert.equal(
commands.filter((command) => command.command === "set-provider-cursor")
.length,
setProviderCountAfterFirstLand + 1
);
let activityReleased = false;
const waiting = playback.waitBeforeActivity(3).then(() => {
activityReleased = true;
});
await playback.runWhilePolling(() => delay(80));
assert.equal(activityReleased, false);
await writeControl({
command: "next-checkpoint",
cassetteId: replayCassetteAID
});
await playback.runWhilePolling(() => waiting);
assert.equal(activityReleased, true);
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("Replay Workspace routes Desktop control DTOs to only their Cassette controller", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-control-router-"));
const controlPath = join(root, "replay-control.json");
const commands = [];
const server = createServer(async (request, response) => {
if (request.method === "GET") {
response.setHeader("content-type", "application/json");
response.end(
JSON.stringify({
drained: false,
paused: false,
playbackElapsedMs: 0,
providerConnections: [],
speed: 1,
timingMode: "realtime"
})
);
return;
}
let body = "";
for await (const chunk of request) body += chunk;
const cassetteId = decodeURIComponent(
request.url.split("/cassettes/")[1].split("/transport/")[0]
);
commands.push({ cassetteId, command: JSON.parse(body) });
response.setHeader("content-type", "application/json");
response.end("{}");
});
await new Promise((resolveListen) =>
server.listen(0, "127.0.0.1", resolveListen)
);
try {
const address = server.address();
assert.notEqual(address, null);
assert.equal(typeof address, "object");
const input = {
baseURL: `http://127.0.0.1:${address.port}`,
checkpoints: [
{
schemaVersion: cassettePolicy.schemaVersion,
index: 0,
kind: "bootstrap",
trigger: { source: "bootstrap" },
cursor: { activityEventSequence: 0, providerConnections: [] }
},
{
schemaVersion: cassettePolicy.schemaVersion,
index: 1,
kind: "after-activity-event",
trigger: {
source: "activity-boundary",
afterActivityEventSequence: 1
},
cursor: { activityEventSequence: 1, providerConnections: [] }
}
],
controlPath,
headers: { "content-type": "application/json" },
targetCheckpoint: null,
timeoutMs: 2_000
};
const controllerA = createReplayPlaybackController({
...input,
cassetteId: replayCassetteAID
});
const controllerB = createReplayPlaybackController({
...input,
cassetteId: replayCassetteBID
});
await Promise.all([controllerA.initialize(), controllerB.initialize()]);
const writeControl = createAgentSessionReplayControlWriter(controlPath);
await writeControl({ command: "pause", cassetteId: replayCassetteAID });
await Promise.all([
controllerA.runWhilePolling(() => delay(80)),
controllerB.runWhilePolling(() => delay(80))
]);
assert.deepEqual(commands, [
{
cassetteId: replayCassetteAID,
command: { command: "pause" }
}
]);
await writeControl({
command: "next-checkpoint",
cassetteId: replayCassetteBID
});
await Promise.all([
controllerA.runWhilePolling(() => delay(80)),
controllerB.runWhilePolling(() => delay(80))
]);
assert.deepEqual(commands.slice(1), [
{
cassetteId: replayCassetteBID,
command: {
command: "set-provider-cursor",
providerConnections: []
}
},
{
cassetteId: replayCassetteBID,
command: {
command: "set-timing-mode",
timingMode: "fast-forward"
}
},
{
cassetteId: replayCassetteBID,
command: { command: "resume" }
}
]);
assert.deepEqual(JSON.parse(await readFile(controlPath, "utf8")), {
schemaVersion: 2,
cassettes: {
[replayCassetteAID]: { command: "pause", revision: 1 },
[replayCassetteBID]: {
command: "next-checkpoint",
revision: 1
}
}
});
} finally {
await new Promise((resolveClose, rejectClose) =>
server.close((error) => (error ? rejectClose(error) : resolveClose()))
);
}
});
test("record arguments default to headed mode", () => {
const options = parseArgs([
"--record",
".tmp/cassettes/example",
"--scenario",
"c01",
"--scenario-file",
"/tmp/cases/c01/scenario.mjs",
"--timeout-ms",
"1234"
]);
assert.equal(options.mode, "record");
assert.equal(options.headless, undefined);
assert.equal(resolveDesktopHeadless(options), false);
assert.equal(options.scenario, "c01");
assert.equal(options.timeoutMs, 1234);
assert.equal(options.stallTimeoutMs, 60_000);
assert.match(
options.cassetteDirectory,
/[/\\]\.tmp[/\\]cassettes[/\\]example$/u
);
});
test("headless flag hides the Electron window", () => {
const options = parseArgs([
"--replay",
".tmp/cassettes/example",
"--headless"
]);
assert.equal(options.headless, true);
assert.equal(resolveDesktopHeadless(options), true);
});
test("managed replay stays headed even with --headless", () => {
const options = parseArgs([
"--replay",
".tmp/cassettes/example",
"--cassette-id",
"example",
"--managed",
"--headless"
]);
assert.equal(options.managed, true);
assert.equal(options.headless, true);
assert.equal(resolveDesktopHeadless(options), false);
});
test("stall timeout accepts an override and zero disables it", () => {
const options = parseArgs([
"--replay",
".tmp/cassettes/example",
"--stall-timeout-ms",
"5000"
]);
assert.equal(options.stallTimeoutMs, 5000);
const disabled = parseArgs([
"--replay",
".tmp/cassettes/example",
"--stall-timeout-ms",
"0"
]);
assert.equal(disabled.stallTimeoutMs, 0);
assert.throws(
() =>
parseArgs([
"--replay",
".tmp/cassettes/example",
"--stall-timeout-ms",
"-1"
]),
/--stall-timeout-ms must be a non-negative integer/
);
});
test("screenshot checkpoints are opt-in for replay only", () => {
const options = parseArgs([
"--replay",
".tmp/cassettes/example",
"--screenshot-checkpoints"
]);
assert.equal(options.screenshotCheckpoints, true);
const workspace = parseArgs([
"--replay-workspace-manifest",
".tmp/replay-workspace.json",
"--screenshot-checkpoints"
]);
assert.equal(workspace.screenshotCheckpoints, true);
assert.throws(
() =>
parseArgs([
"--record",
".tmp/cassettes/example",
"--scenario",
"c01",
"--scenario-file",
"/tmp/cases/c01/scenario.mjs",
"--screenshot-checkpoints"
]),
/--screenshot-checkpoints is only supported with replay/
);
});
test("checkpoint screenshot paths stay Cassette-scoped in a Replay Workspace", () => {
const checkpoints = [{ id: "checkpoint-0000" }, { id: "checkpoint-0004" }];
assert.equal(
replayCheckpointScreenshotPath({
artifactDirectory: "/tmp/artifacts",
checkpointIndex: 4,
checkpoints: [{ id: "checkpoint-0000" }]
}),
join("/tmp/artifacts", "checkpoint-0004.png")
);
assert.equal(
replayCheckpointScreenshotPath({
artifactDirectory: "/tmp/artifacts",
cassetteId: "cassette-a",
checkpointIndex: 1,
checkpoints
}),
join("/tmp/artifacts", "cassette-a", "checkpoint-0004.png")
);
});
test("normalizeScreenshotClip rejects tiny or invalid rects", () => {
assert.equal(normalizeScreenshotClip(null), null);
assert.equal(
normalizeScreenshotClip({ x: 0, y: 0, width: 4, height: 100 }),
null
);
assert.deepEqual(
normalizeScreenshotClip({ x: 10.9, y: 20.1, width: 300.7, height: 400.2 }),
{ x: 10, y: 20, width: 300, height: 400, scale: 1 }
);
});
test("screenshotEvidenceLabel prefers caseId over scenario", () => {
assert.equal(screenshotEvidenceLabel(" C03 "), "C03");
assert.equal(
screenshotEvidenceLabel({ caseId: "C03", scenario: "c03" }),
"C03"
);
assert.equal(screenshotEvidenceLabel({ scenario: "c03" }), "c03");
assert.equal(screenshotEvidenceLabel({}), "");
});
test("captureScreenshot clips to the pinned Agent Session and stamps a case badge", async () => {
const directory = await mkdtemp(join(tmpdir(), "asr-clip-shot-"));
const outputPath = join(directory, "checkpoint.png");
const evaluations = [];
const captures = [];
const client = {
async send(method, params) {
if (method === "Runtime.evaluate") {
evaluations.push(params.expression);
if (params.expression.includes("getBoundingClientRect")) {
return {
result: {
value: { x: 120.4, y: 40.6, width: 640.8, height: 800.2 }
}
};
}
return { result: { value: true } };
}
if (method === "Page.captureScreenshot") {
captures.push(params);
// 1x1 PNG
return {
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
};
}
throw new Error(`unexpected CDP method: ${method}`);
}
};
const result = await captureScreenshot(client, outputPath, {
agentSessionId: "session-left",
label: "C03"
});
assert.deepEqual(result.clip, {
x: 120,
y: 40,
width: 640,
height: 800,
scale: 1
});
assert.equal(captures.length, 1);
assert.deepEqual(captures[0].clip, result.clip);
assert.ok(
evaluations.some((expression) =>
expression.includes('data-tutti-replay-evidence-badge="true"')
)
);
assert.ok(evaluations.some((expression) => expression.includes('"C03"')));
assert.ok(
evaluations.some((expression) =>
expression.includes(
"querySelectorAll('[data-tutti-replay-evidence-badge="
)
)
);
assert.equal((await readFile(outputPath)).length > 0, true);
});
test("captureScreenshot falls back to a full-page shot when the session rect is missing", async () => {
const directory = await mkdtemp(join(tmpdir(), "asr-full-shot-"));
const outputPath = join(directory, "checkpoint.png");
const captures = [];
const client = {
async send(method, params) {
if (method === "Runtime.evaluate") {
if (params.expression.includes("getBoundingClientRect")) {
return { result: { value: null } };
}
return { result: { value: true } };
}
if (method === "Page.captureScreenshot") {
captures.push(params);
return {
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
};
}
throw new Error(`unexpected CDP method: ${method}`);
}
};
const result = await captureScreenshot(client, outputPath, {
agentSessionId: "missing-session",
label: "C05"
});
assert.equal(result.clip, null);
assert.equal(captures.length, 1);
assert.equal(captures[0].clip, undefined);
});
test("captureCheckpointScreenshot keeps Cassette path and forwards clip identity", async () => {
const directory = await mkdtemp(join(tmpdir(), "asr-checkpoint-shot-"));
const captures = [];
const client = {
async send(method, params) {
if (method === "Runtime.evaluate") {
if (params.expression.includes("getBoundingClientRect")) {
return {
result: { value: { x: 0, y: 0, width: 200, height: 300 } }
};
}
return { result: { value: true } };
}
if (method === "Page.captureScreenshot") {
captures.push(params);
return {
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
};
}
throw new Error(`unexpected CDP method: ${method}`);
}
};
const outputPath = await captureCheckpointScreenshot({
agentSessionId: "session-a",
artifactDirectory: directory,
cassetteId: "cassette-a",
checkpointIndex: 0,
checkpoints: [{ id: "checkpoint-0007" }],
client,
label: "R12"
});
assert.equal(
outputPath,
join(directory, "cassette-a", "checkpoint-0007.png")
);
assert.deepEqual(captures[0]?.clip, {
x: 0,
y: 0,
width: 200,
height: 300,
scale: 1
});
});
test("resolveAgentSessionScreenshotClip returns null without a session id", async () => {
assert.equal(
await resolveAgentSessionScreenshotClip({ send() {} }, ""),
null
);
assert.equal(
await resolveAgentSessionScreenshotClip({ send() {} }, null),
null
);
});
test("record arguments accept an external scenario file", () => {
const options = parseArgs([
"--record",
".tmp/cassettes/example",
"--scenario",
"c01",
"--scenario-file",
"/tmp/cases/c01/scenario.mjs"
]);
assert.equal(options.scenario, "c01");
assert.equal(options.scenarioFile, "/tmp/cases/c01/scenario.mjs");
});
test("replay arguments accept an optional scenario file for screenshot settle", () => {
const options = parseArgs([
"--replay",
".tmp/cassettes/example",
"--scenario",
"c01",
"--scenario-file",
"/tmp/cases/c01/scenario.mjs",
"--screenshot-checkpoints"
]);
assert.equal(options.mode, "replay");
assert.equal(options.scenario, "c01");
assert.equal(options.scenarioFile, "/tmp/cases/c01/scenario.mjs");
assert.equal(options.screenshotCheckpoints, true);
});
test("checkpoint settle targets completed tool and terminal turn checkpoints", () => {
assert.equal(checkpointNeedsScreenshotSettle(null), true);
assert.equal(
checkpointNeedsScreenshotSettle({
kind: "tool.completed",
tags: ["tool.completed"]
}),
true
);
assert.equal(
checkpointNeedsScreenshotSettle({
kind: "turn.terminal",
tags: ["turn.terminal"]
}),
true
);
assert.equal(
checkpointNeedsScreenshotSettle({
kind: "tool.started",
tags: ["tool.started"]
}),
false
);
assert.equal(
checkpointNeedsScreenshotSettle({
kind: "submission.accepted",
tags: ["submission.accepted"]
}),
false
);
assert.equal(
checkpointNeedsScreenshotSettle({
kind: "turn.working",
tags: ["turn.working"]
}),
false
);
assert.equal(checkpointNeedsToolSettle(null), false);
assert.equal(
checkpointNeedsToolSettle({
kind: "tool.completed",
tags: ["tool.completed"]
}),
true
);
assert.equal(
checkpointNeedsToolSettle({
kind: "tool.started",
tags: ["tool.started"]
}),
false
);
assert.equal(
checkpointNeedsToolSettle({
kind: "turn.terminal",
tags: ["turn.terminal"]
}),
false
);
assert.equal(
checkpointNeedsToolSettle({ kind: "turn.working", tags: ["turn.working"] }),
false
);
assert.equal(
checkpointAllowsOptionalScreenshotSettle({
kind: "submission.accepted",
tags: ["submission.accepted"]
}),
true
);
assert.equal(
checkpointAllowsOptionalScreenshotSettle({
kind: "plan.waiting",
tags: ["plan.waiting"]
}),
true
);
assert.equal(
checkpointAllowsOptionalScreenshotSettle({
kind: "turn.working",
tags: ["turn.working"]
}),
false
);
});
test("record scenarios require an id and file and reject raw prompt overrides", () => {
assert.throws(
() => parseArgs(["--record", ".tmp/cassettes/example"]),
/--scenario is required/u
);
assert.throws(
() =>
parseArgs(["--record", ".tmp/cassettes/example", "--scenario", "c01"]),
/--scenario and --scenario-file must be provided together/u
);
assert.throws(
() =>
parseArgs([
"--record",
".tmp/cassettes/example",
"--scenario",
"i01",
"--scenario-file",
"/tmp/cases/i01/scenario.mjs",
"--prompt",
"override"
]),
/unknown option: --prompt/u
);
});
test("record runner loads and validates the external scenario module", async () => {
const directory = await mkdtemp(join(tmpdir(), "external-scenario-"));
const scenarioFile = join(directory, "scenario.mjs");
await writeFile(
scenarioFile,
`export default {
id: "c01",
prepare() {},
drive() {},
assert() {}
};\n`
);
const scenario = await loadRecordScenario({
scenario: "c01",
scenarioFile
});
assert.equal(scenario.id, "c01");
await assert.rejects(
loadRecordScenario({ scenario: "c02", scenarioFile }),
/does not export scenario c02/u
);
});
test("record and replay modes are mutually exclusive", () => {
assert.throws(
() =>
parseArgs([
"--record",
".tmp/cassettes/record",
"--replay",
".tmp/cassettes/replay"
]),
/exactly one/u
);
});
test("managed replay requires the daemon-owned Replay Cassette id", () => {
assert.throws(
() => parseArgs(["--replay", ".tmp/cassette", "--managed"]),
/--cassette-id is required/u
);
});
test("Replay Workspace arguments accept one fixed batch manifest", () => {
const options = parseArgs([
"--replay-workspace-manifest",
".tmp/replay-workspace.json",
"--managed"
]);
assert.equal(options.mode, "replay-workspace");
assert.equal(options.managed, true);
assert.match(
options.replayWorkspaceManifestPath,
/[/\\]\.tmp[/\\]replay-workspace\.json$/u
);
assert.throws(
() =>
parseArgs([
"--replay-workspace-manifest",
".tmp/replay-workspace.json",
"--cassette-id",
replayCassetteAID
]),
/--cassette-id is not supported/u
);
});
test("Replay Workspace manifest rejects duplicate cassette and root Session", () => {
const cassette = (cassetteId, rootAgentSessionId) => ({
cassetteId,
cassetteDirectory: `.tmp/${cassetteId}`,
rootAgentSessionId
});
assert.throws(
() =>
validateReplayWorkspaceManifest({
playbackMode: "unexpected",
cassettes: [cassette(replayCassetteAID, "root-a")]
}),
/playback mode is invalid/u
);
assert.throws(
() =>
validateReplayWorkspaceManifest({
playbackMode: "automatic",
workspaceId: "workspace-a",
cassettes: [
cassette(replayCassetteAID, "root-a"),
cassette(replayCassetteAID, "root-b")
]
}),
/duplicate Replay Workspace cassette/u
);
assert.throws(
() =>
validateReplayWorkspaceManifest({
playbackMode: "automatic",
workspaceId: "workspace-a",
cassettes: [
cassette(replayCassetteAID, "root-a"),
cassette(replayCassetteBID, "root-a")
]
}),
/duplicate Replay Workspace root Session/u
);
assert.deepEqual(
validateReplayWorkspaceManifest({
playbackMode: "manual",
cassettes: [{ cassetteDirectory: ".tmp/portable-cassette" }]
}),
{
cassettes: [
{
caseId: "",
cassetteDirectory: join(process.cwd(), ".tmp", "portable-cassette"),
cassetteId: "",
rootAgentSessionId: "",
scenario: "",
scenarioFile: ""
}
],
playbackMode: "manual",
workspaceId: null
}
);
assert.equal(
validateReplayWorkspaceManifest({
playbackMode: "automatic",
cassettes: [
{
caseId: "C03",
cassetteDirectory: ".tmp/c03"
}
]
}).cassettes[0]?.caseId,
"C03"
);
});
test("manual Replay Workspace starts at its first inspectable checkpoint", () => {
assert.equal(
replayWorkspaceInitialTargetCheckpoint(
{
action: { type: "continue-session" },
cassetteId: replayCassetteAID,
checkpoints: [{}]
},
"manual"
),
0
);
assert.equal(
replayWorkspaceInitialTargetCheckpoint(
{
action: { type: "create-session" },
cassetteId: replayCassetteBID,
checkpoints: [{}, {}]
},
"manual"
),
1
);
assert.equal(
replayWorkspaceInitialTargetCheckpoint(
{
action: { type: "create-session" },
cassetteId: replayCassetteBID,
checkpoints: [{}]
},
"automatic"
),
null
);
});
test("Replay Workspace shares the earliest recorded Activity clock origin", () => {
assert.equal(
replayWorkspaceActivityClockOrigin([
{ action: { activityEvents: [{ occurredAtUnixMs: 2_000 }] } },
{ action: { activityEvents: [{ occurredAtUnixMs: 1_000 }] } }
]),
1_000
);
assert.equal(
replayWorkspaceActivityClockOrigin([{ action: { activityEvents: [] } }]),
null
);
});
test("Replay Workspace rejects duplicate identities derived from artifacts", async () => {
let runtimeCreates = 0;
await assert.rejects(
bootstrapReplayWorkspace(
{
playbackMode: "automatic",
cassettes: [
{ cassetteDirectory: ".tmp/cassette-a" },
{ cassetteDirectory: ".tmp/cassette-b" }
]
},
{
createWorkspaceId: () => "replay-workspace",
async loadCassette(cassette) {
return {
...cassette,
cassetteId: replayCassetteAID,
rootAgentSessionId: "root-a"
};
},
async createRuntime() {
runtimeCreates += 1;
return {};
}
}
),
/duplicate Replay Workspace cassette/u
);
assert.equal(runtimeCreates, 0);
});
test("Replay Workspace leaves Workspace creation to the semantic runtime", async () => {
const calls = [];
const manifest = {
playbackMode: "automatic",
workspaceId: "workspace-a",
cassettes: [
{
cassetteId: replayCassetteAID,
cassetteDirectory: ".tmp/cassette-a",
rootAgentSessionId: "root-a"
},
{
cassetteId: replayCassetteBID,
cassetteDirectory: ".tmp/cassette-b",
rootAgentSessionId: "root-b"
}
]
};
const bootstrap = await bootstrapReplayWorkspace(manifest, {
async loadCassette(cassette) {
calls.push(`load:${cassette.cassetteId}`);
return {
...cassette,
action: { activityEvents: [], workspaceId: "workspace-a" },
mode: "create-session"
};
},
async createRuntime(mode) {
calls.push(`create:${mode}`);
return {
directory: "/runtime",
stateDirectory: "/runtime/state"
};
},
async initializeDatabase() {
calls.push("database");
},
async materializeBlobs() {
calls.push("blobs");
},
async removeRuntime() {
calls.push("remove");
}
});
assert.deepEqual(calls, [
`load:${replayCassetteAID}`,
`load:${replayCassetteBID}`,
"create:replay-workspace",
"database",
"blobs"
]);
assert.equal(bootstrap.runtime.directory, "/runtime");
assert.deepEqual(
bootstrap.registrations,
replayWorkspaceTransportRegistrations(bootstrap.cassettes)
);
});
test("Replay Workspace seeds each portable project once before blobs", async () => {
const calls = [];
const sharedProject = resolveRecordScenarioProject(
{ label: "repo", relativePath: "." },
workspaceRoot
);
const nestedProject = resolveRecordScenarioProject(
{ label: "agent", relativePath: "packages/agent" },
workspaceRoot
);
await bootstrapReplayWorkspace(
{
playbackMode: "automatic",
workspaceId: "workspace-a",
cassettes: [
{
cassetteId: replayCassetteAID,
cassetteDirectory: ".tmp/cassette-a",
rootAgentSessionId: "root-a"
},
{
cassetteId: replayCassetteBID,
cassetteDirectory: ".tmp/cassette-b",
rootAgentSessionId: "root-b"
},
{
cassetteId: "a4509255-05f8-4420-aa75-d07234cae38e",
cassetteDirectory: ".tmp/cassette-c",
rootAgentSessionId: "root-c"
}
]
},
{
async loadCassette(cassette) {
return {
...cassette,
action: {
replayProject:
cassette.rootAgentSessionId === "root-c"
? nestedProject
: sharedProject,
workspaceId: "workspace-a"
},
mode: "create-session"
};
},
async createRuntime() {
return {
directory: "/runtime",
stateDirectory: "/runtime/state"
};
},
async initializeDatabase(_runtime, workspaceId) {
calls.push(`database:${workspaceId}`);
},
async seedUserProject(databasePath, project) {
calls.push(`project:${databasePath}:${project.portablePath}`);
},
async materializeBlobs() {
calls.push("blobs");
}
}
);
assert.deepEqual(calls, [
"database:workspace-a",
"project:/runtime/state/tuttid.db:${REPLAY_CWD}",
"project:/runtime/state/tuttid.db:${REPLAY_CWD}/packages/agent",
"blobs"
]);
});
test("Replay registrations carry cassette provider and frozen model metadata", () => {
assert.deepEqual(
replayWorkspaceTransportRegistrations([
{
cassetteId: replayCassetteAID,
rootAgentSessionId: "root-a",
cassetteDirectory: "/tmp/cassette-a",
providers: ["codex"],
replayPrerequisites: replayPrerequisitesForTest(),
action: { workspaceId: "workspace-a" }
}
]),
[
{
cassetteId: replayCassetteAID,
rootAgentSessionId: "root-a",
cassetteDirectory: "/tmp/cassette-a/provider",
artifactDirectory: "/tmp/cassette-a",
workspaceId: "workspace-a",
providers: ["codex"],
frozenModel: "gpt-5.4"
}
]
);
});
test("Replay database enables the agent session recording feature", async () => {
const databasePath = join(
tmpdir(),
`agent-session-replay-feature-${Date.now()}.db`
);
try {
await execFileAsync("sqlite3", [
databasePath,
`CREATE TABLE desktop_preferences (
id TEXT PRIMARY KEY,
feature_flags_json TEXT
);
INSERT INTO desktop_preferences (id, feature_flags_json)
VALUES ('desktop', '{}');`
]);
await enableAgentSessionRecordingFeature(databasePath, workspaceRoot);
const result = await execFileAsync("sqlite3", [
databasePath,
`SELECT json_extract(feature_flags_json, '$."agent.sessionRecording"')
FROM desktop_preferences WHERE id = 'desktop';`
]);
assert.equal(result.stdout.trim(), "1");
} finally {
await rm(databasePath, { force: true });
}
});
test("resolves a project placement from portable expected Session state", () => {
const project = resolveReplayProjectFromExpectedState(
{
agent: {
sessions: [
{
id: "root-a",
railSectionKey: "project:${REPLAY_CWD}/packages/agent"
}
]
}
},
"root-a",
workspaceRoot
);
assert.deepEqual(project, {
id: `replay-project-${createHash("sha256")
.update(join(workspaceRoot, "packages/agent"))
.digest("hex")
.slice(0, 16)}`,
label: "agent",
path: join(workspaceRoot, "packages/agent"),
portablePath: "${REPLAY_CWD}/packages/agent"
});
assert.equal(
resolveReplayProjectFromExpectedState(
{
agent: {
sessions: [{ id: "root-a", railSectionKey: "conversations" }]
}
},
"root-a",
workspaceRoot
),
null
);
assert.throws(
() =>
resolveReplayProjectFromExpectedState(
{
agent: {
sessions: [
{ id: "root-a", railSectionKey: "project:/recording/root" }
]
}
},
"root-a",
workspaceRoot
),
/not portable/u
);
});
test("Replay Workspace does not create a runtime when any cassette is invalid", async () => {
let runtimeCreates = 0;
await assert.rejects(
bootstrapReplayWorkspace(
{
playbackMode: "automatic",
workspaceId: "workspace-a",
cassettes: [
{
cassetteId: replayCassetteAID,
cassetteDirectory: ".tmp/cassette-a",
rootAgentSessionId: "root-a"
},
{
cassetteId: replayCassetteBID,
cassetteDirectory: ".tmp/cassette-b",
rootAgentSessionId: "root-b"
}
]
},
{
async loadCassette(cassette) {
if (cassette.cassetteId === replayCassetteBID) {
throw new Error("tampered cassette");
}
return cassette;
},
async createRuntime() {
runtimeCreates += 1;
return {};
}
}
),
/tampered cassette/u
);
assert.equal(runtimeCreates, 0);
});
test("Replay Workspace verifies every Cassette through its cassette-scoped endpoint", async () => {
const calls = [];
const results = await verifyReplayWorkspaceTransports(
"/runtime/state",
[{ cassetteId: replayCassetteAID }, { cassetteId: replayCassetteBID }],
1234,
async (stateDirectory, cassetteId, timeoutMs) => {
calls.push({ stateDirectory, cassetteId, timeoutMs });
if (cassetteId === replayCassetteAID) throw new Error("leftover frame");
}
);
assert.deepEqual(calls, [
{
stateDirectory: "/runtime/state",
cassetteId: replayCassetteAID,
timeoutMs: 1234
},
{
stateDirectory: "/runtime/state",
cassetteId: replayCassetteBID,
timeoutMs: 1234
}
]);
assert.deepEqual(results, [
{
cassetteId: replayCassetteAID,
verified: false,
error: "leftover frame"
},
{ cassetteId: replayCassetteBID, verified: true }
]);
});
test("non-managed Replay Workspace propagates Cassette failures", () => {
assert.throws(
() =>
assertReplayWorkspaceSucceeded(
[
{ cassetteId: replayCassetteAID, succeeded: true },
{ cassetteId: replayCassetteBID, succeeded: false }
],
false
),
new RegExp(replayCassetteBID, "u")
);
assert.doesNotThrow(() =>
assertReplayWorkspaceSucceeded(
[{ cassetteId: replayCassetteBID, succeeded: false }],
true
)
);
});
test("non-managed Replay Workspace preserves the first Cassette root cause", () => {
const rootCause = new Error("first cassette failed");
assert.throws(
() =>
assertReplayWorkspaceSucceeded(
[
{
cassetteId: replayCassetteAID,
error: rootCause,
succeeded: false
},
{ cassetteId: replayCassetteBID, succeeded: false }
],
false
),
(error) => error === rootCause
);
});
test("Replay Workspace bootstrap calls the renderer bridge once with all Cassettes", async () => {
const evaluations = [];
const snapshot = { ready: false, cassettes: [] };
const result = await bootstrapRendererReplayWorkspace(
{
async send(method, parameters) {
evaluations.push({ method, parameters });
return { result: { value: snapshot } };
}
},
[
{
action: { agentTargetId: "local:codex" },
cassetteId: replayCassetteAID,
rootAgentSessionId: "root-a",
mode: "create-session",
ignored: true
},
{
action: { agentTargetId: "local:claude-code" },
cassetteId: replayCassetteBID,
rootAgentSessionId: "root-b",
mode: "continue-session",
ignored: true
}
],
2_000
);
assert.equal(result, snapshot);
assert.equal(evaluations.length, 1);
assert.equal(evaluations[0].method, "Runtime.evaluate");
assert.match(
evaluations[0].parameters.expression,
/__tuttiAgentSessionReplayWorkspace/u
);
assert.match(
evaluations[0].parameters.expression,
new RegExp(replayCassetteAID, "u")
);
assert.match(evaluations[0].parameters.expression, /local:codex/u);
assert.match(
evaluations[0].parameters.expression,
new RegExp(replayCassetteBID, "u")
);
assert.match(evaluations[0].parameters.expression, /create-session/u);
assert.match(evaluations[0].parameters.expression, /continue-session/u);
assert.doesNotMatch(evaluations[0].parameters.expression, /ignored/u);
});
test("Replay Workspace reactivates a created Session before continuing", async () => {
const evaluations = [];
await activateRendererReplayWorkspaceCassette(
{
async send(method, parameters) {
evaluations.push({ method, parameters });
if (evaluations.length === 1) {
return { result: { value: { ready: false } } };
}
return {
result: {
value: {
ready: true,
cassette: { cassetteId: replayCassetteAID, ready: true }
}
}
};
}
},
replayCassetteAID,
2_000
);
assert.match(evaluations[0].parameters.expression, /\.activate\(/u);
assert.equal(evaluations.length, 2);
});
test("Replay runner never reloads the page when a Session is created", async () => {
const source = await readFile(
new URL("./run-agent-session-replay.mjs", import.meta.url),
"utf8"
);
assert.doesNotMatch(source, /Page\.reload/u);
});
test("managed replacement accepts a stable target checkpoint", () => {
const options = parseArgs([
"--replay",
".tmp/cassette",
"--managed",
"--cassette-id",
"cassette-2",
"--target-checkpoint",
"3"
]);
assert.equal(options.targetCheckpoint, 3);
assert.throws(
() => parseArgs(["--replay", ".tmp/cassette", "--target-checkpoint", "-1"]),
/non-negative integer/u
);
});
test("Replay duration includes provider frames and later activity", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-duration-"));
const providerDirectory = dirname(
join(root, cassettePolicy.files.providerManifest.path)
);
await mkdir(providerDirectory, { recursive: true });
await writeFile(
join(providerDirectory, "frames.jsonl"),
[
JSON.stringify({ elapsedMs: 1_000 }),
JSON.stringify({ elapsedMs: 8_000 })
].join("\n")
);
assert.equal(
await readReplayTotalDurationMs(root, 10_000, [
{ occurredAtUnixMs: 11_000 },
{ occurredAtUnixMs: 19_500 }
]),
9_500
);
});
test("does not accept a source user database", () => {
assert.throws(
() =>
parseArgs([
"--replay",
".tmp/cassettes/replay",
"--source-db",
"/Users/example/.tutti/tuttid.db"
]),
/unknown option/u
);
});
test("action validation accepts create and continue Session scenarios", () => {
assert.doesNotThrow(() =>
validateAction({
schemaVersion: 1,
type: "create-session",
agentTargetId: "local:codex",
prompts: ["one", "two", "three"]
})
);
assert.doesNotThrow(() =>
validateAction({
schemaVersion: 1,
type: "continue-session",
agentTargetId: "local:codex",
prompts: ["next"]
})
);
assert.throws(
() =>
validateAction({
schemaVersion: 1,
type: "new-session-submit",
agentTargetId: "local:codex",
prompts: ["old"]
}),
/invalid or unsupported/u
);
});
test("materializes verified content-addressed attachment blobs", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-blobs-"));
const cassette = join(root, "cassette");
const state = join(root, "state");
const data = Buffer.from("attachment bytes");
const digest = createHash("sha256").update(data).digest("hex");
await mkdir(join(cassette, "blobs", "sha256"), { recursive: true });
await writeFile(join(cassette, "blobs", "sha256", digest), data);
await writeFile(
join(cassette, "blobs", "manifest.json"),
JSON.stringify({
schemaVersion: 1,
blobs: [
{
kind: "agent-prompt-attachment",
sha256: digest,
sizeBytes: data.byteLength,
agentSessionId: "session-1",
attachmentId: "attachment-1",
mimeType: "image/png"
}
]
})
);
await materializeReplayWorkspaceBlobs(
[{ cassetteDirectory: cassette }],
state
);
assert.deepEqual(
await readFile(
join(state, "agent", "attachments", "session-1", "attachment-1.png")
),
data
);
});
test("materializes verified generated image blobs into Codex home", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-generated-image-"));
const cassette = join(root, "cassette");
const state = join(root, "state");
const data = Buffer.from("generated image bytes");
const digest = createHash("sha256").update(data).digest("hex");
await mkdir(join(cassette, "blobs", "sha256"), { recursive: true });
await writeFile(join(cassette, "blobs", "sha256", digest), data);
await writeFile(
join(cassette, "blobs", "manifest.json"),
JSON.stringify({
schemaVersion: 1,
blobs: [
{
kind: "agent-generated-image",
sha256: digest,
sizeBytes: data.byteLength,
agentSessionId: "session-1",
relativePath: "generated_images/call-1/image.png",
mimeType: "image/png"
}
]
})
);
await materializeReplayWorkspaceBlobs(
[{ cassetteDirectory: cassette }],
state
);
assert.deepEqual(
await readFile(
join(
state,
"agent",
"runs",
"session-1",
"codex-home",
"generated_images",
"call-1",
"image.png"
)
),
data
);
});
test("Replay Workspace rejects conflicting blobs before materialization", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-blob-conflict-"));
const state = join(root, "state");
const cassettes = [];
for (const [name, contents] of [
["cassette-a", "one"],
["cassette-b", "two"]
]) {
const cassette = join(root, name);
const digest = createHash("sha256").update(contents).digest("hex");
await mkdir(join(cassette, "blobs", "sha256"), { recursive: true });
await writeFile(join(cassette, "blobs", "sha256", digest), contents);
await writeFile(
join(cassette, "blobs", "manifest.json"),
JSON.stringify({
schemaVersion: 1,
blobs: [
{
kind: "agent-prompt-attachment",
sha256: digest,
sizeBytes: contents.length,
agentSessionId: "session-a",
attachmentId: "attachment-a",
mimeType: "image/png"
}
]
})
);
cassettes.push({ cassetteDirectory: cassette });
}
await assert.rejects(
materializeReplayWorkspaceBlobs(cassettes, state),
/conflicting Replay Workspace blob target/u
);
await assert.rejects(
readFile(
join(state, "agent", "attachments", "session-a", "attachment-a.png")
)
);
});
test("rejects a tampered attachment blob", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-blob-tamper-"));
const cassette = join(root, "cassette");
const data = Buffer.from("expected bytes");
const digest = createHash("sha256").update(data).digest("hex");
await mkdir(join(cassette, "blobs", "sha256"), { recursive: true });
await writeFile(
join(cassette, "blobs", "sha256", digest),
Buffer.from("tampered")
);
await writeFile(
join(cassette, "blobs", "manifest.json"),
JSON.stringify({
schemaVersion: 1,
blobs: [
{
kind: "agent-prompt-attachment",
sha256: digest,
sizeBytes: data.byteLength,
agentSessionId: "session-1",
attachmentId: "attachment-1",
mimeType: "image/png"
}
]
})
);
await assert.rejects(
materializeReplayWorkspaceBlobs(
[{ cassetteDirectory: cassette }],
join(root, "state")
),
/integrity mismatch/u
);
});
test("ignores Finder metadata and rejects other unrelated files", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-inventory-"));
const cassette = join(root, "cassette");
await writeValidCassette(cassette);
await assert.doesNotReject(verifyCassette(cassette));
await writeFile(join(cassette, ".DS_Store"), "finder metadata");
await assert.doesNotReject(verifyCassette(cassette));
await writeFile(join(cassette, "debug.log"), "unrelated");
await assert.rejects(verifyCassette(cassette), /unrelated file/u);
});
test("rejects a cassette file integrity mismatch", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-integrity-"));
const cassette = join(root, "cassette");
await writeValidCassette(cassette);
await writeFile(
join(cassette, cassettePolicy.files.expectedState.path),
"tampered"
);
await assert.rejects(verifyCassette(cassette), /integrity mismatch/u);
});
async function writeValidCassette(cassette) {
const contents = new Map();
for (const file of Object.values(cassettePolicy.files)) {
if (!file.required || file.inventory === false) continue;
contents.set(
file.path,
file.path === cassettePolicy.files.blobManifest.path
? JSON.stringify({
schemaVersion: cassettePolicy.blobManifestSchemaVersion,
blobs: []
})
: ""
);
}
const files = [];
let totalBytes = 0;
for (const [path, content] of contents) {
const absolute = join(cassette, ...path.split("/"));
await mkdir(dirname(absolute), { recursive: true });
await writeFile(absolute, content);
const bytes = Buffer.from(content);
const policyFile = Object.values(cassettePolicy.files).find(
(candidate) => candidate.path === path
);
files.push({
path,
role: policyFile.role,
sizeBytes: bytes.byteLength,
sha256: createHash("sha256").update(bytes).digest("hex")
});
totalBytes += bytes.byteLength;
}
await writeFile(
join(cassette, cassettePolicy.files.cassetteManifest.path),
JSON.stringify({
schemaVersion: cassettePolicy.schemaVersion,
stateFormat: "tutti.agent-session-replay-state.v1",
id: replayCassetteAID,
name: "Valid Cassette",
sourceRecordingId: replayCassetteBID,
agentTargetId: "local:codex",
replayPrerequisites: replayPrerequisitesForTest(),
rootAgentSessionId: "root-a",
mode: "create-session",
maxTotalBytes: cassettePolicy.limits.maxCassetteBytes,
createdAtUnixMs: 1,
totalBytes,
files
})
);
}
test("maps API-origin direct stimuli while Engine events stay renderer-owned", () => {
const base = {
workspaceId: "workspace 1",
agentSessionId: "session/1"
};
const cases = [
[
{
...base,
type: "session.create",
payload: { agentTargetId: "local:codex", content: [] }
},
"/v1/workspaces/workspace%201/agent-sessions",
"session/1"
],
[
{ ...base, type: "session.send", payload: { guidance: "steer" } },
"/v1/workspaces/workspace%201/agent-sessions/session%2F1/input",
undefined
],
[
{ ...base, type: "turn.cancel", payload: { turnId: "turn/1" } },
"/turns/turn%2F1/cancel",
undefined
],
[
{
...base,
type: "interactive.response",
payload: { requestId: "request/1", turnId: "turn-1", action: "yes" }
},
"/interactives/request%2F1/response",
"turn-1"
],
[
{
...base,
type: "plan.decision",
payload: {
turnId: "turn-1",
requestId: "request-1",
promptKind: "plan-implementation",
action: "implement",
idempotencyKey: "decision-1"
}
},
"/plan-decisions/request-1",
"plan-implementation"
],
[
{
...base,
type: "goal.control",
payload: {
action: "set",
clientSubmitId: "goal-submit-1",
objective: "ship"
}
},
"/goal",
"goal-submit-1"
],
[
{
...base,
type: "session.settings.update",
payload: { settings: { planMode: true } }
},
"/settings",
true
]
];
for (const [stimulus, pathSuffix, bodyValue] of cases) {
const request = replayStimulusRequest(stimulus);
assert.ok(request.path.includes(pathSuffix), stimulus.type);
if (bodyValue !== undefined) {
assert.ok(
JSON.stringify(request.body).includes(JSON.stringify(bodyValue)),
stimulus.type
);
}
}
assert.equal(
replayStimulusRequest({ ...base, type: "internal.worker" }),
null
);
for (const type of [
"activation/requested",
"interaction/responseRequested",
"plan/decisionRequested",
"session/cancelRequested",
"session/settingsUpdateRequested"
]) {
assert.equal(replayStimulusRequest({ ...base, type }), null, type);
}
});
test("injects the transient Replay Workspace at the product event boundary", () => {
const manifest = {
schemaVersion: cassettePolicy.schemaVersion,
mode: "create-session",
agentTargetId: "local:codex",
replayPrerequisites: replayPrerequisitesForTest(),
rootAgentSessionId: "session-1"
};
const sourceWorkspaceId = "11111111-1111-4111-8111-111111111111";
const replayWorkspaceId = "22222222-2222-4222-8222-222222222222";
const action = replayActionFromManifest(
manifest,
[
{
schemaVersion: cassettePolicy.schemaVersion,
sequence: 1,
kind: "direct-stimulus",
type: "session.create",
eventId: "create-1",
agentSessionId: "session-1",
payload: { displayPrompt: sourceWorkspaceId }
}
],
replayWorkspaceId
);
assert.equal(action.workspaceId, replayWorkspaceId);
assert.equal(action.activityEvents[0].scopeId, replayWorkspaceId);
assert.equal(action.activityEvents[0].workspaceId, replayWorkspaceId);
assert.equal(
action.activityEvents[0].payload.displayPrompt,
sourceWorkspaceId
);
assert.deepEqual(
action.activityEvents[0].payload.settings,
manifest.replayPrerequisites.composerDefaults
);
});
test("resolves portable recording paths for Engine activation", () => {
const manifest = {
schemaVersion: cassettePolicy.schemaVersion,
mode: "create-session",
agentTargetId: "local:codex",
replayPrerequisites: replayPrerequisitesForTest(),
rootAgentSessionId: "session-1"
};
const action = replayActionFromManifest(
manifest,
[
{
schemaVersion: cassettePolicy.schemaVersion,
sequence: 1,
kind: "intent",
type: "activation/requested",
eventId: "create-1",
agentSessionId: "session-1",
payload: {
cwd: "${REPLAY_CWD}",
displayPrompt: "keep ${REPLAY_CWD} as user text",
settings: { planMode: true },
railPlacement: {
projectPath: "${REPLAY_CWD}/packages/agent",
sectionKey: "project:${REPLAY_CWD}/packages/agent"
},
railSectionKey: "project:${REPLAY_CWD}/packages/agent"
}
}
],
"22222222-2222-4222-8222-222222222222"
);
const payload = action.activityEvents[0].payload;
const replayProjectRoot = resolveAgentSessionReplayProjectRoot();
const agentPackagePath = join(replayProjectRoot, "packages", "agent");
assert.equal(payload.cwd, replayProjectRoot);
assert.equal(payload.cwd.startsWith(`${workspaceRoot}/`), false);
assert.notEqual(payload.cwd, workspaceRoot);
assert.equal(payload.railPlacement.projectPath, agentPackagePath);
assert.equal(payload.railPlacement.sectionKey.startsWith("project:"), true);
assert.equal(payload.railPlacement.sectionKey, `project:${agentPackagePath}`);
assert.equal(
payload.railPlacement.sectionKey.includes("${REPLAY_CWD}"),
false
);
assert.equal(payload.railSectionKey, payload.railPlacement.sectionKey);
assert.equal(payload.displayPrompt, "keep ${REPLAY_CWD} as user text");
assert.deepEqual(payload.settings, {
...manifest.replayPrerequisites.composerDefaults,
planMode: true
});
});
test("materializes portable Composer defaults into creation intent and effect", () => {
const manifest = {
schemaVersion: cassettePolicy.schemaVersion,
mode: "create-session",
agentTargetId: "local:codex",
replayPrerequisites: replayPrerequisitesForTest(),
rootAgentSessionId: "session-1"
};
const action = replayActionFromManifest(
manifest,
[
{
schemaVersion: cassettePolicy.schemaVersion,
sequence: 1,
kind: "intent",
type: "activation/requested",
eventId: "create-1",
agentSessionId: "session-1",
payload: { cwd: "", settings: {} }
},
{
schemaVersion: cassettePolicy.schemaVersion,
sequence: 2,
kind: "effect",
type: "session/activate",
eventId: "create-2",
causedByEventId: "create-1",
agentSessionId: "session-1",
payload: { cwd: "", settings: {} }
}
],
"22222222-2222-4222-8222-222222222222"
);
for (const event of action.activityEvents) {
assert.deepEqual(
event.payload.settings,
manifest.replayPrerequisites.composerDefaults
);
}
});
test("does not apply create-session Composer defaults while continuing a Session", () => {
const action = replayActionFromManifest(
{
schemaVersion: cassettePolicy.schemaVersion,
mode: "continue-session",
agentTargetId: "local:codex",
replayPrerequisites: replayPrerequisitesForTest(),
rootAgentSessionId: "session-1"
},
[
{
schemaVersion: cassettePolicy.schemaVersion,
sequence: 1,
kind: "intent",
type: "activation/requested",
eventId: "activate-1",
agentSessionId: "session-1",
payload: { cwd: "", settings: {} }
}
],
"22222222-2222-4222-8222-222222222222"
);
assert.deepEqual(action.activityEvents[0].payload.settings, {});
});
test("PROJECT_ROOT remaps portable REPLAY_CWD outside Tutti checkout", () => {
const previous = process.env.TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT;
const externalRoot = resolve(tmpdir(), "tutti.sessionrec-unit-test");
try {
delete process.env.TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT;
const defaultRoot = resolveAgentSessionReplayProjectRoot();
assert.equal(
defaultRoot.startsWith(join(tmpdir(), "tutti-agent-session-rec")),
true
);
assert.equal(defaultRoot.startsWith(`${workspaceRoot}/`), false);
assert.notEqual(defaultRoot, workspaceRoot);
process.env.TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT = externalRoot;
assert.equal(resolveAgentSessionReplayProjectRoot(), externalRoot);
const project = resolveRecordScenarioProject(
{ label: "sessionrec", relativePath: "." },
resolveAgentSessionReplayProjectRoot()
);
assert.equal(project.path, externalRoot);
assert.equal(project.portablePath, "${REPLAY_CWD}");
assert.equal(project.path.startsWith(workspaceRoot + "/"), false);
assert.throws(() => {
process.env.TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT = "relative/path";
resolveAgentSessionReplayProjectRoot();
}, /must be an absolute path/u);
process.env.TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT = externalRoot;
const action = replayActionFromManifest(
{
schemaVersion: cassettePolicy.schemaVersion,
mode: "create-session",
agentTargetId: "local:codex",
replayPrerequisites: replayPrerequisitesForTest(),
rootAgentSessionId: "session-1"
},
[
{
schemaVersion: cassettePolicy.schemaVersion,
sequence: 1,
kind: "intent",
type: "activation/requested",
eventId: "create-1",
agentSessionId: "session-1",
payload: {
cwd: "${REPLAY_CWD}",
railPlacement: {
projectPath: "${REPLAY_CWD}",
sectionKey: "project:${REPLAY_CWD}"
},
railSectionKey: "project:${REPLAY_CWD}"
}
}
],
"22222222-2222-4222-8222-222222222222"
);
assert.equal(action.activityEvents[0].payload.cwd, externalRoot);
assert.equal(
action.activityEvents[0].payload.railPlacement.projectPath,
externalRoot
);
} finally {
if (previous === undefined) {
delete process.env.TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT;
} else {
process.env.TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT = previous;
}
}
});
test("P01 selects an in-cwd project and requires portable binding artifacts", async () => {
const root = await mkdtemp(join(tmpdir(), "agent-replay-project-binding-"));
const canonicalRoot = realpathSync(root);
const project = resolveRecordScenarioProject(
{ label: basename(canonicalRoot), relativePath: "." },
root
);
assert.equal(project.path, canonicalRoot);
assert.equal(project.label, basename(canonicalRoot));
assert.equal(project.portablePath, "${REPLAY_CWD}");
assert.throws(
() =>
resolveRecordScenarioProject(
{ label: "Outside", relativePath: ".." },
root
),
/must be inside replay cwd/u
);
const databasePath = join(root, "project-seed.db");
await execFileAsync("sqlite3", [
databasePath,
`CREATE TABLE user_projects (
id TEXT PRIMARY KEY,
path TEXT NOT NULL UNIQUE,
label TEXT NOT NULL,
created_at_unix_ms INTEGER NOT NULL,
updated_at_unix_ms INTEGER NOT NULL,
last_used_at_unix_ms INTEGER NOT NULL DEFAULT 0,
sort_order INTEGER NOT NULL DEFAULT 0,
pinned_at_unix_ms INTEGER NOT NULL DEFAULT 0
);`
]);
await seedRecordingUserProject(databasePath, project);
const seeded = await execFileAsync("sqlite3", [
databasePath,
"SELECT path || '|' || label FROM user_projects;"
]);
assert.equal(
seeded.stdout.trim(),
`${canonicalRoot}|${basename(canonicalRoot)}`
);
await writeFile(
join(root, cassettePolicy.files.activityEvents.path),
`${JSON.stringify({
agentSessionId: "session-1",
correlationId: "request-1",
eventId: "intent-1",
kind: "intent",
occurredAtUnixMs: 1,
payload: {
cwd: "${REPLAY_CWD}",
mode: "new",
railPlacement: {
kind: "project",
projectPath: "${REPLAY_CWD}",
sectionKey: "project:${REPLAY_CWD}"
},
requestId: "request-1"
},
schemaVersion: cassettePolicy.schemaVersion,
sequence: 1,
type: "activation/requested"
})}\n${JSON.stringify({
agentSessionId: "session-1",
causedByEventId: "intent-1",
correlationId: "request-1",
eventId: "effect-1",
kind: "effect",
occurredAtUnixMs: 2,
payload: {
cwd: "${REPLAY_CWD}",
mode: "new",
outcome: "succeeded",
railPlacement: {
kind: "project",
projectPath: "${REPLAY_CWD}",
sectionKey: "project:${REPLAY_CWD}"
}
},
schemaVersion: cassettePolicy.schemaVersion,
sequence: 2,
type: "session/activate"
})}\n`
);
await writeFile(
join(root, cassettePolicy.files.checkpointPlan.path),
JSON.stringify({
checkpoints: [
{
kind: "project.binding-ready",
readiness: {
all: [
{
equals: "recorded",
subject: 0,
type: "project.binding"
}
]
}
}
],
schemaVersion: cassettePolicy.schemaVersion
})
);
await verifyRecordedProjectBindingArtifacts(root, "${REPLAY_CWD}");
});
test("P03 accepts a portable project binding restored from initial state", async () => {
const root = await mkdtemp(
join(tmpdir(), "agent-replay-continued-project-binding-")
);
await writeFile(
join(root, cassettePolicy.files.activityEvents.path),
`${JSON.stringify({
agentSessionId: "session-1",
correlationId: "request-1",
eventId: "intent-1",
kind: "intent",
occurredAtUnixMs: 1,
payload: { content: [{ text: "follow up", type: "text" }] },
schemaVersion: cassettePolicy.schemaVersion,
sequence: 1,
type: "submit/requested"
})}\n`
);
await writeFile(
join(root, cassettePolicy.files.initialState.path),
JSON.stringify({
agent: {
sessions: [
{
cwd: "${REPLAY_CWD}",
id: "session-1",
railProjectPath: "${REPLAY_CWD}",
railSectionKey: "project:${REPLAY_CWD}"
}
]
}
})
);
await writeFile(
join(root, cassettePolicy.files.expectedState.path),
JSON.stringify({
agent: {
sessions: [
{
cwd: "${REPLAY_CWD}",
id: "session-1",
railProjectPath: "${REPLAY_CWD}",
railSectionKey: "project:${REPLAY_CWD}"
}
]
}
})
);
await verifyRecordedProjectBindingArtifacts(root, "${REPLAY_CWD}");
await writeFile(
join(root, cassettePolicy.files.expectedState.path),
JSON.stringify({
agent: {
sessions: [
{
cwd: "${REPLAY_CWD}",
id: "session-1",
railProjectPath: null,
railSectionKey: "conversations"
}
]
}
})
);
await assert.rejects(
verifyRecordedProjectBindingArtifacts(root, "${REPLAY_CWD}"),
/did not preserve portable project binding/u
);
});
function execFileAsync(command, args) {
return new Promise((resolvePromise, rejectPromise) => {
execFile(command, args, (error, stdout, stderr) => {
if (error) {
rejectPromise(
new Error(`${command} failed: ${stderr || error.message}`)
);
return;
}
resolvePromise({ stderr, stdout });
});
});
}
function replayPrerequisitesForTest() {
return {
composerDefaults: {
model: "gpt-5.4",
permissionModeId: "default",
reasoningEffort: "medium",
speed: "normal"
}
};
}
test("replayTransportHardFailureMessage classifies hard outbound faults", () => {
assert.equal(
replayTransportHardFailureMessage(
409,
"connection connection-1 outbound mismatch at chunk 64"
),
"connection connection-1 outbound mismatch at chunk 64"
);
assert.equal(
replayTransportHardFailureMessage(
409,
"connection connection-1 received unexpected outbound bytes after cassette end"
),
"connection connection-1 received unexpected outbound bytes after cassette end"
);
assert.equal(
replayTransportHardFailureMessage(
409,
"connection connection-1 consumed 64 of 131 chunks"
),
""
);
assert.equal(replayTransportHardFailureMessage(500, "outbound mismatch"), "");
assert.equal(replayTransportHardFailureMessage(409, ""), "");
});