def add_llm_span_attributes(
    span: "Span",
    service_name: str,
    model: str,
    stream: bool = True,
    messages: Optional[str] = None,
    output: Optional[str] = None,
    tools: Optional[str] = None,
    tool_count: Optional[int] = None,
    tool_choice: Optional[str] = None,
    system: Optional[str] = None,
    parameters: Optional[Dict[str, Any]] = None,
    extra_parameters: Optional[Dict[str, Any]] = None,
    ttfb: Optional[float] = None,
    **kwargs,
) -> None:
    """Add LLM-specific attributes to a span.

    Args:
        span: The span to add attributes to
        service_name: Name of the LLM service (e.g., "openai")
        model: Model name/identifier
        stream: Whether streaming is enabled
        messages: JSON-serialized messages
        output: Aggregated output text from the LLM
        tools: JSON-serialized tools configuration
        tool_count: Number of tools available
        tool_choice: Tool selection configuration
        system: System message
        parameters: Service parameters
        extra_parameters: Additional parameters
        ttfb: Time to first byte in seconds
        **kwargs: Additional attributes to add
    """
    # Add standard attributes
    span.set_attribute("gen_ai.system", _get_gen_ai_system_from_service_name(service_name))
    span.set_attribute("gen_ai.request.model", model)
    span.set_attribute("gen_ai.operation.name", "chat")
    span.set_attribute("gen_ai.output.type", "text")
    span.set_attribute("stream", stream)

    # Add optional attributes
    if messages:
        span.set_attribute("input", messages)

    if output:
        span.set_attribute("output", output)

    if tools:
        span.set_attribute("tools", tools)

    if tool_count is not None:
        span.set_attribute("tool_count", tool_count)

    if tool_choice:
        span.set_attribute("tool_choice", tool_choice)

    if system:
        span.set_attribute("system", system)

    if ttfb is not None:
        span.set_attribute("metrics.ttfb", ttfb)

    # Add parameters if provided
    if parameters:
        for key, value in parameters.items():
            if isinstance(value, (str, int, float, bool)):
                if key in [
                    "temperature",
                    "max_tokens",
                    "max_completion_tokens",
                    "top_p",
                    "top_k",
                    "frequency_penalty",
                    "presence_penalty",
                    "seed",
                ]:
                    span.set_attribute(f"gen_ai.request.{key}", value)
                else:
                    span.set_attribute(f"param.{key}", value)

    # Add extra parameters if provided
    if extra_parameters:
        for key, value in extra_parameters.items():
            if isinstance(value, (str, int, float, bool)):
                span.set_attribute(f"extra.{key}", value)

    # Add any additional keyword arguments as attributes
    for key, value in kwargs.items():
        if isinstance(value, (str, int, float, bool)):
            span.set_attribute(key, value)
Add LLM-specific attributes to a span.

    Args:
        span: The span to add attributes to
        service_name: Name of the LLM service (e.g., "openai")
        model: Model name/identifier
        stream: Whether streaming is enabled
        messages: JSON-serialized messages
        output: Aggregated output text from the LLM
        tools: JSON-serialized tools configuration
        tool_count: Number of tools available
        tool_choice: Tool selection configuration
        system: System message
        parameters: Service parameters
        extra_parameters: Additional parameters
        ttfb: Time to first byte in seconds
        **kwargs: Additional attributes to add
    
src/pipecat/utils/tracing/service_attributes.py