GuidesFiles and durable work

Configure file operations

Attach a durable Sandbox and the file-operation Tool group when an Agent needs private mutable workspace state. This guide writes an exact sentinel in one Turn and reads it from a new Session in another Turn.

Outcome

You will attach one Sandbox to an existing Agent, enable file operations, and prove that durable.txt retains the exact value BA_DURABLE_42 across Turns.

Before you begin

You need an existing Agent, a backend SDK client, and available Sandbox capacity. Review Sandboxes, file operations, and Tools before enabling workspace access.

Create a Sandbox

The smallest valid client.sandboxes.create() request is an empty object. Store the returned platform ID; the Agent attachment uses sandbox.id.

const sentinel = "BA_DURABLE_42";
const sandbox = await client.sandboxes.create({});
const agent = await client.agents.get(agentId);
const tools = agent.tools.includes("file_operation_sandbox")
  ? agent.tools
  : [...agent.tools, "file_operation_sandbox" as const];

await client.agents.update(agentId, { sandboxId: sandbox.id, tools });

const writeTurn = await client.chat({
  agentId,
  message: { id: crypto.randomUUID(), role: "user", parts: [{
    type: "text", text: `Use write to create durable.txt containing exactly ${sentinel}. Do not publish it.`,
  }] },
});
for await (const _chunk of writeTurn.toUIMessageStream()) { /* drain */ }

const readTurn = await client.chat({
  agentId,
  message: { id: crypto.randomUUID(), role: "user", parts: [{
    type: "text", text: "Use read to read durable.txt, then summarize.",
  }] },
});
const sessionId = await readTurn.sessionId;
for await (const _chunk of readTurn.toUIMessageStream()) { /* drain */ }
const { data } = await client.sessions.messages(agentId, sessionId);
const read = data.flatMap((message) => message.parts).find((part) =>
  part.type === "tool-read" && part.state === "output-available")?.output;
if (typeof read !== "object" || read === null || !("path" in read) || !("content" in read)
  || read.path !== "/workspace/durable.txt" || read.content !== sentinel) throw new Error("Persistence check failed");

Attach the Sandbox and Tools

Agent updates leave omitted fields unchanged, while tools replaces the complete Tool-group selection. Reading the Agent and adding file_operation_sandbox preserves its unrelated configuration and existing Tool groups.

Write a file in one Turn

The first client.chat() call creates a Session because it omits sessionId. Draining its stream lets the Turn finish writing the private workspace file.

Read it in another Turn

The second call also omits sessionId, so it creates a different Session. Both Turns use the same Agent attachment and therefore the same Sandbox.

Verify persistence

After the second Turn succeeds, client.sessions.messages() returns its persisted transcript. The final assertion requires a successful tool-read result for /workspace/durable.txt containing the exact sentinel, proving that the second Turn read the bytes written by the first.

Production notes

  • Keep sandboxId and file_operation_sandbox consistent. Creation, update, detachment, and Turn dispatch reject a file-enabled Agent without a Sandbox.
  • One Sandbox admits one active Turn at a time. Turns also share fleet capacity; contention waits in durable queues rather than creating parallel workspace writers.
  • Pass an AbortSignal as signal to cancel a Turn. Filesystem changes that completed before cancellation remain, and capacity is released only after accepted operations settle and actor sleep is confirmed.
  • Detach the Sandbox before deletion. Deletion destroys its workspace and can return either "completed" or "pending" while durable cleanup continues.
  • Treat capacity and resource ceilings as production constraints; see limits and reliability.

SDK and REST reference

On this page