Skip to main content
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 CaseWhy Code Works
SQL query processorDynamic query construction based on user input
Custom validatorsComplex validation rules with multiple conditions
Data transformersParse and reshape data from various formats
Algorithm executionMathematical 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

  1. Navigate to Tools+ New Tool.
  2. Select Code Tool.
  3. Choose language (JavaScript or Python).

Step 2: Define Metadata

FieldDescriptionExample
NameA 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
DescriptionA 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 ArtifactsWhen 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:
FieldDescription
NameA unique identifier for the parameter
DescriptionExplains the parameter’s purpose; helps the agent extract relevant data from user input
TypeThe expected data type (see below)
isMandatoryWhether the parameter is required
Default ValueA fallback value used when the parameter isn’t found in the input; must match the parameter’s data type
Supported types:
TypeDescription
stringSequence of characters
numberAn integer value
booleantrue or false
list of valuesA restricted set of predefined options (enum). Add all values the parameter can accept. Example: low, medium, high for a priority field.
objectA 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

  1. Click Run Sample Execution
  2. Provide sample input values for each parameter
  3. Review the output and execution logs
  4. 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:
  1. Navigate to tool settings → Environment.
  2. Add key-value pairs.
  3. 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

LimitValue
Timeout30 seconds (configurable)
Memory256 MB
Output size1 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.