What Is Captured
- Chat Completions request and response messages
- Responses API input and output text
- Tool call names, IDs, and JSON arguments
- Tool result messages passed back into later turns
- JSON schema response format in invocation parameters
- Model name, finish reason, usage, and token counts
Install
bun add @inference/tracing openai
pip install 'inference-catalyst-tracing[openai]'
Basic Chat
import { setup } from "@inference/tracing";
import OpenAI from "openai";
const tracing = await setup({
serviceName: "checkout-agent",
modules: { openai: OpenAI },
});
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: "You answer in one short sentence." },
{ role: "user", content: "Summarize order ABC-123." },
],
max_tokens: 80,
});
console.log(response.choices[0]?.message.content);
await tracing.shutdown();
import os
from inference_catalyst_tracing import setup
from openai import OpenAI
tracing = setup(service_name="checkout-agent")
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You answer in one short sentence."},
{"role": "user", "content": "Summarize order ABC-123."},
],
max_tokens=80,
)
print(response.choices[0].message.content)
tracing.shutdown()
OpenAI Inside An Agent
import { agentSpan } from "@inference/tracing";
await agentSpan(
{
agentId: "checkout-agent",
agentName: "Checkout Agent",
spanName: "checkout-agent.run",
sessionId: "conversation-checkout-1",
role: "checkout",
system: "openai",
},
async (span) => {
const input = "Summarize order ABC-123.";
span.setInput(input);
const response = await client.responses.create({
model: "gpt-4o-mini",
input,
});
span.setOutput(response.output_text);
},
);
from inference_catalyst_tracing import agent_span
with agent_span(
tracing.tracer,
agent_id="checkout-agent",
agent_name="Checkout Agent",
span_name="checkout-agent.run",
session_id="conversation-checkout-1",
agent_role="checkout",
system="openai",
) as span:
user_input = "Summarize order ABC-123."
span.set_input(user_input)
response = client.responses.create(model="gpt-4o-mini", input=user_input)
span.set_output(response.output_text)
Tool Calling
The first model call records the assistant tool call. The second model call records the tool result message and the final answer.The capture below is the model-side view of tool calling — the
request/response the LLM saw. To also capture the caller-side view (the
actual function that ran, its input, output, and duration), wrap the tool
function in a
TOOL span using
Manual spans.
For a full agent loop, see the
Production Agent Example.import { setup } from "@inference/tracing";
import OpenAI from "openai";
const tracing = await setup({ modules: { openai: OpenAI } });
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const tools = [
{
type: "function" as const,
function: {
name: "get_weather",
description: "Look up the current weather in a city.",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
},
},
];
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
{ role: "user", content: "What's the weather in San Francisco?" },
];
const first = await client.chat.completions.create({
model: "gpt-4o-mini",
messages,
tools,
});
const toolCalls = first.choices[0]?.message.tool_calls ?? [];
messages.push({ role: "assistant", content: null, tool_calls: toolCalls });
for (const toolCall of toolCalls) {
const args = JSON.parse(toolCall.function.arguments) as { city: string };
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify({ city: args.city, tempF: 62 }),
});
}
const final = await client.chat.completions.create({
model: "gpt-4o-mini",
messages,
tools,
});
console.log(final.choices[0]?.message.content);
await tracing.shutdown();
import json
import os
from inference_catalyst_tracing import setup
from openai import OpenAI
from openai.types.chat import ChatCompletionMessageParam
tracing = setup()
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Look up the current weather in a city.",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
},
]
messages: list[ChatCompletionMessageParam] = [
{"role": "user", "content": "What's the weather in San Francisco?"},
]
first = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tools,
)
tool_calls = first.choices[0].message.tool_calls or []
messages.append(
{
"role": "assistant",
"content": None,
"tool_calls": [tool_call.model_dump() for tool_call in tool_calls],
},
)
for tool_call in tool_calls:
args = json.loads(tool_call.function.arguments)
messages.append(
{
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps({"city": args["city"], "temp_f": 62}),
},
)
final = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tools,
)
print(final.choices[0].message.content)
tracing.shutdown()
Structured Outputs
response_format is included in invocation parameters, so you can inspect which
schema constrained the model call.
TypeScript
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{
role: "user",
content: "Extract the city, temperature, and unit from: 72F in Berlin.",
},
],
response_format: {
type: "json_schema",
json_schema: {
name: "weather_report",
strict: true,
schema: {
type: "object",
additionalProperties: false,
properties: {
city: { type: "string" },
temperature: { type: "number" },
unit: { type: "string", enum: ["F", "C"] },
},
required: ["city", "temperature", "unit"],
},
},
},
});
console.log(response.choices[0]?.message.content);
Responses API
Responses API calls are traced with the same OpenInference attribute families as Chat Completions.TypeScript
const response = await client.responses.create({
model: "gpt-4o-mini",
input: "In one sentence, what is OpenTelemetry?",
});
console.log(response.output_text);