Tool calls should be instrumented as well. There can be multiple tool calls, so we treat this like we treat input_messages above. This example uses OpenAi tool call type but can be easily adapted to any tool call with a function name and arguments (as JSON).
from typing import List
from openai.types.chat.chat_completion_chunk import ChoiceDeltaToolCall
from openinference.semconv.trace import (
MessageAttributes,
OpenInferenceSpanKindValues,
SpanAttributes,
ToolCallAttributes,
)
from opentelemetry.trace import Span
def set_tool_call_attrs(tool_span: Span, tool_calls: List[ChoiceDeltaToolCall]) -> None:
tool_span.set_attribute(
SpanAttributes.OPENINFERENCE_SPAN_KIND,
OpenInferenceSpanKindValues.TOOL.value,
)
for idx, tool_call in enumerate(tool_calls):
function = tool_call.function
if not function:
continue
tool_span.set_attribute(
f"{MessageAttributes.MESSAGE_TOOL_CALLS}.{idx}."
f"{ToolCallAttributes.TOOL_CALL_FUNCTION_NAME}",
function.name or "",
)
tool_span.set_attribute(
f"{MessageAttributes.MESSAGE_TOOL_CALLS}.{idx}."
f"{ToolCallAttributes.TOOL_CALL_FUNCTION_ARGUMENTS_JSON}",
function.arguments or "",
)