diff --git a/src/agents/pi-embedded-runner.test.ts b/src/agents/pi-embedded-runner.test.ts new file mode 100644 index 000000000..1e34e0eb0 --- /dev/null +++ b/src/agents/pi-embedded-runner.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from "vitest"; + +import type { SandboxContext } from "./sandbox.js"; +import { buildEmbeddedSandboxInfo } from "./pi-embedded-runner.js"; + +describe("buildEmbeddedSandboxInfo", () => { + it("returns undefined when sandbox is missing", () => { + expect(buildEmbeddedSandboxInfo()).toBeUndefined(); + }); + + it("maps sandbox context into prompt info", () => { + const sandbox = { + enabled: true, + sessionKey: "session:test", + workspaceDir: "/tmp/clawdis-sandbox", + containerName: "clawdis-sbx-test", + containerWorkdir: "/workspace", + docker: { + image: "clawdis-sandbox:bookworm-slim", + containerPrefix: "clawdis-sbx-", + workdir: "/workspace", + readOnlyRoot: true, + tmpfs: ["/tmp"], + network: "none", + user: "1000:1000", + capDrop: ["ALL"], + env: { LANG: "C.UTF-8" }, + }, + tools: { + allow: ["bash"], + deny: ["browser"], + }, + browser: { + controlUrl: "http://localhost:9222", + noVncUrl: "http://localhost:6080", + containerName: "clawdis-sbx-browser-test", + }, + } satisfies SandboxContext; + + expect(buildEmbeddedSandboxInfo(sandbox)).toEqual({ + enabled: true, + workspaceDir: "/tmp/clawdis-sandbox", + browserControlUrl: "http://localhost:9222", + browserNoVncUrl: "http://localhost:6080", + }); + }); +}); diff --git a/src/agents/pi-embedded-runner.ts b/src/agents/pi-embedded-runner.ts index dbf734ffc..1f7227d63 100644 --- a/src/agents/pi-embedded-runner.ts +++ b/src/agents/pi-embedded-runner.ts @@ -48,6 +48,7 @@ import { } from "./pi-embedded-subscribe.js"; import { extractAssistantText } from "./pi-embedded-utils.js"; import { createClawdisCodingTools } from "./pi-tools.js"; +import { resolveSandboxContext } from "./sandbox.js"; import { applySkillEnvOverrides, applySkillEnvOverridesFromSnapshot, @@ -103,6 +104,12 @@ const DEFAULT_OAUTH_DIR = path.join(CONFIG_DIR, "credentials"); let oauthStorageConfigured = false; type OAuthStorage = Record; +type EmbeddedSandboxInfo = { + enabled: boolean; + workspaceDir?: string; + browserControlUrl?: string; + browserNoVncUrl?: string; +}; function resolveSessionLane(key: string) { const cleaned = key.trim() || "main"; @@ -114,6 +121,18 @@ function resolveGlobalLane(lane?: string) { return cleaned ? cleaned : "main"; } +export function buildEmbeddedSandboxInfo( + sandbox?: Awaited>, +): EmbeddedSandboxInfo | undefined { + if (!sandbox?.enabled) return undefined; + return { + enabled: true, + workspaceDir: sandbox.workspaceDir, + browserControlUrl: sandbox.browser?.controlUrl, + browserNoVncUrl: sandbox.browser?.noVncUrl, + }; +} + function resolveClawdisOAuthPath(): string { const overrideDir = process.env.CLAWDIS_OAUTH_DIR?.trim() || DEFAULT_OAUTH_DIR; @@ -410,6 +429,12 @@ export async function runEmbeddedPiAgent(params: { config: params.config, entries: skillEntries, }); + const sandboxSessionKey = params.sessionKey?.trim() || params.sessionId; + const sandbox = await resolveSandboxContext({ + config: params.config, + sessionKey: sandboxSessionKey, + workspaceDir: resolvedWorkspace, + }); restoreSkillEnv = params.skillsSnapshot ? applySkillEnvOverridesFromSnapshot({ snapshot: params.skillsSnapshot, @@ -426,6 +451,7 @@ export async function runEmbeddedPiAgent(params: { const promptSkills = resolvePromptSkills(skillsSnapshot, skillEntries); const tools = createClawdisCodingTools({ bash: params.config?.agent?.bash, + sandbox, surface: params.surface, }); const machineName = await getMachineDisplayName(); @@ -436,14 +462,7 @@ export async function runEmbeddedPiAgent(params: { node: process.version, model: `${provider}/${modelId}`, }; - const sandboxInfo = sandbox?.enabled - ? { - enabled: true, - workspaceDir: sandbox.workspaceDir, - browserControlUrl: sandbox.browser?.controlUrl, - browserNoVncUrl: sandbox.browser?.noVncUrl, - } - : undefined; + const sandboxInfo = buildEmbeddedSandboxInfo(sandbox); const reasoningTagHint = provider === "ollama"; const systemPrompt = buildSystemPrompt({ appendPrompt: buildAgentSystemPromptAppend({