AkurAI Build
Menu

popagent

public

Latest change 6edc7e928c57dab23c0973ed3f7ee70b3ebb72d5 - Initial popagent baseline by AkurAI Build

import { LocalFilesystem, LocalSandbox, Workspace, WORKSPACE_TOOLS } from "@mastra/core/workspace";
import { DEFAULT_WORKSPACE_ID, type AgentWorkspace } from "./api-types";
import {
  agentWorkspaces,
  type AgentWorkspaceStore,
  WORKSPACE_ROOT,
} from "./agent-workspaces";

const DEFAULT_WORKSPACE_PATH = `${WORKSPACE_ROOT}/${process.env.POPAGENT_DEFAULT_REPOSITORY ?? "."}`;

function createWorkspace(record: AgentWorkspace, path: string, readOnly: boolean): Workspace {
  return new Workspace({
    id: `popagent-${record.id}-${readOnly ? "read-only" : "writable"}`,
    name: `${record.name}${readOnly ? " (read only)" : ""}`,
    filesystem: new LocalFilesystem({
      basePath: path,
      contained: true,
      readOnly,
    }),
    ...(!readOnly ? {
      sandbox: new LocalSandbox({
        workingDirectory: path,
        isolation: "bwrap" as const,
        timeout: 30_000,
      }),
      tools: {
        [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 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;
  }
}

export const agentWorkspaceRuntime = new AgentWorkspaceRuntime();