fix: describe sandboxed elevated in prompt
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
- CLI: add `clawdbot update` (safe-ish git checkout update) + `--update` shorthand. (#673) — thanks @fm1randa.
|
- CLI: add `clawdbot update` (safe-ish git checkout update) + `--update` shorthand. (#673) — thanks @fm1randa.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
- Agents/System: clarify sandboxed runtime in system prompt and surface elevated availability when sandboxed.
|
||||||
- Auto-reply: prefer `RawBody` for command/directive parsing (WhatsApp + Discord) and prevent fallback runs from clobbering concurrent session updates. (#643) — thanks @mcinteerj.
|
- Auto-reply: prefer `RawBody` for command/directive parsing (WhatsApp + Discord) and prevent fallback runs from clobbering concurrent session updates. (#643) — thanks @mcinteerj.
|
||||||
- WhatsApp: fix group reactions by preserving message IDs and sender JIDs in history; normalize participant phone numbers to JIDs in outbound reactions. (#640) — thanks @mcinteerj.
|
- WhatsApp: fix group reactions by preserving message IDs and sender JIDs in history; normalize participant phone numbers to JIDs in outbound reactions. (#640) — thanks @mcinteerj.
|
||||||
- WhatsApp: expose group participant IDs to the model so reactions can target the right sender.
|
- WhatsApp: expose group participant IDs to the model so reactions can target the right sender.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ The prompt is intentionally compact and uses fixed sections:
|
|||||||
- **Clawdbot Self-Update**: how to run `config.apply` and `update.run`.
|
- **Clawdbot Self-Update**: how to run `config.apply` and `update.run`.
|
||||||
- **Workspace**: working directory (`agents.defaults.workspace`).
|
- **Workspace**: working directory (`agents.defaults.workspace`).
|
||||||
- **Workspace Files (injected)**: indicates bootstrap files are included below.
|
- **Workspace Files (injected)**: indicates bootstrap files are included below.
|
||||||
|
- **Sandbox** (when enabled): indicates sandboxed runtime, sandbox paths, and whether elevated bash is available.
|
||||||
- **Time**: UTC default + the user’s local time (already converted).
|
- **Time**: UTC default + the user’s local time (already converted).
|
||||||
- **Reply Tags**: optional reply tag syntax for supported providers.
|
- **Reply Tags**: optional reply tag syntax for supported providers.
|
||||||
- **Heartbeats**: heartbeat prompt and ack behavior.
|
- **Heartbeats**: heartbeat prompt and ack behavior.
|
||||||
|
|||||||
@@ -61,6 +61,47 @@ describe("buildEmbeddedSandboxInfo", () => {
|
|||||||
browserNoVncUrl: "http://localhost:6080",
|
browserNoVncUrl: "http://localhost:6080",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("includes elevated info when allowed", () => {
|
||||||
|
const sandbox = {
|
||||||
|
enabled: true,
|
||||||
|
sessionKey: "session:test",
|
||||||
|
workspaceDir: "/tmp/clawdbot-sandbox",
|
||||||
|
agentWorkspaceDir: "/tmp/clawdbot-workspace",
|
||||||
|
workspaceAccess: "none",
|
||||||
|
containerName: "clawdbot-sbx-test",
|
||||||
|
containerWorkdir: "/workspace",
|
||||||
|
docker: {
|
||||||
|
image: "clawdbot-sandbox:bookworm-slim",
|
||||||
|
containerPrefix: "clawdbot-sbx-",
|
||||||
|
workdir: "/workspace",
|
||||||
|
readOnlyRoot: true,
|
||||||
|
tmpfs: ["/tmp"],
|
||||||
|
network: "none",
|
||||||
|
user: "1000:1000",
|
||||||
|
capDrop: ["ALL"],
|
||||||
|
env: { LANG: "C.UTF-8" },
|
||||||
|
},
|
||||||
|
tools: {
|
||||||
|
allow: ["bash"],
|
||||||
|
deny: ["browser"],
|
||||||
|
},
|
||||||
|
} satisfies SandboxContext;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildEmbeddedSandboxInfo(sandbox, {
|
||||||
|
enabled: true,
|
||||||
|
allowed: true,
|
||||||
|
defaultLevel: "on",
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
enabled: true,
|
||||||
|
workspaceDir: "/tmp/clawdbot-sandbox",
|
||||||
|
workspaceAccess: "none",
|
||||||
|
agentWorkspaceMount: undefined,
|
||||||
|
elevated: { allowed: true, defaultLevel: "on" },
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("resolveSessionAgentIds", () => {
|
describe("resolveSessionAgentIds", () => {
|
||||||
|
|||||||
@@ -479,6 +479,10 @@ type EmbeddedSandboxInfo = {
|
|||||||
agentWorkspaceMount?: string;
|
agentWorkspaceMount?: string;
|
||||||
browserControlUrl?: string;
|
browserControlUrl?: string;
|
||||||
browserNoVncUrl?: string;
|
browserNoVncUrl?: string;
|
||||||
|
elevated?: {
|
||||||
|
allowed: boolean;
|
||||||
|
defaultLevel: "on" | "off";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function resolveSessionLane(key: string) {
|
function resolveSessionLane(key: string) {
|
||||||
@@ -552,8 +556,10 @@ function describeUnknownError(error: unknown): string {
|
|||||||
|
|
||||||
export function buildEmbeddedSandboxInfo(
|
export function buildEmbeddedSandboxInfo(
|
||||||
sandbox?: Awaited<ReturnType<typeof resolveSandboxContext>>,
|
sandbox?: Awaited<ReturnType<typeof resolveSandboxContext>>,
|
||||||
|
bashElevated?: BashElevatedDefaults,
|
||||||
): EmbeddedSandboxInfo | undefined {
|
): EmbeddedSandboxInfo | undefined {
|
||||||
if (!sandbox?.enabled) return undefined;
|
if (!sandbox?.enabled) return undefined;
|
||||||
|
const elevatedAllowed = Boolean(bashElevated?.enabled && bashElevated.allowed);
|
||||||
return {
|
return {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
workspaceDir: sandbox.workspaceDir,
|
workspaceDir: sandbox.workspaceDir,
|
||||||
@@ -562,6 +568,14 @@ export function buildEmbeddedSandboxInfo(
|
|||||||
sandbox.workspaceAccess === "ro" ? "/agent" : undefined,
|
sandbox.workspaceAccess === "ro" ? "/agent" : undefined,
|
||||||
browserControlUrl: sandbox.browser?.controlUrl,
|
browserControlUrl: sandbox.browser?.controlUrl,
|
||||||
browserNoVncUrl: sandbox.browser?.noVncUrl,
|
browserNoVncUrl: sandbox.browser?.noVncUrl,
|
||||||
|
...(elevatedAllowed
|
||||||
|
? {
|
||||||
|
elevated: {
|
||||||
|
allowed: true,
|
||||||
|
defaultLevel: bashElevated?.defaultLevel ?? "off",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -887,7 +901,10 @@ export async function compactEmbeddedPiSession(params: {
|
|||||||
provider: runtimeProvider,
|
provider: runtimeProvider,
|
||||||
capabilities: runtimeCapabilities,
|
capabilities: runtimeCapabilities,
|
||||||
};
|
};
|
||||||
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox);
|
const sandboxInfo = buildEmbeddedSandboxInfo(
|
||||||
|
sandbox,
|
||||||
|
params.bashElevated,
|
||||||
|
);
|
||||||
const reasoningTagHint = provider === "ollama";
|
const reasoningTagHint = provider === "ollama";
|
||||||
const userTimezone = resolveUserTimezone(
|
const userTimezone = resolveUserTimezone(
|
||||||
params.config?.agents?.defaults?.userTimezone,
|
params.config?.agents?.defaults?.userTimezone,
|
||||||
@@ -1264,7 +1281,10 @@ export async function runEmbeddedPiAgent(params: {
|
|||||||
node: process.version,
|
node: process.version,
|
||||||
model: `${provider}/${modelId}`,
|
model: `${provider}/${modelId}`,
|
||||||
};
|
};
|
||||||
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox);
|
const sandboxInfo = buildEmbeddedSandboxInfo(
|
||||||
|
sandbox,
|
||||||
|
params.bashElevated,
|
||||||
|
);
|
||||||
const reasoningTagHint = provider === "ollama";
|
const reasoningTagHint = provider === "ollama";
|
||||||
const userTimezone = resolveUserTimezone(
|
const userTimezone = resolveUserTimezone(
|
||||||
params.config?.agents?.defaults?.userTimezone,
|
params.config?.agents?.defaults?.userTimezone,
|
||||||
|
|||||||
@@ -169,4 +169,21 @@ describe("buildAgentSystemPrompt", () => {
|
|||||||
expect(prompt).toContain("provider=telegram");
|
expect(prompt).toContain("provider=telegram");
|
||||||
expect(prompt).toContain("capabilities=inlineButtons");
|
expect(prompt).toContain("capabilities=inlineButtons");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("describes sandboxed runtime and elevated when allowed", () => {
|
||||||
|
const prompt = buildAgentSystemPrompt({
|
||||||
|
workspaceDir: "/tmp/clawd",
|
||||||
|
sandboxInfo: {
|
||||||
|
enabled: true,
|
||||||
|
workspaceDir: "/tmp/sandbox",
|
||||||
|
workspaceAccess: "ro",
|
||||||
|
agentWorkspaceMount: "/agent",
|
||||||
|
elevated: { allowed: true, defaultLevel: "on" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(prompt).toContain("You are running in a sandboxed runtime");
|
||||||
|
expect(prompt).toContain("User can toggle with /elevated on|off.");
|
||||||
|
expect(prompt).toContain("Current elevated level: on");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ export function buildAgentSystemPrompt(params: {
|
|||||||
agentWorkspaceMount?: string;
|
agentWorkspaceMount?: string;
|
||||||
browserControlUrl?: string;
|
browserControlUrl?: string;
|
||||||
browserNoVncUrl?: string;
|
browserNoVncUrl?: string;
|
||||||
|
elevated?: {
|
||||||
|
allowed: boolean;
|
||||||
|
defaultLevel: "on" | "off";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}) {
|
}) {
|
||||||
const toolSummaries: Record<string, string> = {
|
const toolSummaries: Record<string, string> = {
|
||||||
@@ -219,7 +223,7 @@ export function buildAgentSystemPrompt(params: {
|
|||||||
params.sandboxInfo?.enabled ? "## Sandbox" : "",
|
params.sandboxInfo?.enabled ? "## Sandbox" : "",
|
||||||
params.sandboxInfo?.enabled
|
params.sandboxInfo?.enabled
|
||||||
? [
|
? [
|
||||||
"Tool execution is isolated in a Docker sandbox.",
|
"You are running in a sandboxed runtime (tools execute in Docker).",
|
||||||
"Some tools may be unavailable due to sandbox policy.",
|
"Some tools may be unavailable due to sandbox policy.",
|
||||||
params.sandboxInfo.workspaceDir
|
params.sandboxInfo.workspaceDir
|
||||||
? `Sandbox workspace: ${params.sandboxInfo.workspaceDir}`
|
? `Sandbox workspace: ${params.sandboxInfo.workspaceDir}`
|
||||||
@@ -237,6 +241,20 @@ export function buildAgentSystemPrompt(params: {
|
|||||||
params.sandboxInfo.browserNoVncUrl
|
params.sandboxInfo.browserNoVncUrl
|
||||||
? `Sandbox browser observer (noVNC): ${params.sandboxInfo.browserNoVncUrl}`
|
? `Sandbox browser observer (noVNC): ${params.sandboxInfo.browserNoVncUrl}`
|
||||||
: "",
|
: "",
|
||||||
|
params.sandboxInfo.elevated?.allowed
|
||||||
|
? "Elevated bash is available for this session."
|
||||||
|
: "",
|
||||||
|
params.sandboxInfo.elevated?.allowed
|
||||||
|
? "User can toggle with /elevated on|off."
|
||||||
|
: "",
|
||||||
|
params.sandboxInfo.elevated?.allowed
|
||||||
|
? "You may also send /elevated on|off when needed."
|
||||||
|
: "",
|
||||||
|
params.sandboxInfo.elevated?.allowed
|
||||||
|
? `Current elevated level: ${
|
||||||
|
params.sandboxInfo.elevated.defaultLevel
|
||||||
|
} (on runs bash on host; off runs in sandbox).`
|
||||||
|
: "",
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user