Skip to content
58 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { gather, homeKey, ndjson, outcomeLine, transcriptOf } from "./computer-shape.ts";
5
6test("a computer's home is kept under one key per agent", () => {
7 assert.equal(homeKey("agt_1"), "homes/agt_1.tar.zst");
8});
9
10test("lines gather in order and stop at the cap", () => {
11 const lines = [
12 { stream: "stdout", line: "one" },
13 { stream: "stderr", line: "two" },
14 { stream: "stdout", line: "three" },
15 ];
16 assert.deepEqual(gather(lines), { output: "one\ntwo\nthree", truncated: false });
17 assert.deepEqual(gather(lines, 7), { output: "one\ntwo", truncated: true });
18 assert.deepEqual(gather([]), { output: "", truncated: false });
19});
20
21test("how a command ended reads as one line", () => {
22 assert.equal(outcomeLine({ exit_code: 0, duration_ms: 1234, timed_out: false, truncated: false }), "exit 0 · 1.2 s");
23 assert.equal(outcomeLine({ exit_code: 1, duration_ms: 42_000, timed_out: false, truncated: true }), "exit 1 · 42 s · output cut");
24 assert.equal(outcomeLine({ exit_code: 124, duration_ms: 300_000, timed_out: true, truncated: false }), "exit 124 · 5 min · timed out");
25});
26
27test("a transcript carries the closing note, or says the computer stopped answering", () => {
28 const lines = [{ stream: "stdout", line: "hello" }];
29 const plain = transcriptOf(lines, { exit_code: 0, duration_ms: 10 }, null);
30 assert.equal(plain.output, "hello");
31 assert.equal(plain.exit_code, 0);
32 assert.equal(plain.duration_ms, 10);
33 const cut = transcriptOf(lines, { exit_code: 0, duration_ms: 10, truncated: true, note: "Output past 1.0 MB was dropped: 5 more bytes." }, null);
34 assert.equal(cut.output, "hello\n[Output past 1.0 MB was dropped: 5 more bytes.]");
35 assert.equal(cut.truncated, true);
36 const gone = transcriptOf(lines, null, "connection reset");
37 assert.equal(gone.exit_code, -1);
38 assert.equal(gone.duration_ms, null);
39 assert.equal(gone.output, "hello\n[The computer stopped answering: connection reset.]");
40 assert.equal(transcriptOf([], null, null).output, "[The computer stopped answering.]");
41});
42
43test("NDJSON is read line by line across chunks, skipping what is not an object", async () => {
44 const parts = ['{"stream":"stdout","li', 'ne":"a"}\n{"stream":"stderr","line":"b"}\nnot json\n[1]\n{"exit_code":0,"duration_ms":5}'];
45 const body = new ReadableStream<Uint8Array>({
46 start(controller) {
47 for (const part of parts) controller.enqueue(new TextEncoder().encode(part));
48 controller.close();
49 },
50 });
51 const seen: Record<string, unknown>[] = [];
52 for await (const line of ndjson(body)) seen.push(line);
53 assert.deepEqual(seen, [
54 { stream: "stdout", line: "a" },
55 { stream: "stderr", line: "b" },
56 { exit_code: 0, duration_ms: 5 },
57 ]);
58});