Code Mode Dynamic Worker Sandboxes

Agentic AI Systems advanced Building with AI ~35 min read

Overview

Tool-calling agents usually make one structured call at a time: choose a tool, provide JSON arguments, wait for the result, then decide the next call. That loop is easy to inspect, but it becomes inefficient when a task requires many small API operations, local filtering, pagination, retries, or conditional control flow. Code Mode changes the execution contract. The model receives a narrow typed API and writes a short program that calls that API, while the host runs the generated program inside a controlled sandbox.

Cloudflare’s Dynamic Workers provide a concrete version of this pattern. A parent Worker loads AI-generated JavaScript or TypeScript into a separate V8 isolate at runtime, passes only the bindings the code is allowed to use, and can block or intercept outbound network access. Cloudflare reports that these isolates start in a few milliseconds, use a few megabytes of memory, and are roughly 100x faster to start and 10x-100x more memory efficient than typical container-based sandboxes.

The transferable idea is not tied to one provider: give the model a programmable, typed capability surface instead of a bag of loosely related tools, then execute its code in an ephemeral environment with capability bindings, resource limits, audit trails, and network mediation. This lets agents perform complex local orchestration without giving generated code direct access to the application process or production secrets.

Core Concepts

Code Mode

Code Mode asks the model to solve an operation by writing code rather than by emitting one tool call per step. The code can loop over results, compose calls, retry transient failures, filter data locally, and return a compact answer. The host still controls the available capabilities: the generated program can call only the APIs exposed through bindings or helper modules.

Dynamic Worker Loader

A Dynamic Worker Loader is a runtime binding that creates or retrieves an isolate containing code supplied at runtime. The parent Worker provides the module source, compatibility date, entrypoint, environment bindings, and outbound network policy. The generated program runs outside the parent application’s isolate, so accidental globals, memory corruption, and direct secret access do not cross the boundary.

Capability Bindings

Instead of handing the generated program credentials, the host passes object-capability style bindings. A binding may expose a chat-room API, a search service, a database facade, or a domain-specific operation. The sandbox sees methods on an object; the parent host owns authentication, logging, rate limits, and policy checks behind that object.

Key Concept: Sandboxed Code Needs Capabilities, Not Secrets

The safest generated-code sandbox is not a tiny clone of production. It is a constrained runtime with no ambient authority. Every useful action should flow through an explicit binding that the host can validate, log, throttle, and revoke.

How It Works

Load Generated Code into an Isolate

The parent Worker receives or generates source code, then loads it through a Worker Loader binding. The current Cloudflare documentation exposes a get() method that takes an isolate id and a callback returning the code bundle. The id gives the runtime a cache key, but callers must not rely on the isolate staying warm forever.

export default {
  async fetch(request, env, ctx) {
    const agentCode = `
      export default {
        async run(input, env) {
          const items = await env.SEARCH.find(input.query);
          return items
            .filter((item) => item.score >= input.minScore)
            .slice(0, 5);
        }
      }
    `;

    const worker = env.LOADER.get("task-" + crypto.randomUUID(), async () => ({
      compatibilityDate: "2026-03-01",
      mainModule: "agent.js",
      modules: { "agent.js": agentCode },
      env: {
        SEARCH: ctx.exports.SearchFacade({
          props: { tenant: "acme" }
        })
      },
      globalOutbound: null
    }));

    const result = await worker.getEntrypoint().run(
      { query: "invoice exceptions", minScore: 0.72 }
    );

    return Response.json(result);
  }
};

The generated program can perform multi-step logic, but it cannot fetch arbitrary URLs because globalOutbound is blocked. It also cannot read a database credential because no credential was placed into its environment. The only useful authority is the SEARCH binding.

Expose Typed APIs Instead of Verbose Tool Lists

The host should describe bindings in compact TypeScript. A typed interface gives the model method names, argument shapes, return shapes, and comments in a form it can naturally use while writing code. This is usually smaller and more expressive than exposing every action as a separate JSON tool schema.

interface SearchFacade {
  /** Search tenant-scoped documents with policy filtering already applied. */
  find(query: string, options?: { limit?: number }): Promise<SearchHit[]>;

  /** Fetch one result body by stable id after search has authorized access. */
  read(id: string): Promise<DocumentBody>;
}

type SearchHit = {
  id: string;
  title: string;
  score: number;
  snippet: string;
};

The model’s prompt can include this interface plus a single instruction: write an exported function that receives task input and calls only these APIs. The host compiles or bundles the result, runs it in the isolate, and captures the return value and execution events.

Mediate Network and RPC Boundaries

Some tasks need HTTP access. Instead of allowing open egress, route requests through a fetcher that can inspect, rewrite, authenticate, or block each request. For first-party APIs, prefer service bindings or RPC-style objects so the sandbox does not need bearer tokens at all.

Practical Applications

Multi-Step API Operations

Agents often need to perform a sequence such as list projects, filter by metadata, fetch each matching record, update a subset, and summarize the outcome. A tool-call loop may spend one model turn per API call. Code Mode lets the model write the loop once and execute it close to the data path, returning only the final structured result to the reasoning loop.

Agent-Generated App Previews

AI app builders need to run generated application code for previews without trusting that code. Dynamic isolates make it practical to load one app per user or per preview, cold-start it on demand, intercept network requests, collect logs, and discard it when no longer needed. Fast startup matters because preview feedback loops are interactive.

Data Transformation and Filtering

A sandboxed generated program can pull a bounded result set through a host-controlled binding and perform local transformations before returning a compact answer. This is useful for spreadsheet-like cleanup, search-result filtering, report generation, and small ETL tasks where asking the model to reason over every raw row would waste context.

Implementation Patterns

Use a Harness Contract

Define exactly what the generated module must export, how input is passed, what output schema is accepted, and which exceptions are retryable. The harness should reject code that does not match the contract before it reaches the sandbox. This keeps model prompts short and makes failures diagnosable.

type SandboxResult =
  | { ok: true; value: unknown; events: AuditEvent[] }
  | { ok: false; errorType: "compile" | "timeout" | "policy" | "runtime"; message: string };

async function executeGeneratedTask(code: string, input: unknown, env: Env): Promise<SandboxResult> {
  const worker = env.LOADER.get(crypto.randomUUID(), async () => ({
    compatibilityDate: "2026-03-01",
    mainModule: "task.js",
    modules: { "task.js": code },
    env: { API: env.POLICY_CHECKED_API },
    globalOutbound: null
  }));

  try {
    return { ok: true, value: await worker.getEntrypoint().run(input), events: [] };
  } catch (err) {
    return classifySandboxError(err);
  }
}

Prefer Facades Over Raw Services

Do not expose the production database, queue, or payment client directly. Wrap it in a facade with task-specific methods. A facade can enforce tenant scoping, redact fields, cap page sizes, add idempotency keys, and collapse dangerous operations behind explicit approval checks.

Keep Generated Code Disposable

Treat each program as an artifact of one agent turn or one app version. Persist the source, prompt, type definitions, execution result, and policy decisions for audit, but avoid building business state into the sandbox itself. Durable state should live behind controlled bindings.

Performance Considerations

Common Pitfalls

Further Reading