11from abc import ABC , abstractmethod
2- from typing import TYPE_CHECKING , Any , Literal , Optional , TypedDict , cast
2+ from typing import TYPE_CHECKING , Any , Literal , Optional , TypedDict , Union , cast
33
44from typing_extensions import NotRequired
55
@@ -142,44 +142,76 @@ def can_normalize(self, message: Any) -> bool:
142142 from openai .types .chat import ChatCompletion
143143
144144 return isinstance (message , ChatCompletion )
145- except ImportError :
145+ except Exception :
146146 return False
147147
148148 def can_normalize_chunk (self , chunk : Any ) -> bool :
149149 try :
150150 from openai .types .chat import ChatCompletionChunk
151151
152152 return isinstance (chunk , ChatCompletionChunk )
153- except ImportError :
153+ except Exception :
154154 return False
155155
156156
157157class AnthropicNormalizer (BaseMessageNormalizer ):
158158 def normalize (self , message : Any ) -> ChatMessage :
159159 x = cast ("AnthropicMessage" , message )
160- content = x .content [0 ].text
161- return ChatMessage (content = content , role = "assistant" )
160+ content = x .content [0 ]
161+ if content .type != "text" :
162+ raise ValueError (
163+ f"Anthropic message type { content .type } not supported. "
164+ "Only 'text' type is supported"
165+ )
166+ return ChatMessage (content = content .text , role = "assistant" )
162167
163168 def normalize_chunk (self , chunk : Any ) -> ChatMessageChunk :
164- cnk = cast ("MessageStreamEvent" , chunk )
165- content = cnk .delta .text if cnk .type == "content_block_delta" else ""
166- type = "message_start" if cnk .type == "content_block_start" else "message_chunk"
169+ x = cast ("MessageStreamEvent" , chunk )
170+ content = ""
171+ if x .type == "content_block_delta" :
172+ if x .delta .type != "text_delta" :
173+ raise ValueError (
174+ f"Anthropic message delta type { x .delta .type } not supported. "
175+ "Only 'text_delta' type is supported"
176+ )
177+ content = x .delta .text
178+
179+ type = "message_start" if x .type == "content_block_start" else "message_chunk"
167180 return ChatMessageChunk (content = content , type = type , role = "assistant" )
168181
169182 def can_normalize (self , message : Any ) -> bool :
170183 try :
171184 from anthropic .types import Message as AnthropicMessage
172185
173186 return isinstance (message , AnthropicMessage )
174- except ImportError :
187+ except Exception :
175188 return False
176189
177190 def can_normalize_chunk (self , chunk : Any ) -> bool :
178191 try :
179- from anthropic .types import MessageStreamEvent
192+ from anthropic .types import (
193+ RawContentBlockDeltaEvent ,
194+ RawContentBlockStartEvent ,
195+ RawContentBlockStopEvent ,
196+ RawMessageDeltaEvent ,
197+ RawMessageStartEvent ,
198+ RawMessageStopEvent ,
199+ )
200+
201+ # The actual MessageStreamEvent is a generic, so isinstance() can't
202+ # be used to check the type. Instead, we manually construct the relevant
203+ # union of relevant classes...
204+ MessageStreamEvent = Union [
205+ RawMessageStartEvent ,
206+ RawMessageDeltaEvent ,
207+ RawMessageStopEvent ,
208+ RawContentBlockStartEvent ,
209+ RawContentBlockDeltaEvent ,
210+ RawContentBlockStopEvent ,
211+ ]
180212
181213 return isinstance (chunk , MessageStreamEvent )
182- except ImportError :
214+ except Exception :
183215 return False
184216
185217
@@ -199,7 +231,7 @@ def can_normalize(self, message: Any) -> bool:
199231 )
200232
201233 return isinstance (message , GenerateContentResponse )
202- except ImportError :
234+ except Exception :
203235 return False
204236
205237 def can_normalize_chunk (self , chunk : Any ) -> bool :
0 commit comments