Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from phoenix.otel import register
from smolagents import OpenAIServerModel

register(auto_instrument=True)

model = OpenAIServerModel(model_id="gpt-4o")
output = model(messages=[{"role": "user", "content": "hello world"}])
print(output.content)
Original file line number Diff line number Diff line change
Expand Up @@ -278,14 +278,50 @@ def process_message(idx: int, role: str, content: str) -> Iterator[Tuple[str, An
if isinstance(prompt := arguments.get("prompt"), str):
yield from process_message(0, "user", prompt)
elif isinstance(messages := arguments.get("messages"), list):
for i, message in enumerate(messages):
if not isinstance(message, dict):
continue
role, content = message.get("role"), message.get("content")
if isinstance(content, list) and role:
for subcontent in content:
if isinstance(subcontent, dict) and (text := subcontent.get("text")):
yield from process_message(i, role, text)
oi_messages: list[oi.Message] = []
for message in messages:
oi_message: oi.Message = {}
oi_message_contents: list[oi.MessageContent] = []
if (role := getattr(message, "role", None)) is not None:
oi_message["role"] = role
if (content := getattr(message, "content", None)) is not None:
oi_message_contents.extend(content)

# Add the reasoning_content if available in raw.choices[0].message structure
if (raw := getattr(message, "raw", None)) is not None:
if (choices := getattr(raw, "choices", None)) is not None:
if isinstance(choices, list) and len(choices) > 0:
if (message := getattr(choices[0], "message", None)) is not None:
if (
reasoning_content := getattr(message, "reasoning_content", None)
) is not None:
oi_message_contents.append(
oi.TextMessageContent(type="text", text=reasoning_content)
)

oi_message["contents"] = oi_message_contents
oi_tool_calls: list[oi.ToolCall] = []
if isinstance(tool_calls := getattr(message, "tool_calls", None), list):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Variable Shadowing and Type Error

The loop variable message is shadowed by a nested assignment, causing subsequent attribute access (e.g., tool_calls) to use the wrong message object. Additionally, a TypeError may occur when oi_message_contents.extend(content) is called if content is not iterable, as the previous type check was removed.

Fix in Cursor Fix in Web

for tool_call in tool_calls:
oi_tool_call: oi.ToolCall = {}
if (tool_call_id := getattr(tool_call, "id", None)) is not None:
oi_tool_call["id"] = tool_call_id
if (function := getattr(tool_call, "function", None)) is not None:
oi_function: oi.ToolCallFunction = {}
if (name := getattr(function, "name", None)) is not None:
oi_function["name"] = name
if isinstance(
function_arguments := getattr(function, "arguments", None), str
):
oi_function["arguments"] = function_arguments
oi_tool_call["function"] = oi_function
oi_tool_calls.append(oi_tool_call)

oi_message["tool_calls"] = oi_tool_calls
oi_messages.append(oi_message)

for k, v in oi.get_llm_input_message_attributes(messages=oi_messages).items():
yield k, v


def _llm_output_messages(output_message: Any) -> Mapping[str, AttributeValue]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def anthropic_api_key(monkeypatch: pytest.MonkeyPatch) -> str:

class TestInstrumentor:
def test_entrypoint_for_opentelemetry_instrument(self) -> None:
(instrumentor_entrypoint,) = entry_points(
(instrumentor_entrypoint,) = entry_points( # type: ignore[no-untyped-call]
group="opentelemetry_instrumentor", name="smolagents"
)
instrumentor = instrumentor_entrypoint.load()()
Expand Down
Loading