Skip to content

Commit 697d621

Browse files
feat(anthropic): Emit gen_ai.chat spans for asynchronous messages.stream()
1 parent 3b641be commit 697d621

1 file changed

Lines changed: 67 additions & 1 deletion

File tree

sentry_sdk/integrations/anthropic.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@
3838
Omit = None
3939

4040
from anthropic.resources import AsyncMessages, Messages
41-
from anthropic.lib.streaming._messages import MessageStreamManager
41+
from anthropic.lib.streaming._messages import (
42+
MessageStreamManager,
43+
AsyncMessageStreamManager,
44+
)
4245

4346
from anthropic.types import (
4447
MessageStartEvent,
@@ -66,6 +69,7 @@
6669
ModelParam,
6770
TextBlockParam,
6871
ToolUnionParam,
72+
AsyncMessageStream,
6973
)
7074

7175

@@ -96,6 +100,13 @@ def setup_once() -> None:
96100
MessageStreamManager.__enter__
97101
)
98102

103+
AsyncMessages.stream = _wrap_async_message_stream(AsyncMessages.stream)
104+
AsyncMessageStreamManager.__aenter__ = (
105+
_wrap_async_message_stream_manager_aenter(
106+
AsyncMessageStreamManager.__aenter__
107+
)
108+
)
109+
99110

100111
def _capture_exception(exc: "Any") -> None:
101112
set_span_errored()
@@ -824,6 +835,61 @@ def _sentry_patched_enter(self: "MessageStreamManager") -> "MessageStreamManager
824835
return _sentry_patched_enter
825836

826837

838+
def _wrap_async_message_stream(f: "Any") -> "Any":
839+
"""
840+
Attaches user-provided arguments to the returned context manager.
841+
The attributes are set on `gen_ai.chat` spans in the patch for the context manager.
842+
"""
843+
844+
@wraps(f)
845+
def _sentry_patched_stream(
846+
*args: "Any", **kwargs: "Any"
847+
) -> "AsyncMessageStreamManager":
848+
stream_manager = f(*args, **kwargs)
849+
850+
stream_manager._max_tokens = kwargs.get("max_tokens")
851+
stream_manager._messages = kwargs.get("messages")
852+
stream_manager._model = kwargs.get("model")
853+
stream_manager._system = kwargs.get("system")
854+
stream_manager._temperature = kwargs.get("temperature")
855+
stream_manager._top_k = kwargs.get("top_k")
856+
stream_manager._top_p = kwargs.get("top_p")
857+
stream_manager._tools = kwargs.get("tools")
858+
859+
return stream_manager
860+
861+
return _sentry_patched_stream
862+
863+
864+
def _wrap_async_message_stream_manager_aenter(f: "Any") -> "Any":
865+
"""
866+
Creates and manages `gen_ai.chat` spans.
867+
"""
868+
869+
@wraps(f)
870+
async def _sentry_patched_aenter(
871+
self: "MessageStreamManager",
872+
) -> "AsyncMessageStream":
873+
stream = await f(self)
874+
if not hasattr(self, "_max_tokens"):
875+
return stream
876+
877+
_sentry_patched_stream_common(
878+
stream=stream,
879+
max_tokens=self._max_tokens,
880+
messages=self._messages,
881+
model=self._model,
882+
system=self._system,
883+
temperature=self._temperature,
884+
top_k=self._top_k,
885+
top_p=self._top_p,
886+
tools=self._tools,
887+
)
888+
return stream
889+
890+
return _sentry_patched_aenter
891+
892+
827893
def _is_given(obj: "Any") -> bool:
828894
"""
829895
Check for givenness safely across different anthropic versions.

0 commit comments

Comments
 (0)