Skip to main content

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

run_id
str
required
The run ID that this tool call belongs to. Get this from r.run_id.
tool_call_id
str
Unique identifier for this tool call. If not provided, a UUID will be automatically generated.
tool_name
str
Name of the tool being called. Can also be set using tc.name().
api_key
str
Observatory API key. If not provided, uses the TCC_API_KEY environment variable.
tcc_url
str
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
tool_name
str
required
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
code
int
required
Status code: 0 = success, 1 = partial success, 2 = error
message
str
Human-readable status message

end()

Finalize and send the tool call data:
tc.end() -> None
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
status_message
str
Error message describing what went wrong

Usage Examples

Creating Tool Calls from a Run

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()

Creating Tool Calls Independently

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()

Tool Call with String Arguments

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()

Setting Tool Name Later

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()

Multiple Tool Calls

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()

Tool Call from a Step

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()

Tool Call with Structured Output

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

  1. Always set the tool name: The name is required before calling tc.end().
  2. Use descriptive names: Choose clear, descriptive names for your tools (e.g., “search_database” not “db_search”).
  3. Capture both args and results: Record what was requested and what was returned for complete observability.
  4. Handle errors gracefully: Use tc.error() to capture tool failures without breaking your agent.
  5. Use dictionaries for structured data: Pass complex arguments and results as dictionaries instead of manually serializing JSON.
  6. Create tool calls from runs: Use r.tool_call() instead of tool_call(run_id=...) for cleaner code.
  7. Set appropriate status codes: Use status codes to indicate partial success or validation issues.

Common Patterns

API Tool Call

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

Build docs developers (and LLMs) love