char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Soma bash call that exits nonzero says so in its card's header, rather than ok3339f51

main
3.5 KiB79 linesraw
1import { assertEquals } from "@std/assert";
2import { TERMINAL_PALETTE } from "@berry/util/palette.ts";
3import type { ToolCall } from "@berry/api/web.ts";
4import { withDom } from "@berry/util/dom.ts";
5import { bashRenderer, bashView } from "./bash-view.tsx";
6
7Deno.test("bash colors live raw output before completion and keeps older streams working", async () => {
8  await withDom(() => {
9    const view = bashView();
10    const call: ToolCall = {
11      name: "bash",
12      args: { command: "printf colors" },
13      status: "running",
14      output: null,
15      details: null,
16      result: null,
17      error: null,
18      startedAt: null,
19      durationMs: null,
20    };
21    // the raw stream carries colour that the sanitized output has lost
22    view.update({ ...call, output: "[31mred", details: { rawOutput: "\x1b[31mred" } });
23    const output = view.element.querySelector<HTMLPreElement>("pre:not(.code)")!;
24    assertEquals(output.textContent, "red");
25    const red = output.firstElementChild as HTMLElement;
26    const color = document.createElement("span");
27    color.style.color = TERMINAL_PALETTE[1];
28    assertEquals(red.style.color, color.style.color);
29    const rawOutput = "\x1b[31mredder\x1b[0m plain";
30    view.update({ ...call, status: "ok", result: `${rawOutput}\n\n[exit code 0]` });
31    assertEquals(output.firstElementChild, red);
32    assertEquals(output.textContent, "redder plain\n\n[exit code 0]");
33
34    const legacy = bashView();
35    legacy.update({ ...call, output: "\x1b[31mred" });
36    const legacyOutput = legacy.element.querySelector("pre:not(.code)")!;
37    assertEquals(legacyOutput.textContent, "red");
38    assertEquals((legacyOutput.firstElementChild as HTMLElement).style.color, color.style.color);
39    legacy.update({ ...call, status: "ok", result: { output: "final", exitCode: 3 } });
40    assertEquals(legacyOutput.textContent, "final");
41    assertEquals(legacy.element.querySelector(".exit")!.textContent, "exit 3");
42    legacy.update({ ...call, output: "", details: { rawOutput: "" } });
43    assertEquals((legacyOutput as HTMLElement).hidden, true);
44  });
45});
46
47Deno.test("bash keeps timeout metadata out of the command summary", () => {
48  const args = { command: "echo one\necho two", timeout: 60 };
49  assertEquals(bashRenderer.summary?.(args), "echo one");
50  assertEquals(bashRenderer.timeout?.(args), 60);
51  assertEquals(bashRenderer.timeout?.({ command: "sleep 5", timeout: 0.2 }), 0.2);
52  assertEquals(bashRenderer.summary?.({ command: "pwd" }), "pwd");
53  assertEquals(bashRenderer.timeout?.({ command: "pwd" }), null);
54  assertEquals(bashRenderer.summary?.(null), null);
55  assertEquals(bashRenderer.timeout?.(null), null);
56});
57
58Deno.test("a nonzero exit is a bash call's outcome, from the text a model saw or a script's result", () => {
59  const call = (result: ToolCall["result"]): ToolCall => ({
60    name: "bash",
61    args: { command: "false" },
62    status: "ok",
63    output: null,
64    details: null,
65    result,
66    error: null,
67    startedAt: null,
68    durationMs: null,
69  });
70  assertEquals(bashRenderer.outcome?.(call("failed\n\n[exit code 3]")), "exit 3");
71  assertEquals(
72    bashRenderer.outcome?.(call("long\n\n[exit code 2; full output: /tmp/out]")),
73    "exit 2",
74  );
75  assertEquals(bashRenderer.outcome?.(call({ output: "", exitCode: 1 })), "exit 1");
76  assertEquals(bashRenderer.outcome?.(call("fine\n\n[exit code 0]")), null);
77  assertEquals(bashRenderer.outcome?.(call({ output: "", exitCode: 0 })), null);
78  assertEquals(bashRenderer.outcome?.(call("mentions [exit code 9] in passing\nthen more")), null);
79});