def read_full_response(stream):
    """
    Concatenate complete reasoning_content and content from qwen streaming response,
    and wait for the final chunk with usage information to get token usage.
    """
    full_reasoning = ""
    full_content = ""
    token_usage = {}

    for chunk in stream:
        # If this chunk has usage info, consider it the final usage chunk, get the data and finish
        if (
            getattr(chunk, "usage", None)
            and getattr(chunk.usage, "total_tokens", None) is not None
        ):
            u = chunk.usage
            token_usage = {
                "completion_tokens": u.completion_tokens,
                "prompt_tokens": u.prompt_tokens,
                "total_tokens": u.total_tokens,
                "reasoning_tokens": u.completion_tokens_details.reasoning_tokens,
                "rejected_prediction_tokens": u.completion_tokens_details.rejected_prediction_tokens,
            }
            break

        # Regular chunk, concatenate delta
        choice = chunk.choices[0]
        delta = choice.delta
        if getattr(delta, "reasoning_content", None):
            full_reasoning += delta.reasoning_content
        if getattr(delta, "content", None):
            full_content += delta.content

    return full_reasoning, full_content, token_usage