From 2bf330777f61c87da2869685a2cb2bb0b6bc88ac Mon Sep 17 00:00:00 2001 From: Vignesh Natarajan Date: Sat, 14 Feb 2026 20:20:29 -0800 Subject: [PATCH] fix (sandbox/prompts): align workspace guidance with container workdir --- ...unner.buildembeddedsandboxinfo.e2e.test.ts | 2 ++ src/agents/pi-embedded-runner/sandbox-info.ts | 1 + src/agents/pi-embedded-runner/types.ts | 1 + src/agents/system-prompt.e2e.test.ts | 7 +++++++ src/agents/system-prompt.ts | 19 ++++++++++++++++--- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts b/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts index 38431f14c..35611c486 100644 --- a/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts +++ b/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.e2e.test.ts @@ -42,6 +42,7 @@ describe("buildEmbeddedSandboxInfo", () => { expect(buildEmbeddedSandboxInfo(sandbox)).toEqual({ enabled: true, workspaceDir: "/tmp/openclaw-sandbox", + containerWorkspaceDir: "/workspace", workspaceAccess: "none", agentWorkspaceMount: undefined, browserBridgeUrl: "http://localhost:9222", @@ -86,6 +87,7 @@ describe("buildEmbeddedSandboxInfo", () => { ).toEqual({ enabled: true, workspaceDir: "/tmp/openclaw-sandbox", + containerWorkspaceDir: "/workspace", workspaceAccess: "none", agentWorkspaceMount: undefined, hostBrowserAllowed: false, diff --git a/src/agents/pi-embedded-runner/sandbox-info.ts b/src/agents/pi-embedded-runner/sandbox-info.ts index a81ae114c..2e0118860 100644 --- a/src/agents/pi-embedded-runner/sandbox-info.ts +++ b/src/agents/pi-embedded-runner/sandbox-info.ts @@ -13,6 +13,7 @@ export function buildEmbeddedSandboxInfo( return { enabled: true, workspaceDir: sandbox.workspaceDir, + containerWorkspaceDir: sandbox.containerWorkdir, workspaceAccess: sandbox.workspaceAccess, agentWorkspaceMount: sandbox.workspaceAccess === "ro" ? "/agent" : undefined, browserBridgeUrl: sandbox.browser?.bridgeUrl, diff --git a/src/agents/pi-embedded-runner/types.ts b/src/agents/pi-embedded-runner/types.ts index 4c1e24120..5f0d0b989 100644 --- a/src/agents/pi-embedded-runner/types.ts +++ b/src/agents/pi-embedded-runner/types.ts @@ -83,6 +83,7 @@ export type EmbeddedPiCompactResult = { export type EmbeddedSandboxInfo = { enabled: boolean; workspaceDir?: string; + containerWorkspaceDir?: string; workspaceAccess?: "none" | "ro" | "rw"; agentWorkspaceMount?: string; browserBridgeUrl?: string; diff --git a/src/agents/system-prompt.e2e.test.ts b/src/agents/system-prompt.e2e.test.ts index 15262ddb1..1c26d0915 100644 --- a/src/agents/system-prompt.e2e.test.ts +++ b/src/agents/system-prompt.e2e.test.ts @@ -418,12 +418,19 @@ describe("buildAgentSystemPrompt", () => { sandboxInfo: { enabled: true, workspaceDir: "/tmp/sandbox", + containerWorkspaceDir: "/workspace", workspaceAccess: "ro", agentWorkspaceMount: "/agent", elevated: { allowed: true, defaultLevel: "on" }, }, }); + expect(prompt).toContain("Your working directory is: /workspace"); + expect(prompt).toContain( + "For read/write/edit/apply_patch, file paths resolve against host workspace: /tmp/openclaw.", + ); + expect(prompt).toContain("Sandbox container workdir: /workspace"); + expect(prompt).toContain("Sandbox host workspace: /tmp/sandbox"); expect(prompt).toContain("You are running in a sandboxed runtime"); expect(prompt).toContain("Sub-agents stay sandboxed"); expect(prompt).toContain("User can toggle with /elevated on|off|ask|full."); diff --git a/src/agents/system-prompt.ts b/src/agents/system-prompt.ts index 6fe11cc4f..3c3847b1b 100644 --- a/src/agents/system-prompt.ts +++ b/src/agents/system-prompt.ts @@ -199,6 +199,7 @@ export function buildAgentSystemPrompt(params: { sandboxInfo?: { enabled: boolean; workspaceDir?: string; + containerWorkspaceDir?: string; workspaceAccess?: "none" | "ro" | "rw"; agentWorkspaceMount?: string; browserBridgeUrl?: string; @@ -348,6 +349,15 @@ export function buildAgentSystemPrompt(params: { const messageChannelOptions = listDeliverableMessageChannels().join("|"); const promptMode = params.promptMode ?? "full"; const isMinimal = promptMode === "minimal" || promptMode === "none"; + const sandboxContainerWorkspace = params.sandboxInfo?.containerWorkspaceDir?.trim(); + const displayWorkspaceDir = + params.sandboxInfo?.enabled && sandboxContainerWorkspace + ? sandboxContainerWorkspace + : params.workspaceDir; + const workspaceGuidance = + params.sandboxInfo?.enabled && sandboxContainerWorkspace + ? `For read/write/edit/apply_patch, file paths resolve against host workspace: ${params.workspaceDir}. Prefer relative paths so both sandboxed exec and file tools work consistently.` + : "Treat this directory as the single global workspace for file operations unless explicitly instructed otherwise."; const safetySection = [ "## Safety", "You have no independent goals: do not pursue self-preservation, replication, resource acquisition, or power-seeking; avoid long-term plans beyond the user's request.", @@ -450,8 +460,8 @@ export function buildAgentSystemPrompt(params: { ? "If you need the current date, time, or day of week, run session_status (📊 session_status)." : "", "## Workspace", - `Your working directory is: ${params.workspaceDir}`, - "Treat this directory as the single global workspace for file operations unless explicitly instructed otherwise.", + `Your working directory is: ${displayWorkspaceDir}`, + workspaceGuidance, ...workspaceNotes, "", ...docsSection, @@ -461,8 +471,11 @@ export function buildAgentSystemPrompt(params: { "You are running in a sandboxed runtime (tools execute in Docker).", "Some tools may be unavailable due to sandbox policy.", "Sub-agents stay sandboxed (no elevated/host access). Need outside-sandbox read/write? Don't spawn; ask first.", + params.sandboxInfo.containerWorkspaceDir + ? `Sandbox container workdir: ${params.sandboxInfo.containerWorkspaceDir}` + : "", params.sandboxInfo.workspaceDir - ? `Sandbox workspace: ${params.sandboxInfo.workspaceDir}` + ? `Sandbox host workspace: ${params.sandboxInfo.workspaceDir}` : "", params.sandboxInfo.workspaceAccess ? `Agent workspace access: ${params.sandboxInfo.workspaceAccess}${