Skip to content

Commit 68c905c

Browse files
committed
fix(test): observe complete records in live journey journal
1 parent 1e2edbf commit 68c905c

1 file changed

Lines changed: 46 additions & 1 deletion

File tree

‎packages/cli/tests/repl-agent-journey.test.ts‎

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ import { resolveAgentStack } from "../src/agent-stack.ts";
2929
import { createFakeAcp, makeRegistry, makeStore, tripwireAcp } from "./support/fake-acp.ts";
3030
import type { FakeAcp } from "./support/fake-acp.ts";
3131
import { ADAPTERS, AGENT } from "./support/plan-harness.ts";
32-
import { parseDurableEvent } from "@executablemd/durable-streams";
32+
import {
33+
MalformedDurableEventError,
34+
parseDurableEvent,
35+
serializeDurableEvent,
36+
} from "@executablemd/durable-streams";
3337
import type { DurableEvent } from "@executablemd/durable-streams";
3438
import { z } from "zod";
3539
import {
@@ -1703,9 +1707,50 @@ function holds(asked: readonly string[]): Holds {
17031707
};
17041708
}
17051709

1710+
describe("Live journey journal observation", () => {
1711+
it("observes an appended prompt only after its terminating newline", function* () {
1712+
const hostRoot = yield* useTempDirectory("xmd-live-journal-");
1713+
const directory = join(hostRoot, "xmd", "repl");
1714+
yield* ensureDir(directory);
1715+
const path = join(directory, "entry.jsonl");
1716+
const events: DurableEvent[] = [1, 2, 3].map((turn) => ({
1717+
type: "yield",
1718+
coroutineId: "root",
1719+
description: { type: "agent_prompt", name: `turn:${turn}` },
1720+
result: { status: "ok", value: null },
1721+
}));
1722+
const lines = events.map(serializeDurableEvent);
1723+
yield* writeTextFile(path, lines[0]);
1724+
const next = lines[1];
1725+
const split = Math.floor(next.length / 2);
1726+
yield* untilResolved(appendFile(path, next.slice(0, split)));
1727+
expect(yield* journal(hostRoot)).toEqual(events.slice(0, 1));
1728+
yield* untilResolved(appendFile(path, next.slice(split, -1)));
1729+
expect(yield* journal(hostRoot)).toEqual(events.slice(0, 1));
1730+
yield* untilResolved(appendFile(path, `\n${lines[2]}`));
1731+
const retained = yield* journal(hostRoot);
1732+
expect(retained).toEqual(events);
1733+
expect(recorded(retained).filter((kind) => kind === "agent_prompt")).toHaveLength(3);
1734+
});
1735+
1736+
it("rejects a malformed terminated record even with an incomplete tail", function* () {
1737+
const hostRoot = yield* useTempDirectory("xmd-live-journal-malformed-");
1738+
const directory = join(hostRoot, "xmd", "repl");
1739+
yield* ensureDir(directory);
1740+
yield* writeTextFile(join(directory, "entry.jsonl"), '{"type":\n{"type":');
1741+
expect(
1742+
yield* failing(function* () {
1743+
yield* journal(hostRoot);
1744+
}),
1745+
).toBeInstanceOf(MalformedDurableEventError);
1746+
});
1747+
});
1748+
17061749
function* journal(hostRoot: string): Operation<DurableEvent[]> {
17071750
const text = yield* entryHistory(hostRoot);
1751+
// Live observations can race an append; its final newline commits the record.
17081752
return text
1753+
.slice(0, text.lastIndexOf("\n") + 1)
17091754
.split("\n")
17101755
.filter((line) => line.length > 0)
17111756
.map((line) => {

0 commit comments

Comments
 (0)