char-slop/berry

multipurpose self-modifiable agentic harness

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

Charlotte Somcodemode: omit duplicate input schemas for direct tools70e18bf

main
6.8 KiB178 linesraw
1import { assert, assertEquals, assertRejects, assertStringIncludes } from "@std/assert";
2import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
3import { Type } from "@earendil-works/pi-ai";
4import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai/providers/faux";
5import { defineExtension } from "@berry/api";
6import { localEnvironment } from "@berry/api/environment.ts";
7import { onPath, tempDir } from "@berry/util";
8import code from "../extensions/code/mod.ts";
9import { ShellEntry } from "./shell.ts";
10import { lastToolResult, script, sectionsSeen, setup, toolsOffered, turn } from "./fixture.ts";
11
12Deno.test("environment-gated tools disappear from both catalogs and cannot be called while disabled", async () => {
13  await using root = await tempDir();
14  let offline = false;
15  await using h = await setup({
16    open: (name, cwd) => {
17      if (offline) return Promise.reject(new Error("offline"));
18      return Promise.resolve(Object.assign(localEnvironment(cwd ?? root.path), {
19        name,
20        platform: name === "windows" ? "win32" : "linux",
21      }));
22    },
23    close: () => Promise.resolve(),
24  });
25  let calls = 0;
26  await h.berry.install(defineExtension({
27    name: "conditional",
28    initial: () => null,
29    setup(ext) {
30      ext.tool({
31        name: "windowsOnly",
32        description: "Windows only",
33        parameters: Type.Object({}),
34        expose: "both",
35        enabled: ({ env }) => Promise.resolve(env?.platform === "win32"),
36        execute: () => ++calls,
37      });
38    },
39  }));
40  await h.berry.install(code);
41  const tid = await h.berry.create({ extensions: { conditional: {}, code: {} }, model: h.model });
42  const direct = fauxAssistantMessage(fauxToolCall("windowsOnly", {}), { stopReason: "toolUse" });
43  const disabled = await turn(h, tid, [direct, script("return await tools.windowsOnly({})")]);
44  assert(!toolsOffered(disabled[0]).includes("windowsOnly"));
45  assert(!toolsOffered(disabled[0]).includes("powershell"));
46  const catalog = sectionsSeen(disabled[0]).at(-1)?.codemode ?? "";
47  assert(!catalog.includes("windowsOnly"));
48  assert(!catalog.includes("powershell"));
49  assert(lastToolResult(disabled[1]).isError);
50  assert(lastToolResult(disabled[2]).isError);
51  assertEquals(calls, 0);
52
53  await h.berry.configureExtension(tid, "environment", { environment: "windows" });
54  const enabled = await turn(h, tid, [direct, script("return await tools.windowsOnly({})")]);
55  assert(toolsOffered(enabled[0]).includes("powershell"));
56  assertStringIncludes(sectionsSeen(enabled[0]).at(-1)?.codemode ?? "", "powershell:");
57  assertEquals(calls, 2);
58
59  offline = true;
60  const unavailable = await turn(h, tid, [
61    script("return await tools.powershell({ command: 'Get-Location', timeout: 10 })"),
62  ]);
63  assert(!sectionsSeen(unavailable[0]).at(-1)?.codemode?.includes("powershell"));
64  assert(lastToolResult(unavailable[1]).isError);
65  offline = false;
66
67  await h.berry.configureExtension(tid, "environment", { environment: "local" });
68  const [again] = await turn(h, tid, []);
69  assert(!toolsOffered(again).includes("powershell"));
70  assert(!toolsOffered(again).includes("windowsOnly"));
71  assert(!sectionsSeen(again).at(-1)?.codemode?.includes("powershell"));
72});
73
74Deno.test({
75  name: "workspace command follows the target jj workspace and disappears for unavailable targets",
76  ignore: !onPath("jj"),
77  async fn() {
78    await using root = await tempDir();
79    const repo = root.path + "/repo";
80    const nested = repo + "/nested";
81    const secondary = root.path + "/secondary";
82    for (
83      const args of [
84        ["git", "init", repo],
85        ["-R", repo, "workspace", "add", secondary],
86      ]
87    ) {
88      const result = await new Deno.Command("jj", { args, stdout: "null", stderr: "piped" })
89        .output();
90      assert(result.success, new TextDecoder().decode(result.stderr));
91    }
92    await Deno.mkdir(nested);
93    let offline = false;
94    await using h = await setup({
95      open: (name, cwd) => {
96        if (offline) return Promise.reject(new Error("offline"));
97        const env = localEnvironment(cwd ?? root.path);
98        if (name === "no-jj") env.exec = () => Promise.reject(new Error("jj missing"));
99        return Promise.resolve(env);
100      },
101      close: () => Promise.resolve(),
102    });
103    await h.berry.install(code);
104    const tid = await h.berry.create({ extensions: { code: {} }, model: h.model });
105    const offered = async () =>
106      (await h.berry.commands(tid)).some(({ name }) => name === "workspace");
107    assertEquals(await offered(), false);
108    await assertRejects(
109      () => h.berry.command(tid, "workspace", ""),
110      Error,
111      "No command /workspace",
112    );
113
114    await h.berry.configureExtension(tid, "environment", { cwd: nested });
115    assertEquals(await offered(), true);
116    await h.berry.configureExtension(tid, "environment", { cwd: secondary });
117    assertEquals(await offered(), true);
118    await h.berry.command(tid, "cd", root.path);
119    assertEquals(await offered(), false);
120
121    await h.berry.configureExtension(tid, "environment", { cwd: repo, environment: "no-jj" });
122    assertEquals(await offered(), false);
123    await h.berry.configureExtension(tid, "environment", { environment: "local", cwd: nested });
124    assertEquals(await offered(), true);
125    offline = true;
126    assertEquals(await offered(), false);
127    await assertRejects(
128      () => h.berry.command(tid, "workspace", ""),
129      Error,
130      "No command /workspace",
131    );
132    assert((await h.berry.commands(tid)).some(({ name }) => name === "cd"));
133  },
134});
135
136Deno.test("user shell commands choose PowerShell on the target Windows machine", async () => {
137  await using root = await tempDir();
138  await using h = await setup({
139    open: (name, cwd) =>
140      Promise.resolve(Object.assign(localEnvironment(cwd ?? root.path), {
141        name,
142        platform: "win32",
143      })),
144    close: () => Promise.resolve(),
145  });
146  await h.berry.install(defineExtension({
147    name: "code",
148    initial: () => null,
149    setup() {
150      return (conv) => {
151        if (conv.env?.platform !== "win32") return;
152        conv.tool({
153          name: "powershell",
154          description: "PowerShell",
155          expose: "codemode",
156          parameters: Type.Object({ command: Type.String() }),
157          execute: ({ command }, { env }) => ({ shell: "powershell", command, cwd: env.cwd }),
158        });
159      };
160    },
161  }));
162  const tid = await h.berry.create({ extensions: { code: {} }, model: h.model });
163  const task = await h.berry.shell(tid, "Get-Location");
164  await h.berry.harness.waitForTask(task, BACKGROUND_CONTEXT);
165  const conversation = (await h.berry.conversation(tid))!;
166  await conversation.waitForIdle(BACKGROUND_CONTEXT);
167  const entries = await conversation.entries(
168    { order: "ascending" },
169    100,
170    undefined,
171    BACKGROUND_CONTEXT,
172  );
173  assertEquals(entries.items.find(ShellEntry.is)?.data.result, {
174    shell: "powershell",
175    command: "Get-Location",
176    cwd: root.path,
177  });
178});