Skip to main content

What You’ll Learn

  • Defining a createTool with @mastra/core/tools that executes Python in a Declaw sandbox
  • Validating tool inputs with Zod schemas
  • Creating a Mastra Agent with the tool and an OpenAI model
  • Demo mode that exercises the sandbox tool directly without needing an OpenAI key

Prerequisites

  • Declaw instance running and DECLAW_API_KEY / DECLAW_DOMAIN set
  • OPENAI_API_KEY (optional — the example runs in demo mode without it)
npm install @declaw/sdk @mastra/core @ai-sdk/openai zod dotenv

Code Walkthrough

1. Define the Declaw sandbox tool

createTool accepts an id, description, a Zod inputSchema, and an async execute function. The context parameter contains the validated input:
import { Sandbox } from "@declaw/sdk";
import { createTool } from "@mastra/core/tools";
import { z } from "zod";

const executePython = createTool({
  id: "execute-python",
  description: "Execute Python code in a secure Declaw sandbox",
  inputSchema: z.object({
    code: z.string().describe("Python code to execute"),
  }),
  execute: async ({ context }) => {
    const sbx = await Sandbox.create({ template: "python", timeout: 300 });
    try {
      await sbx.files.write("/tmp/code.py", context.code);
      const result = await sbx.commands.run("python3 /tmp/code.py", {
        timeout: 30,
      });
      return {
        stdout: result.stdout,
        stderr: result.stderr,
        exitCode: result.exitCode,
      };
    } finally {
      await sbx.kill();
    }
  },
});
Zod validates the input before execute is called, so context.code is always a string. The tool returns a structured object — Mastra serializes it as JSON for the LLM to read.

2. Create a Mastra Agent

import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";

const agent = new Agent({
  name: "Code Runner",
  instructions:
    "You are a helpful assistant that can execute Python code in a secure sandbox. Use the execute-python tool to run code.",
  model: openai("gpt-4o-mini"),
  tools: { executePython },
});

3. Run the agent

const prompt =
  "Write Python code to compute the first 15 numbers of the Fibonacci sequence and print them.";
const result = await agent.generate(prompt);
console.log(result.text);

4. Demo mode (no API key needed)

Run the sandbox tool directly without creating a Mastra Agent:
import { Sandbox } from "@declaw/sdk";

const code = `
a, b = 0, 1
fibs = []
for _ in range(15):
    fibs.append(a)
    a, b = b, a + b
print("Fibonacci:", fibs)
`.trim();

const sbx = await Sandbox.create({ template: "python", timeout: 300 });
try {
  await sbx.files.write("/tmp/code.py", code);
  const result = await sbx.commands.run("python3 /tmp/code.py", {
    timeout: 30,
  });
  console.log(result.stdout);
} finally {
  await sbx.kill();
}

Expected Output

In demo mode:
=======================================================
Mastra + Declaw Sandbox Example
=======================================================
No OPENAI_API_KEY found -- running demo mode.

--- Tool Definition ---
const executePython = createTool({
    id: 'execute-python',
    description: 'Execute Python code in a secure Declaw sandbox',
    inputSchema: z.object({ code: z.string() }),
    execute: async ({ context }) => {
        const sbx = await Sandbox.create({ template: 'python', timeout: 300 });
        ...
    },
});

--- Running Code Directly in Declaw Sandbox ---
Code:
a, b = 0, 1
fibs = []
for _ in range(15):
    fibs.append(a)
    a, b = b, a + b
print("Fibonacci:", fibs)

stdout: Fibonacci: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
stderr:
exitCode: 0

Sandbox cleaned up.

=======================================================
Done!
=======================================================