Inputs, outputs, and environment

A code tool has four parts: the inputs it receives, the environment variables it reads for configuration and secrets, the outputs it returns, and the code that produces the result. The inputs, environment variables, and outputs are defined when the tool is created and referenced by name in the code.

Inputs

Each input to a code tool comes from one of two sources:

  • Supplied by the AI Agent: the Agent works the value out from the conversation. Agent-supplied inputs can be text, a number, true/false, or a list.
  • Linked to a variable: the value is read from a saved variable. An object must be linked to a variable; the Agent cannot supply one directly.

Define each input the tool needs, along with its source and type. The Agent only fills in the inputs marked as Agent-supplied.

Environment variables

Environment variables hold configuration and secrets, for example a base URL or an API key. Keeping these outside the code means the same tool can point at different systems or credentials without rewriting it.

Read them in code with os.getenv("NAME") or os.environ["NAME"] after import os. Only the variables you declare here are exposed; nothing from Ada’s own environment is reachable.

Secrets are stored redacted. Once saved, a secret’s value is not shown again in the dashboard.

Outputs

Each output is a field the tool returns. For every output, choose how it is used:

  • Exposed to the AI Agent: the Agent can use the value in its replies.
  • Saved to a variable: the value is written to a variable for later steps to read.

An output can be exposed to the Agent, saved to a variable, or both. Declare one output per field so each value is addressed on its own.

The code

The tool returns the value of its last expression: whatever the final line evaluates to becomes the result. You don’t wrap it in a function or write a return. Your inputs are available as variables by name, and you call the available functions below directly.

Supported Python

The code runs on a sandboxed Python interpreter — a restricted subset, not full Python. Here is exactly what’s available.

You can use

  • Variables, arithmetic, string operations, and f-strings (including format specs like f"{price:.2f}").
  • Conditionals (if), loops (for / while), comprehensions, try / except, and your own def and lambda functions.
  • Import these standard-library modules as usual: json, re, datetime, math, os, pathlib, sys, and typing. (pathlib can only build paths; reading a file is blocked.)
  • The current date and time: after from datetime import datetime, date, datetime.now() and date.today() return the time in your AI Agent’s configured timezone.

You can’t use

  • Any other import. No requests, random, collections, itertools, and so on. A disallowed import fails when the tool runs, not when you save it. Common gaps (hashing, Base64, URL-encoding, UUIDs) are covered by the built-in functions instead.
  • Classes, generators, and del. No class definitions (which also rules out @dataclass and custom exception types), no generators (yield), and no del statement. These are caught when you save.
  • eval, exec, open and file access, input, and dynamic tricks like globals().
  • % or .format() string formatting. Use f-strings instead.

The result

The result is the tool’s last expression, and it must be a JSON value: text, a number, true/false, a list, or an object with text keys, not a file or an image. A few common Python types aren’t JSON and must be converted before you return them: a datetime (call .isoformat()), a set or tuple (wrap in list(...)), or bytes (decode it first). Returning nothing (None) counts as no result.

To make a network request, read an environment variable, or read and write variables, use the built-in functions below rather than a library. For the full sandbox limits, see Limits and best practices.

Available functions

Ada provides these functions directly in your code, no import needed.

fetch — make an HTTP request

1response = fetch("GET", "https://api.example.com/orders/123")
2# -> {"status_code": 200, "headers": {...}, "body": "..."}

fetch(method, url, headers=None, body=None, timeout=None) returns an object with status_code, headers, and body. The body is a string, so parse it with json.loads if it’s JSON. Requests reach only the domains on your allowed-domains list (plus your own Ada instance); a blocked or failed request raises an error you can catch. Redirects aren’t followed, so a request to a redirecting URL returns the 3xx response, not the final page. Per run: up to 10 requests, a 1 MB response each, and about 60 seconds of network time.

get_variable and set_variable — read and write variables

1tier = get_variable("customer_tier")
2set_variable("last_lookup_status", "ok")

get_variable(name) returns a saved variable’s current value, and raises if it doesn’t exist. set_variable(name, value) saves a value, applied only if the run succeeds. Sensitive-scoped variables can’t be read or written from code.

Utilities — hashing, encoding, and IDs

Common helpers that would otherwise need a library, available directly (no import):

  • uuid4() — a random UUID string.
  • sha256(text) and hmac_sha256(key, text) — hex digests.
  • b64encode(text) and b64decode(text) — Base64 encode and decode.
  • quote(text) and urlencode(mapping) — URL-encode a single value, or a set of query parameters.

log — write to the run log

1log("looked up order", order_id)

log(...) (and print(...)) adds a line to the tool’s run log for debugging. Logs show in the conversation’s run detail, have secrets redacted, and are never shown to the AI Agent.

Voice capture

For voice-enabled AI Agents, code-tool inputs support the same voice capture settings as API tools (speech, keypad, or SMS), along with confirmation before the value is used. This lets an Agent collect an input reliably over a voice call.