v1.1.1 - OTel-canonical dual emission
v1.1.1 — Dual-emission of OTel-canonical gen_ai.input/output.messages
What changed
After filing issue #3672
and reading the upstream JSON schemas more carefully, it became clear that OTel's
gen-ai-input-messages.json / gen-ai-output-messages.json already define BlobPart,
FilePart, UriPart and a Modality enum (image, video, audio). The flat attribute
namespace shipped in v1.1.0 was a different shape from upstream's established pattern.
v1.1.1 keeps the flat attributes (still useful as a query-friendly convenience for backends
that index attribute scalars) but adds dual-emission so multimodal traces remain portable
across OTel-compatible backends.
How it works
When OTEL_SEMCONV_STABILITY_OPT_IN includes gen_ai, the instrumentor now also writes:
gen_ai.input.messages— JSON list ofChatMessageper the upstream schemagen_ai.output.messages— same for completions
ContentParts map as:
| Our internal shape | Upstream canonical shape |
|---|---|
text part |
TextPart |
image/audio/video with media_uri |
UriPart (with modality, mime_type, byte_size) |
image/audio/video with inline bytes |
BlobPart (base64 content) |
document parts |
UriPart/BlobPart with modality: "document" (proposed addition) |
reference_only / stripped parts |
StrippedPart (proposed addition, with stripped_reason) |
New public API
from genai_otel.media import build_canonical_messages, ContentPart
messages = build_canonical_messages([
("user", [
ContentPart(type="text", text="describe"),
ContentPart(type="image", media_uri="s3://bucket/key.png", media_mime_type="image/png"),
]),
])Upstream proposal narrowed
The redrafted upstream PR (in docs/proposals/upstream-pr-draft/) is much smaller:
- Add
documentvalue to theModalityenum - Add optional
byte_sizefield toBlobPart/FilePart/UriPart - Add new
StrippedParttype for fail-closed observability
This is ~30 lines of JSON schema diff vs the 480-line registry expansion originally
drafted. Mirrors the upstream pattern, not a parallel one.
New tests
9 new tests:
- 7 in
tests/media/test_canonical.pycovering the ContentPart → upstream-shape mapping - 2 in
tests/media/test_instrumentor_emit.pyverifying dual-emission gating
Backwards compatibility
Purely additive. The flat gen_ai.prompt.{n}.content.{m}.* attributes from v1.1.0 are
unchanged. Dual-emission is gated on OTEL_SEMCONV_STABILITY_OPT_IN so existing deployments
see no change unless they opt in.