Skip to content

Commit 64197f6

Browse files
committed
fix(fara): populate gen_ai.tool.definitions on AGENT span (Review #1)
AgentRunWrapper now attaches gen_ai.tool.definitions as a JSON array covering the 11 canonical Fara tools, reusing _attrs.tool_definitions(capture). capture=False -> {type, name} entries; capture=True -> entries with description. Adds two unit tests asserting the AGENT span carries an 11-element JSON array with the expected canonical tool names, in both capture modes.
1 parent b15a8e8 commit 64197f6

2 files changed

Lines changed: 57 additions & 2 deletions

File tree

instrumentation-loongsuite/loongsuite-instrumentation-fara/src/opentelemetry/instrumentation/fara/internal/_wrappers.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,19 @@ async def __call__(
194194
request_model = client_config.get("model") if isinstance(client_config, dict) else None
195195
conversation_id = state.get_entry_session_id()
196196

197+
capture = capture_message_content()
197198
inv = InvokeAgentInvocation(
198199
provider="openai",
199200
agent_name=agent_name,
200201
agent_description="Fara-7B Computer Use Agent",
201202
conversation_id=conversation_id,
202203
request_model=request_model,
203-
attributes={"gen_ai.framework": FRAMEWORK_NAME},
204+
attributes={
205+
"gen_ai.framework": FRAMEWORK_NAME,
206+
"gen_ai.tool.definitions": safe_json_dumps(tool_definitions(capture)),
207+
},
204208
)
205-
if capture_message_content() and user_message:
209+
if capture and user_message:
206210
inv.input_messages = _make_input_messages(str(user_message))
207211

208212
# Reset STEP rotation state for this agent run.

instrumentation-loongsuite/loongsuite-instrumentation-fara/tests/test_wrappers.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from __future__ import annotations
2222

2323
import asyncio
24+
import json
2425
import uuid
2526

2627
import fara.fara_agent as fara_agent_mod
@@ -129,6 +130,56 @@ def test_agent_span_error_on_exception(instrument, span_exporter):
129130
assert agent_spans[0].status.is_ok is False
130131

131132

133+
def _canonical_tool_names():
134+
return [
135+
"key",
136+
"type",
137+
"mouse_move",
138+
"left_click",
139+
"scroll",
140+
"visit_url",
141+
"web_search",
142+
"history_back",
143+
"pause_and_memorize_fact",
144+
"wait",
145+
"terminate",
146+
]
147+
148+
149+
def test_agent_span_tool_definitions_default(instrument, span_exporter):
150+
# capture disabled: AGENT span must still carry gen_ai.tool.definitions
151+
# as a JSON array of 11 {type, name} entries (no description).
152+
agent = _build_agent()
153+
_await(agent.run("click the search box"))
154+
spans = span_exporter.get_finished_spans()
155+
agent_span = spans_by_name(spans, "invoke_agent FaraAgent")[0]
156+
raw = span_attr(agent_span, "gen_ai.tool.definitions")
157+
assert raw is not None
158+
defs = json.loads(raw)
159+
assert isinstance(defs, list)
160+
assert len(defs) == 11
161+
assert [d["name"] for d in defs] == _canonical_tool_names()
162+
for d in defs:
163+
assert d["type"] == "function"
164+
assert "description" not in d
165+
166+
167+
def test_agent_span_tool_definitions_with_content(instrument_with_content, span_exporter):
168+
# capture enabled: each entry should also carry a description.
169+
agent = _build_agent()
170+
_await(agent.run("click the search box"))
171+
spans = span_exporter.get_finished_spans()
172+
agent_span = spans_by_name(spans, "invoke_agent FaraAgent")[0]
173+
raw = span_attr(agent_span, "gen_ai.tool.definitions")
174+
assert raw is not None
175+
defs = json.loads(raw)
176+
assert len(defs) == 11
177+
assert [d["name"] for d in defs] == _canonical_tool_names()
178+
for d in defs:
179+
assert d["type"] == "function"
180+
assert d.get("description")
181+
182+
132183
# ---------------------------------------------------------------------------
133184
# STEP span
134185
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)