"""
Chat API parameter configuration classes.
Provides dataclass-based parameter configuration for OpenAI-compatible chat completions,
with support for standard parameters and custom extensions.
"""
from __future__ import annotations
from collections.abc import Sequence
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lexilux.chat.tools import Tool, ToolChoice
[docs]
@dataclass
class ChatParams:
"""
Standard parameters for chat completion requests.
This class defines the most commonly used parameters for OpenAI-compatible
chat completion APIs. All parameters are optional and have sensible defaults.
Attributes:
temperature: What sampling temperature to use, between 0 and 2.
Higher values like 0.8 will make the output more random, while lower
values like 0.2 will make it more focused and deterministic.
Default: 0.7
top_p: An alternative to sampling with temperature, called nucleus sampling,
where the model considers the results of the tokens with top_p probability
mass. So 0.1 means only the tokens comprising the top 10% probability
mass are considered.
Range: 0.0 to 1.0. Default: 1.0
max_tokens: The maximum number of tokens to generate in the chat completion.
The total length of input tokens and generated tokens is limited by the
model's context length.
Default: None (no limit, up to model's maximum)
stop: Up to 4 sequences where the API will stop generating further tokens.
The returned text will not contain the stop sequence.
Can be a single string or a list of strings.
Default: None
presence_penalty: Number between -2.0 and 2.0. Positive values penalize
new tokens based on whether they appear in the text so far, increasing
the model's likelihood to talk about new topics.
Default: 0.0
frequency_penalty: Number between -2.0 and 2.0. Positive values penalize
new tokens based on their existing frequency in the text so far,
decreasing the model's likelihood to repeat the same line verbatim.
Default: 0.0
logit_bias: Modify the likelihood of specified tokens appearing in the
completion. Accepts a dictionary mapping token IDs (integers) to an
associated bias value from -100 to 100. Values around -100 should
decrease the likelihood of the token appearing, while values around 100
should increase it.
Default: None (empty dict)
user: A unique identifier representing your end-user, which can help OpenAI
to monitor and detect abuse. This is useful for tracking and rate limiting.
Default: None
n: How many chat completion choices to generate for each input message.
Note: Most implementations return only the first choice. This parameter
is included for compatibility but may not be fully supported by all
providers.
Default: 1
tools: List of tools (functions) that the model may call.
Enables function calling capabilities. When provided, the model can
decide to call these functions instead of or in addition to generating text.
Default: None (no tools)
tool_choice: Controls when the model uses tools.
Can be "auto" (model decides), "required" (must call tools),
a specific tool name, or a ToolChoice object.
Default: None (auto mode)
parallel_tool_calls: Whether to enable parallel function calling.
When True, the model may call multiple functions in a single turn.
Default: None (provider default)
extra: Additional custom parameters for OpenAI-compatible servers that may
accept non-standard parameters. These will be merged into the request
payload.
Common use cases:
- Provider-specific experimental features
- Custom provider options not in OpenAI standard
- Specialized model behaviors (e.g., response format, seed)
For parameter name mapping, use param_aliases instead of extra when
the provider uses standard OpenAI-compatible parameters with different keys.
Default: None (empty dict)
param_aliases: Parameter name mapping for edge cases where providers
use different names for standard OpenAI parameters.
Most providers won't need this feature.
Maps standard OpenAI parameter names to provider-specific names.
Applied after standard parameter processing but before extra merging.
Example (rare cases):
>>> params = ChatParams(
... temperature=0.7,
... param_aliases={"temperature": "temp"}
... )
# Sends: {"temp": 0.7} instead of {"temperature": 0.7}
Default: None (no mapping needed for standard providers)
Examples:
Basic usage with defaults:
>>> params = ChatParams()
>>> # temperature=0.7, top_p=1.0, etc.
Custom temperature and max_tokens:
>>> params = ChatParams(temperature=0.5, max_tokens=100)
With stop sequences:
>>> params = ChatParams(stop=["\\n\\n", "Human:"])
With penalties:
>>> params = ChatParams(
... presence_penalty=0.6,
... frequency_penalty=0.3
... )
With tools:
>>> from lexilux.chat.tools import FunctionTool
>>> params = ChatParams(
... tools=[
... FunctionTool(
... name="get_weather",
... description="Get current weather",
... parameters={"type": "object", "properties": {...}}
... )
... ]
... )
With custom provider features:
>>> params = ChatParams(
... temperature=0.8,
... extra={
... "response_format": {"type": "json_object"},
... "seed": 12345,
... "logprobs": True,
... "top_logprobs": 5
... }
... )
With parameter aliases (rare cases):
>>> params = ChatParams(
... temperature=0.7,
... param_aliases={"temperature": "temp"}
... )
"""
temperature: float = 0.7
top_p: float = 1.0
max_tokens: int | None = None
stop: str | Sequence[str] | None = None
presence_penalty: float = 0.0
frequency_penalty: float = 0.0
logit_bias: dict[int, float] | None = None
user: str | None = None
n: int = 1
# Tool calling parameters
tools: list[Tool] | None = None
tool_choice: str | ToolChoice | None = None
parallel_tool_calls: bool | None = None
# Reasoning mode (extended thinking)
reasoning: bool | dict[str, Any] | None = None
# Extra parameters
extra: dict[str, Any] | None = None
# ✅ NEW: Parameter alias mapping
param_aliases: dict[str, str] | None = None
[docs]
def to_dict(self, exclude_none: bool = True) -> dict[str, Any]:
"""
Convert parameters to dictionary for API request.
Args:
exclude_none: Whether to exclude None values from the output.
Default: True
Returns:
Dictionary of parameters ready for API request.
Examples:
Basic usage:
>>> params = ChatParams(temperature=0.5, max_tokens=100)
>>> params.to_dict()
{'temperature': 0.5, 'top_p': 1.0, 'max_tokens': 100, ...}
With parameter aliases:
>>> params = ChatParams(
... temperature=0.8,
... param_aliases={"temperature": "temp"} # Some providers use "temp"
... )
>>> params.to_dict()
{'temp': 0.8, 'top_p': 1.0, ...}
"""
result: dict[str, Any] = {}
# Add standard parameters
if not exclude_none or self.temperature is not None:
result["temperature"] = self.temperature
if not exclude_none or self.top_p is not None:
result["top_p"] = self.top_p
if not exclude_none or self.max_tokens is not None:
result["max_tokens"] = self.max_tokens
if not exclude_none or self.stop is not None:
if self.stop is not None:
if isinstance(self.stop, str):
result["stop"] = [self.stop]
else:
result["stop"] = list(self.stop)
if not exclude_none or self.presence_penalty != 0.0:
result["presence_penalty"] = self.presence_penalty
if not exclude_none or self.frequency_penalty != 0.0:
result["frequency_penalty"] = self.frequency_penalty
if not exclude_none or self.logit_bias is not None:
if self.logit_bias is not None:
result["logit_bias"] = self.logit_bias
if not exclude_none or self.user is not None:
if self.user is not None:
result["user"] = self.user
if not exclude_none or self.n != 1:
result["n"] = self.n
# Add tools parameters
if not exclude_none or self.tools is not None:
if self.tools is not None:
result["tools"] = [tool.to_dict() for tool in self.tools]
if not exclude_none or self.tool_choice is not None:
if self.tool_choice is not None:
if isinstance(self.tool_choice, str):
result["tool_choice"] = self.tool_choice
else:
result["tool_choice"] = self.tool_choice.to_dict()
if not exclude_none or self.parallel_tool_calls is not None:
if self.parallel_tool_calls is not None:
result["parallel_tool_calls"] = self.parallel_tool_calls
# ✅ NEW: Apply parameter aliases
if self.param_aliases:
aliased_params = {}
for standard_key, provider_key in self.param_aliases.items():
if standard_key in result:
# Move parameter to provider-specific key
aliased_params[provider_key] = result[standard_key]
del result[standard_key]
result.update(aliased_params)
# Merge extra parameters (lowest priority)
if self.extra:
result.update(self.extra)
return result