Menu
popagent
publicLatest change 4565eb356975518dfc0202eab29b56dff51e8f71 - add deterministic agent health validation by AkurAI Build
import { LocalFilesystem, LocalSandbox, Workspace, WORKSPACE_TOOLS } from "@mastra/core/workspace";
import { realpathSync } from "node:fs";
import { access } from "node:fs/promises";
import { isAbsolute, join, relative, resolve } from "node:path";
import { DEFAULT_WORKSPACE_ID, type AgentWorkspace } from "./api-types";
import {
agentWorkspaces,
type AgentWorkspaceStore,
WORKSPACE_ROOT,
} from "./agent-workspaces";
const AUTONOMOUS_DATA_ROOT = resolve(
process.env.POPAGENT_DATA_DIR ?? join(process.cwd(), "data"),
);
const DEFAULT_WORKSPACE_PATH = `${WORKSPACE_ROOT}/${process.env.POPAGENT_DEFAULT_REPOSITORY ?? "."}`;
const APPLICATION_NODE_MODULES = resolve("node_modules");
const NODE_EXECUTABLE = realpathSync(process.execPath);
const TYPESCRIPT_LANGUAGE_SERVER = join(
APPLICATION_NODE_MODULES,
"typescript-language-server",
"lib",
"cli.mjs",
);
class ContainedWorkspaceFilesystem extends LocalFilesystem {
override exists(inputPath: string): Promise<boolean> {
if (!isAbsolute(inputPath)) return super.exists(inputPath);
const containedPath = relative(this.basePath, inputPath);
if (containedPath === ".." || containedPath.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`)) {
return Promise.resolve(false);
}
return super.exists(containedPath || ".");
}
}
function createWorkspace(
record: AgentWorkspace,
path: string,
readOnly: boolean,
sandboxReadOnlyPaths: string[] = [],
): Workspace {
const readOnlyPaths = [...new Set([
APPLICATION_NODE_MODULES,
NODE_EXECUTABLE,
...sandboxReadOnlyPaths,
...(readOnly ? [path] : []),
])];
const sandbox = new LocalSandbox({
workingDirectory: path,
isolation: "bwrap" as const,
timeout: 30_000,
nativeSandbox: {
allowNetwork: false,
readOnlyPaths,
},
});
const hostSandbox = new LocalSandbox({ workingDirectory: path });
const workspaceSandbox = Object.assign(
Object.create(sandbox) as LocalSandbox,
{ processes: hostSandbox.processes },
);
return new Workspace({
id: `popagent-${record.id}-${readOnly ? "read-only" : "writable"}`,
name: `${record.name}${readOnly ? " (read only)" : ""}`,
filesystem: new ContainedWorkspaceFilesystem({
basePath: path,
contained: true,
readOnly,
instructions: ({ defaultInstructions }) => [
defaultInstructions,
"Use repository-relative paths for every workspace tool, including LSP inspection. Never pass sandbox-visible absolute paths such as /workspace/repository/file.ts.",
].join("\n"),
}),
sandbox: workspaceSandbox,
lsp: {
root: path,
initTimeout: 30_000,
diagnosticTimeout: 10_000,
binaryOverrides: {
typescript: `${NODE_EXECUTABLE} ${TYPESCRIPT_LANGUAGE_SERVER} --stdio`,
},
},
tools: readOnly ? {
[WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE]: { enabled: false },
[WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE]: { enabled: false },
[WORKSPACE_TOOLS.FILESYSTEM.DELETE]: { enabled: false },
[WORKSPACE_TOOLS.FILESYSTEM.MKDIR]: { enabled: false },
[WORKSPACE_TOOLS.FILESYSTEM.AST_EDIT]: { enabled: false },
[WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND]: { enabled: false },
[WORKSPACE_TOOLS.SANDBOX.GET_PROCESS_OUTPUT]: { enabled: false },
[WORKSPACE_TOOLS.SANDBOX.KILL_PROCESS]: { enabled: false },
} : {
[WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE]: { requireReadBeforeWrite: true },
[WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE]: { requireReadBeforeWrite: true },
[WORKSPACE_TOOLS.FILESYSTEM.AST_EDIT]: { requireReadBeforeWrite: true },
},
});
}
const defaultRecord: AgentWorkspace = {
id: DEFAULT_WORKSPACE_ID,
name: "Default workspace",
repositoryPath: process.env.POPAGENT_DEFAULT_REPOSITORY ?? ".",
createdAt: "",
updatedAt: "",
};
export const agentWorkspace = createWorkspace(defaultRecord, DEFAULT_WORKSPACE_PATH, false);
export const readOnlyAgentWorkspace = createWorkspace(defaultRecord, DEFAULT_WORKSPACE_PATH, true);
export function resolveAutonomousWorkspacePath(
path: string,
source: "self-update" | "build-maintenance",
): string {
const containedPath = resolve(path);
const managedRoot = join(AUTONOMOUS_DATA_ROOT, source);
const relativePath = relative(managedRoot, containedPath);
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute(relativePath)) {
throw new Error("Autonomous workspace path is outside the managed root");
}
return containedPath;
}
export class AgentWorkspaceRuntime {
private readonly cache = new Map<string, { updatedAt: string; workspace: Workspace }>();
constructor(private readonly workspaces: AgentWorkspaceStore = agentWorkspaces) {}
async resolve(id = DEFAULT_WORKSPACE_ID, readOnly = false): Promise<Workspace> {
const { workspace: record, path } = await this.workspaces.resolveRepository(id);
const key = `${record.id}:${readOnly}`;
const cached = this.cache.get(key);
if (cached?.updatedAt === record.updatedAt) return cached.workspace;
const workspace = createWorkspace(record, path, readOnly);
this.cache.set(key, { updatedAt: record.updatedAt, workspace });
return workspace;
}
async resolveAutonomous(
id: string,
path: string,
readOnly: boolean,
source: "self-update" | "build-maintenance",
): Promise<Workspace> {
const containedPath = resolveAutonomousWorkspacePath(path, source);
const { workspace: record, path: repositoryPath } = await this.workspaces.resolveRepository(id);
const dependencyPath = join(repositoryPath, "node_modules");
const sandboxReadOnlyPaths: string[] = [];
try {
await access(dependencyPath);
sandboxReadOnlyPaths.push(dependencyPath);
} catch {
// Dependency-free repositories need no additional read-only mount.
}
return createWorkspace(record, containedPath, readOnly, sandboxReadOnlyPaths);
}
}
export const agentWorkspaceRuntime = new AgentWorkspaceRuntime();