Skip to content

feat(eap): implement gen_ai attribute transformations#6201

Draft
constantinius wants to merge 2 commits into
masterfrom
constantinius/feat/eap/gen-ai-attribute-transformations
Draft

feat(eap): implement gen_ai attribute transformations#6201
constantinius wants to merge 2 commits into
masterfrom
constantinius/feat/eap/gen-ai-attribute-transformations

Conversation

@constantinius

Copy link
Copy Markdown
Contributor

Summary

Implements the two gen_ai attribute transformations introduced in sentry-conventions PR #465:

  • gen_ai_request_messages_to_input_messages — transforms gen_ai.request.messages (with content field per message) into gen_ai.input.messages (with parts array)
  • gen_ai_response_to_output_messages — combines gen_ai.response.text and gen_ai.response.tool_calls into a single gen_ai.output.messages assistant message with typed parts

These go beyond simple key renaming — they reshape attribute values to match the new schema.

How it works

Attributes with _status: "transform" in sentry-conventions produce WriteBehavior::CurrentName, so normalize_attribute_names leaves them alone. The dedicated transformation code in the new gen_ai_transform module handles the full move-and-reshape, called from normalize_ai as part of AI span normalization (processing mode only).

The gen_ai.request.messages, gen_ai.response.text, and gen_ai.response.tool_calls legacy aliases are removed from SpanV1 SpanData so these deprecated keys survive into SpanV2 attributes where the transformation can process them.

gen_ai.request.messagesgen_ai.input.messages

For each message object, the content field is converted to a parts array:

  • String content "hello"[{"type": "text", "content": "hello"}]
  • Array content (already parts-like) → kept, with text copied to content on each part if missing
  • Other content types (e.g., tool message objects) → left unchanged
  • Non-JSON values → moved as-is (key rename only)

gen_ai.response.text + gen_ai.response.tool_callsgen_ai.output.messages

gen_ai.response.text handles multiple formats:

  • Plain string, JSON string, JSON array of strings, JSON object with content, JSON array of objects with content

Tool calls get "type": "tool_call" added. Both are combined into one assistant message: [{"role": "assistant", "parts": [...]}].

Changes

  • relay-conventions/build/attributes.rs — add Transform variant to DeprecationStatus, producing WriteBehavior::CurrentName
  • relay-event-normalization/src/eap/gen_ai_transform.rs — new module with transformation logic
  • relay-event-normalization/src/eap/ai.rsnormalize_ai calls transform_gen_ai as its first step
  • relay-event-schema/src/protocol/span.rs — remove legacy aliases for the three deprecated attributes
  • relay-conventions/sentry-conventions — update submodule to PR fix(server): Allow multipart requests without trailing newline #465 branch

Tests

  • 21 Rust unit tests covering all input formats, edge cases, and idempotency
  • 4 Python integration tests covering both SpanV1 (transaction) and SpanV2 (direct ingestion) paths
  • Updated existing test_ai_spans_example_transaction expectations

Contributes to TET-2587

Implement the two attribute transformations introduced in
sentry-conventions PR #465: `gen_ai_request_messages_to_input_messages`
and `gen_ai_response_to_output_messages`.

These go beyond simple key renaming — they reshape attribute values to
match the new schema. `gen_ai.request.messages` with a `content` field
on each message is converted to `gen_ai.input.messages` with a `parts`
array. `gen_ai.response.text` (plain string, JSON string array, or
objects with content) and `gen_ai.response.tool_calls` are combined into
a single `gen_ai.output.messages` assistant message with typed parts.

The transformations run inside `normalize_ai` as part of AI span
normalization (processing mode only). Attributes with the new
`"transform"` deprecation status produce `WriteBehavior::CurrentName`
so `normalize_attribute_names` leaves them alone — the dedicated
transformation code handles the full move-and-reshape.

The `gen_ai.request.messages`, `gen_ai.response.text`, and
`gen_ai.response.tool_calls` legacy aliases are removed from SpanV1
SpanData so these deprecated keys survive into SpanV2 attributes where
the transformation can process them.

Key changes:
- Add `Transform` variant to `DeprecationStatus` in the build script,
  producing `WriteBehavior::CurrentName` instead of `NewName`
- New `gen_ai_transform` module with the two transformation functions
- `normalize_ai` calls `transform_gen_ai` as its first step
- Remove legacy aliases for the three deprecated attributes from SpanData
- Update sentry-conventions submodule to PR #465 branch
- 21 unit tests, 4 new integration tests covering SpanV1 and SpanV2
@linear-code

linear-code Bot commented Jul 9, 2026

Copy link
Copy Markdown

TET-2587

Clippy lint fix for the Transform arm in format_write_behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant