Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.langchain.com/llms.txt

Use this file to discover all available pages before exploring further.

Interpreters give agents a programmable workspace where they can explore data, coordinate tool calls, and keep intermediate work out of the model context. The agent writes code to express its intent, then an in-memory runtime executes that code and returns the relevant results. Where sandboxes are a code-first way for acting on an environment (such as running commands, installing dependencies, and editing files), interpreters are a code-first way for acting inside the agent loop: composing tools, preserving state, and deciding what information should return to the model.
Interpreters are experimental. APIs and lifecycle behavior may change between releases.

When to use an interpreter

Most agent work alternates between model reasoning and tool execution. That works for simple actions, but it becomes awkward when the agent needs to compose many steps, reason over structured data, or manage intermediate state. An interpreter gives the agent a runtime for that work. Instead of asking the model to choose every next step one tool call at a time, the agent can write a small program that runs control flow, calls allowlisted tools, stores variables, and returns a compact result to the model. Use interpreters when the agent needs to:
  • Compose multiple tool calls with code, including loops, branching, retries, and concurrency.
  • Coordinate subagents from code by splitting work into focused calls, storing their results, and stitching those results into a final synthesis.
  • Keep intermediate values in runtime state instead of sending every temporary result back through the model context.
  • Transform structured data deterministically, such as sorting, grouping, parsing, validating, scoring, or aggregating.
  • Explore a large variable space and return only selected evidence, summaries, or outputs to the model.
This works by running code against QuickJS, a lightweight JavaScript runtime designed for embedded execution. The runtime gives the agent a place to evaluate code without exposing host filesystem, network, shell, package, or clock APIs by default. QuickJS is the execution boundary for interpreter code. Explicit bridges, such as programmatic tool calling, decide what capabilities the code can access.

Choose the right execution path

NeedUse
One or two simple external callsNormal tool calling
A small program that loops, branches, retries, or aggregates resultsInterpreter
Many selected tool calls that should run from codeInterpreter with programmatic tool calling
Reusable helpers used across threadsInterpreter with interpreter skills
Shell commands, package installs, tests, or full OS filesystem accessSandboxes

Add an interpreter to an agent

Install the QuickJS middleware package, then add the middleware when creating the agent.
npm install deepagents @langchain/quickjs
import { createDeepAgent } from "deepagents";
import { createCodeInterpreterMiddleware } from "@langchain/quickjs";

const agent = createDeepAgent({
  model: "openai:gpt-5.4",
  middleware: [createCodeInterpreterMiddleware()],
});

Run code in the interpreter

The middleware adds an eval tool to the agent. The tool runs TypeScript in a persistent context, captures console.log, and returns the result of the last expression. The agent can write code like this:
const rows = [
  { team: "alpha", score: 8 },
  { team: "beta", score: 13 },
  { team: "alpha", score: 21 },
];

const totals = rows.reduce((acc, row) => {
  acc[row.team] = (acc[row.team] ?? 0) + row.score;
  console.log(`${row.team} score: ${acc[row.team]}`)
  return acc;
}, {});

totals;

Programmatic tool calling

Programmatic tool calling (PTC) exposes selected agent tools inside the interpreter under the global tools namespace. Instead of asking the model to issue one tool call, wait for the result, and then decide the next call, the agent can write code that calls tools in loops, branches, retries, or parallel batches. This is useful when intermediate tool results are only inputs to the next step. The interpreter can process, filter, or aggregate those results before anything returns to the model context, which can make multi-tool/multi-step workflows more token efficient. PTC is model-agnostic in Deep Agents. It is implemented by middleware rather than a provider-specific code-execution or tool-calling API.

How it works

  1. You choose which tools the interpreter can call with the ptc allowlist.
  2. The middleware exposes those tools as async JavaScript functions under tools.
  3. The agent writes interpreter code that calls those functions with await.
  4. The interpreter runs the tool bridge, receives the tool result, and continues executing code.
  5. The model receives the final interpreter output, not every intermediate value.
Each allowlisted tool becomes an async function. Tool names are converted to camel case, but the input object still follows the tool’s schema. For example, a tool named web_search becomes tools.webSearch(...):
const result: string = await tools.webSearch({
  query: "deepagents interpreters",
});

Useful patterns

PatternWhat the interpreter can do
Batch processingLoop over many inputs and call a tool for each one.
Parallel workUse Promise.all for independent calls.
Conditional logicChoose the next tool call based on earlier results.
Early terminationStop calling tools once a success condition is met.
Data filteringReturn only relevant rows, snippets, errors, or summaries to the model.
Recursive orchestrationCall task repeatedly, then combine subagent results in code.

Enable PTC

Enable PTC with an explicit allowlist:
import { createDeepAgent } from "deepagents";
import { createCodeInterpreterMiddleware } from "@langchain/quickjs";

const agent = createDeepAgent({
  model: "openai:gpt-5.4",
  middleware: [createCodeInterpreterMiddleware({ ptc: ["task"] })],
});
After PTC is enabled, the agent can call the allowlisted tool from interpreter code. This example launches several subagents in parallel and combines their final reports before returning to the model:
const topics = ["retrieval", "memory", "evaluation"];

const reports = await Promise.all(
  topics.map((topic) =>
    tools.task({
      description: `Research ${topic} in Deep Agents and return three concise findings.`,
      subagent_type: "general-purpose",
    }),
  ),
);

reports.join("\n\n");
Because this is code, the agent can also handle failures locally:
try {
  const report = await tools.task({
    description: "Check the migration notes and return breaking changes.",
    subagent_type: "general-purpose",
  });
  console.log(report);
} catch (error) {
  console.log(`Subagent failed: ${error.message}`);
}
PTC calls currently execute through the interpreter bridge and do not go through the normal tool calling path. As a result, interrupt_on approval workflows are not enforced per PTC-invoked tool call.

Recursive language models

Recursive language models use an interpreter as a workspace for decomposition. The model keeps a large input or working set in runtime variables, writes code to inspect and split it, calls subagents or other model tools on smaller pieces, and then stitches the returned results together in code. This separates the variable space from the agent’s context. The variable space is information stored in the interpreter, and the agent’s context is what the model actually processes in the next model call. The model can decide which snippets become subagent tasks, which results need another pass, and what final synthesis should return to the main conversation. For background on this pattern, see the Recursive Language Models paper. In Deep Agents, the recursive call is often the task tool exposed through programmatic tool calling. The interpreter can call subagents over many slices, combine their answers, and return a single synthesized result:
const candidates = notes
  .filter((note) => note.includes("migration"))
  .slice(0, 5);

const riskReports = await Promise.all(
  candidates.map((note) =>
    tools.task({
      description: `Analyze this migration note for release risk. Return risks, affected users, and recommended follow-up:\n\n${note}`,
      subagent_type: "general-purpose",
    }),
  ),
);

const releaseSummary = riskReports
  .map((report, index) => `## Candidate ${index + 1}\n${report}`)
  .join("\n\n");

releaseSummary;

Interpreter skills

Interpreter skills are skills that expose code modules to an interpreter. When configured with interpreter middleware, the agent can import these modules from code and use them for deterministic helper logic. Interpreter skills are useful when the agent needs reusable helpers for structured data workflows, such as sorting, grouping, scoring, parsing, validating, or aggregating data. For setup details, see Interpreter skills.

Security and limits

Interpreters use QuickJS to run untrusted JavaScript with strict default isolation. Treat that as a scoped interpreter runtime, not a full production sandbox backend. Every tool you expose through PTC is an outside capability that interpreter code can use. Treat the PTC allowlist as a permission boundary: expose only the tools the agent needs, and avoid bridging broad tools that can access sensitive systems, spend money, mutate data, or call unrestricted networks unless that behavior is intentional.
CapabilityAvailable by defaultHow to expose it
JavaScript executionYesAdd interpreter middleware
Top-level awaitYesUse promises in interpreter code
console.log captureYesDisable with captureConsole: false
Agent toolsNoAdd a PTC allowlist
Interpreter skill modulesNoAdd a module entry and configure skills_backend or skillsBackend
Filesystem accessNoAdd the built-in filesystem tools via the PTC allowlist
Network accessNoExpose a specific network tool through PTC
Wall-clock or datetime accessNoExpose an explicit time tool if needed
Shell commands, package installs, tests, OS-level executionNoUse a sandbox backend

Middleware options

createCodeInterpreterMiddleware accepts the following options:
OptionDefaultPurpose
ptcomittedPTC allowlist: array of tool names or StructuredToolInterface instances.
memoryLimitBytes64 * 1024 * 1024
(64 MB)
QuickJS memory limit in bytes.
maxStackSizeBytes320 * 1024QuickJS stack size limit in bytes.
executionTimeoutMs5000Per-eval timeout in milliseconds. Negative values disable the timeout.
systemPromptnullOverride the built-in interpreter system prompt.
skillsBackendomittedBackend used to resolve interpreter skill modules.
maxPtcCalls256Maximum tools.* calls per eval. Use null only in trusted environments.
maxResultChars4000Maximum characters retained from console output, result, and error strings.
toolName"eval"Name of the interpreter tool exposed to the model.
captureConsoletrueWhether console.log, console.warn, and console.error output is captured.