refactor(otel): trim the message cap docstrings to one line each

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-09-11 23:32:44 +00:00
parent a067557dae
commit a15309dfe8
3 changed files with 9 additions and 46 deletions

View file

@ -104,22 +104,13 @@ class OpenInferenceMapper:
@staticmethod
def _indexed_split(inputs: int, outputs: int) -> tuple[int, int]:
"""How many prompt and response messages get per-index attributes.
Both directions share one span-wide allowance. The response is reserved at
least half of it, so a long prompt can never push the completion off the
span, and the prompt takes whatever the response leaves unused.
"""
"""Prompt and response share one allowance; the response is reserved at least half of it."""
indexed_out: Final = min(outputs, max(_MAX_INDEXED_MESSAGES // 2, _MAX_INDEXED_MESSAGES - inputs))
return _MAX_INDEXED_MESSAGES - indexed_out, indexed_out
@staticmethod
def _prompt_positions(total: int, indexed: int) -> tuple[int, ...]:
"""Which prompt messages get per-index attributes: message 0 and the most recent turns.
A value length limit clips the ``input.value`` blob, so the system prompt and the
live turn each keep a short key of their own. The middle of a long prompt does not.
"""
"""Prompt messages that get per-index attributes: message 0 and the most recent turns."""
if total <= indexed:
return tuple(range(total))
return (0, *range(total - indexed + 1, total))

View file

@ -33,17 +33,10 @@ core telemetry no matter how many vocabularies are configured.
MAX_MESSAGE_ATTRS_PER_SPAN: Final = DEFAULT_SPAN_ATTRIBUTE_LIMIT // 8
"""Span-wide ceiling on attributes spent spelling out chat messages per index.
"""Span-wide ceiling on per-index chat message attributes, prompt and response together.
A conversation is the other unbounded family: two attributes per message, for
the prompt and the response alike, on the same span. Past a few dozen turns the
family alone exceeds the span attribute limit and evicts the core telemetry
written before it. The ceiling covers both directions together, since a budget
handed to each direction separately doubles. An eighth is the largest share
that still fits beside the tool ceiling and the core of every vocabulary at
once, request parameters, cost breakdown and identity included. The complete
conversation still rides the JSON blob attributes; only the per-index
convenience keys are capped.
An eighth is the largest share that still fits beside the tool ceiling and the core
of every vocabulary at once. The complete conversation still rides the JSON blobs.
"""

View file

@ -485,13 +485,7 @@ def _indexed_message_count(attributes, prefix):
@pytest.mark.parametrize("turns", [60, 200])
def test_long_conversation_does_not_evict_core_attributes(turns):
"""Per-message OpenInference attributes must never crowd core telemetry off the span.
With content capture on, the OpenInference vocabulary spells every prompt and
response message out as two per-index attributes. A few dozen turns overruns
the OTel SDK's 128-attribute span limit, which evicts oldest-first, so the
``gen_ai.*`` set written before it is what disappears.
"""
"""Per-message OpenInference attributes must never crowd core telemetry off the span."""
span = _conversation_span(["genai", "openinference"], _conversation_payload(turns))
a = span.attributes
@ -522,12 +516,7 @@ def test_short_conversation_keeps_every_message_indexed():
def test_indexed_prompt_keeps_opener_and_latest_turns_under_a_value_length_limit(monkeypatch):
"""The per-index keys are the only untruncated copy once the SDK clips string values.
Operators bound attribute sizes with ``OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT``,
which cuts the ``input.value`` blob short. The system prompt and the live turn
then have to survive as their own short keys, whatever the conversation length.
"""
"""The system prompt and the live turn keep their own keys once the SDK clips ``input.value``."""
monkeypatch.setenv("OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "256")
payload = _conversation_payload(60)
payload["messages"][0] = {"role": "system", "content": "be terse"}
@ -547,11 +536,7 @@ def test_indexed_prompt_keeps_opener_and_latest_turns_under_a_value_length_limit
def test_message_cap_is_shared_across_input_and_output():
"""One span-wide allowance covers both directions, and the response always keeps a share.
A long prompt takes what a single reply leaves over, and a many-choice reply
cannot take the whole allowance away from the prompt either.
"""
"""One span-wide allowance covers both directions, and the response always keeps a share."""
long_prompt = _conversation_span(["genai", "openinference"], _conversation_payload(60, choices=1)).attributes
many_choices = _conversation_span(["genai", "openinference"], _conversation_payload(60, choices=20)).attributes
@ -569,13 +554,7 @@ def test_message_cap_is_shared_across_input_and_output():
def test_fully_populated_span_with_every_vocabulary_stays_within_the_attribute_limit():
"""Every capped family maxed at once still leaves the whole core intact.
Every vocabulary in the registry plus ``legacy``, every request parameter,
every cost component, a hundred-plus tools, a two-hundred-turn prompt and
twenty choices is the worst case the two span-wide ceilings have to absorb
together.
"""
"""Every capped family maxed at once still leaves the whole core intact."""
payload = _conversation_payload(
200,
choices=20,