Skip to content

Commit 01525be

Browse files
chore(tracing): add invocation span attrs (#113)
1 parent e1371c3 commit 01525be

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

veadk/tracing/telemetry/telemetry.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,63 @@ def upload_metrics(
5151
exporter.meter_uploader.record(llm_request, llm_response)
5252

5353

54+
def _set_agent_input_attribute(
55+
span: _Span, invocation_context: InvocationContext
56+
) -> None:
57+
# We only save the original user input as the agent input
58+
# hence once the `agent.input` has been set, we don't overwrite it
59+
event_names = [event.name for event in span.events]
60+
if "gen_ai.user.message" in event_names:
61+
return
62+
63+
# input = {
64+
# "agent_name": invocation_context.agent.name,
65+
# "app_name": invocation_context.session.app_name,
66+
# "user_id": invocation_context.user_id,
67+
# "session_id": invocation_context.session.id,
68+
# "input": invocation_context.user_content.model_dump(exclude_none=True)
69+
# if invocation_context.user_content
70+
# else None,
71+
# }
72+
73+
user_content = invocation_context.user_content
74+
if user_content and user_content.parts:
75+
span.add_event(
76+
"gen_ai.user.message",
77+
{
78+
"agent_name": invocation_context.agent.name,
79+
"app_name": invocation_context.session.app_name,
80+
"user_id": invocation_context.user_id,
81+
"session_id": invocation_context.session.id,
82+
},
83+
)
84+
for idx, part in enumerate(user_content.parts):
85+
if part.text:
86+
span.add_event(
87+
"gen_ai.user.message",
88+
{f"parts.{idx}.type": "text", f"parts.{idx}.content": part.text},
89+
)
90+
91+
92+
def _set_agent_output_attribute(span: _Span, llm_response: LlmResponse) -> None:
93+
content = llm_response.content
94+
if content and content.parts:
95+
for idx, part in enumerate(content.parts):
96+
if part.text:
97+
span.add_event(
98+
"gen_ai.choice",
99+
{
100+
f"message.parts.{idx}.type": "text",
101+
f"message.parts.{idx}.text": part.text,
102+
},
103+
)
104+
105+
54106
def set_common_attributes_on_model_span(
55-
invocation_context: InvocationContext, current_span: _Span, **kwargs
107+
invocation_context: InvocationContext,
108+
llm_response: LlmResponse,
109+
current_span: _Span,
110+
**kwargs,
56111
) -> None:
57112
if current_span.context:
58113
current_span_id = current_span.context.trace_id
@@ -76,8 +131,12 @@ def set_common_attributes_on_model_span(
76131
if span.is_recording():
77132
if span.name.startswith("invocation"):
78133
span.set_attribute("gen_ai.operation.name", "chain")
134+
_set_agent_input_attribute(span, invocation_context)
135+
_set_agent_output_attribute(span, llm_response)
79136
elif span.name.startswith("agent_run"):
80137
span.set_attribute("gen_ai.operation.name", "agent")
138+
_set_agent_input_attribute(span, invocation_context)
139+
_set_agent_output_attribute(span, llm_response)
81140
for attr_name, attr_extractor in common_attributes.items():
82141
value = attr_extractor(**kwargs)
83142
span.set_attribute(attr_name, value)
@@ -139,6 +198,7 @@ def trace_call_llm(
139198

140199
set_common_attributes_on_model_span(
141200
invocation_context=invocation_context,
201+
llm_response=llm_response,
142202
current_span=span, # type: ignore
143203
agent_name=invocation_context.agent.name,
144204
user_id=invocation_context.user_id,

veadk/utils/misc.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import sys
1717
import time
1818
import types
19+
from typing import Any, Dict, List, MutableMapping, Tuple
1920

2021
import requests
2122

@@ -60,3 +61,23 @@ def load_module_from_file(module_name: str, file_path: str) -> types.ModuleType:
6061
)
6162
else:
6263
raise ImportError(f"Could not load module {module_name} from {file_path}")
64+
65+
66+
def flatten_dict(
67+
d: MutableMapping[str, Any], parent_key: str = "", sep: str = "_"
68+
) -> Dict[str, Any]:
69+
"""Flatten a nested dictionary.
70+
71+
Input:
72+
{"a": {"b": 1}}
73+
Output:
74+
{"a_b": 1}
75+
"""
76+
items: List[Tuple[str, Any]] = []
77+
for k, v in d.items():
78+
new_key = f"{parent_key}{sep}{k}" if parent_key else k
79+
if isinstance(v, MutableMapping):
80+
items.extend(flatten_dict(v, new_key, sep=sep).items())
81+
else:
82+
items.append((new_key, v))
83+
return dict(items)

0 commit comments

Comments
 (0)