Build tools with custom JavaScript or Python code.
Overview
Code tools execute custom scripts to perform tasks that require:
- Complex business logic
- Dynamic data processing
- Custom calculations
- Conditional operations beyond visual flows
- Integration with systems requiring custom protocols
Supported languages: JavaScript (Node.js) and Python (Python 3.x)
When to Use
Code tools are ideal when:
- Logic is dynamic or conditional
- You need fine-grained control over data handling
- Visual workflows become too complex
- External services require custom integration
- You need computational operations
Good Fit Examples
| Use Case | Why Code Works |
|---|
| SQL query processor | Dynamic query construction based on user input |
| Custom validators | Complex validation rules with multiple conditions |
| Data transformers | Parse and reshape data from various formats |
| Algorithm execution | Mathematical calculations, sorting, filtering |
Creating a Code Tool
┌─────────────────────────────────────────────────────────────────────────┐
│ Creating a Code Tool │
└─────────────────────────────────────────────────────────────────────────┘
│
│ Step 1 Step 2 Step 3 Step 4
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ Create │ │ Define │ │ Define │ │ Write │
│ │ Tool │─────▶│ Metadata │─────▶│ Input │─────▶│ Code │
│ │ │ │ │ │ Params │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │ │ │ │
│ New Tool Name, Parameters execute()
│ + Language Description, & Types function
│ Artifacts
│ │
│ ┌─────────────────────────────────┘
│ ▼
│ Step 5 Step 6
│ ┌──────────┐ ┌──────────┐
│ │ Test │─────▶│ Deploy │
│ │ │ │ │
│ │ │ │ │
│ └──────────┘ └──────────┘
│ │ │
│ Run Sample Tool live &
│ Execution agent-invocable
Step 1: Create the Tool
- Navigate to Tools → + New Tool.
- Select Code Tool.
- Choose language (JavaScript or Python).
Step 2: Define Metadata
| Field | Description | Example |
|---|
| Name | A unique and descriptive name that identifies the tool’s purpose. Only alphabets, numbers, and underscores are allowed—no spaces or special characters. | SQL_Query_Processor |
| Description | A clear description of the tool’s functionality, covering what it does, when to use it, and how to use it. The agent uses this description to determine when to invoke the tool. | This tool will execute an SQL query and return the result. |
| Include Tool Response in Artifacts | When enabled, the tool’s response is included in the artifacts field of the Execute API response payload. This setting only affects the API response—it does not change tool execution behavior, playground simulations, or other agent and tool functionalities. | — |
Step 3: Define Input Parameters
Define the parameters the tool needs to perform its task. For each parameter, specify:
| Field | Description |
|---|
| Name | A unique identifier for the parameter |
| Description | Explains the parameter’s purpose; helps the agent extract relevant data from user input |
| Type | The expected data type (see below) |
| isMandatory | Whether the parameter is required |
| Default Value | A fallback value used when the parameter isn’t found in the input; must match the parameter’s data type |
Supported types:
| Type | Description |
|---|
string | Sequence of characters |
number | An integer value |
boolean | true or false |
list of values | A restricted set of predefined options (enum). Add all values the parameter can accept. Example: low, medium, high for a priority field. |
object | A structured type with one or more nested parameters. Use when multiple related values must be grouped. |
Defining an Object Parameter
Use an object parameter when the tool requires structured input that groups multiple related fields. Object parameters enable structured, nested inputs and allow the agent to validate and construct accurate tool requests before execution.
When defining an object-type parameter:
- Use the
properties field to list all fields inside the object (mandatory for object types)
- For each field in
properties, specify:
type: string, number, boolean, enum, or object
description (optional): A brief explanation of the field’s purpose
required (optional): Whether the field is mandatory
- Use the
required array to list mandatory fields of the object
- Nested objects must define their own
properties and required fields
Example: An employee object with id and email (mandatory), and a nested location object containing city, state, and country (where city and state are mandatory):
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique user identifier"
},
"email": {
"type": "string",
"description": "User email address"
},
"location": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City where user resides"
},
"state": {
"type": "string",
"description": "State where user resides"
},
"country": {
"type": "string",
"description": "Country where user resides"
}
},
"required": ["city", "state"]
}
},
"required": ["id", "email"]
}
Step 4: Write Code
Your code must define an execute function as the entry point.
JavaScript Example:
async function execute(input, context) {
const { query_text, max_results = 100 } = input;
// Parse the natural language query
const sqlQuery = constructSQLFromText(query_text);
// Execute against database
const client = await getDBClient(context.env.DB_CONNECTION);
try {
const results = await client.query(sqlQuery, { limit: max_results });
return {
success: true,
data: results.rows,
count: results.rowCount,
query: sqlQuery
};
} catch (error) {
return {
success: false,
error: error.message,
query: sqlQuery
};
}
}
function constructSQLFromText(text) {
// Your SQL generation logic here
}
Python Example:
def execute(input: dict, context: dict) -> dict:
query_text = input.get("query_text")
max_results = input.get("max_results", 100)
# Parse the natural language query
sql_query = construct_sql_from_text(query_text)
# Execute against database
connection = get_db_connection(context["env"]["DB_CONNECTION"])
try:
cursor = connection.cursor()
cursor.execute(sql_query)
results = cursor.fetchmany(max_results)
return {
"success": True,
"data": results,
"count": len(results),
"query": sql_query
}
except Exception as e:
return {
"success": False,
"error": str(e),
"query": sql_query
}
def construct_sql_from_text(text: str) -> str:
# Your SQL generation logic here
pass
Step 5: Test
- Click Run Sample Execution
- Provide sample input values for each parameter
- Review the output and execution logs
- Debug any issues
Execution logs include timestamps, log levels, messages, and execution context—useful for troubleshooting.
Step 6: Deploy
Click Deploy to make the tool available to agents. Once deployed, the agent automatically invokes the tool when a matching intent is detected.
Code Structure
Entry Point
JavaScript:
async function execute(input, context) {
// Your code here
return output;
}
Python:
def execute(input: dict, context: dict) -> dict:
# Your code here
return output
Input Parameter
Contains the parameters defined in your tool spec:
const input = {
query_text: "Show orders from last week",
max_results: 50
};
Context Object
Provides access to environment and runtime info:
const context = {
env: {
API_KEY: "sk-xxxx",
DB_CONNECTION: "postgres://..."
},
session: {
id: "session_123",
user_id: "user_456"
},
memory: {
// Session memory store
}
};
Return Value
Return a JSON-serializable object:
return {
status: "success",
data: [...],
metadata: {
processed_at: new Date().toISOString()
}
};
Environment Variables
Access secrets and configuration:
JavaScript:
const apiKey = context.env.API_KEY;
const dbUrl = context.env.DATABASE_URL;
Python:
api_key = context["env"]["API_KEY"]
db_url = context["env"]["DATABASE_URL"]
Setting variables:
- Navigate to tool settings → Environment.
- Add key-value pairs.
- Mark sensitive values as secrets.
HTTP Requests
JavaScript (fetch)
async function execute(input, context) {
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${context.env.API_KEY}`
},
body: JSON.stringify(input)
});
const data = await response.json();
return { success: true, data };
}
Python (requests)
import requests
def execute(input: dict, context: dict) -> dict:
response = requests.post(
'https://api.example.com/data',
headers={
'Content-Type': 'application/json',
'Authorization': f'Bearer {context["env"]["API_KEY"]}'
},
json=input
)
return {"success": True, "data": response.json()}
Error Handling
Always handle errors gracefully:
JavaScript:
async function execute(input, context) {
try {
const result = await riskyOperation(input);
return { success: true, data: result };
} catch (error) {
console.error('Operation failed:', error);
return {
success: false,
error: error.message,
error_code: error.code || 'UNKNOWN'
};
}
}
Python:
def execute(input: dict, context: dict) -> dict:
try:
result = risky_operation(input)
return {"success": True, "data": result}
except Exception as e:
print(f"Operation failed: {e}")
return {
"success": False,
"error": str(e),
"error_code": getattr(e, 'code', 'UNKNOWN')
}
Examples
Data Validator
async function execute(input, context) {
const { email, phone, date_of_birth } = input;
const errors = [];
// Validate email
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
errors.push({ field: 'email', message: 'Invalid email format' });
}
// Validate phone
const phoneRegex = /^\+?[\d\s-]{10,}$/;
if (!phoneRegex.test(phone)) {
errors.push({ field: 'phone', message: 'Invalid phone format' });
}
// Validate age
const dob = new Date(date_of_birth);
const age = Math.floor((Date.now() - dob) / (365.25 * 24 * 60 * 60 * 1000));
if (age < 18) {
errors.push({ field: 'date_of_birth', message: 'Must be 18 or older' });
}
return {
valid: errors.length === 0,
errors
};
}
Price Calculator
def execute(input: dict, context: dict) -> dict:
items = input.get("items", [])
discount_code = input.get("discount_code")
shipping_country = input.get("shipping_country", "US")
# Calculate subtotal
subtotal = sum(item["price"] * item["quantity"] for item in items)
# Apply discount
discount = 0
if discount_code:
discount = get_discount(discount_code, subtotal)
# Calculate tax
tax_rate = get_tax_rate(shipping_country)
tax = (subtotal - discount) * tax_rate
# Calculate shipping
shipping = calculate_shipping(items, shipping_country)
total = subtotal - discount + tax + shipping
return {
"subtotal": round(subtotal, 2),
"discount": round(discount, 2),
"tax": round(tax, 2),
"shipping": round(shipping, 2),
"total": round(total, 2)
}
Execution Limits
| Limit | Value |
|---|
| Timeout | 30 seconds (configurable) |
| Memory | 256 MB |
| Output size | 1 MB |
Debugging
Console Logging
JavaScript:
console.log('Input received:', input);
console.log('Processing step 1...');
console.error('Error occurred:', error);
Python:
print(f"Input received: {input}")
print("Processing step 1...")
print(f"Error occurred: {error}", file=sys.stderr)
Execution Logs
View logs in the tool’s monitoring section:
- Timestamp
- Log level
- Message content
- Execution context
Best Practices
Keep Functions Focused
One tool = one capability. Don’t combine unrelated logic.
Validate Input Early
if (!input.required_field) {
return { error: 'required_field is required' };
}
Use Type Checking
def execute(input: dict, context: dict) -> dict:
if not isinstance(input.get("amount"), (int, float)):
return {"error": "amount must be a number"}
Handle Edge Cases
- Empty inputs
- Null values
- Invalid formats
- API failures
Document Your Code
Add comments for complex logic and business rules.