Repository: phidatahq/phidata
File: libs/agno/agno/models/base.py (Python)

Code before:
        tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
        run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
    ) -> AsyncIterator[ModelResponse]:
        """
        Process a streaming response from the model.
        """
        async for response_delta in self.ainvoke_stream(
            messages=messages,
            assistant_message=assistant_message,
            response_format=response_format,
            tools=tools,
            tool_choice=tool_choice or self._tool_choice,
            run_response=run_response,
        ):  # type: ignore
            for model_response_delta in self._populate_stream_data(
                stream_data=stream_data,
                model_response_delta=response_delta,
            ):
                yield model_response_delta

                # Add role to assistant message
                if model_response_delta.role is not None:
                    assistant_message.role = model_response_delta.role

                if model_response_delta.response_usage is not None:
                    assistant_message.metrics += model_response_delta.response_usage

            # Populate assistant message from stream data after the stream ends
            if stream_data.response_content:
                assistant_message.content = stream_data.response_content
            if stream_data.response_reasoning_content:
                assistant_message.reasoning_content = stream_data.response_reasoning_content
            if stream_data.response_redacted_reasoning_content:
                assistant_message.redacted_reasoning_content = stream_data.response_redacted_reasoning_content
            if stream_data.response_provider_data:
                assistant_message.provider_data = stream_data.response_provider_data
            if stream_data.response_citations:
                assistant_message.citations = stream_data.response_citations
            if stream_data.response_audio:
                assistant_message.audio_output = stream_data.response_audio
            if stream_data.response_image:
                assistant_message.image_output = stream_data.response_image
            if stream_data.response_video:
                assistant_message.video_output = stream_data.response_video
            if stream_data.response_file:
                assistant_message.file_output = stream_data.response_file
            if stream_data.response_tool_calls and len(stream_data.response_tool_calls) > 0:
                assistant_message.tool_calls = self.parse_tool_calls(stream_data.response_tool_calls)

    async def aresponse_stream(
        self,

Review comment (suggestion):
I think we only need to do these once, after the loop. 

After the loop `model_response_delta` should be equal to its value in the last iteration, and we have both the role and metrics there

Code after:
        self,
        messages: List[Message],
        response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
        tools: Optional[List[Union[Function, dict]]] = None,
        tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
        tool_call_limit: Optional[int] = None,
        stream_model_response: bool = True,
        run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
        send_media_to_model: bool = True,
    ) -> AsyncIterator[Union[ModelResponse, RunOutputEvent, TeamRunOutputEvent]]:
        """
        Generate an asynchronous streaming response from the model.
        """

        # Check cache if enabled - capture key BEFORE streaming to avoid mismatch
        cache_key = None
        if self.cache_response:
            cache_key = self._get_model_cache_key(messages, stream=True, response_format=response_format, tools=tools)
            cached_data = self._get_cached_model_response(cache_key)

            if cached_data:
                log_info("Cache hit for async streaming model response")
                # Yield cached responses
                for response in self._streaming_responses_from_cache(cached_data["streaming_responses"]):
                    yield response
                return

            log_info("Cache miss for async streaming model response")

        # Track streaming responses for caching
        streaming_responses: List[ModelResponse] = []

        log_debug(f"{self.get_provider()} Async Response Stream Start", center=True, symbol="-")
        log_debug(f"Model: {self.id}", center=True, symbol="-")
        _log_messages(messages)

        _tool_dicts = self._format_tools(tools) if tools is not None else []
        _functions = {tool.name: tool for tool in tools if isinstance(tool, Function)} if tools is not None else {}

        function_call_count = 0

        while True:
            # Create assistant message and stream data
            assistant_message = Message(role=self.assistant_message_role)
            stream_data = MessageData()
            model_response = ModelResponse()
            if stream_model_response:
                # Generate response
                async for model_response in self.aprocess_response_stream(
                    messages=messages,
                    assistant_message=assistant_message,