@@ -288,7 +288,7 @@ def append(self, message: Union[chat_pb2.Message, "Response"]) -> Self:
288288 elif isinstance (message , Response ):
289289 self ._proto .messages .append (
290290 chat_pb2 .Message (
291- role = message ._choice .message .role ,
291+ role = message ._get_output () .message .role ,
292292 content = [text (message .content )],
293293 tool_calls = message .tool_calls ,
294294 )
@@ -472,6 +472,10 @@ def _get_span_completion_attributes(self, responses: Sequence["Response"]) -> di
472472
473473 return completion_attributes
474474
475+ def _uses_server_side_tools (self ) -> bool :
476+ """Returns True if the server side tool is used in the request."""
477+ return any (tool .WhichOneof ("tool" ) != "function" for tool in self ._proto .tools )
478+
475479 @property
476480 def messages (self ) -> Sequence [chat_pb2 .Message ]:
477481 """Returns the messages in the conversation."""
@@ -682,22 +686,26 @@ def _format_type_to_proto(format_type: ResponseFormat) -> chat_pb2.FormatType:
682686class Chunk (ProtoDecorator [chat_pb2 .GetChatCompletionChunk ]):
683687 """Adds convenience functions to the chunk proto."""
684688
685- _index : int
689+ _index : int | None
686690
687- def __init__ (self , proto : chat_pb2 .GetChatCompletionChunk , index : int ):
691+ def __init__ (self , proto : chat_pb2 .GetChatCompletionChunk , index : int | None ):
688692 """Creates a new decorator instance.
689693
690694 Args:
691695 proto: Chunk proto to wrap.
692- index: Index of the response to track.
696+ index: Index of the response to track. If set to None, the chunk will expose all assistant outputs.
693697 """
694698 super ().__init__ (proto )
695699 self ._index = index
696700
697701 @property
698702 def choices (self ) -> Sequence ["ChoiceChunk" ]:
699703 """Returns the choices belonging to this index."""
700- return [ChoiceChunk (c ) for c in self .proto .outputs if c .index == self ._index ]
704+ return [
705+ ChoiceChunk (c )
706+ for c in self .proto .outputs
707+ if c .delta .role == chat_pb2 .MessageRole .ROLE_ASSISTANT and (c .index == self ._index or self ._index is None )
708+ ]
701709
702710 @property
703711 def output (self ) -> str :
@@ -777,6 +785,14 @@ def process_chunk(self, chunk: chat_pb2.GetChatCompletionChunk):
777785 self ._proto .system_fingerprint = chunk .system_fingerprint
778786 self ._proto .citations .extend (chunk .citations )
779787
788+ # Make sure all chunk outputs has corresponding response outputs.
789+ if chunk .outputs :
790+ max_index = max (c .index for c in chunk .outputs )
791+ if max_index >= len (self ._proto .outputs ):
792+ self ._proto .outputs .extend (
793+ [chat_pb2 .CompletionOutput () for _ in range (max_index + 1 - len (self ._proto .outputs ))]
794+ )
795+
780796 for c in chunk .outputs :
781797 choice = self ._proto .outputs [c .index ]
782798 choice .index = c .index
@@ -792,29 +808,30 @@ class Response(_ResponseProtoDecorator):
792808
793809 # A single request can produce multiple responses. This index is used to retrieve the content of
794810 # a single answer from the response proto.
795- _index : int
796- # Cache to the answer indexed by this response.
797- _choice : chat_pb2 .CompletionOutput
811+ _index : int | None
798812
799- def __init__ (self , response : chat_pb2 .GetChatCompletionResponse , index : int ) -> None :
813+ def __init__ (self , response : chat_pb2 .GetChatCompletionResponse , index : int | None ) -> None :
800814 """Initializes a new instance of the `Response` class.
801815
802816 Args:
803817 response: The response proto, which can hold multiple answers.
804818 index: The index of the answer this class exposes via its convenience methods.
819+ If set to None, the response will expose all answers, the content and reasoning content
820+ will be only from the assistant response.
805821 """
806822 super ().__init__ (response )
807823 self ._index = index
808824
809- # Find and cache the answer identified by the index.
810- choices = [c for c in response .outputs if c .index == index ]
811-
812- if not choices :
813- raise ValueError (f"Invalid response proto or index. { response :} { index :} " )
814- elif len (choices ) > 1 :
815- raise ValueError (f"More than one response for index { index :} . { response :} " )
816- else :
817- self ._choice = choices [0 ]
825+ def _get_output (self ) -> chat_pb2 .CompletionOutput :
826+ outputs = [
827+ output
828+ for output in self .proto .outputs
829+ if output .message .role == chat_pb2 .MessageRole .ROLE_ASSISTANT
830+ and (output .index == self ._index or self ._index is None )
831+ ]
832+ if not outputs :
833+ return chat_pb2 .CompletionOutput ()
834+ return outputs [- 1 ]
818835
819836 @property
820837 def id (self ) -> str :
@@ -824,12 +841,12 @@ def id(self) -> str:
824841 @property
825842 def content (self ) -> str :
826843 """Returns the answer content of this response."""
827- return self ._choice .message .content
844+ return self ._get_output () .message .content
828845
829846 @property
830847 def role (self ) -> str :
831848 """Returns the role of this response."""
832- return chat_pb2 .MessageRole .Name (self ._choice .message .role )
849+ return chat_pb2 .MessageRole .Name (self ._get_output () .message .role )
833850
834851 @property
835852 def usage (self ) -> usage_pb2 .SamplingUsage :
@@ -842,17 +859,17 @@ def reasoning_content(self) -> str:
842859
843860 This is only available for models that support reasoning.
844861 """
845- return self ._choice .message .reasoning_content
862+ return self ._get_output () .message .reasoning_content
846863
847864 @property
848865 def finish_reason (self ) -> str :
849866 """Returns the finish reason of this response."""
850- return sample_pb2 .FinishReason .Name (self ._choice .finish_reason )
867+ return sample_pb2 .FinishReason .Name (self ._get_output () .finish_reason )
851868
852869 @property
853870 def logprobs (self ) -> chat_pb2 .LogProbs :
854871 """Returns the logprobs of this response."""
855- return self ._choice .logprobs
872+ return self ._get_output () .logprobs
856873
857874 @property
858875 def system_fingerprint (self ) -> str :
@@ -861,8 +878,13 @@ def system_fingerprint(self) -> str:
861878
862879 @property
863880 def tool_calls (self ) -> Sequence [chat_pb2 .ToolCall ]:
864- """Returns the tool calls of this response."""
865- return self ._choice .message .tool_calls
881+ """Returns the all tool calls of this response."""
882+ return [
883+ tc
884+ for c in self .proto .outputs
885+ if c .message .role == chat_pb2 .MessageRole .ROLE_ASSISTANT
886+ for tc in c .message .tool_calls
887+ ]
866888
867889 @property
868890 def citations (self ) -> Sequence [str ]:
0 commit comments