@tool_span¶
Wraps a tool or function call with an OpenInference TOOL span. Captures the tool name, description, and parameters as span attributes.
Decorator only
@tool_span is a decorator only -- there is no context manager alternative. The attribute-setting logic is straightforward (name, description, and serialized kwargs), so a context manager is not needed.
Signature¶
interface ToolSpanOptions {
name: string;
description?: string;
}
function toolSpan<A extends unknown[], R>(
options: ToolSpanOptions,
fn: (...args: A) => R | Promise<R>,
): (...args: A) => Promise<R>
Wrapper function pattern
In TypeScript, toolSpan() wraps a function and returns a new function with the same signature. The name option is required (not optional like in Python).
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str \| None |
None |
Tool name and span name. Defaults to the decorated function's name. |
description |
str \| None |
None |
Human-readable description of what the tool does. Recorded as a span attribute. |
Span Attributes¶
| Attribute | Value |
|---|---|
openinference.span.kind |
"TOOL" |
tool.name |
The tool name (from name parameter or function name) |
tool.description |
Tool description (set when description parameter is provided) |
tool.parameters |
JSON-encoded keyword arguments passed to the function |
Parameter serialization
Only keyword arguments are captured in tool.parameters. Positional arguments are not recorded. If serialization fails (e.g., non-JSON-serializable types), the attribute is silently skipped.
Examples¶
Basic tool call¶
from coalex.ext.tool import tool_span
@tool_span(name="calculate_bmi", description="Calculate Body Mass Index from height and weight")
def calculate_bmi(weight_kg: float, height_m: float) -> float:
return weight_kg / (height_m ** 2)
# Usage
bmi = calculate_bmi(weight_kg=75.0, height_m=1.80)
# Span "calculate_bmi" is emitted with:
# openinference.span.kind = "TOOL"
# tool.name = "calculate_bmi"
# tool.description = "Calculate Body Mass Index from height and weight"
# tool.parameters = '{"weight_kg": 75.0, "height_m": 1.8}'
import { toolSpan } from "@coalex-ai/sdk/ext";
const calculateBmi = toolSpan(
{ name: "calculate_bmi", description: "Calculate Body Mass Index from height and weight" },
async (weightKg: number, heightM: number): Promise<number> => {
return weightKg / (heightM ** 2);
},
);
// Usage
const bmi = await calculateBmi(75.0, 1.80);
// Span "calculate_bmi" is emitted with:
// openinference.span.kind = "TOOL"
// tool.name = "calculate_bmi"
// tool.description = "Calculate Body Mass Index from height and weight"
// tool.parameters = '[75, 1.8]'
API call tool¶
@tool_span(name="get_patient_record", description="Fetch patient record from EHR system")
def get_patient_record(patient_id: str, include_history: bool = True) -> dict:
response = ehr_client.get(f"/patients/{patient_id}", params={"history": include_history})
return response.json()
record = get_patient_record(patient_id="P-12345", include_history=True)
# tool.parameters = '{"patient_id": "P-12345", "include_history": true}'
const getPatientRecord = toolSpan(
{ name: "get_patient_record", description: "Fetch patient record from EHR system" },
async (patientId: string, includeHistory = true): Promise<Record<string, unknown>> => {
const resp = await ehrClient.get(`/patients/${patientId}`, { params: { history: includeHistory } });
return resp.data;
},
);
const record = await getPatientRecord("P-12345", true);
// tool.parameters = '["P-12345", true]'
Database query tool¶
const queryClaims = toolSpan(
{ name: "query_claims", description: "Search insurance claims database" },
async (policyNumber: string, dateFrom: string, dateTo: string): Promise<Record<string, unknown>[]> => {
return db.query(
"SELECT * FROM claims WHERE policy = $1 AND date BETWEEN $2 AND $3",
[policyNumber, dateFrom, dateTo],
);
},
);
Async tool¶
Agent Tool Pattern¶
A common pattern is to use @tool_span / toolSpan() with LLM agents that call tools based on model output:
import coalex
from coalex.ext.tool import tool_span
from openai import OpenAI
coalex.register(api_key="your-key")
coalex.auto_instrument()
client = OpenAI()
@tool_span(name="search_knowledge_base", description="Search internal knowledge base")
def search_kb(query: str) -> str:
results = kb_client.search(query, top_k=3)
return "\n".join(r.content for r in results)
@tool_span(name="get_account_balance", description="Get customer account balance")
def get_balance(account_id: str) -> dict:
return billing_api.get_balance(account_id)
@tool_span(name="create_support_ticket", description="Create a support ticket")
def create_ticket(subject: str, description: str, priority: str = "medium") -> str:
ticket = ticketing_api.create(subject=subject, description=description, priority=priority)
return ticket.id
# Map tool names to functions
tools = {
"search_knowledge_base": search_kb,
"get_account_balance": get_balance,
"create_support_ticket": create_ticket,
}
with coalex.coalex_context(agent_id="support-agent", request_id="req-001"):
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What is my account balance?"}],
tools=[...], # OpenAI function calling schema
)
# Execute the tool call
tool_call = response.choices[0].message.tool_calls[0]
tool_fn = tools[tool_call.function.name]
result = tool_fn(**json.loads(tool_call.function.arguments))
# Trace:
# coalex.invocation
# ├── openai.chat.completions (LLM)
# └── get_account_balance (TOOL)
# tool.parameters = '{"account_id": "ACC-789"}'
import { register, coalexContext, autoInstrument } from "@coalex-ai/sdk";
import { toolSpan } from "@coalex-ai/sdk/ext";
import OpenAI from "openai";
register({ apiKey: "your-key" });
autoInstrument();
const client = new OpenAI();
const searchKb = toolSpan(
{ name: "search_knowledge_base", description: "Search internal knowledge base" },
async (query: string): Promise<string> => {
const results = await kbClient.search(query, { topK: 3 });
return results.map(r => r.content).join("\n");
},
);
const getBalance = toolSpan(
{ name: "get_account_balance", description: "Get customer account balance" },
async (accountId: string): Promise<Record<string, unknown>> => {
return billingApi.getBalance(accountId);
},
);
const createTicket = toolSpan(
{ name: "create_support_ticket", description: "Create a support ticket" },
async (subject: string, description: string, priority = "medium"): Promise<string> => {
const ticket = await ticketingApi.create({ subject, description, priority });
return ticket.id;
},
);
// Map tool names to functions
const tools: Record<string, (...args: any[]) => Promise<any>> = {
search_knowledge_base: searchKb,
get_account_balance: getBalance,
create_support_ticket: createTicket,
};
await coalexContext({ agentId: "support-agent", requestId: "req-001" }, async () => {
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "What is my account balance?" }],
tools: [...], // OpenAI function calling schema
});
// Execute the tool call
const toolCall = response.choices[0].message.tool_calls![0];
const toolFn = tools[toolCall.function.name];
const args = JSON.parse(toolCall.function.arguments);
const result = await toolFn(...Object.values(args));
// Trace:
// coalex.invocation
// ├── openai.chat.completions (LLM)
// └── get_account_balance (TOOL)
// tool.parameters = '["ACC-789"]'
});
API Reference¶
coalex.ext.tool ¶
Tool span decorator.
Functions¶
tool_span ¶
Decorator that wraps a tool function with an OpenInference TOOL span.
Supports both sync and async functions. The span captures:
- openinference.span.kind = TOOL
- tool.name — span name
- tool.description — if provided
- tool.parameters — JSON-encoded kwargs passed to the function
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
Tool name and span name. Defaults to the function name. |
None
|
description
|
str | None
|
Human-readable tool description. |
None
|