watsonx requires tool_call_id on role=tool messages. Added field to ChatMessage model and passthrough in transformer.
219 lines
6.6 KiB
Python
219 lines
6.6 KiB
Python
"""OpenAI-compatible request and response models."""
|
|
|
|
from typing import Any, Dict, List, Literal, Optional, Union
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
# ============================================================================
|
|
# Chat Completions Models
|
|
# ============================================================================
|
|
|
|
class ChatMessage(BaseModel):
|
|
model_config = {"extra": "allow"}
|
|
"""A chat message in the conversation."""
|
|
role: Literal["system", "user", "assistant", "function", "tool", "developer"]
|
|
content: Optional[Union[str, List[Dict[str, Any]]]] = None
|
|
name: Optional[str] = None
|
|
function_call: Optional[Dict[str, Any]] = None
|
|
tool_calls: Optional[List[Dict[str, Any]]] = None
|
|
tool_call_id: Optional[str] = None
|
|
|
|
|
|
class FunctionCall(BaseModel):
|
|
"""Function call specification."""
|
|
name: str
|
|
arguments: str
|
|
|
|
|
|
class ToolCall(BaseModel):
|
|
"""Tool call specification."""
|
|
id: str
|
|
type: Literal["function"]
|
|
function: FunctionCall
|
|
|
|
|
|
class ChatCompletionRequest(BaseModel):
|
|
"""OpenAI chat completion request."""
|
|
model_config = {"extra": "allow"}
|
|
|
|
model: str
|
|
messages: List[ChatMessage]
|
|
temperature: Optional[float] = Field(default=1.0, ge=0, le=2)
|
|
top_p: Optional[float] = Field(default=1.0, ge=0, le=1)
|
|
n: Optional[int] = Field(default=1, ge=1)
|
|
stream: Optional[bool] = False
|
|
stop: Optional[Union[str, List[str]]] = None
|
|
max_tokens: Optional[int] = Field(default=None, ge=1)
|
|
presence_penalty: Optional[float] = Field(default=0, ge=-2, le=2)
|
|
frequency_penalty: Optional[float] = Field(default=0, ge=-2, le=2)
|
|
logit_bias: Optional[Dict[str, float]] = None
|
|
user: Optional[str] = None
|
|
functions: Optional[List[Dict[str, Any]]] = None
|
|
function_call: Optional[Union[str, Dict[str, str]]] = None
|
|
tools: Optional[List[Dict[str, Any]]] = None
|
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None
|
|
|
|
|
|
class ChatCompletionChoice(BaseModel):
|
|
"""A single chat completion choice."""
|
|
index: int
|
|
message: ChatMessage
|
|
finish_reason: Optional[str] = None
|
|
logprobs: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class ChatCompletionUsage(BaseModel):
|
|
"""Token usage information."""
|
|
prompt_tokens: int
|
|
completion_tokens: int
|
|
total_tokens: int
|
|
|
|
|
|
class ChatCompletionResponse(BaseModel):
|
|
"""OpenAI chat completion response."""
|
|
id: str
|
|
object: Literal["chat.completion"] = "chat.completion"
|
|
created: int
|
|
model: str
|
|
choices: List[ChatCompletionChoice]
|
|
usage: ChatCompletionUsage
|
|
system_fingerprint: Optional[str] = None
|
|
|
|
|
|
class ChatCompletionChunkDelta(BaseModel):
|
|
"""Delta content in streaming response."""
|
|
role: Optional[str] = None
|
|
content: Optional[Union[str, List[Dict[str, Any]]]] = None
|
|
function_call: Optional[Dict[str, Any]] = None
|
|
tool_calls: Optional[List[Dict[str, Any]]] = None
|
|
tool_call_id: Optional[str] = None
|
|
|
|
|
|
class ChatCompletionChunkChoice(BaseModel):
|
|
"""A single streaming chunk choice."""
|
|
index: int
|
|
delta: ChatCompletionChunkDelta
|
|
finish_reason: Optional[str] = None
|
|
logprobs: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class ChatCompletionChunk(BaseModel):
|
|
"""OpenAI streaming chat completion chunk."""
|
|
id: str
|
|
object: Literal["chat.completion.chunk"] = "chat.completion.chunk"
|
|
created: int
|
|
model: str
|
|
choices: List[ChatCompletionChunkChoice]
|
|
system_fingerprint: Optional[str] = None
|
|
|
|
|
|
# ============================================================================
|
|
# Completions Models (Legacy)
|
|
# ============================================================================
|
|
|
|
class CompletionRequest(BaseModel):
|
|
"""OpenAI completion request (legacy)."""
|
|
model: str
|
|
prompt: Union[str, List[str], List[int], List[List[int]]]
|
|
suffix: Optional[str] = None
|
|
max_tokens: Optional[int] = Field(default=16, ge=1)
|
|
temperature: Optional[float] = Field(default=1.0, ge=0, le=2)
|
|
top_p: Optional[float] = Field(default=1.0, ge=0, le=1)
|
|
n: Optional[int] = Field(default=1, ge=1)
|
|
stream: Optional[bool] = False
|
|
logprobs: Optional[int] = Field(default=None, ge=0, le=5)
|
|
echo: Optional[bool] = False
|
|
stop: Optional[Union[str, List[str]]] = None
|
|
presence_penalty: Optional[float] = Field(default=0, ge=-2, le=2)
|
|
frequency_penalty: Optional[float] = Field(default=0, ge=-2, le=2)
|
|
best_of: Optional[int] = Field(default=1, ge=1)
|
|
logit_bias: Optional[Dict[str, float]] = None
|
|
user: Optional[str] = None
|
|
|
|
|
|
class CompletionChoice(BaseModel):
|
|
"""A single completion choice."""
|
|
text: str
|
|
index: int
|
|
logprobs: Optional[Dict[str, Any]] = None
|
|
finish_reason: Optional[str] = None
|
|
|
|
|
|
class CompletionResponse(BaseModel):
|
|
"""OpenAI completion response."""
|
|
id: str
|
|
object: Literal["text_completion"] = "text_completion"
|
|
created: int
|
|
model: str
|
|
choices: List[CompletionChoice]
|
|
usage: ChatCompletionUsage
|
|
|
|
|
|
# ============================================================================
|
|
# Embeddings Models
|
|
# ============================================================================
|
|
|
|
class EmbeddingRequest(BaseModel):
|
|
"""OpenAI embedding request."""
|
|
model: str
|
|
input: Union[str, List[str], List[int], List[List[int]]]
|
|
encoding_format: Optional[Literal["float", "base64"]] = "float"
|
|
dimensions: Optional[int] = None
|
|
user: Optional[str] = None
|
|
|
|
|
|
class EmbeddingData(BaseModel):
|
|
"""A single embedding result."""
|
|
object: Literal["embedding"] = "embedding"
|
|
embedding: List[float]
|
|
index: int
|
|
|
|
|
|
class EmbeddingUsage(BaseModel):
|
|
"""Token usage for embeddings."""
|
|
prompt_tokens: int
|
|
total_tokens: int
|
|
|
|
|
|
class EmbeddingResponse(BaseModel):
|
|
"""OpenAI embedding response."""
|
|
object: Literal["list"] = "list"
|
|
data: List[EmbeddingData]
|
|
model: str
|
|
usage: EmbeddingUsage
|
|
|
|
|
|
# ============================================================================
|
|
# Models List
|
|
# ============================================================================
|
|
|
|
class ModelInfo(BaseModel):
|
|
"""Information about a single model."""
|
|
id: str
|
|
object: Literal["model"] = "model"
|
|
created: int
|
|
owned_by: str
|
|
|
|
|
|
class ModelsResponse(BaseModel):
|
|
"""List of available models."""
|
|
object: Literal["list"] = "list"
|
|
data: List[ModelInfo]
|
|
|
|
|
|
# ============================================================================
|
|
# Error Models
|
|
# ============================================================================
|
|
|
|
class ErrorDetail(BaseModel):
|
|
"""Error detail information."""
|
|
message: str
|
|
type: str
|
|
param: Optional[str] = None
|
|
code: Optional[str] = None
|
|
|
|
|
|
class ErrorResponse(BaseModel):
|
|
"""OpenAI error response."""
|
|
error: ErrorDetail
|