add support for -w,--writable-root to add more writable roots for sandbox (#263)
This adds support for a new flag, `-w,--writable-root`, that can be specified multiple times to _amend_ the list of folders that should be configured as "writable roots" by the sandbox used in `full-auto` mode. Values that are passed as relative paths will be resolved to absolute paths. Incidentally, this required updating a number of the `agent*.test.ts` files: it feels like some of the setup logic across those tests could be consolidated. In my testing, it seems that this might be slightly out of distribution for the model, as I had to explicitly tell it to run `apply_patch` and that it had the permissions to write those files (initially, it just showed me a diff and told me to apply it myself). Nevertheless, I think this is a good starting point.
This commit is contained in:
@@ -88,6 +88,7 @@ describe("cancel before first function_call", () => {
|
||||
const { _test } = (await import("openai")) as any;
|
||||
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
|
||||
@@ -99,6 +99,7 @@ describe("cancel clears previous_response_id", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: () => {},
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -92,6 +92,7 @@ describe("Agent cancellation race", () => {
|
||||
const items: Array<any> = [];
|
||||
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "any",
|
||||
instructions: "",
|
||||
config: { model: "any", instructions: "" },
|
||||
|
||||
@@ -91,6 +91,7 @@ describe("Agent cancellation", () => {
|
||||
instructions: "",
|
||||
config: { model: "any", instructions: "" },
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (item) => {
|
||||
received.push(item);
|
||||
},
|
||||
@@ -136,6 +137,7 @@ describe("Agent cancellation", () => {
|
||||
const received: Array<any> = [];
|
||||
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "any",
|
||||
instructions: "",
|
||||
config: { model: "any", instructions: "" },
|
||||
|
||||
@@ -118,6 +118,7 @@ describe("function_call_output includes original call ID", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: () => {},
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -56,6 +56,7 @@ describe("AgentLoop – generic network/server errors", () => {
|
||||
const received: Array<any> = [];
|
||||
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
@@ -99,6 +100,7 @@ describe("AgentLoop – generic network/server errors", () => {
|
||||
const received: Array<any> = [];
|
||||
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
|
||||
@@ -34,6 +34,7 @@ describe("Agent interrupt and continue", () => {
|
||||
|
||||
// Create the agent
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "test-model",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
|
||||
@@ -58,6 +58,7 @@ describe("AgentLoop – invalid request / 4xx errors", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (i) => received.push(i),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -58,6 +58,7 @@ describe("AgentLoop – max_tokens too large error", () => {
|
||||
const received: Array<any> = [];
|
||||
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
|
||||
@@ -109,6 +109,7 @@ describe("AgentLoop – network resilience", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (i) => received.push(i),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
@@ -150,6 +151,7 @@ describe("AgentLoop – network resilience", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (i) => received.push(i),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -112,6 +112,7 @@ describe("AgentLoop", () => {
|
||||
expect(config.instructions).toContain("Hello docs!");
|
||||
|
||||
const agent = new AgentLoop({
|
||||
additionalWritableRoots: [],
|
||||
model: "o3", // arbitrary
|
||||
instructions: config.instructions,
|
||||
config,
|
||||
|
||||
@@ -79,6 +79,7 @@ describe("AgentLoop – rate‑limit handling", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (i) => received.push(i),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -97,6 +97,7 @@ describe("AgentLoop – automatic retry on 5xx errors", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (i) => received.push(i),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
@@ -134,6 +135,7 @@ describe("AgentLoop – automatic retry on 5xx errors", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (i) => received.push(i),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -82,7 +82,14 @@ describe("Agent terminate (hard cancel)", () => {
|
||||
it("suppresses function_call_output and stops processing once terminate() is invoked", async () => {
|
||||
// Simulate a long‑running exec that would normally resolve with output.
|
||||
vi.spyOn(handleExec, "handleExecCommand").mockImplementation(
|
||||
async (_args, _config, _policy, _getConf, abortSignal) => {
|
||||
async (
|
||||
_args,
|
||||
_config,
|
||||
_policy,
|
||||
_additionalWritableRoots,
|
||||
_getConf,
|
||||
abortSignal,
|
||||
) => {
|
||||
// Wait until the abort signal is fired or 2s (whichever comes first).
|
||||
await new Promise<void>((resolve) => {
|
||||
if (abortSignal?.aborted) {
|
||||
@@ -106,6 +113,7 @@ describe("Agent terminate (hard cancel)", () => {
|
||||
instructions: "",
|
||||
config: { model: "any", instructions: "" },
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (item) => received.push(item),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
@@ -141,6 +149,7 @@ describe("Agent terminate (hard cancel)", () => {
|
||||
instructions: "",
|
||||
config: { model: "any", instructions: "" },
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: () => {},
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -107,6 +107,7 @@ describe("thinking time counter", () => {
|
||||
model: "any",
|
||||
instructions: "",
|
||||
approvalPolicy: { mode: "auto" } as any,
|
||||
additionalWritableRoots: [],
|
||||
onItem: (i) => items.push(i),
|
||||
onLoading: () => {},
|
||||
getCommandConfirmation: async () => ({ review: "yes" } as any),
|
||||
|
||||
@@ -53,10 +53,12 @@ describe("handleExecCommand – invalid executable", () => {
|
||||
const policy = { mode: "auto" } as any;
|
||||
const getConfirmation = async () => ({ review: "yes" } as any);
|
||||
|
||||
const additionalWritableRoots: Array<string> = [];
|
||||
const { outputText, metadata } = await handleExecCommand(
|
||||
execInput,
|
||||
config,
|
||||
policy,
|
||||
additionalWritableRoots,
|
||||
getConfirmation,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user