Files
93b0fd229c Release 0.2.0
Co-authored-by: xinchengxx <xinchengxx@deepseek.com>
Co-authored-by: zhu-he <hezhu@deepseek.com>
2026-10-20 00:21:22 +08:00

1043 lines
39 KiB
Python

from collections.abc import Callable, Sequence
from typing import Any, Literal, TypeAlias
__version__: str
IMAGE_SPECIAL_TOKEN_ID: int
ToolChoice: TypeAlias = Literal["auto", "none", "required"]
ReasoningEffort: TypeAlias = Literal["low", "high", "xhigh", "max"]
ResponseFormat: TypeAlias = Literal["text", "json_object", "json_schema", "regex"]
ImageDetail: TypeAlias = Literal["low", "high", "original", "auto"]
Role: TypeAlias = Literal["system", "user", "assistant", "tool", "latest_reminder"]
ImageSourceKind: TypeAlias = Literal["data_url", "url", "bytes"]
RequestBody: TypeAlias = bytes | str | dict[str, Any]
class SpecialToken:
"""A kind of special token."""
Bos: SpecialToken
Eos: SpecialToken
ThinkingStart: SpecialToken
ThinkingEnd: SpecialToken
System: SpecialToken
User: SpecialToken
Assistant: SpecialToken
LatestReminder: SpecialToken
Dsml: SpecialToken
Image: SpecialToken
Ref: SpecialToken
RefEnd: SpecialToken
Box: SpecialToken
BoxEnd: SpecialToken
Point: SpecialToken
PointEnd: SpecialToken
Polygon: SpecialToken
PolygonEnd: SpecialToken
def default_str(self) -> str:
"""Return the default literal spelling of this token."""
class SpecialTokens:
"""A mapping from each `SpecialToken` to its spelling.
Every keyword defaults to the default spelling of its token, so only
overridden tokens need to be supplied.
"""
def __init__(
self,
*,
bos: str | None = None,
eos: str | None = None,
thinking_start: str | None = None,
thinking_end: str | None = None,
system: str | None = None,
user: str | None = None,
assistant: str | None = None,
latest_reminder: str | None = None,
dsml: str | None = None,
image: str | None = None,
ref: str | None = None,
ref_end: str | None = None,
box: str | None = None,
box_end: str | None = None,
point: str | None = None,
point_end: str | None = None,
polygon: str | None = None,
polygon_end: str | None = None,
) -> None: ...
def token(self, token: SpecialToken) -> str:
"""Return the spelling of `token` in this mapping."""
class ConversionError(Exception):
"""Raised when a protocol request is invalid or cannot be converted."""
status_code: int
body: str
class ImageError(Exception):
"""A failure to resolve, fetch, or preprocess images, including request limits.
`kind` names the Rust `ImageError` variant, and `is_retryable` holds its
retry classification.
"""
kind: str
is_retryable: bool
class CalcResizeError(ValueError):
"""The Rust image token calculation did not converge."""
class ToolCall:
"""A historical tool call and its arguments."""
def __init__(self, id: str, name: str, arguments: str) -> None: ...
@property
def id(self) -> str: ...
@property
def name(self) -> str: ...
@property
def arguments(self) -> str:
"""Caller-supplied arguments, expected to encode a JSON object; not validated."""
class ToolDefinition:
"""A client tool definition.
`strict` is passed through. Direct construction does not normalize
`parameters`, unlike conversion, which normalizes the parameters of a tool
with `strict: true`.
"""
def __init__(
self,
name: str,
description: str | None = None,
parameters: Any = None,
strict: bool | None = None,
defer_loading: bool = False,
) -> None: ...
@property
def name(self) -> str: ...
@property
def description(self) -> str | None: ...
@property
def parameters(self) -> Any:
"""Input JSON Schema of the tool."""
@property
def strict(self) -> bool | None:
"""The `strict` setting, passed through without normalizing `parameters`."""
@property
def defer_loading(self) -> bool: ...
class ImageSource:
"""Base class of the image sources supplied with a conversation.
Every source records a `path`: the request location of the image as error
messages report it, such as `messages.0.content[1]`. Conversion fills it; a
source constructed directly has an empty path unless the `path` keyword
supplies one.
"""
@property
def kind(self) -> ImageSourceKind: ...
@property
def detail(self) -> ImageDetail: ...
@property
def data_url(self) -> str | None: ...
@property
def url(self) -> str | None: ...
@property
def data(self) -> bytes | None: ...
@property
def path(self) -> str:
"""Request location of the image; empty when the source has none."""
class DataUrlImageSource(ImageSource):
"""An image referenced by a data URL with a base64 or percent-encoded body."""
def __init__(self, data_url: str, detail: ImageDetail = "high", *, path: str = "") -> None: ...
class UrlImageSource(ImageSource):
"""An image referenced by an external URL."""
def __init__(self, url: str, detail: ImageDetail = "high", *, path: str = "") -> None: ...
class BytesImageSource(ImageSource):
"""An image supplied as encoded bytes."""
def __init__(self, data: bytes, detail: ImageDetail = "high", *, path: str = "") -> None: ...
class Message:
"""Base class of the messages in a conversation.
Every message has a role and content. On a message of another role, the
role-specific properties have fixed values: `reasoning_content`,
`tool_calls`, and `tool_call_id` are `None`, `prefix` is `False`, and
`image_sources` is an empty list.
"""
@property
def role(self) -> Role: ...
@property
def content(self) -> str: ...
@property
def reasoning_content(self) -> str | None: ...
@property
def tool_calls(self) -> list[ToolCall] | None: ...
@property
def tool_call_id(self) -> str | None: ...
@property
def image_sources(self) -> list[ImageSource]: ...
@property
def prefix(self) -> bool:
"""Whether an assistant message is continued instead of starting a new turn."""
class SystemMessage(Message):
"""A system message.
See `UserMessage` for image placeholder rules.
"""
def __init__(
self,
content: str,
image_sources: Sequence[ImageSource] | None = None,
tools: Sequence[ToolDefinition] | None = None,
*,
image_token: str | None = None,
) -> None: ...
@property
def tools(self) -> list[ToolDefinition] | None: ...
class UserMessage(Message):
"""A user message.
The first occurrences of `image_token` in `content`, one per image source,
become the placeholders of the image sources; later occurrences are plain
text. `image_token` defaults to the default image token spelling; a caller
that renders with a `SpecialTokens` mapping whose image token differs
passes that mapping's spelling. When `content` holds fewer occurrences than
there are image sources, the message keeps every image source, so a
rendered prompt holds fewer placeholders than image sources; construction
does not report the mismatch. An empty `image_token` raises `ValueError`.
"""
def __init__(
self,
content: str,
image_sources: Sequence[ImageSource] | None = None,
*,
image_token: str | None = None,
) -> None: ...
class AssistantMessage(Message):
"""An assistant message."""
def __init__(
self,
content: str,
reasoning_content: str | None = None,
tool_calls: Sequence[ToolCall] | None = None,
prefix: bool = False,
) -> None: ...
class ToolMessage(Message):
"""A tool result message.
The first occurrences of `image_token` in `content`, one per image source,
become the placeholders of the image sources; later occurrences are plain
text. `image_token` defaults to the default image token spelling; a caller
that renders with a `SpecialTokens` mapping whose image token differs
passes that mapping's spelling. When `content` holds fewer occurrences than
there are image sources, the message keeps every image source, so a
rendered prompt holds fewer placeholders than image sources; construction
does not report the mismatch. An empty `image_token` raises `ValueError`.
"""
def __init__(
self,
content: str,
tool_call_id: str | None = None,
image_sources: Sequence[ImageSource] | None = None,
*,
image_token: str | None = None,
) -> None: ...
class LatestReminderMessage(Message):
"""A reminder message that carries additional instructions."""
def __init__(self, content: str) -> None: ...
class Conversation:
"""A conversation and its prompt configuration.
Thinking mode is enabled by default, tool selection defaults to `auto`, and
the response format defaults to `text`. `response_format` accepts `text` or
`json_object`; `response_schema` selects the `json_schema` format with that
JSON Schema, and `response_regex` selects the `regex` format with that
regular expression. Supplying both, or either with `json_object`, raises
`ValueError`.
"""
def __init__(
self,
messages: Sequence[Message] | None = None,
*,
thinking_mode: bool = True,
tools: Sequence[ToolDefinition] | None = None,
tool_choice: ToolChoice = "auto",
reasoning_effort: ReasoningEffort | None = None,
response_format: Literal["text", "json_object"] = "text",
response_schema: Any | None = None,
response_regex: str | None = None,
) -> None: ...
@property
def messages(self) -> list[Message]: ...
@property
def thinking_mode(self) -> bool: ...
@property
def tools(self) -> list[ToolDefinition]: ...
@property
def tool_choice(self) -> ToolChoice: ...
@property
def reasoning_effort(self) -> ReasoningEffort | None: ...
@property
def response_format(self) -> ResponseFormat:
"""Requested answer format; the caller enforces it during inference."""
@property
def response_schema(self) -> Any | None:
"""The JSON Schema of a `json_schema` response format, or `None`."""
@property
def response_regex(self) -> str | None:
"""The regular expression of a `regex` response format, or `None`."""
class RenderedPrompt:
"""A rendered prompt and the image sources its placeholders refer to."""
@property
def prompt(self) -> str: ...
@property
def special_ranges(self) -> list[tuple[int, int]]:
"""Ascending, disjoint ranges of `prompt` that hold explicit special tokens.
Each range is a half-open `(start, end)` pair of code point offsets into
`prompt` (Python `str` indices), so `prompt[start:end]` is the spelling of
one token. The Rust `RenderedPrompt::special_ranges` field holds byte
offsets instead.
The text between the ranges is plain text, which prompt encoding encodes
without the tokenizer's added vocabulary. `Tokenizer.encode` uses the full
vocabulary, so it encodes a special-token spelling in plain text as that
token's ID. `DeepseekV4Encoding.encode` and `DeepseekV41Encoding.encode`
perform prompt encoding.
"""
@property
def image_sources(self) -> list[ImageSource]: ...
class DeepseekV4Encoding:
"""The V4 prompt encoding.
It renders a conversation and, with an attached tokenizer, encodes it into
token IDs.
"""
def __init__(self) -> None: ...
def with_tokenizer(self, tokenizer: Tokenizer) -> DeepseekV4Encoding:
"""Return a new prompt encoding that uses `tokenizer` for `encode`."""
def with_special_tokens(self, special_tokens: SpecialTokens) -> DeepseekV4Encoding:
"""Return a new prompt encoding that renders prompts with `special_tokens`."""
def render_conversation(self, conversation: Conversation) -> RenderedPrompt: ...
def encode(self, conversation: Conversation) -> list[int]:
"""Encode a conversation into token IDs using the attached tokenizer.
Raises `RuntimeError` when no tokenizer is attached or encoding fails.
"""
class DeepseekV41Encoding:
"""The V4.1 prompt encoding.
It renders a conversation and, with an attached tokenizer, encodes it into
token IDs.
"""
def __init__(self) -> None: ...
def with_tokenizer(self, tokenizer: Tokenizer) -> DeepseekV41Encoding:
"""Return a new prompt encoding that uses `tokenizer` for `encode`."""
def with_special_tokens(self, special_tokens: SpecialTokens) -> DeepseekV41Encoding:
"""Return a new prompt encoding that renders prompts with `special_tokens`."""
def render_conversation(self, conversation: Conversation) -> RenderedPrompt: ...
def encode(self, conversation: Conversation) -> list[int]:
"""Encode a conversation into token IDs using the attached tokenizer.
Raises `RuntimeError` when no tokenizer is attached or encoding fails.
"""
class WebSearchBehavior:
"""Handling of supported web-search declarations, choices, and Messages blocks."""
Drop: WebSearchBehavior
"""Drop matching declarations and choices, plus Messages server-tool blocks."""
Reject: WebSearchBehavior
"""Reject matching declarations and choices, plus Messages server-tool blocks."""
class ReasoningContentBehavior:
"""Handling of assistant history missing reasoning content in thinking mode."""
FillEmpty: ReasoningContentBehavior
"""Fill missing reasoning content with an empty string."""
Reject: ReasoningContentBehavior
"""Reject the request when reasoning content that must be passed back is missing."""
class ModelVersion:
"""The model version a converted conversation targets.
Conversion resolves it from the request's model name through
`ConversionOptions.model_versions_by_name`, and it selects the prompt
encoding: `DeepseekV4Encoding` or `DeepseekV41Encoding`.
"""
DeepseekV4Pro: ModelVersion
"""DeepSeek V4 Pro, rendered by `DeepseekV4Encoding`."""
DeepseekV41Flash: ModelVersion
"""DeepSeek V4.1 Flash, rendered by `DeepseekV41Encoding`."""
class ConversionOptions:
"""Options for protocol request conversion.
By default, thinking mode is enabled, missing reasoning content is filled
with an empty string, Responses `web_search` is dropped, Messages
`web_search` is rejected, the model version is resolved from the request's
model name (`DeepSeek-V4-Pro` or `DeepSeek-V4.1-Flash`), and the
`max_tokens` upper bound is 393216 in thinking mode and outside it.
"""
def __init__(
self,
*,
default_thinking_mode: bool = True,
reasoning_content_behavior: ReasoningContentBehavior = ReasoningContentBehavior.FillEmpty,
responses_web_search: WebSearchBehavior = WebSearchBehavior.Drop,
messages_web_search: WebSearchBehavior = WebSearchBehavior.Reject,
thinking_max_tokens_upper_bound: int = 393216,
non_thinking_max_tokens_upper_bound: int = 393216,
) -> None: ...
@property
def default_thinking_mode(self) -> bool:
"""Whether requests that do not specify a thinking mode use thinking mode.
Defaults to `True`.
"""
@property
def model_versions_by_name(self) -> dict[str, ModelVersion]:
"""The target model version of each accepted request model name.
Defaults to `DeepSeek-V4-Pro` and `DeepSeek-V4.1-Flash`; conversion
rejects a request whose model is not a key.
"""
@property
def thinking_max_tokens_upper_bound(self) -> int:
"""The largest accepted `max_tokens` (`max_output_tokens` in Responses)
of a request in thinking mode.
Chat Completions and Responses reject a larger value; Messages lowers it
to this bound.
"""
@property
def non_thinking_max_tokens_upper_bound(self) -> int:
"""The largest accepted `max_tokens` (`max_output_tokens` in Responses)
of a request outside thinking mode.
Chat Completions and Responses reject a larger value; Messages lowers it
to this bound.
"""
@property
def reasoning_content_behavior(self) -> ReasoningContentBehavior:
"""Missing-reasoning-content behavior, defaulting to `FillEmpty`."""
@property
def responses_web_search(self) -> WebSearchBehavior:
"""Responses web-search behavior, defaulting to `Drop`."""
@property
def messages_web_search(self) -> WebSearchBehavior:
"""Messages web-search behavior, defaulting to `Reject`."""
@property
def special_tokens(self) -> SpecialTokens:
"""Special token mapping, defaulting to the built-in mapping."""
def with_default_thinking_mode(self, default_thinking_mode: bool) -> ConversionOptions:
"""Construct options with the supplied default thinking mode."""
def with_reasoning_content_behavior(
self, reasoning_content_behavior: ReasoningContentBehavior
) -> ConversionOptions:
"""Construct options with the supplied missing-reasoning-content behavior."""
def with_responses_web_search(
self, responses_web_search: WebSearchBehavior
) -> ConversionOptions:
"""Construct options with the supplied Responses web-search behavior."""
def with_messages_web_search(
self, messages_web_search: WebSearchBehavior
) -> ConversionOptions:
"""Construct options with the supplied Messages web-search behavior."""
def with_special_tokens(self, special_tokens: SpecialTokens) -> ConversionOptions:
"""Construct options with the supplied special token mapping."""
def with_model_alias(self, model: str, model_version: ModelVersion) -> ConversionOptions:
"""Accept `model` as a name of `model_version`.
Adds the name, or replaces the version of an existing one.
"""
def with_model_versions_by_name(
self, model_versions_by_name: dict[str, ModelVersion]
) -> ConversionOptions:
"""Replace the whole table of accepted model names.
Drops the default names unless the mapping includes them.
"""
def with_thinking_max_tokens_upper_bound(
self, thinking_max_tokens_upper_bound: int
) -> ConversionOptions: ...
def with_non_thinking_max_tokens_upper_bound(self, non_thinking_max_tokens_upper_bound: int) -> ConversionOptions: ...
class ConversationRequest:
"""A Rust conversation request with inference and parsing options."""
def __init__(self, conversation: Conversation, model_version: ModelVersion) -> None:
"""Construct a request with default inference, parsing, and transport options."""
@property
def conversation(self) -> Conversation: ...
@property
def inference_options(self) -> InferenceOptions: ...
@property
def parsing_options(self) -> ParsingOptions: ...
@property
def model_version(self) -> ModelVersion:
"""The target model version.
Conversion resolves it from the request's model name; the constructor
takes it as an argument.
"""
@property
def stream(self) -> bool:
"""Whether the protocol request asks for a streamed response."""
def resolve_max_tokens(self, prompt_tokens: int, context_limit: int) -> int:
"""Resolve the `max_tokens` to send to the backend.
`prompt_tokens` is the number of tokens in the encoded prompt, with each
image counted at its image token count instead of as one placeholder,
and `context_limit` is the number of tokens the model's context holds.
A requested `max_tokens` is kept; an unspecified one becomes 8192
outside thinking mode, 131072 in thinking mode with `max` effort, and
65536 in thinking mode otherwise. The result is lowered to the context
left after the prompt and raised to at least 1. Raises `ConversionError`
when `prompt_tokens` plus the requested `max_tokens` exceeds
`context_limit`, or, without a requested `max_tokens`, when
`prompt_tokens` alone exceeds it.
"""
class ChatCompletionRequest:
"""A Rust Chat Completions request; even failed conversion consumes it."""
def __init__(self, body: RequestBody) -> None: ...
@property
def model(self) -> str:
"""The requested model name; read it before `convert` consumes the request."""
def convert(self, options: ConversionOptions) -> ConversationRequest: ...
@staticmethod
def chunk_generator(
request: ConversationRequest, id: str, model: str
) -> ChatCompletionChunkGenerator: ...
class ResponsesRequest:
"""A Rust Responses request; even failed conversion consumes it."""
def __init__(self, body: RequestBody) -> None: ...
@property
def model(self) -> str:
"""The requested model name; read it before `convert` consumes the request."""
def namespace_tool_map(self, options: ConversionOptions) -> dict[str, tuple[str, str]]:
"""Return the function names of the declared namespace tools.
Each function name maps to `(namespace, local name)`, as conversion with
`options` assigns them; read them before `convert` consumes this request.
Raises `ConversionError` for an invalid tool declaration.
"""
def echo(self) -> ResponsesEcho:
"""Return the request settings that responses report.
Read them before `convert` consumes this request.
"""
def convert(self, options: ConversionOptions) -> ConversationRequest: ...
@staticmethod
def chunk_generator(
request: ConversationRequest, id: str, model: str
) -> ResponsesChunkGenerator: ...
class MessagesRequest:
"""A Rust Messages request; even failed conversion consumes it."""
def __init__(self, body: RequestBody) -> None: ...
@property
def model(self) -> str:
"""The requested model name; read it before `convert` consumes the request."""
def convert(self, options: ConversionOptions) -> ConversationRequest: ...
@staticmethod
def chunk_generator(
request: ConversationRequest, id: str, model: str
) -> MessagesChunkGenerator: ...
class InferenceOptions:
"""Inference parameters extracted by protocol conversion.
Conversion always sets `temperature` (1.0 in thinking mode) and `top_p` to
their resolved values. Other unspecified parameters are `None`;
`ConversationRequest.resolve_max_tokens` supplies the default `max_tokens`,
and the caller applies the other model-specific defaults.
"""
@property
def max_tokens(self) -> int | None:
"""Maximum number of output tokens, or `None` when the request sets none.
`ConversationRequest.resolve_max_tokens` supplies the default after the
prompt is encoded.
"""
@property
def temperature(self) -> float | None:
"""Sampling temperature: 1.0 in thinking mode, otherwise the requested value or 1.0."""
@property
def top_p(self) -> float | None:
"""Final `top_p` for the target model version."""
@property
def logprobs(self) -> bool:
"""Whether the request asks for the log probability of each output token."""
@property
def top_logprobs(self) -> int | None:
"""Number of most likely alternatives reported per output token, in `[0, 20]`."""
@property
def seed(self) -> int | None:
"""Sampling seed in `[0, 2^63)`; the caller chooses an unspecified seed."""
@property
def output_constraint(self) -> OutputConstraint | None:
"""The constraint that constrained decoding would enforce on the output,
or `None`; whether the backend applies it is the caller's decision.
"""
class OutputConstraint:
"""A constraint on the model output that the backend can enforce by
constrained decoding, as a kind name and a constraint string.
"""
@property
def kind(self) -> str:
"""`json`, `regex`, `tool_call`, or `tool_call_required`."""
@property
def schema(self) -> str:
"""The schema as compact JSON, the regular expression, the tool list as
a compact JSON array of Chat Completions function tools with
`defer_loading: true` on deferred tools, or an empty string for any JSON
value.
"""
class ImageInfo:
"""A preprocessed image for the inference backend.
It holds the encoded image bytes and the image dimensions in pixels after
preprocessing.
"""
def __init__(self, data: bytes, width: int, height: int) -> None: ...
@property
def data(self) -> bytes: ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
class MultiModalData:
"""Images in the order their placeholders appear in a prompt."""
def __init__(self, images: Sequence[ImageInfo] | None = None) -> None: ...
@property
def images(self) -> list[ImageInfo]: ...
def is_empty(self) -> bool: ...
def image_token_adjustment(self) -> int:
"""Return the number of inference input tokens beyond one per placeholder.
The V4.1 image token specification gives the image token count of each
image, which occupies one placeholder in the prompt; the adjustment is the
sum of the differences. Raises `CalcResizeError` when fitting an image
does not converge.
"""
class ImageQuota:
"""The image count and encoded bytes recorded by the completed resolve calls of one request.
To apply the image count and total byte limits across the resolve calls of a
request, the caller must pass the same quota to every call. A call records
its sources after it preprocesses every one of them, so a failed call adds
nothing.
"""
def __init__(self) -> None: ...
def image_count(self) -> int: ...
def byte_size(self) -> int: ...
class PreprocessOptions:
"""Options passed to one Rust image preprocessing operation."""
def __init__(
self, detail: ImageDetail, max_dimension_px: int, low_detail_max_dimension_px: int
) -> None: ...
@property
def detail(self) -> ImageDetail: ...
@property
def max_dimension_px(self) -> int: ...
@property
def low_detail_max_dimension_px(self) -> int: ...
class ReqwestImageFetcher:
"""An image fetcher that downloads external image URLs through the Rust `reqwest` client.
Without a destination filter, this fetcher connects to any address. When
untrusted clients can supply image URLs, the caller should install a filter
with `with_destination_filter` to protect against SSRF.
"""
def __init__(self) -> None: ...
@staticmethod
def with_max_bytes(max_bytes: int) -> ReqwestImageFetcher: ...
def with_destination_filter(
self, destination_filter: Callable[[str, str], bool]
) -> ReqwestImageFetcher:
"""Return a fetcher with this size limit that connects only to allowed addresses.
`destination_filter(host, address)` receives the host of the image URL or
of a redirect target and one address as a string, such as `"10.0.0.1"`,
and returns whether the fetcher can connect to it. For a host name, the
fetcher connects only to the resolved addresses the filter allows. A host
with no allowed address raises `ImageError` with kind
`"DestinationRejected"`. A callable that raises or returns a non-boolean
value rejects the address. The returned fetcher uses no proxy. The
library does not include a filter implementation; the caller writes the
rule. Raises `TypeError` when `destination_filter` is not callable.
"""
def fetch(self, url: str) -> bytes: ...
class OpenCvImagePreprocessor:
"""An image preprocessor that uses the Rust OpenCV implementation."""
def __init__(self) -> None: ...
def preprocess(self, data: bytes, options: PreprocessOptions) -> ImageInfo: ...
class ImageResolver:
"""An image resolver built from explicit fetching and preprocessing components."""
def __init__(
self, fetcher: ReqwestImageFetcher, preprocessor: OpenCvImagePreprocessor
) -> None: ...
def resolve(self, sources: Sequence[ImageSource], quota: ImageQuota) -> MultiModalData:
"""Resolve image sources and update the supplied quota.
A failed call leaves the quota unchanged.
"""
class PromptUsage:
"""Prompt-side token counts from the backend."""
def __init__(
self, *, prompt_tokens: int = 0, prompt_cache_hit_tokens: int = 0,
) -> None: ...
@property
def prompt_tokens(self) -> int: ...
@property
def prompt_cache_hit_tokens(self) -> int: ...
class InferenceFinishReason:
"""Backend finish reasons; output parsing determines the protocol finish reason."""
Stop: InferenceFinishReason
Length: InferenceFinishReason
ContentFilter: InferenceFinishReason
class InferenceChunk:
"""One backend update, constructed with `ready`, `text`, `tokens`, or `finish`."""
@staticmethod
def ready(
*, prompt_usage: PromptUsage | None = None, system_fingerprint: str | None = None,
) -> InferenceChunk: ...
@staticmethod
def text(content: str, token_count: int = 0) -> InferenceChunk:
"""Construct a text chunk from `content` and the number of tokens it accounts for."""
@staticmethod
def tokens(
token_ids: Sequence[int],
logprobs: Sequence[tuple[float, Sequence[tuple[int, float]]]] | None = None,
) -> InferenceChunk:
"""Construct a chunk from the token IDs of one backend output.
`logprobs` holds one `(logprob, top_logprobs)` pair per token ID.
"""
@staticmethod
def finish(finish_reason: InferenceFinishReason) -> InferenceChunk: ...
@property
def kind(self) -> Literal["ready", "text", "tokens", "finish"]: ...
@property
def content(self) -> str | None: ...
@property
def token_ids(self) -> list[int] | None:
"""The token IDs of a `tokens` chunk."""
@property
def finish_reason(self) -> InferenceFinishReason | None: ...
@property
def prompt_usage(self) -> PromptUsage | None: ...
@property
def token_count(self) -> int | None:
"""The number of tokens this chunk's content accounts for; text chunks only."""
@property
def system_fingerprint(self) -> str | None: ...
class ThinkingInitialStage:
"""The stage where parsing begins in thinking mode."""
ReasoningStart: ThinkingInitialStage
"""Begin the reasoning content of a new assistant turn, discarding leading newlines."""
ReasoningContinuation: ThinkingInitialStage
"""Continue the reasoning content of a prefix continuation, preserving leading newlines."""
ContentContinuation: ThinkingInitialStage
"""Continue the answer content of a prefix continuation whose reasoning content has ended.
Leading newlines are preserved.
"""
def starts_in_reasoning(self) -> bool:
"""Return whether parsing begins in reasoning content."""
class ParsingOptions:
"""Settings passed directly to the Rust stream parser."""
def __init__(
self,
*,
parse_tool_calls: bool = True,
starts_in_tool_calls: bool = False,
parse_json_output: bool = False,
thinking_initial_stage: ThinkingInitialStage | None = None,
stop_sequences: Sequence[str] | None = None,
special_tokens: SpecialTokens | None = None,
) -> None: ...
parse_tool_calls: bool
"""Whether to parse model-specific tool-call markup."""
starts_in_tool_calls: bool
"""Whether parsing begins inside the tool-call block that the prompt opened.
Used for a required tool choice; takes precedence over `thinking_initial_stage`.
"""
parse_json_output: bool
"""Whether to recognize fenced or bare JSON output and replace the text around it with spaces."""
thinking_initial_stage: ThinkingInitialStage | None
"""The stage where parsing begins in thinking mode; `None` means thinking mode is off.
A stage also makes the processor report reasoning tokens.
"""
@property
def stop_sequences(self) -> list[str]: ...
@stop_sequences.setter
def stop_sequences(self, value: Sequence[str]) -> None: ...
@property
def special_tokens(self) -> SpecialTokens: ...
@special_tokens.setter
def special_tokens(self, value: SpecialTokens) -> None: ...
class ChatCompletionChunkGenerator:
"""A Rust Chat Completions generator consumed by a stream processor."""
class ResponsesChunkGenerator:
"""A Rust Responses generator consumed by a stream processor."""
def with_namespace_tool_map(
self, namespace_tool_map: dict[str, tuple[str, str]]
) -> ResponsesChunkGenerator:
"""Consume this generator and construct one that splits namespace tool names."""
def with_echo(self, echo: ResponsesEcho) -> ResponsesChunkGenerator:
"""Consume this generator and construct one whose responses report the request settings."""
class ResponsesEcho:
"""Request settings that Responses response objects report, as the request specified them.
`ResponsesRequest.echo` reads them from a request; the constructor builds
the settings of an unspecified request. The properties expose the scalar
settings; the reasoning, text, tool choice, and tool settings are reported
only through the response.
"""
def __init__(self) -> None:
"""Construct the settings of an unspecified request.
No instructions, output token limit, or user; temperature and `top_p` of
1.0; zero `top_logprobs`.
"""
@property
def instructions(self) -> str | None: ...
@property
def max_output_tokens(self) -> int | None: ...
@property
def temperature(self) -> float:
"""The requested temperature or 1.0, not the sampling temperature."""
@property
def top_p(self) -> float:
"""The requested `top_p` or 1.0, not the sampling `top_p`."""
@property
def top_logprobs(self) -> int:
"""The requested `top_logprobs`, or 0."""
@property
def user(self) -> str | None: ...
class MessagesChunkGenerator:
"""A Rust Messages generator consumed by a stream processor."""
def __init__(self, id: str, model: str, thinking_mode: bool) -> None: ...
def with_signature(self, signature: str) -> MessagesChunkGenerator:
"""Consume this generator and construct one with the supplied signature.
The new generator emits `signature` at the end of each thinking block. The
default signature is the response ID.
"""
class ChatCompletionChunk:
"""A Rust Chat Completions chunk consumed by response accumulation."""
def to_json(self) -> str: ...
class ResponsesStreamEvent:
"""A Rust Responses event consumed by response accumulation."""
def to_json(self) -> str: ...
class MessagesStreamEvent:
"""A Rust Messages event consumed by response accumulation."""
def to_json(self) -> str: ...
class ChatCompletionResponse:
"""A Rust Chat Completions response with explicit accumulation."""
def __init__(
self, id: str, model: str, created: int, prompt_tokens: int, prompt_cache_hit_tokens: int
) -> None: ...
def accumulate(self, chunk: ChatCompletionChunk) -> None:
"""Consume this chunk and apply its delta to the response."""
def to_json(self) -> str: ...
@staticmethod
def sse_event_name(chunk: ChatCompletionChunk) -> str | None:
"""Return the SSE event name of `chunk`, or `None` for an unnamed data event."""
@staticmethod
def sse_done_data() -> str | None:
"""Return the data of the final SSE message, `[DONE]`."""
class ResponsesResponse:
"""A Rust Responses response with explicit accumulation."""
def __init__(
self, id: str, model: str, created: int, prompt_tokens: int, prompt_cache_hit_tokens: int
) -> None: ...
def accumulate(self, chunk: ResponsesStreamEvent) -> None:
"""Consume this event and apply its delta to the response."""
def to_json(self) -> str: ...
@staticmethod
def sse_event_name(chunk: ResponsesStreamEvent) -> str | None:
"""Return the SSE event name of `chunk`."""
@staticmethod
def sse_done_data() -> str | None:
"""Return `None`: a Responses stream has no final data message."""
class MessagesResponse:
"""A Rust Messages response with explicit accumulation."""
def __init__(
self, id: str, model: str, created: int, prompt_tokens: int, prompt_cache_hit_tokens: int
) -> None: ...
def accumulate(self, chunk: MessagesStreamEvent) -> None:
"""Consume this event and apply its delta to the response."""
def to_json(self) -> str: ...
@staticmethod
def sse_event_name(chunk: MessagesStreamEvent) -> str | None:
"""Return the SSE event name of `chunk`."""
@staticmethod
def sse_done_data() -> str | None:
"""Return `None`: a Messages stream has no final data message."""
class Tokenizer:
"""A Hugging Face tokenizer loaded from a `tokenizer.json` file.
A prompt encoding uses it, after `with_tokenizer`, to encode conversations into
token IDs. A stream processor uses it to decode the token IDs of `tokens`
inference chunks.
"""
@staticmethod
def from_file(path: str) -> Tokenizer:
"""Load a tokenizer from a `tokenizer.json` file."""
@staticmethod
def from_str(text: str) -> Tokenizer:
"""Load a tokenizer from the contents of a `tokenizer.json` file."""
@staticmethod
def from_pretrained(
identifier: str, revision: str | None = None, token: str | None = None
) -> Tokenizer:
"""Download and cache `tokenizer.json` from the Hugging Face Hub."""
def encode(self, text: str) -> list[int]:
"""Encode `text` into token IDs with the full vocabulary, including the added vocabulary.
A special-token spelling in `text` encodes as that token's ID. The
post-processor adds no special tokens, such as a BOS token. This is not
prompt encoding, which encodes plain text without the added vocabulary:
`DeepseekV4Encoding.encode` and `DeepseekV41Encoding.encode` perform
prompt encoding.
"""
class StreamProcessor:
"""Adapt Python inference chunks to the Rust processor's input stream."""
def __init__(
self,
generator: ChatCompletionChunkGenerator | ResponsesChunkGenerator | MessagesChunkGenerator,
options: ParsingOptions,
tokenizer: Tokenizer | None = None,
) -> None:
"""Consume the generator and construct a Rust stream processor.
The optional tokenizer decodes `tokens` chunks. Without one, such a chunk
raises `RuntimeError` and closes the processor.
"""
@property
def finished(self) -> bool:
"""Whether processing completed normally and the processor remains unclosed."""
def push(
self, chunk: InferenceChunk
) -> list[ChatCompletionChunk | ResponsesStreamEvent | MessagesStreamEvent]:
"""Process one chunk.
Raises `RuntimeError` after completion or close, or on a stream error: a
`tokens` chunk without a tokenizer, a decoding failure, or a log
probability count that differs from the token ID count. A stream error
closes the processor.
"""
def finish(self) -> list[ChatCompletionChunk | ResponsesStreamEvent | MessagesStreamEvent]:
"""Close the input and process buffered output; repeated calls after completion yield no chunks.
Calls after close or a stream error raise `RuntimeError`.
"""
def close(self) -> None:
"""Release processing state without producing successful completion."""