AkurAI Build
Menu

popagent

public

Latest change 572cf477ba991d2e95ea351a5ad85fcd2a0ba51e - Test sandbox device contract directly by Ólafur Búi Ólafsson

import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { resolve } from "node:path";
import { createWorkspaceTools, WORKSPACE_TOOLS } from "@mastra/core/workspace";
import { agentWorkspace } from "./workspace";

const testFile = `workspace-test-${crypto.randomUUID()}.txt`;
const lspSource = `workspace-lsp-${crypto.randomUUID()}.ts`;
const lspConsumer = `workspace-lsp-${crypto.randomUUID()}.test.ts`;
const workspaceRoot = resolve(
  process.env.POPAGENT_WORKSPACE_ROOT ?? "workspace",
  process.env.POPAGENT_DEFAULT_REPOSITORY ?? ".",
);
const filesystem = agentWorkspace.filesystem!;
const sandbox = agentWorkspace.sandbox!;

beforeAll(() => agentWorkspace.init());
afterAll(async () => {
  await filesystem.deleteFile(testFile, { force: true });
  await filesystem.deleteFile(lspSource, { force: true });
  await filesystem.deleteFile(lspConsumer, { force: true });
  await agentWorkspace.destroy();
});

describe("agentWorkspace", () => {
  test("reads and writes files inside the contained workspace", async () => {
    await filesystem.writeFile(testFile, "workspace file access");
    expect(await filesystem.readFile(testFile, { encoding: "utf8" })).toBe("workspace file access");
    expect(filesystem.basePath).toBe(workspaceRoot);
  });

  test("requires a fresh read before an agent overwrites a file", async () => {
    await filesystem.writeFile(testFile, "original");
    const tools = await createWorkspaceTools(agentWorkspace);
    const readFile = tools[WORKSPACE_TOOLS.FILESYSTEM.READ_FILE]!;
    const writeFile = tools[WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE]!;

    await expect(writeFile.execute!({
      path: testFile,
      content: "unreviewed overwrite",
      overwrite: true,
    }, {} as never)).rejects.toThrow("must read a file before writing");

    await readFile.execute!({ path: testFile }, {} as never);
    await writeFile.execute!({
      path: testFile,
      content: "reviewed overwrite",
      overwrite: true,
    }, {} as never);
    expect(await filesystem.readFile(testFile, { encoding: "utf8" }))
      .toBe("reviewed overwrite");
    await expect(writeFile.execute!({
      path: testFile,
      content: "stale second overwrite",
      overwrite: true,
    }, {} as never)).rejects.toThrow("must read a file before writing");
  });

  test("performs semantic LSP inspection with repository-relative paths", async () => {
    await filesystem.writeFile(lspSource, "export const semanticValue = 42;\n");
    await filesystem.writeFile(lspConsumer, `import { semanticValue } from "./${lspSource.slice(0, -3)}";\nconsole.log(semanticValue);\n`);
    const tools = await createWorkspaceTools(agentWorkspace);
    const inspect = tools[WORKSPACE_TOOLS.LSP.LSP_INSPECT]!;
    const result = await inspect.execute!({
      path: lspConsumer,
      line: 2,
      match: "console.log(<<<semanticValue);",
    }, {} as never);
    expect(result).toMatchObject({
      hover: { value: expect.stringContaining("semanticValue") },
      definition: expect.arrayContaining([
        expect.objectContaining({ location: expect.stringContaining(lspConsumer) }),
      ]),
    });
  }, 30_000);

  test("instructs agents to use contained repository-relative tool paths", () => {
    expect(filesystem.getInstructions?.()).toContain(
      "Use repository-relative paths for every workspace tool, including LSP inspection",
    );
  });

  test("rejects filesystem paths outside the workspace", async () => {
    await expect(filesystem.readFile("../package.json")).rejects.toThrow();
  });

  test("executes shell commands from the workspace", async () => {
    const result = await sandbox.executeCommand?.("pwd");
    expect(result?.success).toBe(true);
    expect(result?.stdout.trim()).toBe(workspaceRoot);
    const escaped = await sandbox.executeCommand?.("sh", ["-c", "test -e ../package.json"]);
    expect(escaped?.exitCode).not.toBe(0);
  });

  test("provides standard device files to contained commands", async () => {
    const result = await sandbox.executeCommand?.("sh", ["-c", "test -c /dev/null && test -c /dev/urandom"]);
    expect(result?.success).toBe(true);
  });
});