Overview
The tool_call() function creates a new tool call to track when your AI agent invokes a tool or function. Tool calls capture the tool name, arguments, results, and execution status.
Function Signature
from contextcompany import tool_call
tool_call(
run_id: str,
tool_call_id: Optional[str] = None,
tool_name: Optional[str] = None,
api_key: Optional[str] = None,
tcc_url: Optional[str] = None,
) -> ToolCall
Parameters
The run ID that this tool call belongs to. Get this from r.run_id.
Unique identifier for this tool call. If not provided, a UUID will be automatically generated.
Name of the tool being called. Can also be set using tc.name().
Observatory API key. If not provided, uses the TCC_API_KEY environment variable.
Custom Observatory endpoint URL. If not provided, uses the TCC_URL environment variable or defaults to production.
Returns
Returns a ToolCall object with the following methods:
name()
Set the tool name:
tc.name(tool_name: str) -> ToolCall
Name of the tool or function being invoked
args()
Set the arguments passed to the tool:
tc.args(value: Union[str, Dict[str, Any]]) -> ToolCall
value
Union[str, Dict[str, Any]]
required
Tool arguments as a string or dictionary. Dictionaries are automatically JSON-serialized.
result()
Set the result returned by the tool:
tc.result(value: Union[str, Dict[str, Any]]) -> ToolCall
value
Union[str, Dict[str, Any]]
required
Tool result as a string or dictionary. Dictionaries are automatically JSON-serialized.
status()
Set the status code and optional message:
tc.status(
code: int,
message: Optional[str] = None
) -> ToolCall
Status code: 0 = success, 1 = partial success, 2 = error
Human-readable status message
end()
Finalize and send the tool call data:
You must set the tool name (via constructor or tc.name()) before calling tc.end(), or a ValueError will be raised.
error()
Mark the tool call as failed and send immediately:
tc.error(status_message: str = "") -> None
Error message describing what went wrong
Usage Examples
from contextcompany import run
r = run()
# Create a tool call from the run object (recommended)
tc = r.tool_call(tool_name="get_weather")
tc.args({"location": "San Francisco"})
tc.result({"temperature": 65, "condition": "sunny"})
tc.end()
r.prompt(user_prompt="What's the weather in SF?")
r.response("It's 65°F and sunny.")
r.end()
from contextcompany import run, tool_call
r = run()
# Create a tool call using the run_id
tc = tool_call(run_id=r.run_id, tool_name="search_database")
tc.args({"query": "SELECT * FROM users"})
tc.result({"count": 42, "rows": [...]})
tc.end()
r.prompt(user_prompt="How many users?")
r.response("There are 42 users.")
r.end()
from contextcompany import run
import json
r = run()
tc = r.tool_call(tool_name="execute_code")
# Pass arguments as JSON string
tc.args(json.dumps({
"language": "python",
"code": "print('Hello, world!')"
}))
tc.result("Hello, world!")
tc.end()
r.prompt(user_prompt="Run hello world")
r.response("Code executed successfully.")
r.end()
from contextcompany import run
r = run()
tc = r.tool_call() # No name provided initially
# Set name later
tc.name("fetch_data")
tc.args({"endpoint": "/api/users"})
tc.result({"status": "success", "data": [...]})
tc.end()
r.prompt(user_prompt="Get user data")
r.response("Fetched user data successfully.")
r.end()
from contextcompany import run
r = run()
# First tool call: get weather
tc1 = r.tool_call(tool_name="get_weather")
tc1.args({"location": "San Francisco"})
tc1.result({"temperature": 65, "condition": "sunny"})
tc1.end()
# Second tool call: get time
tc2 = r.tool_call(tool_name="get_time")
tc2.args({"timezone": "America/Los_Angeles"})
tc2.result({"time": "2:30 PM"})
tc2.end()
# Third tool call: search restaurants
tc3 = r.tool_call(tool_name="search_restaurants")
tc3.args({"location": "San Francisco", "cuisine": "Italian"})
tc3.result({"count": 15, "restaurants": [...]})
tc3.end()
r.prompt(user_prompt="Find Italian restaurants in SF")
r.response("Found 15 Italian restaurants. It's currently 2:30 PM and 65°F.")
r.end()
from contextcompany import run
r = run()
s = r.step()
s.prompt("I need to call a tool...")
s.response("Calling the search tool...")
s.finish_reason("tool_calls")
s.end()
# Tool call associated with the step
tc = s.tool_call(tool_name="web_search")
tc.args({"query": "Python tutorials"})
tc.result({"results": [...]})
tc.end()
r.prompt(user_prompt="Search for Python tutorials")
r.response("Here are some Python tutorials...")
r.end()
Error Handling
from contextcompany import run
r = run()
tc = r.tool_call(tool_name="risky_operation")
tc.args({"parameter": "value"})
try:
result = execute_risky_operation()
tc.result(result)
tc.end()
except Exception as e:
tc.error(f"Operation failed: {str(e)}")
# Continue with run even if tool failed
r.prompt(user_prompt="Execute operation")
r.response("Operation failed, please try again.")
r.status(2, "Tool execution failed")
r.end()
Partial Success with Status Codes
from contextcompany import run
r = run()
tc = r.tool_call(tool_name="batch_processor")
tc.args({"items": [1, 2, 3, 4, 5]})
result = process_batch()
if result["failed"] > 0:
tc.status(1, f"{result['failed']} items failed") # Partial success
else:
tc.status(0, "All items processed") # Complete success
tc.result(result)
tc.end()
r.prompt(user_prompt="Process batch")
r.response(f"Processed {result['succeeded']} items successfully.")
r.end()
from contextcompany import run
r = run()
tc = r.tool_call(tool_name="analyze_sentiment")
tc.args({
"text": "I love this product!"
})
tc.result({
"sentiment": "positive",
"confidence": 0.95,
"scores": {
"positive": 0.95,
"neutral": 0.04,
"negative": 0.01
}
})
tc.end()
r.prompt(user_prompt="Analyze sentiment")
r.response("The sentiment is positive with 95% confidence.")
r.end()
Best Practices
-
Always set the tool name: The name is required before calling
tc.end().
-
Use descriptive names: Choose clear, descriptive names for your tools (e.g., “search_database” not “db_search”).
-
Capture both args and results: Record what was requested and what was returned for complete observability.
-
Handle errors gracefully: Use
tc.error() to capture tool failures without breaking your agent.
-
Use dictionaries for structured data: Pass complex arguments and results as dictionaries instead of manually serializing JSON.
-
Create tool calls from runs: Use
r.tool_call() instead of tool_call(run_id=...) for cleaner code.
-
Set appropriate status codes: Use status codes to indicate partial success or validation issues.
Common Patterns
tc = r.tool_call(tool_name="api_request")
tc.args({
"method": "GET",
"url": "https://api.example.com/data",
"headers": {"Authorization": "Bearer ..."}
})
tc.result({
"status": 200,
"data": {...}
})
tc.end()
Database Query
tc = r.tool_call(tool_name="database_query")
tc.args({
"query": "SELECT * FROM orders WHERE status = ?",
"params": ["pending"]
})
tc.result({
"rows": [...],
"count": 25,
"execution_time_ms": 45
})
tc.end()
File Operation
tc = r.tool_call(tool_name="read_file")
tc.args({"path": "/data/config.json"})
tc.result({
"content": {...},
"size_bytes": 1024,
"modified": "2024-03-15T10:30:00Z"
})
tc.end()
See Also