fix: tolerate missing sandbox config in embedded runner
This commit is contained in:
47
src/agents/pi-embedded-runner.test.ts
Normal file
47
src/agents/pi-embedded-runner.test.ts
Normal file
@@ -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",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -48,6 +48,7 @@ import {
|
|||||||
} from "./pi-embedded-subscribe.js";
|
} from "./pi-embedded-subscribe.js";
|
||||||
import { extractAssistantText } from "./pi-embedded-utils.js";
|
import { extractAssistantText } from "./pi-embedded-utils.js";
|
||||||
import { createClawdisCodingTools } from "./pi-tools.js";
|
import { createClawdisCodingTools } from "./pi-tools.js";
|
||||||
|
import { resolveSandboxContext } from "./sandbox.js";
|
||||||
import {
|
import {
|
||||||
applySkillEnvOverrides,
|
applySkillEnvOverrides,
|
||||||
applySkillEnvOverridesFromSnapshot,
|
applySkillEnvOverridesFromSnapshot,
|
||||||
@@ -103,6 +104,12 @@ const DEFAULT_OAUTH_DIR = path.join(CONFIG_DIR, "credentials");
|
|||||||
let oauthStorageConfigured = false;
|
let oauthStorageConfigured = false;
|
||||||
|
|
||||||
type OAuthStorage = Record<string, OAuthCredentials>;
|
type OAuthStorage = Record<string, OAuthCredentials>;
|
||||||
|
type EmbeddedSandboxInfo = {
|
||||||
|
enabled: boolean;
|
||||||
|
workspaceDir?: string;
|
||||||
|
browserControlUrl?: string;
|
||||||
|
browserNoVncUrl?: string;
|
||||||
|
};
|
||||||
|
|
||||||
function resolveSessionLane(key: string) {
|
function resolveSessionLane(key: string) {
|
||||||
const cleaned = key.trim() || "main";
|
const cleaned = key.trim() || "main";
|
||||||
@@ -114,6 +121,18 @@ function resolveGlobalLane(lane?: string) {
|
|||||||
return cleaned ? cleaned : "main";
|
return cleaned ? cleaned : "main";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildEmbeddedSandboxInfo(
|
||||||
|
sandbox?: Awaited<ReturnType<typeof resolveSandboxContext>>,
|
||||||
|
): EmbeddedSandboxInfo | undefined {
|
||||||
|
if (!sandbox?.enabled) return undefined;
|
||||||
|
return {
|
||||||
|
enabled: true,
|
||||||
|
workspaceDir: sandbox.workspaceDir,
|
||||||
|
browserControlUrl: sandbox.browser?.controlUrl,
|
||||||
|
browserNoVncUrl: sandbox.browser?.noVncUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function resolveClawdisOAuthPath(): string {
|
function resolveClawdisOAuthPath(): string {
|
||||||
const overrideDir =
|
const overrideDir =
|
||||||
process.env.CLAWDIS_OAUTH_DIR?.trim() || DEFAULT_OAUTH_DIR;
|
process.env.CLAWDIS_OAUTH_DIR?.trim() || DEFAULT_OAUTH_DIR;
|
||||||
@@ -410,6 +429,12 @@ export async function runEmbeddedPiAgent(params: {
|
|||||||
config: params.config,
|
config: params.config,
|
||||||
entries: skillEntries,
|
entries: skillEntries,
|
||||||
});
|
});
|
||||||
|
const sandboxSessionKey = params.sessionKey?.trim() || params.sessionId;
|
||||||
|
const sandbox = await resolveSandboxContext({
|
||||||
|
config: params.config,
|
||||||
|
sessionKey: sandboxSessionKey,
|
||||||
|
workspaceDir: resolvedWorkspace,
|
||||||
|
});
|
||||||
restoreSkillEnv = params.skillsSnapshot
|
restoreSkillEnv = params.skillsSnapshot
|
||||||
? applySkillEnvOverridesFromSnapshot({
|
? applySkillEnvOverridesFromSnapshot({
|
||||||
snapshot: params.skillsSnapshot,
|
snapshot: params.skillsSnapshot,
|
||||||
@@ -426,6 +451,7 @@ export async function runEmbeddedPiAgent(params: {
|
|||||||
const promptSkills = resolvePromptSkills(skillsSnapshot, skillEntries);
|
const promptSkills = resolvePromptSkills(skillsSnapshot, skillEntries);
|
||||||
const tools = createClawdisCodingTools({
|
const tools = createClawdisCodingTools({
|
||||||
bash: params.config?.agent?.bash,
|
bash: params.config?.agent?.bash,
|
||||||
|
sandbox,
|
||||||
surface: params.surface,
|
surface: params.surface,
|
||||||
});
|
});
|
||||||
const machineName = await getMachineDisplayName();
|
const machineName = await getMachineDisplayName();
|
||||||
@@ -436,14 +462,7 @@ export async function runEmbeddedPiAgent(params: {
|
|||||||
node: process.version,
|
node: process.version,
|
||||||
model: `${provider}/${modelId}`,
|
model: `${provider}/${modelId}`,
|
||||||
};
|
};
|
||||||
const sandboxInfo = sandbox?.enabled
|
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox);
|
||||||
? {
|
|
||||||
enabled: true,
|
|
||||||
workspaceDir: sandbox.workspaceDir,
|
|
||||||
browserControlUrl: sandbox.browser?.controlUrl,
|
|
||||||
browserNoVncUrl: sandbox.browser?.noVncUrl,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
const reasoningTagHint = provider === "ollama";
|
const reasoningTagHint = provider === "ollama";
|
||||||
const systemPrompt = buildSystemPrompt({
|
const systemPrompt = buildSystemPrompt({
|
||||||
appendPrompt: buildAgentSystemPromptAppend({
|
appendPrompt: buildAgentSystemPromptAppend({
|
||||||
|
|||||||
Reference in New Issue
Block a user