66from sentry_sdk .ai .utils import (
77 set_data_normalized ,
88 normalize_message_roles ,
9+ truncate_and_annotate_messages ,
910)
1011
1112from typing import TYPE_CHECKING
1617
1718import sentry_sdk
1819from sentry_sdk .scope import should_send_default_pii
19- from sentry_sdk .utils import capture_internal_exceptions , event_from_exception , reraise
20+ from sentry_sdk .utils import capture_internal_exceptions , reraise
2021
2122from sentry_sdk .integrations .cohere import (
2223 CohereIntegration ,
2627
2728try :
2829 from cohere .v2 .client import V2Client as CohereV2Client
29- from cohere .v2 .types import V2ChatResponse
30- from cohere .v2 .types .v2chat_stream_response import MessageEndV2ChatStreamResponse
3130
32- if TYPE_CHECKING :
33- from cohere .v2 .types import V2ChatStreamResponse
31+ # Type locations changed between cohere versions:
32+ # 5.13.x: cohere.types (ChatResponse, MessageEndStreamedChatResponseV2)
33+ # 5.20+: cohere.v2.types (V2ChatResponse, MessageEndV2ChatStreamResponse)
34+ try :
35+ from cohere .v2 .types import V2ChatResponse
36+ from cohere .v2 .types import MessageEndV2ChatStreamResponse
37+
38+ if TYPE_CHECKING :
39+ from cohere .v2 .types import V2ChatStreamResponse
40+ except ImportError :
41+ from cohere .types import ChatResponse as V2ChatResponse
42+ from cohere .types import (
43+ MessageEndStreamedChatResponseV2 as MessageEndV2ChatStreamResponse ,
44+ )
45+
46+ if TYPE_CHECKING :
47+ from cohere .types import StreamedChatResponseV2 as V2ChatStreamResponse
3448
3549 _has_v2 = True
3650except ImportError :
3953
4054def setup_v2 (wrap_embed_fn ):
4155 # type: (Callable[..., Any]) -> None
42- """Called from CohereIntegration.setup_once() to patch V2Client methods."""
56+ """Called from CohereIntegration.setup_once() to patch V2Client methods.
57+
58+ The embed wrapper is passed in from cohere.py to reuse the same _wrap_embed
59+ for both V1 and V2, since the embed response format (.meta.billed_units)
60+ is identical across both API versions.
61+ """
4362 if not _has_v2 :
4463 return
4564
@@ -52,16 +71,25 @@ def setup_v2(wrap_embed_fn):
5271
5372def _extract_messages_v2 (messages ):
5473 # type: (Any) -> list[dict[str, str]]
55- """Extract role/content dicts from V2-style message objects."""
74+ """Extract role/content dicts from V2-style message objects.
75+
76+ Handles both plain dicts and Pydantic model instances.
77+ """
5678 result = []
5779 for msg in messages :
58- role = getattr (msg , "role" , "unknown" )
59- content = getattr (msg , "content" , "" )
80+ if isinstance (msg , dict ):
81+ role = msg .get ("role" , "unknown" )
82+ content = msg .get ("content" , "" )
83+ else :
84+ role = getattr (msg , "role" , "unknown" )
85+ content = getattr (msg , "content" , "" )
6086 if isinstance (content , str ):
6187 text = content
6288 elif isinstance (content , list ):
6389 text = " " .join (
64- getattr (item , "text" , "" ) for item in content if hasattr (item , "text" )
90+ (item .get ("text" , "" ) if isinstance (item , dict ) else getattr (item , "text" , "" ))
91+ for item in content
92+ if (isinstance (item , dict ) and "text" in item ) or hasattr (item , "text" )
6593 )
6694 else :
6795 text = str (content ) if content else ""
@@ -138,7 +166,7 @@ def new_chat(*args, **kwargs):
138166
139167 span = sentry_sdk .start_span (
140168 op = OP .GEN_AI_CHAT ,
141- name = "chat {}" . format ( model ) .strip (),
169+ name = f "chat { model } " .strip (),
142170 origin = CohereIntegration .origin ,
143171 )
144172 span .__enter__ ()
@@ -160,12 +188,17 @@ def new_chat(*args, **kwargs):
160188 if should_send_default_pii () and integration .include_prompts :
161189 messages = _extract_messages_v2 (kwargs .get ("messages" , []))
162190 messages = normalize_message_roles (messages )
163- set_data_normalized (
164- span ,
165- SPANDATA .GEN_AI_REQUEST_MESSAGES ,
166- messages ,
167- unpack = False ,
191+ scope = sentry_sdk .get_current_scope ()
192+ messages_data = truncate_and_annotate_messages (
193+ messages , span , scope
168194 )
195+ if messages_data is not None :
196+ set_data_normalized (
197+ span ,
198+ SPANDATA .GEN_AI_REQUEST_MESSAGES ,
199+ messages_data ,
200+ unpack = False ,
201+ )
169202 if "tools" in kwargs :
170203 set_data_normalized (
171204 span ,
0 commit comments