Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add response.id semantic convention attribute to interactions telemetry.
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ def _apply_interaction_response_attributes(
telemetry_handler: TelemetryHandler,
) -> None:
invocation.response_model_name = response.model
if getattr(response, "id", None):
invocation.response_id = response.id
Comment thread
DylanRussell marked this conversation as resolved.

usage = response.usage or Usage()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.test.weaver_live_check import LiveCheckReport
from opentelemetry.test_util_genai.conformance import Scenario
from opentelemetry.test_util_genai.instrumentor import instrument

Expand Down Expand Up @@ -49,3 +50,16 @@ def run(
model="gemini-2.5-flash",
contents="Say this is a test",
)

def validate(self, report: LiveCheckReport) -> None:
super().validate(report)
response_ids = [
attr["value"]
for entry in report["samples"]
if "span" in entry
for attr in entry["span"]["attributes"]
if attr["name"] == "gen_ai.response.id"
]
assert response_ids == ["Ibo-aoj4EpSy1MkPsezpqQE"], (
f"Expected gen_ai.response.id ['Ibo-aoj4EpSy1MkPsezpqQE'] but saw {response_ids}"
)
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.test.weaver_live_check import LiveCheckReport
from opentelemetry.test_util_genai.conformance import (
ExpectedViolation,
Scenario,
Expand Down Expand Up @@ -58,3 +59,20 @@ def run(
model="gemini-2.5-flash",
input="Hello, how can you help me today?",
)

def validate(self, report: LiveCheckReport) -> None:
super().validate(report)
response_ids = [
attr["value"]
for entry in report["samples"]
if "span" in entry
for attr in entry["span"]["attributes"]
if attr["name"] == "gen_ai.response.id"
]
assert response_ids == [
"v1_ChdMaWM4YXF2ekNMQ1k5TW9QLUpHZ3dBYxIXTGljOGFxdnpDTENZOU1vUC1KR2d3QWM"
], (
"Expected gen_ai.response.id "
"['v1_ChdMaWM4YXF2ekNMQ1k5TW9QLUpHZ3dBYxIXTGljOGFxdnpDTENZOU1vUC1KR2d3QWM'] "
f"but saw {response_ids}"
)
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,26 @@ def test_generated_span_has_minimal_genai_attributes(self) -> None:
"generativelanguage.googleapis.com",
)

def test_generated_span_has_response_id(self) -> None:
self.configure_valid_interaction(interaction_id="interaction-123")
self.run_interaction(
model="gemini-2.5-flash",
input="Follow-up question",
)
span = self.otel.get_span_named("interactions.create gemini-2.5-flash")
self.assertEqual(
span.attributes["gen_ai.response.id"], "interaction-123"
)
self.otel.assert_has_event_named(
"gen_ai.client.inference.operation.details"
)
event = self.otel.get_event_named(
"gen_ai.client.inference.operation.details"
)
self.assertEqual(
event.attributes["gen_ai.response.id"], "interaction-123"
)

def test_span_and_event_still_written_when_response_is_exception(
self,
) -> None:
Expand Down