Skip to content

Instrument LiteLLM Anthropic messages acreate for GenAI traces - #28

Merged
t-santoshsahu merged 3 commits into
mainfrom
instrument-litellm-anthropic-messages-acreate
Sep 16, 2026
Merged

t-santoshsahu merged 3 commits into
mainfrom
instrument-litellm-anthropic-messages-acreate

Conversation

@shreyas-n-harness

Copy link
Copy Markdown
Collaborator

Summary

  • LiteLLM GenAI instrumentation only wrapped completion/acompletion/embedding, so native litellm.anthropic.messages.acreate (Anthropic Messages pass-through used by llm-model-service) produced no litellm_request spans.
  • Wrap create/acreate on the LiteLLM Anthropic messages interface, reuse the existing span/stream/policy path, and keep a single span when acreate falls back to acompletion.

Test plan

  • pytest test/instrumentation/litellm/ (or ./scripts/run-unit-tests.sh scoped) passes
  • Native acreate (no acompletion) emits one litellm_request span with gen_ai.request.model and usage
  • acreate that delegates to acompletion still emits exactly one span
  • Existing acompletion/embedding instrumentation still works

Made with Cursor

shreyas-n-harness and others added 3 commits September 10, 2026 13:25
…hrough calls emit GenAI spans.

acompletion wrapping misses Bedrock/Vertex Claude HTTP pass-through, which never re-enters acompletion.

Co-authored-by: Cursor <cursoragent@cursor.com>
…t usage and stop_reason.

OpenAI stream_chunk_builder never sees id/tokens/stop_reason on a single last chunk for SSE or message_start/message_delta events.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
target[key] = value


def _aggregate_anthropic_messages_stream(chunks: list[Any]) -> dict[str, Any]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be turned into more generic function handling any sse chunks, not only from this Litellm antrhopic? How do we handle chunks from other instrumentation, are they also processed separately?

return isinstance(event_type, str) and event_type in _ANTHROPIC_STREAM_EVENT_TYPES


def _looks_like_anthropic_messages_stream(chunks: list[Any]) -> bool:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw data: substring check is a reasonable fast path for native SSE byte streams, but it could theoretically false-positive if streamed text content contains data:. In practice this is unlikely because OpenAI-shaped LiteLLM chunks are dict/ModelResponse objects, not raw SSE strings — so I think this is fine as-is. Worth a brief docstring noting the trade-off for future readers.

@suyashro

Copy link
Copy Markdown

Follow-up on the stream-detection note: docstring to add on _looks_like_anthropic_messages_stream (see diff in thread). @shreyas-n-harness happy to cherry-pick if useful.

@t-santoshsahu
t-santoshsahu merged commit 524c2e1 into main Sep 16, 2026
7 checks passed
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.

3 participants