Source code for rath.llm.openai.create_kwargs
"""Build keyword arguments for ``OpenAI().chat.completions.create``."""
from __future__ import annotations
from typing import Any
from rath.llm.chat_request import (
RathLLMChatRequest,
RathLLMFunctionTool,
RathLLMMessage,
)
__all__ = ["to_create_kwargs", "to_create_kwargs_stream"]
def _message_as_openai_dict(message: RathLLMMessage) -> dict[str, Any]:
d: dict[str, Any] = {"role": message.role}
if message.content is not None:
d["content"] = message.content
if message.name is not None:
d["name"] = message.name
if message.tool_call_id is not None:
d["tool_call_id"] = message.tool_call_id
if message.tool_calls is not None:
d["tool_calls"] = [dict(tc) for tc in message.tool_calls]
return d
def _drop_additional_properties(obj: Any) -> Any:
"""Recursively drop ``additionalProperties`` keys from nested dict/list schema."""
if isinstance(obj, dict):
return {
k: _drop_additional_properties(v)
for k, v in obj.items()
if k != "additionalProperties"
}
if isinstance(obj, list):
return [_drop_additional_properties(x) for x in obj]
return obj
def _function_tool_as_openai_dict(tool: RathLLMFunctionTool) -> dict[str, Any]:
params = _drop_additional_properties(dict(tool.parameters))
fn: dict[str, Any] = {
"name": tool.name,
"parameters": params,
}
if tool.description is not None:
fn["description"] = tool.description
if tool.strict is not None:
fn["strict"] = tool.strict
return {"type": "function", "function": fn}
[docs]
def to_create_kwargs(
req: RathLLMChatRequest,
*,
default_model: str | None,
) -> dict[str, Any]:
"""Map :class:`RathLLMChatRequest` to ``OpenAI.chat.completions.create`` kwargs.
Non-streaming only: ``stream`` is forced to ``False`` after
``extra_create_args`` are merged. ``stream=True`` in extras raises
``ValueError``.
"""
model = req.model or default_model
if not model:
raise ValueError(
"model is required: set RathLLMChatRequest.model or Provider.model",
)
out: dict[str, Any] = {
"model": model,
"messages": [_message_as_openai_dict(m) for m in req.messages],
}
if req.tools is not None:
out["tools"] = [_function_tool_as_openai_dict(t) for t in req.tools]
if req.tool_choice is not None:
out["tool_choice"] = req.tool_choice
if req.parallel_tool_calls is not None:
out["parallel_tool_calls"] = req.parallel_tool_calls
if req.response_format is not None:
out["response_format"] = req.response_format
if req.temperature is not None:
out["temperature"] = req.temperature
if req.top_p is not None:
out["top_p"] = req.top_p
if req.max_completion_tokens is not None:
out["max_completion_tokens"] = req.max_completion_tokens
if req.max_tokens is not None:
out["max_tokens"] = req.max_tokens
if req.stop is not None:
out["stop"] = req.stop
if req.n is not None:
out["n"] = req.n
if req.seed is not None:
out["seed"] = req.seed
if req.frequency_penalty is not None:
out["frequency_penalty"] = req.frequency_penalty
if req.presence_penalty is not None:
out["presence_penalty"] = req.presence_penalty
if req.logit_bias is not None:
out["logit_bias"] = req.logit_bias
if req.logprobs is not None:
out["logprobs"] = req.logprobs
if req.top_logprobs is not None:
out["top_logprobs"] = req.top_logprobs
if req.reasoning_effort is not None:
out["reasoning_effort"] = req.reasoning_effort
if req.verbosity is not None:
out["verbosity"] = req.verbosity
if req.metadata is not None:
out["metadata"] = req.metadata
if req.user is not None:
out["user"] = req.user
if req.store is not None:
out["store"] = req.store
if req.service_tier is not None:
out["service_tier"] = req.service_tier
extra = dict(req.extra_create_args)
if extra.pop("stream", None) is True:
raise ValueError(
"stream=True is not supported here; use to_create_kwargs_stream",
)
out.update(extra)
out["stream"] = False
return out
def to_create_kwargs_stream(
req: RathLLMChatRequest,
*,
default_model: str | None,
) -> dict[str, Any]:
"""Same as :func:`to_create_kwargs` but builds a streaming-mode payload.
``stream`` is forced to ``True`` and ``stream_options={"include_usage": True}``
is set when not already supplied via ``extra_create_args``, so the terminal
chunk carries token usage.
"""
out = to_create_kwargs(req, default_model=default_model)
out["stream"] = True
extra = dict(req.extra_create_args)
if "stream_options" not in extra:
out["stream_options"] = {"include_usage": True}
return out