Skip to main content
Version: v2.0

Python Sandbox

The Python sandbox lets you deploy any Python function as a callable tool. The function runs in an isolated environment and can be used standalone or attached to an agent.

Setup​

pip install aixplain
from aixplain import Aixplain
import inspect
import time

aix = Aixplain(api_key="YOUR_API_KEY")

Quick start​

def add_numbers(a: int, b: int):
return a + b

script_tool = aix.Tool(
name=f"Addition Tool {int(time.time())}",
integration="688779d8bfb8e46c273982ca", # Python Sandbox
config={
"code": inspect.getsource(add_numbers),
"function_name": "add_numbers",
},
)
script_tool.save()

result = script_tool.run(data={"a": 4, "b": 6}, action="add_numbers")
print(result.data) # 10
Show output

Create a script tool​

1. Define and extract the function​

Use inspect.getsource() to capture the function source as a string:

def calculate_statistics(numbers: list):
import statistics
return {
"mean": statistics.mean(numbers),
"median": statistics.median(numbers),
"stdev": statistics.stdev(numbers) if len(numbers) > 1 else 0,
"count": len(numbers),
}

script_content = inspect.getsource(calculate_statistics)

To load from a file instead:

with open("my_function.py") as f:
script_content = f.read()

Function requirements:

Most legacy authoring rules have been relaxed — multi-line def signatures, short parameter names, default values, missing type hints, top-level imports, and zero-argument functions all work. The only hard constraints today are:

  • function_name must exactly match a function defined in code. Helper functions in the same file are fine — only the one named by function_name is registered as the tool
  • Do not use bool parameters. The runtime serializer emits JSON true/false (lowercase), which then errors inside Python with NameError: name 'true' is not defined. Use int (0/1) instead until this is fixed
  • Avoid returning tuples or unpacking multiple values. Tuple returns round-trip as a string repr (e.g. "(2, 3)") rather than structured data. Return a dict or list when you need more than one value
  • Return values must be JSON-serialisable (dicts, lists, strings, numbers)

Type hints are no longer enforced, but we still recommend them — they help the agent infer a clean tool schema and make the function easier to call correctly.

2. Save the tool​

stats_tool = aix.Tool(
name=f"Statistics Calculator {int(time.time())}",
integration="688779d8bfb8e46c273982ca",
config={
"code": script_content,
"function_name": "calculate_statistics",
},
)
stats_tool.save()
Config keyRequiredDescription
code✅Complete function source as a string
function_name✅Name of the function to expose — must match the definition in code

3. Run the function​

result = stats_tool.run(
data={"numbers": [10, 20, 30, 40, 50]},
action="calculate_statistics",
)
print(result.data)
Show output

Pass parameters as a dict with keys matching the function's argument names. If the tool has only one action, the action parameter can be omitted.

Examples​

Text processing​

def process_text(text: str, uppercase: str):
result = text.strip()
if uppercase == "True":
result = result.upper()
return {"original": text, "processed": result, "length": len(result)}

text_tool = aix.Tool(
name=f"Text Processor {int(time.time())}",
integration="688779d8bfb8e46c273982ca",
config={"code": inspect.getsource(process_text), "function_name": "process_text"},
)
text_tool.save()

result = text_tool.run(
data={"text": " hello world ", "uppercase": "True"},
action="process_text",
)
print(result.data)
Show output

Record filtering​

def transform_records(records: list, filter_key: str, filter_value: str):
filtered = [r for r in records if r.get(filter_key) == filter_value]
return {
"total_input": len(records),
"total_output": len(filtered),
"filtered_records": filtered,
}

transform_tool = aix.Tool(
name=f"Record Transformer {int(time.time())}",
integration="688779d8bfb8e46c273982ca",
config={"code": inspect.getsource(transform_records), "function_name": "transform_records"},
)
transform_tool.save()

result = transform_tool.run(
data={
"records": [
{"id": 1, "category": "fruit", "name": "apple"},
{"id": 2, "category": "vegetable", "name": "carrot"},
{"id": 3, "category": "fruit", "name": "banana"},
],
"filter_key": "category",
"filter_value": "fruit",
},
action="transform_records",
)
print(result.data)
Show output

Error handling inside functions​

Return errors as data rather than raising exceptions — the agent can reason about them:

def safe_divide(a: float, b: float):
if b == 0:
return {"error": "Cannot divide by zero", "result": None}
return {"result": a / b, "error": None}

Use with agents​

note
# replaces: LangChain @tool decorator + StructuredTool + manual schema definition
# Python function becomes an agent tool directly; schema inferred automatically
def calculate_discount(price: float, discount_percent: float):
discount = price * (discount_percent / 100)
return {
"original_price": price,
"discount_amount": round(discount, 2),
"final_price": round(price - discount, 2),
}

discount_tool = aix.Tool(
name=f"Discount Calculator {int(time.time())}",
integration="688779d8bfb8e46c273982ca",
config={"code": inspect.getsource(calculate_discount), "function_name": "calculate_discount"},
)
discount_tool.save()

agent = aix.Agent(
name="Pricing Assistant",
description="Calculates prices with discounts.",
instructions="Use the discount calculator tool to compute final prices. Always show the original price, discount amount, and final price.",
tools=[discount_tool],
)
agent.save()

response = agent.run("What's the final price for a $100 item with 20% off?")
print(response.data.output)
Show output

Troubleshooting​

function_name not found - Confirm the value in config["function_name"] matches the function name in config["code"] exactly. Print script_content to verify what was captured.

Import errors in the sandbox - Only Python standard library modules and commonly available packages are supported. Top-level import statements now work (you no longer need to move every import inside the function body), but if a package is unavailable in the sandbox runtime you'll see an ImportError at call time.

Boolean parameters errors out with NameError: name 'true' is not defined - The runtime serializer encodes bool arguments as JSON true/false (lowercase), which Python then rejects. Use an int (0/1) parameter and coerce inside the function as a workaround.

inspect.getsource() fails - The function must be defined in a file, not typed interactively in a REPL. In notebooks, define the function and call inspect.getsource() in the same cell.

Type or serialisation errors - Parameters and return values must be JSON-serialisable. Convert custom objects to dicts, lists, or primitives before returning.