mirror of
https://github.com/deepseek-ai/deepseek-recipe.git
synced 2026-10-28 17:17:08 +08:00
Co-authored-by: xinchengxx <xinchengxx@deepseek.com> Co-authored-by: zhu-he <hezhu@deepseek.com>
246 lines
16 KiB
Markdown
246 lines
16 KiB
Markdown
# Changelog
|
|
|
|
This file lists the changes to the Rust crates and to the `deepseek-recipe`
|
|
Python distribution. All crates and the distribution share one version. The
|
|
format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
versions follow [Semantic Versioning](https://semver.org/): before 1.0, a new
|
|
minor version can contain incompatible changes.
|
|
|
|
## Unreleased
|
|
|
|
## 0.2.0 - 2026-10-20
|
|
|
|
This release changes the public API of every crate and of the Python package.
|
|
[Migrating from 0.1](#migrating-from-01) lists the renamed and removed items.
|
|
|
|
### Added
|
|
|
|
- **Model versions.** Conversion resolves a `ModelVersion` (V4 or V4.1) from
|
|
the request's `model` name through
|
|
`ConversionOptions::model_versions_by_name`. The defaults are
|
|
`DeepSeek-V4-Pro` and `DeepSeek-V4.1-Flash`; `with_model_alias` and
|
|
`with_model_versions_by_name` register other names.
|
|
`ConversationRequest::model_version` reports the result. V4 does not accept
|
|
images (`ModelVersion::supports_image`): conversion replaces each image of a
|
|
V4 request with the text `[Unsupported Image]`. Python:
|
|
`ConversionOptions.model_versions_by_name`, `with_model_alias`, and
|
|
`with_model_versions_by_name`.
|
|
- **Sampling values by model version.** Conversion resolves `temperature` and
|
|
`top_p` instead of passing them through. `temperature` is 1.0 in thinking
|
|
mode and otherwise the requested value or 1.0. `top_p` follows
|
|
`ModelVersion::resolve_top_p`: in thinking mode, V4.1 raises it to at least
|
|
0.95, and V4 uses 0.95 with tools and 1.0 without; outside thinking mode,
|
|
V4.1 uses 1.0 and V4 uses the requested value.
|
|
- **Log probabilities.** Conversion maps Chat Completions `logprobs` and
|
|
`top_logprobs`, and Responses `top_logprobs`, into `InferenceOptions`. The
|
|
caller supplies backend values in `InferenceChunk::Tokens`, and the Chat
|
|
Completions and Responses adapters report them. `OutputChunk::Content` and
|
|
`OutputChunk::Reasoning` carry them as `logprobs`.
|
|
- **Reasoning token counts.** `CompletionUsage::reasoning_tokens`: in thinking
|
|
mode, a stream processor with an attached tokenizer counts the tokens of the
|
|
reasoning content, and Chat Completions and Responses report them.
|
|
- **Structured output.** `ResponseFormat::JsonSchema` and
|
|
`ResponseFormat::Regex`. Conversion validates a Chat Completions
|
|
`response_format` or Responses `text.format` of type `json_schema`, which 0.1
|
|
accepted and ignored, and rendering writes the schema into the prompt. A Chat
|
|
Completions `regex` response format passes through as
|
|
`ResponseFormat::Regex`.
|
|
- **Explicit special tokens.** The new `deepseek-recipe-macros` crate provides
|
|
the `prompt!` macro, and `deepseek-recipe-core` provides `Prompt`.
|
|
`RenderedPrompt::special_ranges` records the byte ranges of the explicit
|
|
special tokens, and `PromptTokenizer` encodes only those ranges as special
|
|
tokens. Apart from the grounding tokens in assistant content and reasoning
|
|
content, a special-token spelling in message text encodes as plain text.
|
|
- **Prefix continuation.** A final Chat Completions assistant message with
|
|
`prefix: true` continues that message instead of starting a new assistant
|
|
turn. `InputMessage::Assistant` gains `prefix`. Python: the `prefix` argument
|
|
of `AssistantMessage`.
|
|
- **Deferred tool loading and tool search.** V4.1 supports deferred tool
|
|
loading in Messages and client-executed `tool_search` in Responses.
|
|
`ToolDefinition` gains `defer_loading`, and `InputMessage::System` gains
|
|
`tools`. Python: `ToolDefinition.defer_loading` and `SystemMessage.tools`.
|
|
- **System images.** V4.1 accepts images in system messages.
|
|
`InputMessage::System` gains `image_sources`. Python: the `image_sources`
|
|
and `image_token` arguments of `SystemMessage`.
|
|
- **Image destination filtering.** `DestinationFilter` and
|
|
`ReqwestImageFetcher::with_destination_filter` check the URL host, every
|
|
resolved address, and every redirect target. A rejected destination fails
|
|
with `ImageError::DestinationRejected`. Python:
|
|
`ReqwestImageFetcher.with_destination_filter`.
|
|
- **Request settings in responses.** Conversion preserves usage inclusion,
|
|
tool output types, namespace mappings, and echoed request settings in
|
|
`ConversationRequest::response_options`. `ProtocolRequest::chunk_generator`
|
|
applies them when constructing a generator. Python: the request types'
|
|
`chunk_generator` methods.
|
|
- **Max tokens upper bounds.**
|
|
`ConversionOptions::thinking_max_tokens_upper_bound` and
|
|
`ConversionOptions::non_thinking_max_tokens_upper_bound`, set by the matching
|
|
`with_*` methods: the largest accepted `max_tokens` in thinking mode and
|
|
outside it, both defaulting to `DEFAULT_MAX_TOKENS_UPPER_BOUND` (393216).
|
|
`resolve_max_tokens_upper_bound` selects the bound of a request's thinking
|
|
mode; Messages lowers a larger value to it, Chat Completions and Responses
|
|
reject it. Python: the matching keywords, properties, and `with_*` methods
|
|
of `ConversionOptions`.
|
|
- **Output constraints.** `InferenceOptions::output_constraint` holds the
|
|
`OutputConstraint` that constrained decoding would enforce. A request with
|
|
tools and a tool choice other than `none` gets `ToolCalls`, which lists the
|
|
tools and whether a call is required. Otherwise a JSON object or JSON Schema
|
|
response format gets `Json`, and a regex response format gets `Regex`.
|
|
`OutputConstraint::kind` returns `json`, `regex`, `tool_call`, or
|
|
`tool_call_required`, and `OutputConstraint::schema` returns the constraint
|
|
text. Whether the backend applies the constraint is the caller's decision.
|
|
Python: `OutputConstraint` and `InferenceOptions.output_constraint`.
|
|
- `ConversationRequest::resolve_max_tokens`: after the caller encodes the
|
|
prompt, it resolves the `max_tokens` to send from the prompt's token count
|
|
and a caller-supplied context limit. A request without `max_tokens` gets 8192
|
|
outside thinking mode, 65536 in thinking mode, and 131072 in thinking mode
|
|
with `max` effort (`DEFAULT_NON_THINKING_MAX_TOKENS`,
|
|
`DEFAULT_THINKING_MAX_TOKENS`, `DEFAULT_MAX_EFFORT_MAX_TOKENS`), lowered to
|
|
the context left after the prompt. When the prompt and the requested
|
|
`max_tokens` together exceed the context limit, it returns a `400 Bad
|
|
Request` error whose message matches the DeepSeek API: `This model's maximum
|
|
context length is {context_limit} tokens. ...`. Python:
|
|
`ConversationRequest.resolve_max_tokens`.
|
|
- `SpecialToken` names the grounding tokens (`Ref`, `RefEnd`, `Box`, `BoxEnd`,
|
|
`Point`, `PointEnd`, `Polygon`, `PolygonEnd`), so a `SpecialTokens` mapping
|
|
can respell them; `SpecialTokensMap` has a field for each. The encoding crate
|
|
lists them as the assistant special tokens that rendering inserts from
|
|
assistant content and reasoning content. Python: the matching `SpecialToken`
|
|
members and `SpecialTokens` keywords.
|
|
- `deepseek_recipe_core::multimodal::UNSUPPORTED_IMAGE_ERROR_MESSAGE`: the text
|
|
of the unsupported-image error.
|
|
- Shared request types `RequestReasoningEffort` and `ThinkingType`.
|
|
- Request schema types: `MessagesMetadata` validates `metadata`, `MessagesTool`
|
|
distinguishes client tools from server tools (`MessagesServerTool`), and
|
|
`ResponsesWebSearchTool` deserializes and validates the `search_context_size`
|
|
and `user_location` of a `web_search` or `web_search_2025_08_26` tool.
|
|
- Python: the `ModelVersion` enum, a `ResponsesEcho` constructor with
|
|
read-only getters, the `response_schema` and `response_regex` arguments of
|
|
`Conversation`, the `image_token` argument of `UserMessage` and
|
|
`ToolMessage`, an optional `tool_call_id` of `ToolMessage`, and the `model`
|
|
property of the protocol requests, readable before `convert`.
|
|
|
|
### Changed
|
|
|
|
- Conversion rejects a request whose `model` is not a key of
|
|
`ConversionOptions::model_versions_by_name`. Register any additional name,
|
|
such as `deepseek-flash`, with `with_model_alias`.
|
|
- Validation error messages and the order of the checks match the DeepSeek API.
|
|
- A Responses reasoning item without text adds nothing to the conversation;
|
|
`encrypted_content` is accepted and ignored.
|
|
- V4.1 preserves Messages `system` and Responses `developer` messages as
|
|
system messages.
|
|
- Messages document blocks require a `source` object. Their unsupported-content
|
|
text includes the media type.
|
|
- A complete Chat Completions response numbers its `tool_calls` with `index`
|
|
(`ChatCompletionIndexedToolCall`), as the streamed deltas do.
|
|
- `StreamProcessor::with_tokenizer` takes a `StreamTokenizer`. Besides
|
|
`decode_ids`, the trait has the optional methods `id_to_token`, for log
|
|
probabilities, `count_tokens`, for reasoning token counts, and
|
|
`is_special_token`, for marker matching.
|
|
- `PromptTokenizer` encodes the plain text regions of a prompt as one batch
|
|
through `Tokenizer::encode_batch_fast` instead of one region at a time. The
|
|
`tokenizers` crate encodes the batch in parallel unless its
|
|
`TOKENIZERS_PARALLELISM` environment variable disables parallelism.
|
|
- Conversion rejects a request that mixes strict and non-strict tools, and a
|
|
request that sets a response format together with strict tools, unless the
|
|
tool choice is `none`.
|
|
- With token input, the stream processor decodes each special token as its own
|
|
piece. Output parsing matches the thinking end token (`</think>` by default)
|
|
and the DSML token within DSML tags only against decoded special tokens; the
|
|
same text spelled with plain tokens is content. The log probabilities of
|
|
these special tokens are reported with the marker rather than with the
|
|
surrounding content. Text chunks still match markers by spelling.
|
|
- The Python distribution takes its version from the Cargo package, so
|
|
`deepseek_recipe.__version__` matches the installed distribution.
|
|
|
|
### Removed
|
|
|
|
- `InferenceChunk::Token`. Send one `InferenceChunk::Tokens` chunk instead.
|
|
- The `arguments` field of `OutputChunk::ToolCall`, now `ToolCallNamed`.
|
|
Arguments arrive in `ToolCallArgumentsDelta` chunks.
|
|
- The `util` modules of `deepseek-recipe` and `deepseek-recipe-core`, and the
|
|
public `state_machine` module and `StreamDecoder` type of `deepseek-recipe`.
|
|
Output parsing and token decoding are internal to `StreamProcessor`;
|
|
`ParsingOptions` and `ThinkingInitialStage` remain public in `stream`.
|
|
- The per-protocol reasoning effort and thinking type enums, replaced by
|
|
`RequestReasoningEffort` and `ThinkingType`.
|
|
- `MessagesContentBlock::ToolReference`. A Messages request can contain a tool
|
|
reference only in `tool_result.content` or `tool_addition.tool`.
|
|
- Public constructors of `ChatCompletionChunkGenerator` and
|
|
`ResponsesChunkGenerator`. Use `ProtocolRequest::chunk_generator` with a
|
|
converted request. Python: use the request type's `chunk_generator` method.
|
|
- `ChatCompletionRequest::include_usage`,
|
|
`ChatCompletionChunkGenerator::with_include_usage`,
|
|
`ResponsesRequest::custom_tool_names`, and
|
|
`ResponsesChunkGenerator::with_custom_tool_names`, including their Python
|
|
equivalents.
|
|
- `InferenceOptions::thinking_budget_tokens` and
|
|
`InferenceOptions::disable_parallel_tool_use`. Conversion accepts and ignores
|
|
Messages `thinking.budget_tokens` and `disable_parallel_tool_use` and Chat
|
|
Completions `parallel_tool_calls`, as the DeepSeek API does. Python: the
|
|
`thinking_budget_tokens` and `disable_parallel_tool_use` properties of
|
|
`InferenceOptions`.
|
|
- Python: `InferenceChunk.token()` and `InferenceChunk.token_id`.
|
|
|
|
### Migrating from 0.1
|
|
|
|
#### Rust
|
|
|
|
| 0.1 | 0.2 |
|
|
| --- | --- |
|
|
| `ConversationRequest::new(conversation)` | `ConversationRequest::new(conversation, model_version)` |
|
|
| `ConversationRequest::model` | `ConversationRequest::model_version`; the model name stays on the protocol request |
|
|
| `ChatCompletionChunkGenerator::new(...)`, `ResponsesChunkGenerator::new(...)` | `ChatCompletionRequest::chunk_generator(&converted, id, model)`, `ResponsesRequest::chunk_generator(&converted, id, model)` |
|
|
| `ConversionError::into_response` | `ConversionError::into_error_response` |
|
|
| `StreamProcessor::process` | `StreamProcessor::into_protocol_stream` |
|
|
| `TokenizerDecoder` | `StreamTokenizer` |
|
|
| `InferenceChunk::Text { content, content_tokens }` | `InferenceChunk::Text { content, token_count }` |
|
|
| `InferenceChunk::Token { token_id }` | `InferenceChunk::Tokens { token_ids: vec![token_id], logprobs: None }` |
|
|
| `OutputChunk::Start { usage }` | `OutputChunk::Start { prompt_usage }` |
|
|
| `OutputChunk::Raw { content }` | `OutputChunk::Content { content, logprobs }` |
|
|
| `OutputChunk::Reasoning { content }` | `OutputChunk::Reasoning { content, logprobs }` |
|
|
| `OutputChunk::ToolCall { tool_name, arguments }` | `OutputChunk::ToolCallNamed { tool_name }` |
|
|
| `OutputChunk::ToolArgumentsDelta { content }` | `OutputChunk::ToolCallArgumentsDelta { arguments }` |
|
|
| `OutputChunk::Finish { reason, usage, .. }` | `OutputChunk::Finish { finish_reason, completion_usage, .. }` |
|
|
| `ParsingOptions::reasoning_initial_stage: Option<ReasoningStage>` | `ParsingOptions::thinking_initial_stage: Option<ThinkingInitialStage>` |
|
|
| `ParsingOptions::tool_call_initial_stage` | `ParsingOptions::starts_in_tool_calls` |
|
|
| `ReasoningStage::start_from_reasoning` | `ThinkingInitialStage::starts_in_reasoning` |
|
|
| `ReasoningContentBehavior::Ignore` | `ReasoningContentBehavior::FillEmpty` |
|
|
| `WebSearchBehavior::Ignore` | `WebSearchBehavior::Drop` |
|
|
| `util::append_delta::AppendDelta` | `response::Accumulate` |
|
|
| `util::json_formatter` | `deepseek_recipe_core::json` |
|
|
| `ImageTokenSpec::calc_token_len` | `ImageTokenSpec::calc_token_count` |
|
|
| `ImageTokenSpec::max_n_token` | `ImageTokenSpec::max_token_count` |
|
|
| `MessagesReasoningEffort`, `ChatCompletionReasoningEffort`, `ResponsesReasoningEffort` | `RequestReasoningEffort` |
|
|
| `MessagesThinkingType`, `ChatCompletionThinkingType` | `ThinkingType` |
|
|
| `MessagesTextOrTextBlocks`, `MessagesTextBlock` | `MessagesSystemContent`, `MessagesSystemBlock` |
|
|
| `MessagesTool { name, description, input_schema, kind }` | `MessagesTool::Client { name, description, input_schema, defer_loading }`, `MessagesTool::Server(MessagesServerTool)` |
|
|
| `MessagesResponseContent`, `MessagesDelta`, `MessagesStopInfo` | `MessagesResponseContentBlock`, `MessagesContentBlockDelta`, `MessagesMessageDelta` |
|
|
| `ChatCompletionToolChoiceMode`, `ChatCompletionNamedToolChoice` | variants of `ChatCompletionToolChoiceOption` |
|
|
| `ResponsesToolChoiceMode` | variants of `ResponsesToolChoice` |
|
|
|
|
#### Python
|
|
|
|
| 0.1 | 0.2 |
|
|
| --- | --- |
|
|
| `ConversationRequest(conversation)` | `ConversationRequest(conversation, model_version)` |
|
|
| `ConversationRequest.model` | `ConversationRequest.model_version`; read the name from the protocol request's `model` before `convert` |
|
|
| `ChatCompletionChunkGenerator(...)`, `ResponsesChunkGenerator(...)` | `ChatCompletionRequest.chunk_generator(converted, id, model)`, `ResponsesRequest.chunk_generator(converted, id, model)` |
|
|
| `*Response.append(chunk)` | `*Response.accumulate(chunk)` |
|
|
| `*Response.chunk_event_type(chunk)` | `*Response.sse_event_name(chunk)` |
|
|
| `*Response.done_message()` | `*Response.sse_done_data()` |
|
|
| `InferenceChunk.text(text, content_tokens)` | `InferenceChunk.text(content, token_count)` |
|
|
| `InferenceChunk.content_tokens` | `InferenceChunk.token_count` |
|
|
| `InferenceChunk.token(token_id)` | `InferenceChunk.tokens([token_id])` |
|
|
| `ReasoningStage` | `ThinkingInitialStage` |
|
|
| `ReasoningStage.start_from_reasoning` | `ThinkingInitialStage.starts_in_reasoning` |
|
|
| model version strings such as `"DeepSeek-V4-Pro"` | `ModelVersion.DeepseekV4Pro`, `ModelVersion.DeepseekV41Flash` |
|
|
|
|
## 0.1.0 - 2026-09-10
|
|
|
|
Initial release: conversion of Messages, Chat Completions, and Responses
|
|
requests into a shared conversation, DeepSeek V4 and V4.1 prompt rendering,
|
|
image fetching and preprocessing, streaming output parsing into protocol
|
|
responses, and the `deepseek-recipe` Python distribution.
|