Tools

Creating custom tools

Write JavaScript or Python code that Agents can execute during a run. Use custom tools for validation, transforms, and business logic that don't need an external API.

Create a custom tool

  1. Click Tools in the sidebar

  2. Click Create Tool

  3. Select Custom Code

  4. Configure the tool:

    • Name: Unique identifier (e.g., calculate_discount)

    • Description: What the tool does and when to use it

    • Sandbox: Execution environment — see below

    • Parameters: Define the input schema

    • Code: Your implementation

  5. Click Create

Pick a sandbox

Runtype runs your code in an isolated environment. Choose the one that matches your needs: | Sandbox | Language | Network | Best for | |---------|----------|---------|----------| | Cloudflare Worker (default) | JavaScript | Blocked | Fast, zero-latency transforms | | Daytona | JavaScript, TypeScript, Python | Configurable | Heavy compute, language flexibility, external packages | | QuickJS (legacy) | JavaScript | Blocked | Minimal footprint, strictest isolation |

Cloudflare Worker runs in-process inside Runtype's edge workers. It is the fastest option and requires no setup.

Daytona is useful when you need Python, TypeScript, or a containerized environment with configurable outbound access. To use Daytona, add your API key in Settings → Integrations. If Daytona is not configured, tool execution fails and the Agent receives a null result.

QuickJS is still available for backwards compatibility but is not recommended for new tools.

Writing tool code

Your code receives input via an injected parameters object. The shape is determined by the parameter schema you define.

JavaScript (Cloudflare Worker / QuickJS)

const { orderAmount, customerTier } = parameters

let discount = 0
if (customerTier === 'premium') {
  discount = orderAmount > 1000 ? 0.20 : 0.15
} else if (customerTier === 'standard') {
  discount = orderAmount > 1000 ? 0.10 : 0.05
}

const discountedAmount = orderAmount * (1 - discount)

return {
  originalAmount: orderAmount,
  discount: discount * 100,
  finalAmount: discountedAmount
}

Python (Daytona)

import json, statistics

data = parameters['numbers']

result = {
    'sum': sum(data),
    'mean': statistics.mean(data),
    'median': statistics.median(data),
    'min': min(data),
    'max': max(data)
}

print(json.dumps(result))

In Python, write the result to stdout as JSON. Runtype captures the output and parses it.

Runtime behavior

Return values. In JavaScript, the returned object is passed directly to the Agent. In Python, the last line of stdout must be valid JSON.

Exceptions. Unhandled exceptions fail the tool and return an error to the Agent. Use structured error returns (see below) if you want the Agent to recover.

Secrets and network. Cloudflare Worker tools have no network access and cannot read managed secrets. Daytona tools inherit network and secret policy from your container configuration.

Available features

Cloudflare Worker / QuickJS:

  • Standard JS built-ins (Array, Object, Math, Date, JSON)

  • async/await, arrow functions, destructuring, template literals

  • Regex and string manipulation

  • Helper utilities: parseHTML, extractEmails, formatDate, stripTags, querySelector

  • console.log output is captured in tool execution logs

    Daytona:

  • Standard library modules available in your Daytona container image

  • pip packages (Python) or npm packages (JS/TS) — availability depends on your Daytona configuration

  • fetch and outbound network calls — allowed or blocked based on your Daytona sandbox policy

Defining parameters

Click + Add Parameter and configure each field: | Field | Purpose | |-------|---------| | Name | Parameter identifier in parameters | | Type | string, number, boolean, object, array | | Description | What this parameter is for — Agents read this | | Required | Whether the parameter is mandatory | | Default | Fallback value if not provided |

Example: | Name | Type | Required | Description | |------|------|----------|-------------| | orderAmount | number | Yes | Total order value in USD | | customerTier | string | Yes | standard, premium, or enterprise |

Execution limits

Set timeout and memory per tool:

  • Timeout: 1,000 ms to 300,000 ms. Default is 30,000 ms (30 s).

  • Memory: 8 MB, 16 MB, or 32 MB. Default is 16 MB.

    If your code exceeds memory, the tool fails and returns an error. Cloudflare Workers return a timeout error to the Agent when the limit is exceeded. Daytona behavior depends on your container policy—typically a hard kill.

Code validation

Runtype runs a static AST check before saving any custom tool. It blocks:

  • eval() — error code USE_OF_EVAL

  • new Function() — error code USE_OF_FUNCTION_CTOR

  • Unbounded while (true) loops — prevents runaway execution

  • Missing return statements (JS/TS) or missing stdout output (Python) — warning code RETURN_UNDEFINED

  • Syntax errors

    Warnings are surfaced in the dashboard after save. The check runs again on every update.

Error handling

Return structured errors so the Agent can recover:

const { email } = parameters

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(email)) {
  return { success: false, error: 'Invalid email format' }
}

return { success: true, isValid: true, email }

Testing tools

Use the Test panel on the tool page:

  1. Enter sample values for your parameters

  2. Click Run Test

  3. Review the output, execution time, and console logs

  4. Iterate until correct

    Test output includes the returned value and any console.log calls.

Best practices

  • Single responsibility. Each tool should do one thing well.

  • Validate inputs. Check parameter values before processing.

  • Clear naming. calculate_shipping_cost is better than process.

  • Return structured data. Objects are easier for Agents to work with than raw strings.

  • Handle errors gracefully. Return { success: false, error: "..." } instead of throwing.

  • One operation per tool. Agents struggle to debug multi-step logic inside a single tool call.

  • Write explicit descriptions. Agents use the tool and parameter descriptions to decide when to invoke the tool and what values to pass.

Examples

Email validator

const { email } = parameters
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return {
  isValid: emailRegex.test(email),
  email
}

Parameters: email (string, required)

Date formatter

const { isoDate, format } = parameters
const date = new Date(isoDate)

if (format === 'short') {
  return { formatted: date.toLocaleDateString() }
} else if (format === 'long') {
  return {
    formatted: date.toLocaleDateString('en-US', {
      weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'
    })
  }
}

return { formatted: date.toISOString() }

Parameters: isoDate (string, required), format (string, default: "iso")

Array aggregator (Python)

import json, statistics

numbers = parameters['numbers']

result = {
    'sum': sum(numbers),
    'average': statistics.mean(numbers),
    'min': min(numbers),
    'max': max(numbers),
    'count': len(numbers)
}

print(json.dumps(result))

Parameters: numbers (array of numbers, required)

Next steps

Was this helpful?