Skip to content
Sign up
Tools
Tool execution

Sandbox Execution

Understand how custom tools execute in sandboxed Python environments with full API access via client injection.

Custom tools execute in sandboxed Python environments to provide security and isolation while maintaining full access to the Letta API.

When a custom tool is called, it runs in an isolated Python environment with:

  • Python 3.x runtime - Standard Python interpreter
  • Package dependencies - Configurable Python packages
  • Environment variables - Custom configuration and secrets
  • Isolated filesystem - Sandboxed file access
  • Client injection - Automatic Letta API access

Custom tools automatically receive environment variables and a pre-initialized Letta client, making it easy to interact with the Letta API from within your tools.

Three environment variables are automatically available in your tool scope:

  • LETTA_API_KEY - API key for authentication
  • LETTA_AGENT_ID - Current agent’s ID
  • LETTA_PROJECT_ID - Current project ID
def get_agent_info() -> str:
"""
Get information about the current agent.
Returns:
str: Agent ID and project ID
"""
import os
agent_id = os.environ.get('LETTA_AGENT_ID')
project_id = os.environ.get('LETTA_PROJECT_ID')
return f"Agent ID: {agent_id}, Project: {project_id}"

A client object is automatically available in your tool scope - no import or initialization needed:

def list_project_agents() -> str:
"""
List all agents in the current project.
Returns:
str: Number of agents found
"""
# 'client' is already initialized - no import needed
agents = client.agents.list()
agent_count = len(list(agents.items))
return f"Found {agent_count} agents in project"

The client is a fully initialized Letta client instance with access to all API endpoints.

Tools can perform any Letta API operation using the injected client:

  • client.agents.list() - List agents in your project
  • client.agents.retrieve(agent_id=...) - Get agent information
  • client.tools.list() - List available tools
  • client.agents.messages.list() - Read message history
  • Multi-agent queries - Retrieve information from other agents
  • client.blocks.update(block_id=..., value=...) - Update memory blocks
  • client.agents.create(...) - Create new agents
  • client.agents.update(agent_id=..., ...) - Modify agent configuration
  • client.tools.upsert_from_function(...) - Create or update tools
  • Any other API operations

Update your agent’s memory blocks dynamically:

def memory_clear(label: str) -> str:
"""
Clear the value of a memory block.
Args:
label: The label of the memory block to clear (e.g., "notes", "human")
Returns:
str: Confirmation message
"""
import os
# Get current agent ID from environment
agent_id = os.environ.get('LETTA_AGENT_ID')
# Retrieve agent to get block IDs
agent = client.agents.retrieve(agent_id=agent_id)
# Find the block by label
target_block = None
for block in agent.memory.blocks:
if block.label == label:
target_block = block
break
if not target_block:
return f"Memory block '{label}' not found"
# Update the block value
client.blocks.update(
block_id=target_block.id,
value=""
)
return f"Cleared memory block '{label}'"

Query other agents in your project to enable collaboration:

def find_specialist_agent(topic: str) -> str:
"""
Find a specialist agent based on topic expertise.
Args:
topic: The topic to find an expert for (e.g., "math", "code", "writing")
Returns:
str: Information about the specialist agent found
"""
# List all agents in the project
agents = client.agents.list()
# Search for an agent with matching expertise
for agent in agents.items:
if topic.lower() in agent.name.lower():
return f"Found specialist: {agent.name} (ID: {agent.id})"
return f"No specialist found for {topic}"

Read your own agent’s memory and configuration:

def analyze_my_memory() -> dict:
"""
Analyze the current agent's memory blocks.
Returns:
dict: Memory analysis with block information
"""
import os
# Get current agent ID from environment
agent_id = os.environ.get('LETTA_AGENT_ID')
# Retrieve agent information
agent = client.agents.retrieve(agent_id=agent_id)
# Analyze memory blocks
memory_info = {}
for block in agent.memory.blocks:
memory_info[block.label] = {
"value": block.value,
"limit": block.limit,
"usage": len(block.value),
"usage_percentage": (len(block.value) / block.limit * 100) if block.limit else 0
}
return memory_info

Create specialized agents dynamically:

def create_specialist_agent(specialty: str, task: str) -> str:
"""
Create a specialist agent for a specific task.
Args:
specialty: The agent's area of expertise (e.g., "math", "research")
task: The initial task for the agent
Returns:
str: New agent ID and status
"""
# Create a specialized agent
new_agent = client.agents.create(
name=f"{specialty}-specialist",
memory_blocks=[
{"label": "human", "value": f"Task: {task}"},
{"label": "persona", "value": f"You are a {specialty} specialist"}
],
model="openai/gpt-4o-mini",
embedding="openai/text-embedding-3-small"
)
return f"Created {specialty} agent (ID: {new_agent.id}) for task: {task}"

Access data from multiple agents:

def gather_team_status() -> str:
"""
Gather status information from all agents in the team.
Returns:
str: Summary of team agent statuses
"""
# List all agents
agents = client.agents.list()
team_summary = []
for agent in agents.items:
# Get detailed agent info
agent_detail = client.agents.retrieve(agent_id=agent.id)
# Summarize agent state
team_summary.append(f"- {agent.name}: {len(agent_detail.memory.blocks)} memory blocks")
return "Team Status:\n" + "\n".join(team_summary)

Specify Python packages your custom tools need to use. See Tool Variables for complete details on configuring dependencies.

// Create a tool with custom dependencies
const tool = await client.tools.upsert({
name: "analyze_sentiment",
defaultRequiresApproval: false,
jsonSchema: {
type: "function",
function: {
name: "analyze_sentiment",
description: "Analyze sentiment of text",
parameters: {
type: "object",
properties: {
text: {
type: "string",
description: "Text to analyze",
},
},
required: ["text"],
},
},
},
sourceCode: `def analyze_sentiment(text: str) -> str:
"""Analyze sentiment of text using TextBlob."""
from textblob import TextBlob
blob = TextBlob(text)
return f"Sentiment: {blob.sentiment.polarity}"`,
packages: ["textblob"],
});

Configure custom environment variables for API keys and configuration. See Tool Variables for details.

// Create agent with custom tool environment variables
const agent = await client.agents.create({
memory_blocks: [
{ label: "human", value: "Name: Alice" },
{ label: "persona", value: "You are a helpful assistant" },
],
tools: ["my_api_tool"],
toolExecEnvironmentVariables: {
EXTERNAL_API_KEY: "your-api-key-here",
API_ENDPOINT: "https://api.example.com",
},
});