diff --git a/aimux-providers/layout.toml b/aimux-providers/layout.toml index 6db6d45f2..5d4ed92a1 100644 --- a/aimux-providers/layout.toml +++ b/aimux-providers/layout.toml @@ -925,3 +925,125 @@ status = "mapped" upstream = "src/version.ts" status = "not-applicable" reason = "the crate version is used instead (RFC-0046 §4.2)" + +[deepseek] +package = "@ai-sdk/deepseek" + +[[deepseek.files]] +upstream = "src/chat/convert-to-deepseek-chat-messages.ts" +rust = "deepseek/convert.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/chat/convert-to-deepseek-usage.ts" +rust = "deepseek/usage.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/chat/deepseek-chat-api-types.ts" +rust = "deepseek/types.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/chat/deepseek-chat-language-model-options.ts" +rust = "deepseek/options.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/chat/deepseek-chat-language-model.ts" +rust = "deepseek/model.rs" +status = "mapped" + +[deepseek.files.tests] +ts-only = [ + { case = "DeepSeekChatLanguageModel › doGenerate › tool call › json response format with structured outputs › should send json_schema response format and skip schema injection", reason = "unreachable through the provider: because the provider never sets supportsStructuredOutputs (deepseek-provider.ts:88-97); the case needs a model built directly" }, + { case = "DeepSeekChatLanguageModel › doGenerate › tool call › json response format with structured outputs › should honor strictJsonSchema provider option", reason = "unreachable through the provider: because the provider never sets supportsStructuredOutputs (deepseek-provider.ts:88-97); the case needs a model built directly" }, + { case = "DeepSeekChatLanguageModel › doGenerate › tool call › json response format with structured outputs › should fall back to json_object without a schema", reason = "unreachable through the provider: because the provider never sets supportsStructuredOutputs (deepseek-provider.ts:88-97); the case needs a model built directly" }, +] + +[[deepseek.files]] +upstream = "src/chat/deepseek-file-part-options.ts" +rust = "deepseek/options.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/chat/deepseek-prepare-tools.ts" +rust = "deepseek/prepare_tools.rs" +status = "mapped" + +[deepseek.files.tests] +ts-only = [ + { case = "prepareTools › should pass through strict mode for multiple tools with different strict settings", reason = "needs supportsStrictToolCalls undefined, which only a directly built model has; the provider always sets it from the base URL (deepseek-provider.ts:95), as aimux does" }, +] + +[[deepseek.files]] +upstream = "src/chat/get-response-metadata.ts" +rust = "deepseek/model.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/chat/is-deepseek-v4-model.ts" +rust = "deepseek/is_v4_model.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/chat/map-deepseek-finish-reason.ts" +rust = "deepseek/finish_reason.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/deepseek-provider.ts" +rust = "deepseek/mod.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/index.ts" +rust = "deepseek/mod.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/internal/index.ts" +rust = "deepseek/mod.rs" +status = "mapped" + +[deepseek.files.tests] + +[[deepseek.files]] +upstream = "src/files/deepseek-files-api.ts" +status = "missing" +issue = 275 + +[[deepseek.files]] +upstream = "src/files/deepseek-files-options.ts" +status = "missing" +issue = 275 + +[[deepseek.files]] +upstream = "src/files/deepseek-files.ts" +status = "missing" +issue = 275 + +[[deepseek.files]] +upstream = "src/version.ts" +status = "not-applicable" +reason = "the crate version is used instead (RFC-0046 §4.2)" diff --git a/aimux-providers/src/deepseek/mod.rs b/aimux-providers/src/deepseek/mod.rs index eadd66868..4e6cb536f 100644 --- a/aimux-providers/src/deepseek/mod.rs +++ b/aimux-providers/src/deepseek/mod.rs @@ -191,3 +191,6 @@ impl ProviderDiscovery for DeepSeekProvider { }) } } + +#[cfg(test)] +mod tests; diff --git a/aimux-providers/src/deepseek/tests/chat/chat_language_model.rs b/aimux-providers/src/deepseek/tests/chat/chat_language_model.rs new file mode 100644 index 000000000..2557dc2eb --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/chat_language_model.rs @@ -0,0 +1,316 @@ +//! Ports of `src/chat/deepseek-chat-language-model.test.ts` from `@ai-sdk/deepseek@3.0.56`: +//! the snapshot cases of `doGenerate` (`text`, `reasoning`, `tool call`, and +//! `tool call › json response format`) and of `doStream` (`text`, `reasoning`, +//! `tool call`). +//! +//! Harness differences from the TypeScript (expectations are unchanged): +//! - `toMatchSnapshot()` values are the `.snap` entries in `snapshots/`, as JSON: +//! `undefined` properties are absent (as `JSON.stringify` drops them) and the +//! `Date` timestamps are ISO strings. The result, or each stream part, is +//! serialized and compared as a `serde_json::Value`. +//! - The `prepare*FixtureResponse` helpers are the `fixtures/` files, served by +//! [`MockFetch`]. The TypeScript test server adds `content-length` to JSON +//! responses and `cache-control` / `connection` to event streams; the mock does +//! the same. +//! - A `stream-chunks` response is one `data:` frame per line of the +//! `.chunks.txt` fixture, then `data: [DONE]`. Blank lines carry no frame and +//! are skipped. +//! +//! Not ported: `json response format with structured outputs` (three cases: +//! `should send json_schema response format and skip schema injection`, +//! `should honor strictJsonSchema provider option` and `should fall back to +//! json_object without a schema`). The upstream builds that model directly with +//! `supportsStructuredOutputs: true`. The public API has no such setting: +//! `create_deepseek(..).chat(..)` only turns on the beta-endpoint flags, and the +//! chat model never sends a `json_schema` response format. + +use std::sync::Arc; + +use crate::deepseek::{DeepSeekProvider, DeepSeekProviderSettings, create_deepseek}; +use aimux_core::language_model::LanguageModel; +use aimux_core::language_model_message::LanguageModelMessage; +use aimux_core::options::{CallOptions, ResponseFormat}; +use aimux_core::result::StreamResult; +use aimux_core::tool::{FunctionTool, Tool}; +use futures::StreamExt; +use serde_json::{Value, json}; + +use crate::test_support::mock_fetch::{Canned, MockFetch}; + +const TEXT_FIXTURE: &str = include_str!("fixtures/deepseek-text.json"); +const REASONING_FIXTURE: &str = include_str!("fixtures/deepseek-reasoning.json"); +const JSON_FIXTURE: &str = include_str!("fixtures/deepseek-json.json"); +const TOOL_CALL_FIXTURE: &str = include_str!("fixtures/deepseek-tool-call.json"); +const TEXT_CHUNKS: &str = include_str!("fixtures/deepseek-text.chunks.txt"); +const REASONING_CHUNKS: &str = include_str!("fixtures/deepseek-reasoning.chunks.txt"); +const TOOL_CALL_CHUNKS: &str = include_str!("fixtures/deepseek-tool-call.chunks.txt"); + +const SNAPSHOT_DO_GENERATE_TEXT: &str = include_str!("snapshots/do_generate_text.json"); +const SNAPSHOT_DO_GENERATE_REASONING: &str = include_str!("snapshots/do_generate_reasoning.json"); +const SNAPSHOT_DO_GENERATE_JSON_RESPONSE_FORMAT: &str = + include_str!("snapshots/do_generate_json_response_format.json"); +const SNAPSHOT_DO_GENERATE_TOOL_CALL: &str = include_str!("snapshots/do_generate_tool_call.json"); +const SNAPSHOT_DO_STREAM_TEXT: &str = include_str!("snapshots/do_stream_text.json"); +const SNAPSHOT_DO_STREAM_REASONING: &str = include_str!("snapshots/do_stream_reasoning.json"); +const SNAPSHOT_DO_STREAM_TOOL_CALL: &str = include_str!("snapshots/do_stream_tool_call.json"); + +// ── helpers ───────────────────────────────────────────────────────────────── + +fn json_value(source: &str) -> Value { + serde_json::from_str(source).expect("fixture or snapshot is JSON") +} + +/// `createDeepSeek({ apiKey })` with a mock transport. +fn provider(fetch: &Arc) -> DeepSeekProvider { + create_deepseek(DeepSeekProviderSettings { + api_key: Some("test-api-key".into()), + fetch: Some(fetch.transport()), + ..Default::default() + }) + .unwrap() +} + +/// `prompt: TEST_PROMPT`. +fn options() -> CallOptions { + CallOptions::new(vec![LanguageModelMessage::user_text("Hello")]) +} + +fn weather_tool() -> Tool { + Tool::Function(FunctionTool::new( + "weather", + json!({ + "type": "object", + "properties": { "location": { "type": "string" } }, + "required": ["location"], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + }), + )) +} + +/// The `tools: [weather]` and `providerOptions.deepseek.thinking: enabled` of +/// the upstream tool-call cases. +fn tool_options() -> CallOptions { + let mut call = options(); + call.tools = Some(vec![weather_tool()]); + call.provider_options = Some( + serde_json::from_value(json!({ "deepseek": { "thinking": { "type": "enabled" } } })) + .unwrap(), + ); + call +} + +/// `responseFormat: { type: 'json' }` (no schema) on top of [`tool_options`]. +fn json_options() -> CallOptions { + let mut call = tool_options(); + call.response_format = Some(ResponseFormat::Json { + schema: None, + name: None, + description: None, + }); + call +} + +/// A non-streaming response with the headers the TypeScript test server sends. +fn json_response(body: &Value) -> Canned { + let bytes = serde_json::to_vec(body).expect("serializable"); + Canned { + status: 200, + headers: vec![ + ("content-type".to_string(), "application/json".to_string()), + ("content-length".to_string(), bytes.len().to_string()), + ], + body: bytes, + } +} + +/// A single-response mock for a JSON body. +fn json_fetch(body: &Value) -> Arc { + MockFetch::new(vec![json_response(body)]) +} + +/// A single event-stream mock: one `data:` frame per payload, then `[DONE]`. +fn stream_fetch(payloads: &[String]) -> Arc { + let mut body: String = payloads + .iter() + .map(|payload| format!("data: {payload}\n\n")) + .collect(); + body.push_str("data: [DONE]\n\n"); + MockFetch::new(vec![Canned { + status: 200, + headers: vec![ + ("content-type".to_string(), "text/event-stream".to_string()), + ("cache-control".to_string(), "no-cache".to_string()), + ("connection".to_string(), "keep-alive".to_string()), + ], + body: body.into_bytes(), + }]) +} + +/// A `stream-chunks` mock from a `.chunks.txt` fixture: one frame per non-blank line. +fn chunks_fetch(source: &str) -> Arc { + let payloads: Vec = source + .lines() + .filter(|line| !line.trim().is_empty()) + .map(str::to_string) + .collect(); + stream_fetch(&payloads) +} + +/// All parts of a stream, each serialized as the AI SDK writes it. +async fn stream_parts(result: StreamResult) -> Value { + Value::Array( + result + .stream + .map(|part| serde_json::to_value(part.expect("stream part")).unwrap()) + .collect() + .await, + ) +} + +// ── doGenerate and doStream ──────────────────────────────────────────────── + +mod deep_seek_chat_language_model { + use super::*; + + mod do_generate { + use super::*; + + mod text { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should extract text content + #[tokio::test] + async fn should_extract_text_content() { + let fetch = json_fetch(&json_value(TEXT_FIXTURE)); + let result = provider(&fetch) + .chat("deepseek-chat") + .do_generate(&options()) + .await + .unwrap(); + assert_eq!( + serde_json::to_value(&result).unwrap(), + json_value(SNAPSHOT_DO_GENERATE_TEXT) + ); + } + } + + mod reasoning { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › reasoning › should extract text content + #[tokio::test] + async fn should_extract_text_content() { + let fetch = json_fetch(&json_value(REASONING_FIXTURE)); + let result = provider(&fetch) + .chat("deepseek-chat") + .do_generate(&options()) + .await + .unwrap(); + assert_eq!( + serde_json::to_value(&result).unwrap(), + json_value(SNAPSHOT_DO_GENERATE_REASONING) + ); + } + } + + mod tool_call { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › tool call › should extract tool call content + #[tokio::test] + async fn should_extract_tool_call_content() { + let fetch = json_fetch(&json_value(TOOL_CALL_FIXTURE)); + let result = provider(&fetch) + .chat("deepseek-reasoner") + .do_generate(&tool_options()) + .await + .unwrap(); + assert_eq!( + serde_json::to_value(&result).unwrap(), + json_value(SNAPSHOT_DO_GENERATE_TOOL_CALL) + ); + } + + mod json_response_format { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › tool call › json response format › should extract text content + #[tokio::test] + async fn should_extract_text_content() { + let fetch = json_fetch(&json_value(JSON_FIXTURE)); + let result = provider(&fetch) + .chat("deepseek-reasoner") + .do_generate(&json_options()) + .await + .unwrap(); + assert_eq!( + serde_json::to_value(&result).unwrap(), + json_value(SNAPSHOT_DO_GENERATE_JSON_RESPONSE_FORMAT) + ); + } + } + } + } + + mod do_stream { + use super::*; + + mod text { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should stream text + #[tokio::test] + async fn should_stream_text() { + let fetch = chunks_fetch(TEXT_CHUNKS); + let result = provider(&fetch) + .chat("deepseek-chat") + .do_stream(&options()) + .await + .unwrap(); + assert_eq!( + stream_parts(result).await, + json_value(SNAPSHOT_DO_STREAM_TEXT) + ); + } + } + + mod reasoning { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › reasoning › should stream reasoning + #[tokio::test] + async fn should_stream_reasoning() { + let fetch = chunks_fetch(REASONING_CHUNKS); + let result = provider(&fetch) + .chat("deepseek-reasoning") + .do_stream(&options()) + .await + .unwrap(); + assert_eq!( + stream_parts(result).await, + json_value(SNAPSHOT_DO_STREAM_REASONING) + ); + } + } + + mod tool_call { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › tool call › should stream tool call + #[tokio::test] + async fn should_stream_tool_call() { + let fetch = chunks_fetch(TOOL_CALL_CHUNKS); + let result = provider(&fetch) + .chat("deepseek-reasoner") + .do_stream(&tool_options()) + .await + .unwrap(); + assert_eq!( + stream_parts(result).await, + json_value(SNAPSHOT_DO_STREAM_TOOL_CALL) + ); + } + } + } +} diff --git a/aimux-providers/src/deepseek/tests/chat/convert_to_chat_messages.rs b/aimux-providers/src/deepseek/tests/chat/convert_to_chat_messages.rs new file mode 100644 index 000000000..6c65e9dba --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/convert_to_chat_messages.rs @@ -0,0 +1,320 @@ +//! Port of `src/chat/convert-to-deepseek-chat-messages.test.ts` +//! (`@ai-sdk/deepseek` 3.0.56): the six cases of "message names", "tool calls" +//! and "assistant prefix completion" that the other cases of this file do not +//! already cover. +//! +//! Upstream writes prompts as object literals. Here they are JSON, read through +//! the request path's own serde shapes. The one `Uint8Array` payload is built as +//! `FileBytes::Binary` directly: JSON can only carry base64, which parses to the +//! other variant. + +use aimux_core::error::AiMuxError; +use aimux_core::language_model_message::{ + FilePart, LanguageModelMessage, LanguageModelPrompt, ToolPart, ToolResultContent, + ToolResultOutput, ToolResultPart, +}; +use aimux_core::shared::{FileBytes, FileData}; +use serde_json::{Value, json}; + +use crate::deepseek::convert::convert_to_deepseek_chat_messages; + +/// A prompt, read as the request path reads it. +fn prompt_from(value: Value) -> LanguageModelPrompt { + serde_json::from_value(value).expect("the prompt literal is valid") +} + +/// A tool-result content part, read as the request path reads it. +fn tool_result_content(value: Value) -> ToolResultContent { + serde_json::from_value(value).expect("the tool result content literal is valid") +} + +mod convert_to_deep_seek_chat_messages { + use super::*; + + mod message_names { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › message names › should serialize names for system, user, and assistant messages + #[test] + fn should_serialize_names_for_system_user_and_assistant_messages() { + let prompt = prompt_from(json!([ + { + "role": "system", + "content": "You are a helpful assistant.", + "providerOptions": { "deepseek": { "name": "guide" } }, + }, + { + "role": "user", + "content": [ + { "type": "text", "text": "Describe this image." }, + { + "type": "file", + "data": { "type": "url", "url": "https://example.com/image.png" }, + "mediaType": "image/png", + }, + ], + "providerOptions": { "deepseek": { "name": "alice" } }, + }, + { + "role": "assistant", + "content": [ + { "type": "text", "text": "I will inspect it." }, + { + "type": "tool-call", + "toolCallId": "call-1", + "toolName": "inspectImage", + "input": { "detail": "high" }, + }, + ], + "providerOptions": { "deepseek": { "name": "vision_assistant" } }, + }, + ])); + + let result = convert_to_deepseek_chat_messages( + &prompt, + None, + "deepseek-v4-flash-vision-exp", + "deepseek", + false, + ) + .expect("the prompt converts"); + + assert_eq!( + Value::Array(result.messages), + json!([ + { + "role": "system", + "content": "You are a helpful assistant.", + "name": "guide", + }, + { + "role": "user", + "content": [ + { "type": "text", "text": "Describe this image." }, + { + "type": "image_url", + "image_url": { "url": "https://example.com/image.png" }, + }, + ], + "name": "alice", + }, + { + "role": "assistant", + "content": "I will inspect it.", + "name": "vision_assistant", + // V4 requires the field on every assistant turn. + "reasoning_content": "", + "tool_calls": [ + { + "id": "call-1", + "type": "function", + "function": { + "name": "inspectImage", + "arguments": "{\"detail\":\"high\"}", + }, + }, + ], + }, + ]) + ); + assert!(result.warnings.is_empty()); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › message names › should serialize a name from a custom provider options namespace + #[test] + fn should_serialize_a_name_from_a_custom_provider_options_namespace() { + let prompt = prompt_from(json!([{ + "role": "user", + "content": [{ "type": "text", "text": "Hello" }], + "providerOptions": { "azure": { "name": "alice" } }, + }])); + + let result = + convert_to_deepseek_chat_messages(&prompt, None, "deepseek-chat", "azure", false) + .expect("the prompt converts"); + + assert_eq!( + Value::Array(result.messages), + json!([{ "role": "user", "content": "Hello", "name": "alice" }]) + ); + } + } + + mod tool_calls { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › tool calls › should convert inline, URL, and referenced images in tool results to content parts + #[test] + fn should_convert_inline_url_and_referenced_images_in_tool_results_to_content_parts() { + let inline_png = ToolResultContent::File(FilePart { + data: FileData::Data { + data: FileBytes::Binary(vec![0, 1, 2, 3]), + }, + media_type: "image/png".to_string(), + filename: None, + provider_options: None, + }); + let prompt = vec![LanguageModelMessage::Tool { + content: vec![ToolPart::ToolResult(ToolResultPart { + tool_call_id: "call-1".to_string(), + tool_name: "inspectImage".to_string(), + output: ToolResultOutput::Content { + value: vec![ + tool_result_content( + json!({ "type": "text", "text": "Screenshot captured." }), + ), + inline_png, + tool_result_content(json!({ + "type": "file", + "data": { "type": "url", "url": "https://example.com/image.webp" }, + "mediaType": "image/webp", + "providerOptions": { "deepseek": { "imageDetail": "low" } }, + })), + tool_result_content(json!({ + "type": "file", + "data": { + "type": "reference", + "reference": { + "deepseek": "file-api-deepseek", + "openai": "file-openai", + }, + }, + "mediaType": "image/png", + })), + ], + }, + provider_options: None, + })], + provider_options: None, + }]; + + let result = convert_to_deepseek_chat_messages( + &prompt, + None, + "deepseek-flash", + "deepseek", + false, + ) + .expect("the prompt converts"); + + assert_eq!( + Value::Array(result.messages), + json!([{ + "role": "tool", + "tool_call_id": "call-1", + "content": [ + { "type": "text", "text": "Screenshot captured." }, + { + "type": "image_url", + "image_url": { "url": "data:image/png;base64,AAECAw==" }, + }, + { + "type": "image_url", + "image_url": { + "url": "https://example.com/image.webp", + "detail": "low", + }, + }, + { "type": "file", "file_id": "file-api-deepseek" }, + ], + }]) + ); + assert!(result.warnings.is_empty()); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › tool calls › should keep tool result content without images JSON-stringified + #[test] + fn should_keep_tool_result_content_without_images_json_stringified() { + let prompt = prompt_from(json!([{ + "role": "tool", + "content": [{ + "type": "tool-result", + "toolCallId": "call-1", + "toolName": "getWeather", + "output": { + "type": "content", + "value": [{ "type": "text", "text": "It is sunny today" }], + }, + }], + }])); + + let result = convert_to_deepseek_chat_messages( + &prompt, + None, + "deepseek-chat", + "deepseek", + false, + ) + .expect("the prompt converts"); + + assert_eq!( + Value::Array(result.messages), + json!([{ + "role": "tool", + "tool_call_id": "call-1", + "content": "[{\"type\":\"text\",\"text\":\"It is sunny today\"}]", + }]) + ); + } + } + + mod assistant_prefix_completion { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › assistant prefix completion › should serialize prefix true on the final assistant message + #[test] + fn should_serialize_prefix_true_on_the_final_assistant_message() { + let prompt = prompt_from(json!([ + { + "role": "user", + "content": [{ "type": "text", "text": "Complete this sentence." }], + }, + { + "role": "assistant", + "content": [{ "type": "text", "text": "The answer is" }], + "providerOptions": { "deepseek": { "prefix": true } }, + }, + ])); + + let result = + convert_to_deepseek_chat_messages(&prompt, None, "deepseek-chat", "deepseek", true) + .expect("the prompt converts"); + + // Upstream's `reasoning_content` and `tool_calls` are undefined, so + // they are absent from the JSON. + assert_eq!( + Value::Array(result.messages), + json!([ + { "role": "user", "content": "Complete this sentence." }, + { "role": "assistant", "content": "The answer is", "prefix": true }, + ]) + ); + assert!(result.warnings.is_empty()); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › assistant prefix completion › should reject prefix completion without a beta base URL capability + #[test] + fn should_reject_prefix_completion_without_a_beta_base_url_capability() { + let prompt = prompt_from(json!([{ + "role": "assistant", + "content": [{ "type": "text", "text": "The answer is" }], + "providerOptions": { "deepseek": { "prefix": true } }, + }])); + + let error = convert_to_deepseek_chat_messages( + &prompt, + None, + "deepseek-chat", + "deepseek", + false, + ) + .err() + .expect("prefix completion is rejected without the beta endpoint"); + + assert!( + matches!(error, AiMuxError::UnsupportedFunctionality(_)), + "{error}" + ); + } + } +} diff --git a/aimux-providers/src/deepseek/tests/chat/convert_to_usage.rs b/aimux-providers/src/deepseek/tests/chat/convert_to_usage.rs new file mode 100644 index 000000000..5ea2b34dd --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/convert_to_usage.rs @@ -0,0 +1,36 @@ +//! Port of `src/chat/convert-to-deepseek-usage.test.ts` (`@ai-sdk/deepseek` 3.0.56). + +use serde_json::{Value, json}; + +use crate::deepseek::usage::convert_deepseek_usage; + +mod convert_deep_seek_usage { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-usage.test.ts › convertDeepSeekUsage › clamps text tokens at 0 when reasoning exceeds completion + #[test] + fn clamps_text_tokens_at_0_when_reasoning_exceeds_completion() { + let usage: Value = json!({ + "prompt_tokens": 951, + "completion_tokens": 6000, + "completion_tokens_details": { "reasoning_tokens": 6001 }, + }); + + let converted = + serde_json::to_value(convert_deepseek_usage(Some(&usage))).expect("usage serializes"); + + // `cacheWrite` is undefined upstream, so it is absent from the JSON. + assert_eq!( + converted, + json!({ + "inputTokens": { + "total": 951, + "noCache": 951, + "cacheRead": 0, + }, + "outputTokens": { "total": 6000, "text": 0, "reasoning": 6001 }, + "raw": usage, + }) + ); + } +} diff --git a/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-json.json b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-json.json new file mode 100644 index 000000000..e756ef37e --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-json.json @@ -0,0 +1,32 @@ +{ + "id": "f03bc170-b375-4561-9685-35182c8152c5", + "object": "chat.completion", + "created": 1764681341, + "model": "deepseek-reasoner", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "{\n \"location\": \"San Francisco\",\n \"condition\": \"cloudy\",\n \"temperature\": 7\n}", + "reasoning_content": "I have the result from the weather tool. It returned a JSON object with location, condition, and temperature. I need to reply with JSON object ONLY. The assistant's response should be the JSON output. So I should output exactly that JSON? Or perhaps wrap it in some way? The instruction says \"Reply with JSON object ONLY.\" Probably I should output the result as is, or maybe a structured response. But the tool result is already JSON. I think I should output that JSON directly. However, I need to ensure it's a valid response. Let me output the JSON object." + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 495, + "completion_tokens": 144, + "total_tokens": 639, + "prompt_tokens_details": { + "cached_tokens": 320 + }, + "completion_tokens_details": { + "reasoning_tokens": 118 + }, + "prompt_cache_hit_tokens": 320, + "prompt_cache_miss_tokens": 175 + }, + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" +} diff --git a/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-reasoning.chunks.txt b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-reasoning.chunks.txt new file mode 100644 index 000000000..59d80eba2 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-reasoning.chunks.txt @@ -0,0 +1,220 @@ +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"role":"assistant","content":null,"reasoning_content":""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"We"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" need"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" count"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" number"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" letter"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" in"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" word"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"st"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"raw"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"berry"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" word"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" spelled"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-t"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-w"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-b"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-e"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-y"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" Let"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"'s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" list"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" letters"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" count"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"Position"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"1"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"2"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" t"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"3"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" ("},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"first"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":")\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"4"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"5"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" w"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"6"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" b"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"7"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" e"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"8"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" ("},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"second"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":")\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"9"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" ("},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"third"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":")\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"10"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" y"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"So"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" there"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" are"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" three"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" But"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" wait"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" let"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"'s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" double"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"-check"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"st"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"raw"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"berry"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" indeed"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" has"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" three"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" one"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" after"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"t"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" then"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" two"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" consecutive"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" before"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"y"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" So"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" answer"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"3"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":".\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" question"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" straightforward"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" However"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" sometimes"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" people"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" might"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" misc"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"ount"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" Let"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"'s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" ensure"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" word"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" has"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"10"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" letters"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"r"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" are"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" at"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" positions"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"3"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"8"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"9"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" So"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" yes"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"3"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":".\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"Thus"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" answer"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"3"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"The","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" word","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" \"","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"st","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"raw","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"berry","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"\"","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" contains","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" three","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" \"","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"r","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"\"s","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":".","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cac7192e-e619-40c6-96b0-ed4276bc03ac","object":"chat.completion.chunk","created":1764661832,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"","reasoning_content":null},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":18,"completion_tokens":219,"total_tokens":237,"prompt_tokens_details":{"cached_tokens":0},"completion_tokens_details":{"reasoning_tokens":205},"prompt_cache_hit_tokens":0,"prompt_cache_miss_tokens":18}} \ No newline at end of file diff --git a/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-reasoning.json b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-reasoning.json new file mode 100644 index 000000000..3c78da546 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-reasoning.json @@ -0,0 +1,32 @@ +{ + "id": "945bb10c-9bf3-47ff-a2a2-43bbe9705c72", + "object": "chat.completion", + "created": 1764660903, + "model": "deepseek-reasoner", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The word \"strawberry\" contains three instances of the letter \"r\": one after the \"t\" and two before the \"y\".", + "reasoning_content": "We are asked: \"How many 'r's are in the word 'strawberry'?\" We need to count the occurrences of the letter 'r' in the word \"strawberry\". Let's write the word: s-t-r-a-w-b-e-r-r-y. Let's count: positions: 1: s, 2: t, 3: r, 4: a, 5: w, 6: b, 7: e, 8: r, 9: r, 10: y. So there are three 'r's? Wait: at position 3: r, position 8: r, position 9: r. That's three. But sometimes people might think it's two because of pronunciation? But strictly counting letters, it's three. However, let's double-check spelling: \"strawberry\" is spelled S-T-R-A-W-B-E-R-R-Y. Yes, it has two 'r's at the end? Actually, after 'b' comes 'e', then 'r', then 'r', then 'y'. So indeed three 'r's total. But wait, the initial 'r' is the first one? The word starts with 's', then 't', then 'r'. So that's one, then later two consecutive 'r's. So total three. So answer is 3.\n\nBut the question is phrased: \"How many 'r's are in the word 'strawberry'?\" So answer is 3." + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 18, + "completion_tokens": 345, + "total_tokens": 363, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 315 + }, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 18 + }, + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" +} diff --git a/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-text.chunks.txt b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-text.chunks.txt new file mode 100644 index 000000000..9e4af4a2c --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-text.chunks.txt @@ -0,0 +1,402 @@ +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"##"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" **"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"H"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"olid"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ay"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Name"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":":**"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" St"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"arl"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ight"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Rem"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"embrance"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"Date"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":":**"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Saturday"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" nearest"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" new"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" moon"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" October"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" when"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" night"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" sky"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" at"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" its"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" darkest"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" stars"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" are"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" most"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" vivid"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":".\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"Origin"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" &"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Meaning"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"St"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"arl"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ight"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Rem"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"embrance"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" emerged"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" from"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" modern"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" collective"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" yearning"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" honor"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" personal"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" loss"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" while"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" celebrating"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" enduring"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" connections"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" that"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" transcend"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" it"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" It"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" not"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" tied"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" any"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" one"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" religion"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" culture"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" but"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" universal"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" human"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" experience"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" core"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" philosophy"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" that"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" people"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" we"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" love"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" ideas"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" that"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" inspired"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" us"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" even"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" versions"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" ourselves"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" that"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" are"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" gone"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" are"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" not"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" vanished"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" but"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" have"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" become"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" part"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" universe"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"'s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" fabric"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"—"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"like"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" st"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ard"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ust"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" holiday"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" asks"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" participants"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" look"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" up"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" at"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" vast"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" shared"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" sky"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" find"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" comfort"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" both"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" darkness"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" ("},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" loss"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":")"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" enduring"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" points"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" light"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" ("},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" memory"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":").\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"---\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"###"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" **"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"T"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"rad"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"itions"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" &"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Rit"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"uals"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":":**\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"1"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Dim"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ming"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Lights"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"As"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" night"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" falls"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" households"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" communities"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" turn"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" off"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" non"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"-"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"essential"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" electric"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" lights"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Streets"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" are"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" lit"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" only"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" by"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" subtle"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" blue"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"-ton"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ed"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" lantern"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"s"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" ("},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"symbol"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"izing"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" night"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" sky"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":")."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" This"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" collective"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" act"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" reduces"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" light"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" pollution"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" literally"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" metaphor"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ically"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" making"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" space"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" stars"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"—"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" reflection"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":".\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"2"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Craft"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ing"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Constellation"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" J"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ars"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"In"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" days"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" leading"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" up"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" holiday"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" people"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" create"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"Const"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ellation"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" J"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"ars"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":".\""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" They"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" take"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" clear"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" jar"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" using"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" small"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" drill"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" adhesive"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" create"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" pattern"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" holes"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" on"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" its"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" lid"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" representing"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" stars"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" specific"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" constellation"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" On"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" night"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" holiday"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" small"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" battery"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"-operated"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" tea"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" light"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" placed"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" inside"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Each"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" jar"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" dedicated"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" someone"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" something"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" remembered"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" constellation"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" might"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" be"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" their"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" birth"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" sign"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" shape"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" that"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" reminds"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" maker"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" them"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" simply"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" pattern"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" sky"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" on"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" night"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" they"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" passed"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":".\n\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"3"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Silent"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Vig"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"il"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" &"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Story"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" Stars"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"**\n"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"At"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" designated"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" time"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" ("},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"e"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":".g"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":".,"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"9"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" PM"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" local"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" time"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"),"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" people"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" step"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" outside"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" alone"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" quiet"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" groups"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" and"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" observe"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"15"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" minutes"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" silent"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" looking"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":" at"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"f6117a0b-129d-46fa-b239-78f01c2c5df9","object":"chat.completion.chunk","created":1764657993,"model":"deepseek-chat","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":""},"logprobs":null,"finish_reason":"length"}],"usage":{"prompt_tokens":13,"completion_tokens":400,"total_tokens":413,"prompt_tokens_details":{"cached_tokens":0},"prompt_cache_hit_tokens":0,"prompt_cache_miss_tokens":13}} \ No newline at end of file diff --git a/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-text.json b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-text.json new file mode 100644 index 000000000..7763e5596 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-text.json @@ -0,0 +1,28 @@ +{ + "id": "00f10ecd-60b3-4707-b5db-e4bcadf7aea1", + "object": "chat.completion", + "created": 1764656316, + "model": "deepseek-chat", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "## **Holiday Name: Gratitude of Small Things Day (GST Day)**\n\n**Date:** The first Saturday after the Spring Equinox (in the Northern Hemisphere) / the first Saturday after the Autumn Equinox (in the Southern Hemisphere). It is intentionally placed at a time of seasonal transition, encouraging people to pause and appreciate the subtle, often overlooked details of life.\n\n**Core Philosophy:** In a world focused on grand achievements and major events, GST Day celebrates the tiny, mundane, yet profoundly beautiful moments, objects, and sensations that form the quiet fabric of our existence. The motto is: *\"Notice the thread, and you see the tapestry.\"*\n\n---\n\n### **Traditions & Practices:**\n\n**1. The \"Quiet Hour\" & Offering Bowl:**\n The holiday begins at sunrise with a \"Quiet Hour.\" Individuals or households sit in a comfortable space with a small, empty bowl (the \"Offering Bowl\"). In silence, they reflect on the past year, noting not major events, but **small, specific gratitudes**: the sound of rain on a specific afternoon, the warmth of a mug in their hands, the scent of a loved one's laundry detergent, the way light fell through a window. They write each on a tiny slip of paper and place it in the bowl. These are not shared aloud; the act is purely personal and reflective.\n\n**2. The \"Micro-Gift\" Exchange:**\n Instead of lavish presents, people exchange" + }, + "logprobs": null, + "finish_reason": "length" + } + ], + "usage": { + "prompt_tokens": 13, + "completion_tokens": 300, + "total_tokens": 313, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 13 + }, + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" +} diff --git a/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-tool-call.chunks.txt b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-tool-call.chunks.txt new file mode 100644 index 000000000..5f498ee2c --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-tool-call.chunks.txt @@ -0,0 +1,52 @@ +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"role":"assistant","content":null,"reasoning_content":""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"The"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" user"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" is"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" asking"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" for"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" weather"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" in"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" San"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" Francisco"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" I"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" need"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" use"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" weather"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" tool"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" get"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" this"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" information"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" Let"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" me"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" invoke"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" weather"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" tool"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" with"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" the"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" location"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" parameter"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" set"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" to"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" \""},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"San"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":" Francisco"},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"\"."},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_00_ioIn7yN9p1ZOMNpDLwd4MgAF","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{"}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"location"}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":": "}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"San"}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Francisco"}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}"}}]},"logprobs":null,"finish_reason":null}],"usage":null} +{"id":"cca85624-4056-401f-b220-d77601d1f70d","object":"chat.completion.chunk","created":1764664568,"model":"deepseek-reasoner","system_fingerprint":"fp_eaab8d114b_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"","reasoning_content":null},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":339,"completion_tokens":83,"total_tokens":422,"prompt_tokens_details":{"cached_tokens":320},"completion_tokens_details":{"reasoning_tokens":39},"prompt_cache_hit_tokens":320,"prompt_cache_miss_tokens":19}} \ No newline at end of file diff --git a/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-tool-call.json b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-tool-call.json new file mode 100644 index 000000000..d3bc7c919 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/fixtures/deepseek-tool-call.json @@ -0,0 +1,43 @@ +{ + "id": "7a630f5b-b7e6-4878-82f8-d77db164d42b", + "object": "chat.completion", + "created": 1764665845, + "model": "deepseek-reasoner", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "", + "reasoning_content": "The user is asking for the weather in San Francisco. I have a weather tool available that can get weather information for a location. I should use this tool with the location parameter set to \"San Francisco\". Let me call the weather function.", + "tool_calls": [ + { + "index": 0, + "id": "call_00_9V0vrf86Pc9aelHCJMZqnJBo", + "type": "function", + "function": { + "name": "weather", + "arguments": "{\"location\": \"San Francisco\"}" + } + } + ] + }, + "logprobs": null, + "finish_reason": "tool_calls" + } + ], + "usage": { + "prompt_tokens": 339, + "completion_tokens": 92, + "total_tokens": 431, + "prompt_tokens_details": { + "cached_tokens": 320 + }, + "completion_tokens_details": { + "reasoning_tokens": 48 + }, + "prompt_cache_hit_tokens": 320, + "prompt_cache_miss_tokens": 19 + }, + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" +} diff --git a/aimux-providers/src/deepseek/tests/chat/is_v4_model.rs b/aimux-providers/src/deepseek/tests/chat/is_v4_model.rs new file mode 100644 index 000000000..eef84ab64 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/is_v4_model.rs @@ -0,0 +1,34 @@ +//! Port of `src/chat/is-deepseek-v4-model.test.ts` (`@ai-sdk/deepseek` 3.0.56). + +use crate::deepseek::is_v4_model::is_deepseek_v4_model; + +mod is_deep_seek_v4_model { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/is-deepseek-v4-model.test.ts › isDeepSeekV4Model › should treat %s as V4 + #[test] + fn should_treat_as_v4() { + for model_id in [ + "deepseek-v4-pro", + "deepseek-v4-pro-0813", + "deepseek-v4-flash", + "deepseek-v4-flash-0731", + "deepseek-v4-flash-vision-exp", + "deepseek-flash", + "deepseek-pro", + ] { + assert!(is_deepseek_v4_model(model_id), "{model_id} should be V4"); + } + } + + /// upstream: @ai-sdk/deepseek src/chat/is-deepseek-v4-model.test.ts › isDeepSeekV4Model › should not treat legacy %s as V4 + #[test] + fn should_not_treat_legacy_as_v4() { + for model_id in ["deepseek-chat", "deepseek-reasoner"] { + assert!( + !is_deepseek_v4_model(model_id), + "{model_id} should not be V4" + ); + } + } +} diff --git a/aimux-providers/src/deepseek/tests/chat/mod.rs b/aimux-providers/src/deepseek/tests/chat/mod.rs new file mode 100644 index 000000000..545e1e65b --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/mod.rs @@ -0,0 +1,8 @@ +//! Ports of the upstream `src/chat/` tests of `@ai-sdk/deepseek` 3.0.56. + +mod chat_language_model; +mod convert_to_chat_messages; +mod convert_to_usage; +mod is_v4_model; +mod prepare_tools; +mod raw_usage; diff --git a/aimux-providers/src/deepseek/tests/chat/prepare_tools.rs b/aimux-providers/src/deepseek/tests/chat/prepare_tools.rs new file mode 100644 index 000000000..34845fa96 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/prepare_tools.rs @@ -0,0 +1,137 @@ +//! Port of `src/chat/deepseek-prepare-tools.test.ts` (`@ai-sdk/deepseek` 3.0.56). +//! +//! Upstream's `supportsStrictToolCalls` is three-state: `undefined` skips both +//! strict checks. The chat model always passes a boolean derived from the base +//! URL (`baseURL.endsWith('/beta')`), so there is no `undefined` to pass. The +//! upstream case "should pass through strict mode for multiple tools with +//! different strict settings" depends on that state and is not ported (no +//! boolean reproduces it; see the report). + +use aimux_core::tool::Tool; +use serde_json::{Value, json}; + +use crate::deepseek::prepare_tools::prepare_tools; + +/// The tools of a request, read as the request path reads them. +fn tools_from(value: Value) -> Vec { + serde_json::from_value(value).expect("the tools literal is valid") +} + +// The describe level `prepareTools` keeps its name; the file is `prepare_tools.rs`. +#[allow(clippy::module_inception)] +mod prepare_tools { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-prepare-tools.test.ts › prepareTools › should pass through strict mode when strict is true + #[test] + fn should_pass_through_strict_mode_when_strict_is_true() { + let tools = tools_from(json!([{ + "type": "function", + "name": "testFunction", + "description": "A test function", + "inputSchema": { "type": "object", "properties": {} }, + "strict": true, + }])); + + // Upstream passes no endpoint flag. `true` gives the same result here: + // an all-strict request raises neither beta-only rejection. + let result = + prepare_tools(Some(&tools), None, true).expect("all-strict tools are accepted"); + + assert_eq!( + result.tools, + Some(vec![json!({ + "type": "function", + "function": { + "name": "testFunction", + "description": "A test function", + "parameters": { "type": "object", "properties": {} }, + "strict": true, + }, + })]) + ); + assert_eq!(result.tool_choice, None); + assert!(result.tool_warnings.is_empty()); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-prepare-tools.test.ts › prepareTools › should reject strict tools when the endpoint does not support them + #[test] + fn should_reject_strict_tools_when_the_endpoint_does_not_support_them() { + let tools = tools_from(json!([{ + "type": "function", + "name": "strictTool", + "inputSchema": { "type": "object", "properties": {} }, + "strict": true, + }])); + + let error = prepare_tools(Some(&tools), None, false) + .err() + .expect("strict tools are rejected without the beta endpoint"); + + assert!( + error + .to_string() + .contains("DeepSeek strict tool calls require a beta base URL ending in `/beta`."), + "{error}" + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-prepare-tools.test.ts › prepareTools › should reject mixed strict and non-strict tools on the beta endpoint + #[test] + fn should_reject_mixed_strict_and_non_strict_tools_on_the_beta_endpoint() { + let tools = tools_from(json!([ + { + "type": "function", + "name": "strictTool", + "inputSchema": { "type": "object", "properties": {} }, + "strict": true, + }, + { + "type": "function", + "name": "nonStrictTool", + "inputSchema": { "type": "object", "properties": {} }, + }, + ])); + + let error = prepare_tools(Some(&tools), None, true) + .err() + .expect("mixed strictness is rejected on the beta endpoint"); + + assert!( + error.to_string().contains( + "DeepSeek strict mode requires every function tool in the request to set `strict: true`." + ), + "{error}" + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-prepare-tools.test.ts › prepareTools › should accept all-strict tools on the beta endpoint + #[test] + fn should_accept_all_strict_tools_on_the_beta_endpoint() { + let tools = tools_from(json!([ + { + "type": "function", + "name": "firstStrictTool", + "inputSchema": { "type": "object", "properties": {} }, + "strict": true, + }, + { + "type": "function", + "name": "secondStrictTool", + "inputSchema": { "type": "object", "properties": {} }, + "strict": true, + }, + ])); + + let result = prepare_tools(Some(&tools), None, true) + .expect("all-strict tools are accepted on the beta endpoint"); + + let prepared = result.tools.expect("the tools are present"); + assert!( + prepared + .iter() + .all(|tool| tool["function"]["strict"] == json!(true)), + "every tool keeps strict: true" + ); + } +} diff --git a/aimux-providers/src/deepseek/tests/chat/raw_usage.rs b/aimux-providers/src/deepseek/tests/chat/raw_usage.rs new file mode 100644 index 000000000..0302797ad --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/raw_usage.rs @@ -0,0 +1,213 @@ +//! Ports of `src/chat/deepseek-raw-usage.test.ts` from `@ai-sdk/deepseek@3.0.56`: +//! the complete provider usage object is kept as `usage.raw` through +//! `doGenerate` and through the final `doStream` usage event, and the known +//! usage fields are still validated. +//! +//! Harness differences from the TypeScript (expectations are unchanged): +//! - The `cacheWrite: undefined` of the TypeScript `toStrictEqual` is `None` in +//! Rust, and the JSON form of the token counts omits it. The usage counts are +//! therefore compared as JSON, where an absent `cacheWrite` is the `undefined`. +//! - The `it.each` rows are one function that checks each row in turn. +//! - Responses are served by [`MockFetch`]. + +use std::sync::Arc; + +use crate::deepseek::{DeepSeekProvider, DeepSeekProviderSettings, create_deepseek}; +use aimux_core::language_model::LanguageModel; +use aimux_core::language_model_message::LanguageModelMessage; +use aimux_core::options::CallOptions; +use aimux_core::stream_part::StreamPart; +use futures::StreamExt; +use serde_json::{Value, json}; + +use crate::test_support::mock_fetch::{Canned, MockFetch}; + +const MODEL: &str = "deepseek-v4-flash"; + +// ── helpers ───────────────────────────────────────────────────────────────── + +/// `createDeepSeek({ apiKey })` with a mock transport. +fn provider(fetch: &Arc) -> DeepSeekProvider { + create_deepseek(DeepSeekProviderSettings { + api_key: Some("test-api-key".into()), + fetch: Some(fetch.transport()), + ..Default::default() + }) + .unwrap() +} + +/// `prompt: TEST_PROMPT`. +fn options() -> CallOptions { + CallOptions::new(vec![LanguageModelMessage::user_text("Hello")]) +} + +/// `completeUsage`: every field the raw usage must keep. +fn complete_usage() -> Value { + json!({ + "prompt_tokens": 100, + "completion_tokens": 50, + "total_tokens": 150, + "prompt_cache_hit_tokens": 20, + "prompt_cache_miss_tokens": 80, + "prompt_tokens_details": { + "cached_tokens": 20, + "provider_prompt_metadata": { "preserved": true } + }, + "completion_tokens_details": { + "reasoning_tokens": 10, + "provider_completion_metadata": ["preserved", 1] + }, + "provider_usage_metadata": { + "nested": { "preserved": true } + } + }) +} + +/// `createResponse(usage)`: a non-streaming completion carrying `usage`. +fn create_response(usage: Value) -> Value { + json!({ + "id": "chatcmpl-raw-usage", + "object": "chat.completion", + "created": 1785880000, + "model": MODEL, + "choices": [{ + "index": 0, + "message": { "role": "assistant", "content": "Hello" }, + "finish_reason": "stop" + }], + "usage": usage + }) +} + +/// An event-stream mock: one `data:` frame per payload, then `[DONE]`. +fn stream_fetch(payloads: &[String]) -> Arc { + let mut body: String = payloads + .iter() + .map(|payload| format!("data: {payload}\n\n")) + .collect(); + body.push_str("data: [DONE]\n\n"); + MockFetch::new(vec![Canned { + status: 200, + headers: vec![ + ("content-type".to_string(), "text/event-stream".to_string()), + ("cache-control".to_string(), "no-cache".to_string()), + ("connection".to_string(), "keep-alive".to_string()), + ], + body: body.into_bytes(), + }]) +} + +mod deep_seek_chat_language_model_raw_usage { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-raw-usage.test.ts › DeepSeekChatLanguageModel raw usage › preserves complete raw usage through doGenerate parsing + #[tokio::test] + async fn preserves_complete_raw_usage_through_do_generate_parsing() { + let fetch = MockFetch::new(vec![Canned::json(&create_response(complete_usage()))]); + let result = provider(&fetch) + .chat(MODEL) + .do_generate(&options()) + .await + .unwrap(); + + assert_eq!(result.usage.raw, complete_usage().as_object().cloned()); + assert_eq!( + serde_json::to_value(&result.usage.input_tokens).unwrap(), + json!({ "total": 100, "noCache": 80, "cacheRead": 20 }) + ); + assert_eq!( + serde_json::to_value(&result.usage.output_tokens).unwrap(), + json!({ "total": 50, "text": 40, "reasoning": 10 }) + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-raw-usage.test.ts › DeepSeekChatLanguageModel raw usage › preserves complete raw usage from the final doStream usage event + #[tokio::test] + async fn preserves_complete_raw_usage_from_the_final_do_stream_usage_event() { + let initial_usage = json!({ + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + "provider_usage_metadata": { "stage": "initial" } + }); + let payloads = [ + json!({ + "id": "chatcmpl-raw-usage", + "object": "chat.completion.chunk", + "choices": [], + "usage": initial_usage + }) + .to_string(), + json!({ + "id": "chatcmpl-raw-usage", + "object": "chat.completion.chunk", + "choices": [{ "index": 0, "delta": {}, "finish_reason": "stop" }], + "usage": complete_usage() + }) + .to_string(), + ]; + let fetch = stream_fetch(&payloads); + let result = provider(&fetch) + .chat(MODEL) + .do_stream(&options()) + .await + .unwrap(); + let parts: Vec = result + .stream + .map(|part| part.expect("stream part")) + .collect() + .await; + let usage = parts + .iter() + .find_map(|part| match part { + StreamPart::Finish { usage, .. } => Some(usage.clone()), + _ => None, + }) + .expect("a finish part"); + + assert_eq!(usage.raw, complete_usage().as_object().cloned()); + assert_eq!( + serde_json::to_value(&usage.input_tokens).unwrap(), + json!({ "total": 100, "noCache": 80, "cacheRead": 20 }) + ); + assert_eq!( + serde_json::to_value(&usage.output_tokens).unwrap(), + json!({ "total": 50, "text": 40, "reasoning": 10 }) + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-raw-usage.test.ts › DeepSeekChatLanguageModel raw usage › continues validating known usage field %s + #[tokio::test] + async fn continues_validating_known_usage_field() { + let mut prompt_tokens = complete_usage(); + prompt_tokens["prompt_tokens"] = json!("100"); + + let mut cached_tokens = complete_usage(); + cached_tokens["prompt_tokens_details"]["cached_tokens"] = json!("20"); + + let mut reasoning_tokens = complete_usage(); + reasoning_tokens["completion_tokens_details"]["reasoning_tokens"] = json!("10"); + + let rows = [ + ("prompt_tokens", prompt_tokens), + ("prompt_tokens_details.cached_tokens", cached_tokens), + ( + "completion_tokens_details.reasoning_tokens", + reasoning_tokens, + ), + ]; + // Every row runs; the rows the provider accepts are reported together. + let mut accepted = Vec::new(); + for (field, usage) in rows { + let fetch = MockFetch::new(vec![Canned::json(&create_response(usage))]); + let outcome = provider(&fetch).chat(MODEL).do_generate(&options()).await; + if outcome.is_ok() { + accepted.push(field); + } + } + assert!( + accepted.is_empty(), + "a string count was accepted for: {accepted:?}" + ); + } +} diff --git a/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_json_response_format.json b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_json_response_format.json new file mode 100644 index 000000000..3e73b4711 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_json_response_format.json @@ -0,0 +1,135 @@ +{ + "content": [ + { + "text": "I have the result from the weather tool. It returned a JSON object with location, condition, and temperature. I need to reply with JSON object ONLY. The assistant's response should be the JSON output. So I should output exactly that JSON? Or perhaps wrap it in some way? The instruction says \"Reply with JSON object ONLY.\" Probably I should output the result as is, or maybe a structured response. But the tool result is already JSON. I think I should output that JSON directly. However, I need to ensure it's a valid response. Let me output the JSON object.", + "type": "reasoning" + }, + { + "text": "{\n \"location\": \"San Francisco\",\n \"condition\": \"cloudy\",\n \"temperature\": 7\n}", + "type": "text" + } + ], + "finishReason": { + "raw": "stop", + "unified": "stop" + }, + "providerMetadata": { + "deepseek": { + "choiceIndex": 0, + "messageRole": "assistant", + "promptCacheHitTokens": 320, + "promptCacheMissTokens": 175, + "responseObject": "chat.completion", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" + } + }, + "request": { + "body": { + "messages": [ + { + "content": "Return JSON.", + "role": "system" + }, + { + "content": "Hello", + "role": "user" + } + ], + "model": "deepseek-reasoner", + "response_format": { + "type": "json_object" + }, + "thinking": { + "type": "enabled" + }, + "tools": [ + { + "function": { + "name": "weather", + "parameters": { + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "location": { + "type": "string" + } + }, + "required": [ + "location" + ], + "type": "object" + } + }, + "type": "function" + } + ] + } + }, + "response": { + "body": { + "choices": [ + { + "finish_reason": "stop", + "index": 0, + "logprobs": null, + "message": { + "content": "{\n \"location\": \"San Francisco\",\n \"condition\": \"cloudy\",\n \"temperature\": 7\n}", + "reasoning_content": "I have the result from the weather tool. It returned a JSON object with location, condition, and temperature. I need to reply with JSON object ONLY. The assistant's response should be the JSON output. So I should output exactly that JSON? Or perhaps wrap it in some way? The instruction says \"Reply with JSON object ONLY.\" Probably I should output the result as is, or maybe a structured response. But the tool result is already JSON. I think I should output that JSON directly. However, I need to ensure it's a valid response. Let me output the JSON object.", + "role": "assistant" + } + } + ], + "created": 1764681341, + "id": "f03bc170-b375-4561-9685-35182c8152c5", + "model": "deepseek-reasoner", + "object": "chat.completion", + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache", + "usage": { + "completion_tokens": 144, + "completion_tokens_details": { + "reasoning_tokens": 118 + }, + "prompt_cache_hit_tokens": 320, + "prompt_cache_miss_tokens": 175, + "prompt_tokens": 495, + "prompt_tokens_details": { + "cached_tokens": 320 + }, + "total_tokens": 639 + } + }, + "headers": { + "content-length": "1194", + "content-type": "application/json" + }, + "id": "f03bc170-b375-4561-9685-35182c8152c5", + "modelId": "deepseek-reasoner", + "timestamp": "2025-12-02T13:15:41.000Z" + }, + "usage": { + "inputTokens": { + "cacheRead": 320, + "noCache": 175, + "total": 495 + }, + "outputTokens": { + "reasoning": 118, + "text": 26, + "total": 144 + }, + "raw": { + "completion_tokens": 144, + "completion_tokens_details": { + "reasoning_tokens": 118 + }, + "prompt_cache_hit_tokens": 320, + "prompt_cache_miss_tokens": 175, + "prompt_tokens": 495, + "prompt_tokens_details": { + "cached_tokens": 320 + }, + "total_tokens": 639 + } + }, + "warnings": [] +} diff --git a/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_reasoning.json b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_reasoning.json new file mode 100644 index 000000000..311e66acc --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_reasoning.json @@ -0,0 +1,104 @@ +{ + "content": [ + { + "text": "We are asked: \"How many 'r's are in the word 'strawberry'?\" We need to count the occurrences of the letter 'r' in the word \"strawberry\". Let's write the word: s-t-r-a-w-b-e-r-r-y. Let's count: positions: 1: s, 2: t, 3: r, 4: a, 5: w, 6: b, 7: e, 8: r, 9: r, 10: y. So there are three 'r's? Wait: at position 3: r, position 8: r, position 9: r. That's three. But sometimes people might think it's two because of pronunciation? But strictly counting letters, it's three. However, let's double-check spelling: \"strawberry\" is spelled S-T-R-A-W-B-E-R-R-Y. Yes, it has two 'r's at the end? Actually, after 'b' comes 'e', then 'r', then 'r', then 'y'. So indeed three 'r's total. But wait, the initial 'r' is the first one? The word starts with 's', then 't', then 'r'. So that's one, then later two consecutive 'r's. So total three. So answer is 3.\n\nBut the question is phrased: \"How many 'r's are in the word 'strawberry'?\" So answer is 3.", + "type": "reasoning" + }, + { + "text": "The word \"strawberry\" contains three instances of the letter \"r\": one after the \"t\" and two before the \"y\".", + "type": "text" + } + ], + "finishReason": { + "raw": "stop", + "unified": "stop" + }, + "providerMetadata": { + "deepseek": { + "choiceIndex": 0, + "messageRole": "assistant", + "promptCacheHitTokens": 0, + "promptCacheMissTokens": 18, + "responseObject": "chat.completion", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" + } + }, + "request": { + "body": { + "messages": [ + { + "content": "Hello", + "role": "user" + } + ], + "model": "deepseek-chat" + } + }, + "response": { + "body": { + "choices": [ + { + "finish_reason": "stop", + "index": 0, + "logprobs": null, + "message": { + "content": "The word \"strawberry\" contains three instances of the letter \"r\": one after the \"t\" and two before the \"y\".", + "reasoning_content": "We are asked: \"How many 'r's are in the word 'strawberry'?\" We need to count the occurrences of the letter 'r' in the word \"strawberry\". Let's write the word: s-t-r-a-w-b-e-r-r-y. Let's count: positions: 1: s, 2: t, 3: r, 4: a, 5: w, 6: b, 7: e, 8: r, 9: r, 10: y. So there are three 'r's? Wait: at position 3: r, position 8: r, position 9: r. That's three. But sometimes people might think it's two because of pronunciation? But strictly counting letters, it's three. However, let's double-check spelling: \"strawberry\" is spelled S-T-R-A-W-B-E-R-R-Y. Yes, it has two 'r's at the end? Actually, after 'b' comes 'e', then 'r', then 'r', then 'y'. So indeed three 'r's total. But wait, the initial 'r' is the first one? The word starts with 's', then 't', then 'r'. So that's one, then later two consecutive 'r's. So total three. So answer is 3.\n\nBut the question is phrased: \"How many 'r's are in the word 'strawberry'?\" So answer is 3.", + "role": "assistant" + } + } + ], + "created": 1764660903, + "id": "945bb10c-9bf3-47ff-a2a2-43bbe9705c72", + "model": "deepseek-reasoner", + "object": "chat.completion", + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache", + "usage": { + "completion_tokens": 345, + "completion_tokens_details": { + "reasoning_tokens": 315 + }, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 18, + "prompt_tokens": 18, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 363 + } + }, + "headers": { + "content-length": "1596", + "content-type": "application/json" + }, + "id": "945bb10c-9bf3-47ff-a2a2-43bbe9705c72", + "modelId": "deepseek-reasoner", + "timestamp": "2025-12-02T07:35:03.000Z" + }, + "usage": { + "inputTokens": { + "cacheRead": 0, + "noCache": 18, + "total": 18 + }, + "outputTokens": { + "reasoning": 315, + "text": 30, + "total": 345 + }, + "raw": { + "completion_tokens": 345, + "completion_tokens_details": { + "reasoning_tokens": 315 + }, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 18, + "prompt_tokens": 18, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 363 + } + }, + "warnings": [] +} diff --git a/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_text.json b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_text.json new file mode 100644 index 000000000..4f8b79fbd --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_text.json @@ -0,0 +1,93 @@ +{ + "content": [ + { + "text": "## **Holiday Name: Gratitude of Small Things Day (GST Day)**\n\n**Date:** The first Saturday after the Spring Equinox (in the Northern Hemisphere) / the first Saturday after the Autumn Equinox (in the Southern Hemisphere). It is intentionally placed at a time of seasonal transition, encouraging people to pause and appreciate the subtle, often overlooked details of life.\n\n**Core Philosophy:** In a world focused on grand achievements and major events, GST Day celebrates the tiny, mundane, yet profoundly beautiful moments, objects, and sensations that form the quiet fabric of our existence. The motto is: *\"Notice the thread, and you see the tapestry.\"*\n\n---\n\n### **Traditions & Practices:**\n\n**1. The \"Quiet Hour\" & Offering Bowl:**\n The holiday begins at sunrise with a \"Quiet Hour.\" Individuals or households sit in a comfortable space with a small, empty bowl (the \"Offering Bowl\"). In silence, they reflect on the past year, noting not major events, but **small, specific gratitudes**: the sound of rain on a specific afternoon, the warmth of a mug in their hands, the scent of a loved one's laundry detergent, the way light fell through a window. They write each on a tiny slip of paper and place it in the bowl. These are not shared aloud; the act is purely personal and reflective.\n\n**2. The \"Micro-Gift\" Exchange:**\n Instead of lavish presents, people exchange", + "type": "text" + } + ], + "finishReason": { + "raw": "length", + "unified": "length" + }, + "providerMetadata": { + "deepseek": { + "choiceIndex": 0, + "messageRole": "assistant", + "promptCacheHitTokens": 0, + "promptCacheMissTokens": 13, + "responseObject": "chat.completion", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" + } + }, + "request": { + "body": { + "messages": [ + { + "content": "Hello", + "role": "user" + } + ], + "model": "deepseek-chat" + } + }, + "response": { + "body": { + "choices": [ + { + "finish_reason": "length", + "index": 0, + "logprobs": null, + "message": { + "content": "## **Holiday Name: Gratitude of Small Things Day (GST Day)**\n\n**Date:** The first Saturday after the Spring Equinox (in the Northern Hemisphere) / the first Saturday after the Autumn Equinox (in the Southern Hemisphere). It is intentionally placed at a time of seasonal transition, encouraging people to pause and appreciate the subtle, often overlooked details of life.\n\n**Core Philosophy:** In a world focused on grand achievements and major events, GST Day celebrates the tiny, mundane, yet profoundly beautiful moments, objects, and sensations that form the quiet fabric of our existence. The motto is: *\"Notice the thread, and you see the tapestry.\"*\n\n---\n\n### **Traditions & Practices:**\n\n**1. The \"Quiet Hour\" & Offering Bowl:**\n The holiday begins at sunrise with a \"Quiet Hour.\" Individuals or households sit in a comfortable space with a small, empty bowl (the \"Offering Bowl\"). In silence, they reflect on the past year, noting not major events, but **small, specific gratitudes**: the sound of rain on a specific afternoon, the warmth of a mug in their hands, the scent of a loved one's laundry detergent, the way light fell through a window. They write each on a tiny slip of paper and place it in the bowl. These are not shared aloud; the act is purely personal and reflective.\n\n**2. The \"Micro-Gift\" Exchange:**\n Instead of lavish presents, people exchange", + "role": "assistant" + } + } + ], + "created": 1764656316, + "id": "00f10ecd-60b3-4707-b5db-e4bcadf7aea1", + "model": "deepseek-chat", + "object": "chat.completion", + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache", + "usage": { + "completion_tokens": 300, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 13, + "prompt_tokens": 13, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 313 + } + }, + "headers": { + "content-length": "1857", + "content-type": "application/json" + }, + "id": "00f10ecd-60b3-4707-b5db-e4bcadf7aea1", + "modelId": "deepseek-chat", + "timestamp": "2025-12-02T06:18:36.000Z" + }, + "usage": { + "inputTokens": { + "cacheRead": 0, + "noCache": 13, + "total": 13 + }, + "outputTokens": { + "reasoning": 0, + "text": 300, + "total": 300 + }, + "raw": { + "completion_tokens": 300, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 13, + "prompt_tokens": 13, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 313 + } + }, + "warnings": [] +} diff --git a/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_tool_call.json b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_tool_call.json new file mode 100644 index 000000000..58efc7931 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/snapshots/do_generate_tool_call.json @@ -0,0 +1,144 @@ +{ + "content": [ + { + "text": "The user is asking for the weather in San Francisco. I have a weather tool available that can get weather information for a location. I should use this tool with the location parameter set to \"San Francisco\". Let me call the weather function.", + "type": "reasoning" + }, + { + "input": "{\"location\": \"San Francisco\"}", + "toolCallId": "call_00_9V0vrf86Pc9aelHCJMZqnJBo", + "toolName": "weather", + "type": "tool-call" + } + ], + "finishReason": { + "raw": "tool_calls", + "unified": "tool-calls" + }, + "providerMetadata": { + "deepseek": { + "choiceIndex": 0, + "messageRole": "assistant", + "promptCacheHitTokens": 320, + "promptCacheMissTokens": 19, + "responseObject": "chat.completion", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache", + "toolCallTypes": [ + "function" + ] + } + }, + "request": { + "body": { + "messages": [ + { + "content": "Hello", + "role": "user" + } + ], + "model": "deepseek-reasoner", + "thinking": { + "type": "enabled" + }, + "tools": [ + { + "function": { + "name": "weather", + "parameters": { + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "location": { + "type": "string" + } + }, + "required": [ + "location" + ], + "type": "object" + } + }, + "type": "function" + } + ] + } + }, + "response": { + "body": { + "choices": [ + { + "finish_reason": "tool_calls", + "index": 0, + "logprobs": null, + "message": { + "content": "", + "reasoning_content": "The user is asking for the weather in San Francisco. I have a weather tool available that can get weather information for a location. I should use this tool with the location parameter set to \"San Francisco\". Let me call the weather function.", + "role": "assistant", + "tool_calls": [ + { + "function": { + "arguments": "{\"location\": \"San Francisco\"}", + "name": "weather" + }, + "id": "call_00_9V0vrf86Pc9aelHCJMZqnJBo", + "index": 0, + "type": "function" + } + ] + } + } + ], + "created": 1764665845, + "id": "7a630f5b-b7e6-4878-82f8-d77db164d42b", + "model": "deepseek-reasoner", + "object": "chat.completion", + "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache", + "usage": { + "completion_tokens": 92, + "completion_tokens_details": { + "reasoning_tokens": 48 + }, + "prompt_cache_hit_tokens": 320, + "prompt_cache_miss_tokens": 19, + "prompt_tokens": 339, + "prompt_tokens_details": { + "cached_tokens": 320 + }, + "total_tokens": 431 + } + }, + "headers": { + "content-length": "952", + "content-type": "application/json" + }, + "id": "7a630f5b-b7e6-4878-82f8-d77db164d42b", + "modelId": "deepseek-reasoner", + "timestamp": "2025-12-02T08:57:25.000Z" + }, + "usage": { + "inputTokens": { + "cacheRead": 320, + "noCache": 19, + "total": 339 + }, + "outputTokens": { + "reasoning": 48, + "text": 44, + "total": 92 + }, + "raw": { + "completion_tokens": 92, + "completion_tokens_details": { + "reasoning_tokens": 48 + }, + "prompt_cache_hit_tokens": 320, + "prompt_cache_miss_tokens": 19, + "prompt_tokens": 339, + "prompt_tokens_details": { + "cached_tokens": 320 + }, + "total_tokens": 431 + } + }, + "warnings": [] +} diff --git a/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_reasoning.json b/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_reasoning.json new file mode 100644 index 000000000..c3bce7447 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_reasoning.json @@ -0,0 +1,1160 @@ +[ + { + "type": "stream-start", + "warnings": [] + }, + { + "id": "cac7192e-e619-40c6-96b0-ed4276bc03ac", + "modelId": "deepseek-reasoner", + "timestamp": "2025-12-02T07:50:32.000Z", + "type": "response-metadata" + }, + { + "id": "reasoning-0", + "type": "reasoning-start" + }, + { + "delta": "We", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " need", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " to", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " count", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " number", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " of", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " letter", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " in", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " word", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "st", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "raw", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "berry", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " The", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " word", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " is", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " spelled", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-t", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-a", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-w", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-b", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-e", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-y", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " Let", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "'s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " list", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " letters", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " and", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " count", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\"s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":\n\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "Position", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "1", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "2", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " t", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "3", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " (", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "first", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ")\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "4", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " a", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "5", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " w", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "6", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " b", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "7", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " e", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "8", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " (", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "second", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ")\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "9", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " (", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "third", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ")\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "10", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " y", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\n\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "So", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " there", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " are", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " three", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\"s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " But", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " wait", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ",", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " let", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "'s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " double", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "-check", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "st", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "raw", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "berry", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " indeed", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " has", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " three", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\"s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " one", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " after", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "t", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\",", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " and", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " then", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " two", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " consecutive", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\"s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " before", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "y", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " So", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " answer", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " is", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "3", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".\n\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "The", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " question", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " is", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " straightforward", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " However", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ",", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " sometimes", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " people", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " might", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " misc", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "ount", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " Let", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "'s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ensure", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ":", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " The", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " word", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " has", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "10", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " letters", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " The", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "r", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\"s", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " are", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " at", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " positions", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "3", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ",", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "8", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ",", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " and", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "9", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " So", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " yes", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ",", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "3", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".\n\n", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "Thus", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ",", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " answer", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " is", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " ", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "3", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "id": "txt-0", + "type": "text-start" + }, + { + "id": "reasoning-0", + "type": "reasoning-end" + }, + { + "delta": "The", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " word", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " \"", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "st", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "raw", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "berry", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "\"", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " contains", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " three", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " \"", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "r", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "\"s", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "id": "txt-0", + "type": "text-end" + }, + { + "finishReason": { + "raw": "stop", + "unified": "stop" + }, + "providerMetadata": { + "deepseek": { + "choiceIndex": 0, + "messageRole": "assistant", + "promptCacheHitTokens": 0, + "promptCacheMissTokens": 18, + "responseObject": "chat.completion.chunk", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" + } + }, + "type": "finish", + "usage": { + "inputTokens": { + "cacheRead": 0, + "noCache": 18, + "total": 18 + }, + "outputTokens": { + "reasoning": 205, + "text": 14, + "total": 219 + }, + "raw": { + "completion_tokens": 219, + "completion_tokens_details": { + "reasoning_tokens": 205 + }, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 18, + "prompt_tokens": 18, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 237 + } + } + } +] diff --git a/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_text.json b/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_text.json new file mode 100644 index 000000000..4c44fd4f4 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_text.json @@ -0,0 +1,2059 @@ +[ + { + "type": "stream-start", + "warnings": [] + }, + { + "id": "f6117a0b-129d-46fa-b239-78f01c2c5df9", + "modelId": "deepseek-chat", + "timestamp": "2025-12-02T06:46:33.000Z", + "type": "response-metadata" + }, + { + "id": "txt-0", + "type": "text-start" + }, + { + "delta": "##", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " **", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "H", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "olid", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ay", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Name", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ":**", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " St", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "arl", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ight", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Rem", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "embrance", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "\n\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "Date", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ":**", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " The", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Saturday", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " nearest", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " new", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " moon", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " in", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " October", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " when", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " night", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " sky", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " is", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " at", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " its", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " darkest", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " stars", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " are", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " most", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " vivid", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".\n\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "Origin", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " &", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Meaning", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ":", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "St", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "arl", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ight", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Rem", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "embrance", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " emerged", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " from", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " modern", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " collective", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " yearning", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " to", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " honor", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " personal", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " loss", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " while", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " celebrating", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " enduring", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " connections", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " that", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " transcend", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " it", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " It", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " is", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " not", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " tied", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " to", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " any", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " one", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " religion", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " or", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " culture", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " but", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " to", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " universal", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " human", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " experience", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " The", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " core", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " philosophy", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " is", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " that", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " people", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " we", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " love", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " ideas", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " that", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " inspired", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " us", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " even", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " versions", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " ourselves", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " that", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " are", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " gone", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " are", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " not", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " vanished", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " but", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " have", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " become", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " part", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " universe", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "'s", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " fabric", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "—", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "like", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " st", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ard", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ust", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " The", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " holiday", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " asks", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " participants", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " to", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " look", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " up", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " at", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " vast", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " shared", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " sky", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " find", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " comfort", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " in", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " both", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " darkness", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " (", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " loss", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ")", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " enduring", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " points", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " light", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " (", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " memory", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ").\n\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "---\n\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "###", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " **", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "T", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "rad", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "itions", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " &", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Rit", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "uals", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ":**\n\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "1", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " The", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Dim", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ming", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Lights", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ":", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "As", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " night", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " falls", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " households", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " communities", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " turn", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " off", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " non", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "-", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "essential", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " electric", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " lights", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Streets", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " are", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " lit", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " only", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " by", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " subtle", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " blue", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "-ton", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ed", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " lantern", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "s", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " (", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "symbol", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "izing", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " night", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " sky", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ").", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " This", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " collective", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " act", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " reduces", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " light", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " pollution", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " literally", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " metaphor", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ically", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " making", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " space", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " for", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " stars", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "—", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " for", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " reflection", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".\n\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "2", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Craft", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ing", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Constellation", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " J", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ars", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ":", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "In", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " days", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " leading", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " up", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " to", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " holiday", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " people", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " create", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " \"", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "Const", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ellation", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " J", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "ars", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".\"", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " They", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " take", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " clear", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " jar", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " using", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " small", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " drill", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " or", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " adhesive", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " create", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " pattern", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " holes", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " on", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " its", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " lid", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " representing", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " stars", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " specific", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " constellation", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " On", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " night", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " holiday", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " small", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " battery", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "-operated", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " tea", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " light", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " is", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " placed", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " inside", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Each", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " jar", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " is", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " dedicated", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " to", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " someone", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " or", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " something", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " remembered", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " The", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " constellation", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " might", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " be", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " their", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " birth", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " sign", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " shape", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " that", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " reminds", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " maker", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " them", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " or", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " simply", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " pattern", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " sky", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " on", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " the", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " night", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " they", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " passed", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".\n\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "3", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " The", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Silent", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Vig", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "il", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " &", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Story", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " Stars", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ":", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "**\n", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "At", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " a", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " designated", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " time", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " (", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "e", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".g", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ".,", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " ", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "9", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " PM", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " local", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " time", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "),", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " people", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " step", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " outside", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " alone", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " or", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " in", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " quiet", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " groups", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": ",", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " and", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " observe", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " ", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": "15", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " minutes", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " of", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " silent", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " looking", + "id": "txt-0", + "type": "text-delta" + }, + { + "delta": " at", + "id": "txt-0", + "type": "text-delta" + }, + { + "id": "txt-0", + "type": "text-end" + }, + { + "finishReason": { + "raw": "length", + "unified": "length" + }, + "providerMetadata": { + "deepseek": { + "choiceIndex": 0, + "messageRole": "assistant", + "promptCacheHitTokens": 0, + "promptCacheMissTokens": 13, + "responseObject": "chat.completion.chunk", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" + } + }, + "type": "finish", + "usage": { + "inputTokens": { + "cacheRead": 0, + "noCache": 13, + "total": 13 + }, + "outputTokens": { + "reasoning": 0, + "text": 400, + "total": 400 + }, + "raw": { + "completion_tokens": 400, + "prompt_cache_hit_tokens": 0, + "prompt_cache_miss_tokens": 13, + "prompt_tokens": 13, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 413 + } + } + } +] diff --git a/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_tool_call.json b/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_tool_call.json new file mode 100644 index 000000000..3e558e6d7 --- /dev/null +++ b/aimux-providers/src/deepseek/tests/chat/snapshots/do_stream_tool_call.json @@ -0,0 +1,325 @@ +[ + { + "type": "stream-start", + "warnings": [] + }, + { + "id": "cca85624-4056-401f-b220-d77601d1f70d", + "modelId": "deepseek-reasoner", + "timestamp": "2025-12-02T08:36:08.000Z", + "type": "response-metadata" + }, + { + "id": "reasoning-0", + "type": "reasoning-start" + }, + { + "delta": "The", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " user", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " is", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " asking", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " for", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " weather", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " in", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " San", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " Francisco", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " I", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " need", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " to", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " use", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " weather", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " tool", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " to", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " get", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " this", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " information", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": ".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " Let", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " me", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " invoke", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " weather", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " tool", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " with", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " the", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " location", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " parameter", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " set", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " to", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " \"", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "San", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": " Francisco", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "delta": "\".", + "id": "reasoning-0", + "type": "reasoning-delta" + }, + { + "id": "reasoning-0", + "type": "reasoning-end" + }, + { + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "toolName": "weather", + "type": "tool-input-start" + }, + { + "delta": "{", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": "\"", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": "location", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": "\"", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": ": ", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": "\"", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": "San", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": " Francisco", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": "\"", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "delta": "}", + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-delta" + }, + { + "id": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "type": "tool-input-end" + }, + { + "input": "{\"location\": \"San Francisco\"}", + "toolCallId": "call_00_ioIn7yN9p1ZOMNpDLwd4MgAF", + "toolName": "weather", + "type": "tool-call" + }, + { + "finishReason": { + "raw": "tool_calls", + "unified": "tool-calls" + }, + "providerMetadata": { + "deepseek": { + "choiceIndex": 0, + "messageRole": "assistant", + "promptCacheHitTokens": 320, + "promptCacheMissTokens": 19, + "responseObject": "chat.completion.chunk", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache", + "toolCallTypes": [ + "function" + ] + } + }, + "type": "finish", + "usage": { + "inputTokens": { + "cacheRead": 320, + "noCache": 19, + "total": 339 + }, + "outputTokens": { + "reasoning": 39, + "text": 44, + "total": 83 + }, + "raw": { + "completion_tokens": 83, + "completion_tokens_details": { + "reasoning_tokens": 39 + }, + "prompt_cache_hit_tokens": 320, + "prompt_cache_miss_tokens": 19, + "prompt_tokens": 339, + "prompt_tokens_details": { + "cached_tokens": 320 + }, + "total_tokens": 422 + } + } + } +] diff --git a/aimux-providers/src/deepseek/tests/mod.rs b/aimux-providers/src/deepseek/tests/mod.rs new file mode 100644 index 000000000..26b2c32fc --- /dev/null +++ b/aimux-providers/src/deepseek/tests/mod.rs @@ -0,0 +1,3 @@ +//! Tests ported from the upstream `@ai-sdk/deepseek` 3.0.56 package. + +mod chat; diff --git a/aimux-providers/tests/deepseek_chat_test.rs b/aimux-providers/tests/deepseek_chat_test.rs index 9c82a88fe..9bd8a01f1 100644 --- a/aimux-providers/tests/deepseek_chat_test.rs +++ b/aimux-providers/tests/deepseek_chat_test.rs @@ -330,2258 +330,2403 @@ fn logprob(token: &str, logprob: f64, bytes: Value) -> Value { }) } -// =========================================================================== -// describe('model IDs') / describe('supportedUrls') -// =========================================================================== +fn reasoning_response() -> Value { + json!({ + "id": "r1", "object": "chat.completion", "created": 1764656316, "model": "deepseek-reasoner", + "choices": [{ + "index": 0, + "message": { + "role": "assistant", + "content": "There are 3 r's in strawberry.", + "reasoning_content": "Let me count the letters." + }, + "finish_reason": "stop" + }], + "usage": { "prompt_tokens": 20, "completion_tokens": 30, "total_tokens": 50, + "completion_tokens_details": { "reasoning_tokens": 10 } } + }) +} -#[tokio::test] -async fn should_forward_the_model_id() { - for model_id in ["deepseek-v4-flash", "deepseek-v4-pro"] { - assert_eq!(generate_body(model_id, &options()).await["model"], model_id); - } +fn logprobs_response() -> Value { + let mut body = text_response(); + body["choices"][0]["message"] = json!({ + "role": "assistant", "content": "OK", "reasoning_content": "Reasoning" + }); + body["choices"][0]["logprobs"] = json!({ + "content": [logprob("OK", -0.00002467602, json!([79, 75]))], + "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] + }); + body } -#[tokio::test] -async fn should_natively_support_http_image_urls() { - let server = MockServer::start().await; - let urls = chat(&server, "deepseek-chat").supported_urls().await; - let patterns = &urls.0["image/*"]; - assert_eq!(patterns.len(), 1); - assert!(patterns[0].is_match("https://example.com/a.png")); - assert!(patterns[0].is_match("http://example.com/a.png")); - assert!(!patterns[0].is_match("data:image/png;base64,AAAA")); +fn reasoning_options(effort: ReasoningEffort) -> CallOptions { + CallOptions { + reasoning: Some(effort), + ..options() + } } -// =========================================================================== -// describe('doGenerate') -// =========================================================================== +fn tool_call_response() -> Value { + json!({ + "id": "t1", "object": "chat.completion", "created": 1764656316, "model": "deepseek-reasoner", + "choices": [{ + "index": 0, + "message": { + "role": "assistant", "content": "", + "reasoning_content": "I should look up the weather.", + "tool_calls": [{ + "id": "call_00_abc", "type": "function", + "function": { "name": "weather", "arguments": "{\"location\":\"San Francisco\"}" } + }] + }, + "finish_reason": "tool_calls" + }], + "usage": { "prompt_tokens": 50, "completion_tokens": 20, "total_tokens": 70 } + }) +} -#[tokio::test] -async fn should_reject_a_response_without_choices() { - let server = json_server(json!({ - "id": "chatcmpl-empty", "object": "chat.completion", "created": 0, - "model": "deepseek-chat", "choices": [], - "usage": { "prompt_tokens": 1, "completion_tokens": 0, "total_tokens": 1 } - })) - .await; - let error = chat(&server, "deepseek-chat") - .do_generate(&options()) - .await - .unwrap_err(); - assert!( - matches!(&error, AiMuxError::InvalidResponseData { message: m, .. } if m == "Response did not contain any choices."), - "{error:?}" +fn tool_options() -> CallOptions { + let mut options = with_provider_options( + options(), + json!({ "deepseek": { "thinking": { "type": "enabled" } } }), ); + options.tools = Some(vec![Tool::Function(weather_tool())]); + options } -// ---- describe('text') ------------------------------------------------------ +fn weather_wire_tool() -> Value { + json!({ + "type": "function", + "function": { + "name": "weather", + "parameters": { + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { "location": { "type": "string" } }, + "required": ["location"], + "type": "object" + } + } + }) +} -#[tokio::test] -async fn text_should_send_correct_request_body() { - let mut options = options_for(vec![ - LanguageModelMessage::System { - content: ("You are a helpful assistant.").into(), - provider_options: None, - }, - LanguageModelMessage::user_text("Hello"), - ]); - options.temperature = Some(0.5); - options.top_p = Some(0.3); - assert_eq!( - generate_body("deepseek-chat", &options).await, - json!({ - "messages": [ - { "content": "You are a helpful assistant.", "role": "system" }, - { "content": "Hello", "role": "user" } - ], - "model": "deepseek-chat", - "temperature": 0.5, - "top_p": 0.3 - }) - ); +fn json_options(schema: Option) -> CallOptions { + let mut options = tool_options(); + options.response_format = Some(ResponseFormat::Json { + schema, + name: None, + description: None, + }); + options } -#[tokio::test] -async fn text_should_omit_deprecated_and_ineffective_sampling_options_in_default_v4_thinking_mode() -{ - let mut options = options(); - options.temperature = Some(0.2); - options.top_p = Some(0.4); - options.frequency_penalty = Some(0.5); - options.presence_penalty = Some(0.6); - let result = generate_result("deepseek-v4-flash", &options).await; - assert_eq!( - result.request.and_then(|request| request.body).unwrap(), - json!({ "model": "deepseek-v4-flash", "messages": [{ "role": "user", "content": "Hello" }] }) - ); - assert_eq!( - warning_values(&result.warnings), - warning_values(&[ - deprecated("frequencyPenalty"), - deprecated("presencePenalty"), - thinking_unsupported("temperature"), - thinking_unsupported("topP"), - ]) - ); +fn prefix_prompt(prefix_options: Value) -> LanguageModelPrompt { + vec![ + LanguageModelMessage::user_text("Complete this sentence."), + with_options( + LanguageModelMessage::Assistant { + content: vec![AssistantPart::Text(TextPart { + text: ("The answer is").into(), + provider_options: None, + })], + provider_options: None, + }, + json!({ "deepseek": prefix_options }), + ), + ] } -#[tokio::test] -async fn text_should_preserve_supported_sampling_options_when_v4_thinking_is_disabled() { - let mut options = with_provider_options( - options(), - json!({ "deepseek": { "thinking": { "type": "disabled" } } }), - ); - options.temperature = Some(0.2); - options.top_p = Some(0.4); - options.frequency_penalty = Some(0.5); - options.presence_penalty = Some(0.6); - let result = generate_result("deepseek-v4-flash", &options).await; - assert_eq!( - result.request.and_then(|request| request.body).unwrap(), - json!({ - "model": "deepseek-v4-flash", - "messages": [{ "role": "user", "content": "Hello" }], - "temperature": 0.2, - "top_p": 0.4, - "thinking": { "type": "disabled" } +// Upstream emits provider error envelopes as error parts, including the first event. +async fn stream_error(data: &Value) -> aimux_core::error::ApiCallError { + let server = sse_server(vec![data_event(data)]).await; + let result = chat(&server, "deepseek-chat") + .do_stream(&options()) + .await + .unwrap(); + collect(result) + .await + .into_iter() + .find_map(|part| match part { + StreamPart::Error { + error: AiMuxError::ApiCall(error), + } => Some(*error), + _ => None, }) - ); - assert_eq!( - warning_values(&result.warnings), - warning_values(&[ - deprecated("frequencyPenalty"), - deprecated("presencePenalty") - ]) - ); + .expect("expected a provider error part") } -#[tokio::test] -async fn text_should_send_max_tokens_and_stop_sequences() { - let mut options = options(); - options.max_output_tokens = Some(64); - options.stop_sequences = Some(vec!["END".to_string()]); - let body = generate_body("deepseek-chat", &options).await; - assert_eq!(body["max_tokens"], 64); - assert_eq!(body["stop"], json!(["END"])); - assert!(body.get("max_completion_tokens").is_none()); +async fn stream_parts( + model_id: &str, + options: &CallOptions, + chunks: Vec, +) -> (Value, Vec) { + let server = sse_server(chunks).await; + let result = chat(&server, model_id).do_stream(options).await.unwrap(); + let body = result.request.clone().and_then(|r| r.body).unwrap(); + (body, collect(result).await) } -#[tokio::test] -async fn text_should_send_message_names() { - let name = |value: &str| json!({ "deepseek": { "name": value } }); - let messages = wire_messages( - "deepseek-chat", - vec![ - with_options( - LanguageModelMessage::System { - content: ("You are a helpful assistant.").into(), - provider_options: None, - }, - name("guide"), - ), - with_options(LanguageModelMessage::user_text("Hello"), name("alice")), - with_options( - LanguageModelMessage::Assistant { - content: vec![AssistantPart::Text(TextPart { - text: ("Hello, Alice.").into(), - provider_options: None, - })], - provider_options: None, - }, - name("assistant"), - ), - with_options( - LanguageModelMessage::user_text("How are you?"), - name("alice"), - ), - ], - ) - .await; - assert_eq!( - messages, - [ - json!({ "content": "You are a helpful assistant.", "name": "guide", "role": "system" }), - json!({ "content": "Hello", "name": "alice", "role": "user" }), - json!({ "content": "Hello, Alice.", "name": "assistant", "role": "assistant" }), - json!({ "content": "How are you?", "name": "alice", "role": "user" }), - ] - ); +fn png_data() -> UserPart { + UserPart::File(FilePart { + data: FileData::Data { + data: FileBytes::Base64("AAECAw==".into()), + }, + media_type: "image/png".into(), + filename: None, + provider_options: None, + }) } -#[tokio::test] -async fn text_should_pass_provider_options_user_id_as_user_id() { - let options = with_provider_options( - options(), - json!({ "deepseek": { "userId": "tenant_123-user" } }), - ); - assert_eq!( - generate_body("deepseek-chat", &options).await["user_id"], - "tenant_123-user" - ); +fn file_with_options(mut part: UserPart, options: Value) -> UserPart { + if let UserPart::File(file) = &mut part { + file.provider_options = Some(serde_json::from_value(options).unwrap()); + } + part } -#[tokio::test] -async fn text_should_omit_user_id_when_user_id_is_not_provided() { - assert!( - generate_body("deepseek-chat", &options()) - .await - .get("user_id") - .is_none() - ); +fn tool_turn(reasoning: bool) -> Vec { + let mut assistant = vec![]; + if reasoning { + assistant.push(AssistantPart::Reasoning(ReasoningPart { + text: ("I think the tool will return the correct value.").into(), + provider_options: None, + })); + } + assistant.push(AssistantPart::ToolCall(ToolCallPart { + tool_call_id: ("quux").into(), + tool_name: ("thwomp").into(), + input: json!({ "foo": "bar123" }), + provider_executed: None, + provider_options: None, + })); + vec![ + LanguageModelMessage::Assistant { + content: assistant, + provider_options: None, + }, + LanguageModelMessage::Tool { + content: vec![ToolPart::ToolResult(ToolResultPart { + tool_call_id: ("quux").into(), + output: ToolResultOutput::Json { + value: json!({ "oof": "321rab" }), + provider_options: None, + }, + tool_name: "thwomp".into(), + provider_options: None, + })], + provider_options: None, + }, + ] } -#[tokio::test] -async fn text_should_not_send_unknown_provider_options() { - // upstream: `deepseekLanguageModelChatOptions` is a zod object, which - // strips keys it does not declare. - let options = - with_provider_options(options(), json!({ "deepseek": { "user": "u1", "foo": 1 } })); - let body = generate_body("deepseek-chat", &options).await; - assert!(body.get("user").is_none() && body.get("foo").is_none()); +fn wire_tool_call() -> Value { + json!([{ + "id": "quux", "type": "function", + "function": { "name": "thwomp", "arguments": "{\"foo\":\"bar123\"}" } + }]) } -/// TS: "should pass through strict mode when strict is false" (line ~40). -/// -/// A tool with `strict: false` should produce `"strict": false` in the -/// serialized tool definition. -#[tokio::test] -async fn should_pass_through_strict_mode_when_strict_is_false() { - let tool = FunctionTool { - name: "testFunction".to_string(), - description: Some("A test function".to_string()), - input_schema: json!({ "type": "object", "properties": {} }), - strict: Some(false), - provider_options: None, - input_examples: None, - }; - let mut options = options(); - options.tools = Some(vec![Tool::from(tool)]); - let body = generate_body("deepseek-chat", &options).await; +mod deep_seek_chat_language_model { + use super::*; - assert_eq!( - body["tools"], - json!([{ - "type": "function", - "function": { - "description": "A test function", - "name": "testFunction", - "parameters": { "type": "object", "properties": {} }, - "strict": false + mod model_ids { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › model IDs › should forward the %s model ID + #[tokio::test] + async fn should_forward_the_model_id() { + for model_id in ["deepseek-v4-flash", "deepseek-v4-pro"] { + assert_eq!(generate_body(model_id, &options()).await["model"], model_id); } - }]) - ); -} + } + } -/// TS: "should not include strict mode when strict is undefined" (line ~75). -/// -/// A tool without `strict` set should NOT have a `"strict"` field in the -/// serialized tool definition. -#[tokio::test] -async fn should_not_include_strict_mode_when_strict_is_undefined() { - let tool = FunctionTool { - name: "testFunction".to_string(), - description: Some("A test function".to_string()), - input_schema: json!({ "type": "object", "properties": {} }), - strict: None, - provider_options: None, - input_examples: None, - }; - let mut options = options(); - options.tools = Some(vec![Tool::from(tool)]); - let body = generate_body("deepseek-chat", &options).await; + mod supported_urls { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › supportedUrls › should natively support HTTP image URLs + #[tokio::test] + async fn should_natively_support_http_image_urls() { + let server = MockServer::start().await; + let urls = chat(&server, "deepseek-chat").supported_urls().await; + let patterns = &urls.0["image/*"]; + assert_eq!(patterns.len(), 1); + assert!(patterns[0].is_match("https://example.com/a.png")); + assert!(patterns[0].is_match("http://example.com/a.png")); + assert!(!patterns[0].is_match("data:image/png;base64,AAAA")); + } + } - assert_eq!( - body["tools"], - json!([{ - "type": "function", - "function": { - "description": "A test function", - "name": "testFunction", - "parameters": { "type": "object", "properties": {} } + mod do_generate { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › should reject a response without choices + #[tokio::test] + async fn should_reject_a_response_without_choices() { + let server = json_server(json!({ + "id": "chatcmpl-empty", "object": "chat.completion", "created": 0, + "model": "deepseek-chat", "choices": [], + "usage": { "prompt_tokens": 1, "completion_tokens": 0, "total_tokens": 1 } + })) + .await; + let error = chat(&server, "deepseek-chat") + .do_generate(&options()) + .await + .unwrap_err(); + assert!( + matches!(&error, AiMuxError::InvalidResponseData { message: m, .. } if m == "Response did not contain any choices."), + "{error:?}" + ); + } + + mod text { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should send correct request body + #[tokio::test] + async fn text_should_send_correct_request_body() { + let mut options = options_for(vec![ + LanguageModelMessage::System { + content: ("You are a helpful assistant.").into(), + provider_options: None, + }, + LanguageModelMessage::user_text("Hello"), + ]); + options.temperature = Some(0.5); + options.top_p = Some(0.3); + assert_eq!( + generate_body("deepseek-chat", &options).await, + json!({ + "messages": [ + { "content": "You are a helpful assistant.", "role": "system" }, + { "content": "Hello", "role": "user" } + ], + "model": "deepseek-chat", + "temperature": 0.5, + "top_p": 0.3 + }) + ); } - }]) - ); - // Verify strict is absent. - assert!( - body["tools"][0]["function"].get("strict").is_none(), - "strict should be absent" - ); -} -#[tokio::test] -async fn text_should_reject_strict_tools_on_the_standard_endpoint_before_fetching() { - let mut options = options(); - options.tools = Some(vec![strict_tool("getWeather", Some(true))]); - let message = generate_error("deepseek-chat", &options).await; - assert!( - message.contains("DeepSeek strict tool calls require a beta base URL ending in `/beta`."), - "{message}" - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should omit deprecated and ineffective sampling options in default V4 thinking mode + #[tokio::test] + async fn text_should_omit_deprecated_and_ineffective_sampling_options_in_default_v4_thinking_mode() + { + let mut options = options(); + options.temperature = Some(0.2); + options.top_p = Some(0.4); + options.frequency_penalty = Some(0.5); + options.presence_penalty = Some(0.6); + let result = generate_result("deepseek-v4-flash", &options).await; + assert_eq!( + result.request.and_then(|request| request.body).unwrap(), + json!({ "model": "deepseek-v4-flash", "messages": [{ "role": "user", "content": "Hello" }] }) + ); + assert_eq!( + warning_values(&result.warnings), + warning_values(&[ + deprecated("frequencyPenalty"), + deprecated("presencePenalty"), + thinking_unsupported("temperature"), + thinking_unsupported("topP"), + ]) + ); + } -#[tokio::test] -async fn text_should_send_all_strict_tools_on_the_beta_endpoint() { - let server = json_server(text_response()).await; - let mut options = options(); - options.tools = Some(vec![strict_tool("getWeather", Some(true))]); - let body = beta_chat(&server, "deepseek-chat") - .do_generate(&options) - .await - .unwrap() - .request - .and_then(|r| r.body) - .unwrap(); - assert_eq!(body["tools"][0]["type"], "function"); - assert_eq!(body["tools"][0]["function"]["name"], "getWeather"); - assert_eq!(body["tools"][0]["function"]["strict"], true); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should preserve supported sampling options when V4 thinking is disabled + #[tokio::test] + async fn text_should_preserve_supported_sampling_options_when_v4_thinking_is_disabled() + { + let mut options = with_provider_options( + options(), + json!({ "deepseek": { "thinking": { "type": "disabled" } } }), + ); + options.temperature = Some(0.2); + options.top_p = Some(0.4); + options.frequency_penalty = Some(0.5); + options.presence_penalty = Some(0.6); + let result = generate_result("deepseek-v4-flash", &options).await; + assert_eq!( + result.request.and_then(|request| request.body).unwrap(), + json!({ + "model": "deepseek-v4-flash", + "messages": [{ "role": "user", "content": "Hello" }], + "temperature": 0.2, + "top_p": 0.4, + "thinking": { "type": "disabled" } + }) + ); + assert_eq!( + warning_values(&result.warnings), + warning_values(&[ + deprecated("frequencyPenalty"), + deprecated("presencePenalty") + ]) + ); + } -#[tokio::test] -async fn text_should_reject_mixed_strict_tools_in_streaming_requests() { - let server = sse_server(text_chunks()).await; - let mut options = options(); - options.tools = Some(vec![ - strict_tool("strictTool", Some(true)), - strict_tool("nonStrictTool", None), - ]); - let Err(error) = beta_chat(&server, "deepseek-chat") - .do_stream(&options) - .await - else { - panic!("the call must be rejected"); - }; - assert!( + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should send message names + #[tokio::test] + async fn text_should_send_message_names() { + let name = |value: &str| json!({ "deepseek": { "name": value } }); + let messages = wire_messages( + "deepseek-chat", + vec![ + with_options( + LanguageModelMessage::System { + content: ("You are a helpful assistant.").into(), + provider_options: None, + }, + name("guide"), + ), + with_options(LanguageModelMessage::user_text("Hello"), name("alice")), + with_options( + LanguageModelMessage::Assistant { + content: vec![AssistantPart::Text(TextPart { + text: ("Hello, Alice.").into(), + provider_options: None, + })], + provider_options: None, + }, + name("assistant"), + ), + with_options( + LanguageModelMessage::user_text("How are you?"), + name("alice"), + ), + ], + ) + .await; + assert_eq!( + messages, + [ + json!({ "content": "You are a helpful assistant.", "name": "guide", "role": "system" }), + json!({ "content": "Hello", "name": "alice", "role": "user" }), + json!({ "content": "Hello, Alice.", "name": "assistant", "role": "assistant" }), + json!({ "content": "How are you?", "name": "alice", "role": "user" }), + ] + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should pass providerOptions userId as user_id + #[tokio::test] + async fn text_should_pass_provider_options_user_id_as_user_id() { + let options = with_provider_options( + options(), + json!({ "deepseek": { "userId": "tenant_123-user" } }), + ); + assert_eq!( + generate_body("deepseek-chat", &options).await["user_id"], + "tenant_123-user" + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should omit user_id when userId is not provided + #[tokio::test] + async fn text_should_omit_user_id_when_user_id_is_not_provided() { + assert!( + generate_body("deepseek-chat", &options()) + .await + .get("user_id") + .is_none() + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should reject strict tools on the standard endpoint before fetching + #[tokio::test] + async fn text_should_reject_strict_tools_on_the_standard_endpoint_before_fetching() { + let mut options = options(); + options.tools = Some(vec![strict_tool("getWeather", Some(true))]); + let message = generate_error("deepseek-chat", &options).await; + assert!( + message.contains( + "DeepSeek strict tool calls require a beta base URL ending in `/beta`." + ), + "{message}" + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should send all-strict tools on the beta endpoint + #[tokio::test] + async fn text_should_send_all_strict_tools_on_the_beta_endpoint() { + let server = json_server(text_response()).await; + let mut options = options(); + options.tools = Some(vec![strict_tool("getWeather", Some(true))]); + let body = beta_chat(&server, "deepseek-chat") + .do_generate(&options) + .await + .unwrap() + .request + .and_then(|r| r.body) + .unwrap(); + assert_eq!(body["tools"][0]["type"], "function"); + assert_eq!(body["tools"][0]["function"]["name"], "getWeather"); + assert_eq!(body["tools"][0]["function"]["strict"], true); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should reject mixed strict tools in streaming requests + #[tokio::test] + async fn text_should_reject_mixed_strict_tools_in_streaming_requests() { + let server = sse_server(text_chunks()).await; + let mut options = options(); + options.tools = Some(vec![ + strict_tool("strictTool", Some(true)), + strict_tool("nonStrictTool", None), + ]); + let Err(error) = beta_chat(&server, "deepseek-chat") + .do_stream(&options) + .await + else { + panic!("the call must be rejected"); + }; + assert!( error.to_string().contains( "DeepSeek strict mode requires every function tool in the request to set `strict: true`." ), "{error}" ); - assert!(request_paths(&server).await.is_empty()); -} + assert!(request_paths(&server).await.is_empty()); + } -#[tokio::test] -async fn text_should_reject_invalid_user_id_before_making_an_api_request() { - for (user_id, expected) in [ - ("".to_string(), "userId must match /^[a-zA-Z0-9_-]+$/"), - ( - "contains space".to_string(), - "userId must match /^[a-zA-Z0-9_-]+$/", - ), - ( - "a".repeat(513), - "userId must be at most 512 characters long", - ), - ] { - let options = - with_provider_options(options(), json!({ "deepseek": { "userId": user_id } })); - let message = generate_error("deepseek-chat", &options).await; - assert!(message.contains("invalid provider options"), "{message}"); - assert!(message.contains(expected), "{message}"); - } -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should reject invalid userId %j before making an API request + #[tokio::test] + async fn text_should_reject_invalid_user_id_before_making_an_api_request() { + for (user_id, expected) in [ + ("".to_string(), "userId must match /^[a-zA-Z0-9_-]+$/"), + ( + "contains space".to_string(), + "userId must match /^[a-zA-Z0-9_-]+$/", + ), + ( + "a".repeat(513), + "userId must be at most 512 characters long", + ), + ] { + let options = with_provider_options( + options(), + json!({ "deepseek": { "userId": user_id } }), + ); + let message = generate_error("deepseek-chat", &options).await; + assert!(message.contains("invalid provider options"), "{message}"); + assert!(message.contains(expected), "{message}"); + } + } -#[tokio::test] -async fn text_should_extract_text_content() { - let result = generate_result("deepseek-chat", &options()).await; - assert_eq!(result.content.len(), 1); - assert!( - matches!(&result.content[0], GenerateContent::Text { text, .. } if text == "Hello, World!") - ); - assert_eq!(result.finish_reason.unified, FinishReasonUnified::Stop); - assert_eq!(result.finish_reason.raw.as_deref(), Some("stop")); - assert_eq!(result.usage.input_tokens.total, Some(13)); - assert_eq!(result.usage.output_tokens.total, Some(300)); - assert_eq!( - result.response.as_ref().and_then(|r| r.id.as_deref()), - Some("00f10ecd-60b3-4707-b5db-e4bcadf7aea1") - ); - assert_eq!( - result.response.as_ref().and_then(|r| r.model_id.as_deref()), - Some("deepseek-chat") - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should include the system fingerprint in provider metadata + #[tokio::test] + async fn text_should_include_the_system_fingerprint_in_provider_metadata() { + let result = generate_result("deepseek-chat", &options()).await; + assert_eq!( + result.provider_metadata.unwrap()["deepseek"]["systemFingerprint"], + "fp_eaab8d114b_prod0820_fp8_kvcache" + ); + } -#[tokio::test] -async fn text_should_report_usage_with_prompt_cache_tokens() { - // upstream convert-to-deepseek-usage.ts: cache hits are the cache-read tokens. - let mut body = text_response(); - body["usage"] = json!({ - "prompt_tokens": 100, "completion_tokens": 20, "total_tokens": 120, - "prompt_cache_hit_tokens": 70, "prompt_cache_miss_tokens": 30, - "completion_tokens_details": { "reasoning_tokens": 5 } - }); - let server = json_server(body).await; - let usage = chat(&server, "deepseek-chat") - .do_generate(&options()) - .await - .unwrap() - .usage; - assert_eq!(usage.input_tokens.total, Some(100)); - assert_eq!(usage.input_tokens.cache_read, Some(70)); - assert_eq!(usage.input_tokens.no_cache, Some(30)); - assert_eq!(usage.output_tokens.total, Some(20)); - assert_eq!(usage.output_tokens.reasoning, Some(5)); - assert_eq!(usage.output_tokens.text, Some(15)); - assert_eq!(usage.raw.unwrap()["prompt_cache_hit_tokens"], 70); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › text › should tolerate a %s system fingerprint + #[tokio::test] + async fn text_should_tolerate_a_null_or_missing_system_fingerprint() { + for fingerprint in [Some(Value::Null), None] { + let mut body = text_response(); + match fingerprint { + Some(value) => body["system_fingerprint"] = value, + None => { + body.as_object_mut().unwrap().remove("system_fingerprint"); + } + } + let server = json_server(body).await; + let result = chat(&server, "deepseek-chat") + .do_generate(&options()) + .await + .unwrap(); + assert!( + result.provider_metadata.unwrap()["deepseek"] + .get("systemFingerprint") + .is_none() + ); + } + } + } -#[tokio::test] -async fn text_should_report_the_provider_metadata() { - // upstream doGenerate: promptCacheHitTokens, promptCacheMissTokens, - // responseObject, choiceIndex, messageRole, systemFingerprint. - let result = generate_result("deepseek-chat", &options()).await; - assert_eq!( - serde_json::to_value(result.provider_metadata.unwrap()).unwrap(), - json!({ "deepseek": { - "promptCacheHitTokens": 0, - "promptCacheMissTokens": 13, - "responseObject": "chat.completion", - "choiceIndex": 0, - "messageRole": "assistant", - "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" - } }) - ); -} + mod reasoning { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › reasoning › should send correct request body + #[tokio::test] + async fn reasoning_should_send_correct_request_body() { + let options = with_provider_options( + options_for(vec![LanguageModelMessage::user_text( + "How many \"r\"s are in the word \"strawberry\"?", + )]), + json!({ "deepseek": { "thinking": { "type": "enabled" } } }), + ); + assert_eq!( + generate_body("deepseek-reasoner", &options).await, + json!({ + "messages": [{ "content": "How many \"r\"s are in the word \"strawberry\"?", "role": "user" }], + "model": "deepseek-reasoner", + "thinking": { "type": "enabled" } + }) + ); + } + } -#[tokio::test] -async fn text_should_include_the_system_fingerprint_in_provider_metadata() { - let result = generate_result("deepseek-chat", &options()).await; - assert_eq!( - result.provider_metadata.unwrap()["deepseek"]["systemFingerprint"], - "fp_eaab8d114b_prod0820_fp8_kvcache" - ); -} + mod logprobs { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › logprobs › should send logprobs provider options + #[tokio::test] + async fn logprobs_should_send_logprobs_provider_options() { + let options = with_provider_options( + options(), + json!({ "deepseek": { "logprobs": true, "topLogprobs": 1 } }), + ); + assert_eq!( + generate_body("deepseek-v4-flash", &options).await, + json!({ + "logprobs": true, + "messages": [{ "content": "Hello", "role": "user" }], + "model": "deepseek-v4-flash", + "top_logprobs": 1 + }) + ); + } -#[tokio::test] -async fn text_should_tolerate_a_null_or_missing_system_fingerprint() { - for fingerprint in [Some(Value::Null), None] { - let mut body = text_response(); - match fingerprint { - Some(value) => body["system_fingerprint"] = value, - None => { - body.as_object_mut().unwrap().remove("system_fingerprint"); + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › logprobs › should enable logprobs when topLogprobs is set + #[tokio::test] + async fn logprobs_should_enable_logprobs_when_top_logprobs_is_set() { + let options = + with_provider_options(options(), json!({ "deepseek": { "topLogprobs": 1 } })); + let body = generate_body("deepseek-v4-flash", &options).await; + assert_eq!(body["logprobs"], true); + assert_eq!(body["top_logprobs"], 1); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › logprobs › should extract content and reasoning logprobs + #[tokio::test] + async fn logprobs_should_extract_content_and_reasoning_logprobs() { + let server = json_server(logprobs_response()).await; + let options = + with_provider_options(options(), json!({ "deepseek": { "logprobs": true } })); + let result = chat(&server, "deepseek-v4-flash") + .do_generate(&options) + .await + .unwrap(); + assert_eq!( + result.provider_metadata.unwrap()["deepseek"]["logprobs"], + json!({ + "content": [logprob("OK", -0.00002467602, json!([79, 75]))], + "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] + }) + ); } } - let server = json_server(body).await; - let result = chat(&server, "deepseek-chat") - .do_generate(&options()) - .await - .unwrap(); - assert!( - result.provider_metadata.unwrap()["deepseek"] - .get("systemFingerprint") - .is_none() - ); - } -} -// ---- describe('reasoning') --------------------------------------------------- + mod top_level_reasoning { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map top-level reasoning to thinking enabled + #[tokio::test] + async fn top_level_reasoning_should_map_to_thinking_enabled() { + let body = generate_body( + "deepseek-reasoner", + &reasoning_options(ReasoningEffort::High), + ) + .await; + assert_eq!(body["thinking"], json!({ "type": "enabled" })); + assert_eq!(body["reasoning_effort"], "high"); + } -fn reasoning_response() -> Value { - json!({ - "id": "r1", "object": "chat.completion", "created": 1764656316, "model": "deepseek-reasoner", - "choices": [{ - "index": 0, - "message": { - "role": "assistant", - "content": "There are 3 r's in strawberry.", - "reasoning_content": "Let me count the letters." - }, - "finish_reason": "stop" - }], - "usage": { "prompt_tokens": 20, "completion_tokens": 30, "total_tokens": 50, - "completion_tokens_details": { "reasoning_tokens": 10 } } - }) -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map top-level reasoning none to thinking disabled + #[tokio::test] + async fn top_level_reasoning_none_should_map_to_thinking_disabled() { + let body = generate_body( + "deepseek-reasoner", + &reasoning_options(ReasoningEffort::None), + ) + .await; + assert_eq!(body["thinking"], json!({ "type": "disabled" })); + assert!(body.get("reasoning_effort").is_none()); + } -#[tokio::test] -async fn reasoning_should_send_correct_request_body() { - let options = with_provider_options( - options_for(vec![LanguageModelMessage::user_text( - "How many \"r\"s are in the word \"strawberry\"?", - )]), - json!({ "deepseek": { "thinking": { "type": "enabled" } } }), - ); - assert_eq!( - generate_body("deepseek-reasoner", &options).await, - json!({ - "messages": [{ "content": "How many \"r\"s are in the word \"strawberry\"?", "role": "user" }], - "model": "deepseek-reasoner", - "thinking": { "type": "enabled" } - }) - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map top-level reasoning xhigh to reasoning_effort max + #[tokio::test] + async fn top_level_reasoning_xhigh_should_map_to_reasoning_effort_max() { + let result = generate_result( + "deepseek-reasoner", + &reasoning_options(ReasoningEffort::Xhigh), + ) + .await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], + "max" + ); + assert!(warning_values(&result.warnings).contains(&serde_json::to_value(compatibility( + "reasoning", + "reasoning \"xhigh\" is not directly supported by this model. mapped to effort \"max\"." + )) + .unwrap())); + } -#[tokio::test] -async fn reasoning_should_extract_reasoning_before_text() { - let server = json_server(reasoning_response()).await; - let result = chat(&server, "deepseek-reasoner") - .do_generate(&options()) - .await - .unwrap(); - assert_eq!(result.content.len(), 2); - assert!( - matches!(&result.content[0], GenerateContent::Reasoning(ReasoningOutput { text, .. }) if text == "Let me count the letters.") - ); - assert!( - matches!(&result.content[1], GenerateContent::Text { text, .. } if text == "There are 3 r's in strawberry.") + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map top-level reasoning low to reasoning_effort low without a compatibility warning + #[tokio::test] + async fn top_level_reasoning_low_should_map_to_reasoning_effort_low_without_a_compatibility_warning() + { + let result = generate_result( + "deepseek-reasoner", + &reasoning_options(ReasoningEffort::Low), + ) + .await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], + "low" + ); + assert!( + !result + .warnings + .iter() + .any(|w| matches!(w, Warning::Compatibility { feature, .. } if feature == "reasoning")) ); - assert_eq!(result.usage.output_tokens.reasoning, Some(10)); - assert_eq!(result.usage.output_tokens.text, Some(20)); -} + } -#[tokio::test] -async fn reasoning_should_not_read_the_reasoning_field() { - // upstream deepseekChatResponseSchema only declares `reasoning_content`. - let mut body = reasoning_response(); - let message = body["choices"][0]["message"].as_object_mut().unwrap(); - let reasoning = message.remove("reasoning_content").unwrap(); - message.insert("reasoning".to_string(), reasoning); - let server = json_server(body).await; - let result = chat(&server, "deepseek-reasoner") - .do_generate(&options()) - .await - .unwrap(); - assert_eq!(result.content.len(), 1); - assert!(matches!(&result.content[0], GenerateContent::Text { .. })); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map top-level reasoning medium to reasoning_effort high with a compatibility warning + #[tokio::test] + async fn top_level_reasoning_medium_should_map_to_reasoning_effort_high_with_a_compatibility_warning() + { + let result = generate_result( + "deepseek-reasoner", + &reasoning_options(ReasoningEffort::Medium), + ) + .await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], + "high" + ); + assert_eq!( + warning_values(&result.warnings), + warning_values(&[compatibility( + "reasoning", + "reasoning \"medium\" is not directly supported by this model. mapped to effort \"high\"." + )]) + ); + } -// ---- describe('logprobs') ---------------------------------------------------- + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map top-level reasoning minimal to reasoning_effort low with compatibility warning + #[tokio::test] + async fn top_level_reasoning_minimal_should_map_to_reasoning_effort_low_with_compatibility_warning() + { + let result = generate_result( + "deepseek-reasoner", + &reasoning_options(ReasoningEffort::Minimal), + ) + .await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], + "low" + ); + assert_eq!( + warning_values(&result.warnings), + warning_values(&[compatibility( + "reasoning", + "reasoning \"minimal\" is not directly supported by this model. mapped to effort \"low\"." + )]) + ); + } -fn logprobs_response() -> Value { - let mut body = text_response(); - body["choices"][0]["message"] = json!({ - "role": "assistant", "content": "OK", "reasoning_content": "Reasoning" - }); - body["choices"][0]["logprobs"] = json!({ - "content": [logprob("OK", -0.00002467602, json!([79, 75]))], - "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] - }); - body -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map providerOptions reasoningEffort $input to $output + #[tokio::test] + async fn top_level_reasoning_should_map_provider_options_reasoning_effort() { + for (input, output, warns) in [ + ("low", "low", false), + ("medium", "high", true), + ("xhigh", "max", true), + ] { + let options = with_provider_options( + options(), + json!({ "deepseek": { "reasoningEffort": input } }), + ); + let result = generate_result("deepseek-reasoner", &options).await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], + output + ); + let expected = if warns { + vec![compatibility( + "reasoningEffort", + &format!( + "reasoningEffort \"{input}\" is not a canonical DeepSeek value. mapped to \"{output}\"." + ), + )] + } else { + vec![] + }; + assert_eq!(warning_values(&result.warnings), warning_values(&expected)); + } + } -#[tokio::test] -async fn logprobs_should_send_logprobs_provider_options() { - let options = with_provider_options( - options(), - json!({ "deepseek": { "logprobs": true, "topLogprobs": 1 } }), - ); - assert_eq!( - generate_body("deepseek-v4-flash", &options).await, - json!({ - "logprobs": true, - "messages": [{ "content": "Hello", "role": "user" }], - "model": "deepseek-v4-flash", - "top_logprobs": 1 - }) - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should map legacy providerOptions thinking.type=adaptive to enabled with a compatibility warning + #[tokio::test] + async fn top_level_reasoning_should_map_legacy_thinking_type_adaptive_to_enabled_with_a_compatibility_warning() + { + let options = with_provider_options( + options(), + json!({ "deepseek": { "thinking": { "type": "adaptive" } } }), + ); + let result = generate_result("deepseek-reasoner", &options).await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["thinking"], + json!({ "type": "enabled" }) + ); + assert!(warning_values(&result.warnings).contains(&serde_json::to_value(compatibility( + "thinking.type", + "thinking.type \"adaptive\" is not a canonical DeepSeek value. mapped to \"enabled\"." + )) + .unwrap())); + } -#[tokio::test] -async fn logprobs_should_enable_logprobs_when_top_logprobs_is_set() { - let options = with_provider_options(options(), json!({ "deepseek": { "topLogprobs": 1 } })); - let body = generate_body("deepseek-v4-flash", &options).await; - assert_eq!(body["logprobs"], true); - assert_eq!(body["top_logprobs"], 1); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should pass providerOptions reasoningEffort + #[tokio::test] + async fn top_level_reasoning_should_pass_provider_options_reasoning_effort() { + let options = with_provider_options( + options(), + json!({ "deepseek": { "reasoningEffort": "max" } }), + ); + let body = generate_body("deepseek-reasoner", &options).await; + assert_eq!(body["reasoning_effort"], "max"); + // When only reasoningEffort is set without thinking, thinking stays unset. + assert!(body.get("thinking").is_none()); + } -#[tokio::test] -async fn logprobs_should_extract_content_and_reasoning_logprobs() { - let server = json_server(logprobs_response()).await; - let options = with_provider_options(options(), json!({ "deepseek": { "logprobs": true } })); - let result = chat(&server, "deepseek-v4-flash") - .do_generate(&options) - .await - .unwrap(); - assert_eq!( - result.provider_metadata.unwrap()["deepseek"]["logprobs"], - json!({ - "content": [logprob("OK", -0.00002467602, json!([79, 75]))], - "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] - }) - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should prefer providerOptions thinking over top-level reasoning + #[tokio::test] + async fn top_level_reasoning_should_prefer_provider_options_thinking_over_top_level_reasoning() + { + let options = with_provider_options( + reasoning_options(ReasoningEffort::None), + json!({ "deepseek": { "thinking": { "type": "enabled" } } }), + ); + assert_eq!( + generate_body("deepseek-reasoner", &options).await["thinking"], + json!({ "type": "enabled" }) + ); + } -// ---- describe('top-level reasoning') ------------------------------------------- + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should prefer providerOptions reasoningEffort over top-level reasoning + #[tokio::test] + async fn top_level_reasoning_should_prefer_provider_options_reasoning_effort_over_top_level_reasoning() + { + let options = with_provider_options( + reasoning_options(ReasoningEffort::High), + json!({ "deepseek": { "reasoningEffort": "max" } }), + ); + assert_eq!( + generate_body("deepseek-reasoner", &options).await["reasoning_effort"], + "max" + ); + } -fn reasoning_options(effort: ReasoningEffort) -> CallOptions { - CallOptions { - reasoning: Some(effort), - ..options() - } -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › top-level reasoning › should not set thinking when reasoning is not specified + #[tokio::test] + async fn top_level_reasoning_should_not_set_thinking_when_reasoning_is_not_specified() { + assert!( + generate_body("deepseek-reasoner", &options()) + .await + .get("thinking") + .is_none() + ); + } + } -#[tokio::test] -async fn top_level_reasoning_should_map_to_thinking_enabled() { - let body = generate_body( - "deepseek-reasoner", - &reasoning_options(ReasoningEffort::High), - ) - .await; - assert_eq!(body["thinking"], json!({ "type": "enabled" })); - assert_eq!(body["reasoning_effort"], "high"); -} - -#[tokio::test] -async fn top_level_reasoning_none_should_map_to_thinking_disabled() { - let body = generate_body( - "deepseek-reasoner", - &reasoning_options(ReasoningEffort::None), - ) - .await; - assert_eq!(body["thinking"], json!({ "type": "disabled" })); - assert!(body.get("reasoning_effort").is_none()); -} - -#[tokio::test] -async fn top_level_reasoning_none_should_keep_the_temperature() { - // thinking is disabled, so temperature applies and is not warned about. - let mut options = reasoning_options(ReasoningEffort::None); - options.temperature = Some(0.4); - let result = generate_result("deepseek-reasoner", &options).await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["temperature"], - 0.4 - ); - assert!(result.warnings.is_empty()); -} - -#[tokio::test] -async fn top_level_reasoning_xhigh_should_map_to_reasoning_effort_max() { - let result = generate_result( - "deepseek-reasoner", - &reasoning_options(ReasoningEffort::Xhigh), - ) - .await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], - "max" - ); - assert!(warning_values(&result.warnings).contains(&serde_json::to_value(compatibility( - "reasoning", - "reasoning \"xhigh\" is not directly supported by this model. mapped to effort \"max\"." - )) - .unwrap())); -} + mod tool_call { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › tool call › should send correct request body + #[tokio::test] + async fn tool_call_should_send_correct_request_body() { + assert_eq!( + generate_body("deepseek-reasoner", &tool_options()).await, + json!({ + "messages": [{ "content": "Hello", "role": "user" }], + "model": "deepseek-reasoner", + "thinking": { "type": "enabled" }, + "tools": [weather_wire_tool()] + }) + ); + } -#[tokio::test] -async fn top_level_reasoning_low_should_map_to_reasoning_effort_low_without_a_compatibility_warning() - { - let result = generate_result( - "deepseek-reasoner", - &reasoning_options(ReasoningEffort::Low), - ) - .await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], - "low" - ); - assert!( - !result - .warnings - .iter() - .any(|w| matches!(w, Warning::Compatibility { feature, .. } if feature == "reasoning")) - ); -} + mod json_response_format { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › tool call › json response format › should send correct request body without schema + #[tokio::test] + async fn json_response_format_should_send_correct_request_body_without_schema() { + assert_eq!( + generate_body("deepseek-reasoner", &json_options(None)).await, + json!({ + "messages": [ + { "content": "Return JSON.", "role": "system" }, + { "content": "Hello", "role": "user" } + ], + "model": "deepseek-reasoner", + "response_format": { "type": "json_object" }, + "thinking": { "type": "enabled" }, + "tools": [weather_wire_tool()] + }) + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › tool call › json response format › should send correct request body with schema + #[tokio::test] + async fn json_response_format_should_send_correct_request_body_with_schema() { + let schema = json!({ + "type": "object", + "properties": { "elements": { "type": "array", "items": { "type": "object", + "properties": { "location": { "type": "string" }, "temperature": { "type": "number" }, + "condition": { "type": "string" } }, + "required": ["location", "temperature", "condition"], "additionalProperties": false } } }, + "required": ["elements"], "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + }); + let result = + generate_result("deepseek-reasoner", &json_options(Some(schema.clone()))) + .await; + let body = result.request.and_then(|r| r.body).unwrap(); + assert_eq!( + body["messages"][0], + json!({ + "role": "system", + "content": format!("Return JSON that conforms to the following schema: {schema}") + }) + ); + assert_eq!( + body["messages"][1], + json!({ "role": "user", "content": "Hello" }) + ); + assert_eq!(body["response_format"], json!({ "type": "json_object" })); + // upstream: supportsStructuredOutputs is false, so the schema is injected + // into the system message with a compatibility warning. + assert_eq!( + warning_values(&result.warnings), + warning_values(&[compatibility( + "responseFormat JSON schema", + "JSON response schema is injected into the system message." + )]) + ); + } + } + } -#[tokio::test] -async fn top_level_reasoning_medium_should_map_to_reasoning_effort_high_with_a_compatibility_warning() - { - let result = generate_result( - "deepseek-reasoner", - &reasoning_options(ReasoningEffort::Medium), - ) - .await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], - "high" - ); - assert_eq!( - warning_values(&result.warnings), - warning_values(&[compatibility( - "reasoning", - "reasoning \"medium\" is not directly supported by this model. mapped to effort \"high\"." - )]) - ); -} + mod assistant_prefix_completion { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › assistant prefix completion › should send name and prefix on the final assistant message + #[tokio::test] + async fn prefix_should_send_name_and_prefix_on_the_final_assistant_message() { + let server = json_server(text_response()).await; + let body = beta_chat(&server, "deepseek-chat") + .do_generate(&options_for(prefix_prompt( + json!({ "name": "assistant", "prefix": true }), + ))) + .await + .unwrap() + .request + .and_then(|r| r.body) + .unwrap(); + assert_eq!( + body["messages"], + json!([ + { "role": "user", "content": "Complete this sentence." }, + { "role": "assistant", "content": "The answer is", "name": "assistant", "prefix": true } + ]) + ); + assert_eq!(body["model"], "deepseek-chat"); + } -#[tokio::test] -async fn top_level_reasoning_minimal_should_map_to_reasoning_effort_low_with_compatibility_warning() -{ - let result = generate_result( - "deepseek-reasoner", - &reasoning_options(ReasoningEffort::Minimal), - ) - .await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], - "low" - ); - assert_eq!( - warning_values(&result.warnings), - warning_values(&[compatibility( - "reasoning", - "reasoning \"minimal\" is not directly supported by this model. mapped to effort \"low\"." - )]) + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doGenerate › assistant prefix completion › should reject prefix completion with the default base URL + #[tokio::test] + async fn prefix_should_reject_prefix_completion_with_the_default_base_url() { + let message = generate_error( + "deepseek-chat", + &options_for(vec![with_options( + LanguageModelMessage::Assistant { + content: vec![AssistantPart::Text(TextPart { + text: ("The answer is").into(), + provider_options: None, + })], + provider_options: None, + }, + json!({ "deepseek": { "prefix": true } }), + )]), + ) + .await; + assert!( + message.contains( + "DeepSeek assistant prefix completion requires a beta base URL ending in `/beta`." + ), + "{message}" ); -} - -#[tokio::test] -async fn top_level_reasoning_should_map_provider_options_reasoning_effort() { - for (input, output, warns) in [ - ("low", "low", false), - ("medium", "high", true), - ("xhigh", "max", true), - ] { - let options = with_provider_options( - options(), - json!({ "deepseek": { "reasoningEffort": input } }), - ); - let result = generate_result("deepseek-reasoner", &options).await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["reasoning_effort"], - output - ); - let expected = if warns { - vec![compatibility( - "reasoningEffort", - &format!( - "reasoningEffort \"{input}\" is not a canonical DeepSeek value. mapped to \"{output}\"." - ), - )] - } else { - vec![] - }; - assert_eq!(warning_values(&result.warnings), warning_values(&expected)); + } + } } -} - -#[tokio::test] -async fn top_level_reasoning_should_map_legacy_thinking_type_adaptive_to_enabled_with_a_compatibility_warning() - { - let options = with_provider_options( - options(), - json!({ "deepseek": { "thinking": { "type": "adaptive" } } }), - ); - let result = generate_result("deepseek-reasoner", &options).await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["thinking"], - json!({ "type": "enabled" }) - ); - assert!(warning_values(&result.warnings).contains(&serde_json::to_value(compatibility( - "thinking.type", - "thinking.type \"adaptive\" is not a canonical DeepSeek value. mapped to \"enabled\"." - )) - .unwrap())); -} -#[tokio::test] -async fn top_level_reasoning_should_pass_provider_options_reasoning_effort() { - let options = with_provider_options( - options(), - json!({ "deepseek": { "reasoningEffort": "max" } }), - ); - let body = generate_body("deepseek-reasoner", &options).await; - assert_eq!(body["reasoning_effort"], "max"); - // When only reasoningEffort is set without thinking, thinking stays unset. - assert!(body.get("thinking").is_none()); -} - -#[tokio::test] -async fn top_level_reasoning_should_prefer_provider_options_thinking_over_top_level_reasoning() { - let options = with_provider_options( - reasoning_options(ReasoningEffort::None), - json!({ "deepseek": { "thinking": { "type": "enabled" } } }), - ); - assert_eq!( - generate_body("deepseek-reasoner", &options).await["thinking"], - json!({ "type": "enabled" }) - ); -} - -#[tokio::test] -async fn top_level_reasoning_should_prefer_provider_options_reasoning_effort_over_top_level_reasoning() - { - let options = with_provider_options( - reasoning_options(ReasoningEffort::High), - json!({ "deepseek": { "reasoningEffort": "max" } }), - ); - assert_eq!( - generate_body("deepseek-reasoner", &options).await["reasoning_effort"], - "max" - ); -} - -#[tokio::test] -async fn top_level_reasoning_should_not_set_thinking_when_reasoning_is_not_specified() { - assert!( - generate_body("deepseek-reasoner", &options()) - .await - .get("thinking") - .is_none() - ); -} + mod do_stream { + use super::*; -#[tokio::test] -async fn top_level_reasoning_provider_default_sends_neither_thinking_nor_effort() { - let body = generate_body( - "deepseek-reasoner", - &reasoning_options(ReasoningEffort::ProviderDefault), - ) - .await; - assert!(body.get("thinking").is_none() && body.get("reasoning_effort").is_none()); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › should preserve a provider error envelope in stream errors + #[tokio::test] + async fn stream_should_preserve_a_provider_error_envelope_in_stream_errors() { + let data = json!({ "error": { + "message": "Rate limit reached", "type": "rate_limit_error", "code": "rate_limit_exceeded" + } }); + let error = stream_error(&data).await; + assert_eq!(error.message, "Rate limit reached"); + assert_eq!(error.provider_code.as_deref(), Some("rate_limit_exceeded")); + assert_eq!(error.status_code, Some(429)); + assert!(error.is_retryable); + // upstream: `data` is the whole error envelope. + let envelope: Value = + serde_json::from_str(error.response_body.as_deref().unwrap()).unwrap(); + assert_eq!(envelope, data); + } -// ---- describe('tool call') --------------------------------------------------- + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › should classify insufficient quota as non-retryable + #[tokio::test] + async fn stream_should_classify_insufficient_quota_as_non_retryable() { + let data = json!({ "error": { + "message": "You exceeded your current quota.", "type": "rate_limit_error", + "code": "insufficient_quota" + } }); + let error = stream_error(&data).await; + assert_eq!(error.status_code, Some(429)); + assert!(!error.is_retryable); + } -fn tool_call_response() -> Value { - json!({ - "id": "t1", "object": "chat.completion", "created": 1764656316, "model": "deepseek-reasoner", - "choices": [{ - "index": 0, - "message": { - "role": "assistant", "content": "", - "reasoning_content": "I should look up the weather.", - "tool_calls": [{ - "id": "call_00_abc", "type": "function", - "function": { "name": "weather", "arguments": "{\"location\":\"San Francisco\"}" } - }] - }, - "finish_reason": "tool_calls" - }], - "usage": { "prompt_tokens": 50, "completion_tokens": 20, "total_tokens": 70 } - }) -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › should preserve the provider type when code is an HTTP status + #[tokio::test] + async fn stream_should_preserve_the_provider_type_when_code_is_an_http_status() { + let data = json!({ "error": { + "message": "Rate limit reached", "type": "rate_limit_error", "code": "429" + } }); + let error = stream_error(&data).await; + assert_eq!(error.provider_code.as_deref(), Some("429")); + assert_eq!(error.status_code, Some(429)); + assert!(error.is_retryable); + } -fn tool_options() -> CallOptions { - let mut options = with_provider_options( - options(), - json!({ "deepseek": { "thinking": { "type": "enabled" } } }), - ); - options.tools = Some(vec![Tool::Function(weather_tool())]); - options -} + mod text { + use super::*; -fn weather_wire_tool() -> Value { - json!({ - "type": "function", - "function": { - "name": "weather", - "parameters": { - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { "location": { "type": "string" } }, - "required": ["location"], - "type": "object" + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should send model id, settings, and input + #[tokio::test] + async fn stream_text_should_send_model_id_settings_and_input() { + let mut options = options_for(vec![ + LanguageModelMessage::System { + content: ("You are a helpful assistant.").into(), + provider_options: None, + }, + LanguageModelMessage::user_text("Hello"), + ]); + options.temperature = Some(0.5); + options.top_p = Some(0.3); + let (body, _) = stream_parts("deepseek-chat", &options, text_chunks()).await; + assert_eq!( + body, + json!({ + "messages": [ + { "content": "You are a helpful assistant.", "role": "system" }, + { "content": "Hello", "role": "user" } + ], + "model": "deepseek-chat", + "stream": true, + "stream_options": { "include_usage": true }, + "temperature": 0.5, + "top_p": 0.3 + }) + ); } - } - }) -} -#[tokio::test] -async fn tool_call_should_send_correct_request_body() { - assert_eq!( - generate_body("deepseek-reasoner", &tool_options()).await, - json!({ - "messages": [{ "content": "Hello", "role": "user" }], - "model": "deepseek-reasoner", - "thinking": { "type": "enabled" }, - "tools": [weather_wire_tool()] - }) - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should omit deprecated and ineffective sampling options in default V4 thinking mode + #[tokio::test] + async fn stream_text_should_omit_deprecated_and_ineffective_sampling_options_in_default_v4_thinking_mode() + { + let mut options = options(); + options.temperature = Some(0.2); + options.top_p = Some(0.4); + options.frequency_penalty = Some(0.5); + options.presence_penalty = Some(0.6); + let (body, parts) = + stream_parts("deepseek-v4-flash", &options, text_chunks()).await; + assert_eq!( + body, + json!({ + "model": "deepseek-v4-flash", + "messages": [{ "role": "user", "content": "Hello" }], + "stream": true, + "stream_options": { "include_usage": true } + }) + ); + assert_eq!( + stream_start_warnings(&parts), + warning_values(&[ + deprecated("frequencyPenalty"), + deprecated("presencePenalty"), + thinking_unsupported("temperature"), + thinking_unsupported("topP"), + ]) + ); + } -#[tokio::test] -async fn tool_call_should_send_the_tool_choice() { - use aimux_core::options::LanguageModelV4ToolChoice; - let mut options = tool_options(); - options.tool_choice = Some(LanguageModelV4ToolChoice::Tool { - tool_name: "weather".to_string(), - }); - assert_eq!( - generate_body("deepseek-reasoner", &options).await["tool_choice"], - json!({ "type": "function", "function": { "name": "weather" } }) - ); - options.tool_choice = Some(LanguageModelV4ToolChoice::Required); - assert_eq!( - generate_body("deepseek-reasoner", &options).await["tool_choice"], - "required" - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should preserve supported sampling options when V4 thinking is disabled + #[tokio::test] + async fn stream_text_should_preserve_supported_sampling_options_when_v4_thinking_is_disabled() + { + let mut options = with_provider_options( + options(), + json!({ "deepseek": { "thinking": { "type": "disabled" } } }), + ); + options.temperature = Some(0.2); + options.top_p = Some(0.4); + options.frequency_penalty = Some(0.5); + options.presence_penalty = Some(0.6); + let (body, parts) = + stream_parts("deepseek-v4-flash", &options, text_chunks()).await; + assert_eq!( + body, + json!({ + "model": "deepseek-v4-flash", + "messages": [{ "role": "user", "content": "Hello" }], + "temperature": 0.2, + "top_p": 0.4, + "thinking": { "type": "disabled" }, + "stream": true, + "stream_options": { "include_usage": true } + }) + ); + assert_eq!( + stream_start_warnings(&parts), + warning_values(&[ + deprecated("frequencyPenalty"), + deprecated("presencePenalty") + ]) + ); + } -#[tokio::test] -async fn tool_call_should_warn_about_provider_defined_tools() { - use aimux_core::tool::ProviderTool; - let mut options = options(); - options.tools = Some(vec![Tool::Provider(ProviderTool { - id: "test.search".parse().unwrap(), - name: "search".to_string(), - args: serde_json::Map::new(), - supports_deferred_results: None, - })]); - let result = generate_result("deepseek-chat", &options).await; - assert_eq!( - warning_values(&result.warnings), - warning_values(&[Warning::Unsupported { - feature: "provider-defined tool test.search".to_string(), - details: None, - }]) - ); - assert!( - result.request.and_then(|r| r.body).unwrap()["tools"] - .as_array() - .unwrap() - .is_empty() - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should send message names + #[tokio::test] + async fn stream_text_should_send_message_names() { + let name = |value: &str| json!({ "deepseek": { "name": value } }); + let options = options_for(vec![ + with_options( + LanguageModelMessage::System { + content: ("You are a helpful assistant.").into(), + provider_options: None, + }, + name("guide"), + ), + with_options(LanguageModelMessage::user_text("Hello"), name("alice")), + with_options( + LanguageModelMessage::Assistant { + content: vec![AssistantPart::Text(TextPart { + text: ("Hello, Alice.").into(), + provider_options: None, + })], + provider_options: None, + }, + name("assistant"), + ), + ]); + let (body, _) = stream_parts("deepseek-chat", &options, text_chunks()).await; + assert_eq!( + body["messages"], + json!([ + { "content": "You are a helpful assistant.", "name": "guide", "role": "system" }, + { "content": "Hello", "name": "alice", "role": "user" }, + { "content": "Hello, Alice.", "name": "assistant", "role": "assistant" } + ]) + ); + } -#[tokio::test] -async fn tool_call_should_extract_tool_call_content() { - let server = json_server(tool_call_response()).await; - let result = chat(&server, "deepseek-reasoner") - .do_generate(&tool_options()) - .await - .unwrap(); - assert!( - matches!(&result.content[0], GenerateContent::Reasoning(ReasoningOutput { text, .. }) if text == "I should look up the weather.") - ); - assert!(matches!( - &result.content[1], - GenerateContent::ToolCall(RawToolCall { tool_call_id, tool_name, input, .. }) - if tool_call_id == "call_00_abc" && tool_name == "weather" - && input == "{\"location\":\"San Francisco\"}" - )); - assert_eq!(result.content.len(), 2); - assert_eq!(result.finish_reason.unified, FinishReasonUnified::ToolCalls); - assert_eq!( - result.provider_metadata.unwrap()["deepseek"]["toolCallTypes"], - json!(["function"]) - ); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should pass providerOptions userId as user_id + #[tokio::test] + async fn stream_text_should_pass_provider_options_user_id_as_user_id() { + let options = with_provider_options( + options(), + json!({ "deepseek": { "userId": "tenant_123-user" } }), + ); + let (body, _) = stream_parts("deepseek-chat", &options, text_chunks()).await; + assert_eq!(body["user_id"], "tenant_123-user"); + assert_eq!(body["stream"], true); + } -#[tokio::test] -async fn tool_call_should_generate_an_id_when_the_server_sends_none() { - let mut body = tool_call_response(); - body["choices"][0]["message"]["tool_calls"][0]["id"] = Value::Null; - let server = json_server(body).await; - let result = chat(&server, "deepseek-reasoner") - .do_generate(&tool_options()) - .await - .unwrap(); - assert!(matches!( - &result.content[1], - GenerateContent::ToolCall(RawToolCall { tool_call_id, .. }) if !tool_call_id.is_empty() - )); -} - -// ---- describe('json response format') ------------------------------------------- - -fn json_options(schema: Option) -> CallOptions { - let mut options = tool_options(); - options.response_format = Some(ResponseFormat::Json { - schema, - name: None, - description: None, - }); - options -} - -#[tokio::test] -async fn json_response_format_should_send_correct_request_body_without_schema() { - assert_eq!( - generate_body("deepseek-reasoner", &json_options(None)).await, - json!({ - "messages": [ - { "content": "Return JSON.", "role": "system" }, - { "content": "Hello", "role": "user" } - ], - "model": "deepseek-reasoner", - "response_format": { "type": "json_object" }, - "thinking": { "type": "enabled" }, - "tools": [weather_wire_tool()] - }) - ); -} - -#[tokio::test] -async fn json_response_format_should_send_correct_request_body_with_schema() { - let schema = json!({ - "type": "object", - "properties": { "elements": { "type": "array", "items": { "type": "object", - "properties": { "location": { "type": "string" }, "temperature": { "type": "number" }, - "condition": { "type": "string" } }, - "required": ["location", "temperature", "condition"], "additionalProperties": false } } }, - "required": ["elements"], "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema#" - }); - let result = generate_result("deepseek-reasoner", &json_options(Some(schema.clone()))).await; - let body = result.request.and_then(|r| r.body).unwrap(); - assert_eq!( - body["messages"][0], - json!({ - "role": "system", - "content": format!("Return JSON that conforms to the following schema: {schema}") - }) - ); - assert_eq!( - body["messages"][1], - json!({ "role": "user", "content": "Hello" }) - ); - assert_eq!(body["response_format"], json!({ "type": "json_object" })); - // upstream: supportsStructuredOutputs is false, so the schema is injected - // into the system message with a compatibility warning. - assert_eq!( - warning_values(&result.warnings), - warning_values(&[compatibility( - "responseFormat JSON schema", - "JSON response schema is injected into the system message." - )]) - ); -} - -#[tokio::test] -async fn json_response_format_should_extract_text_content() { - let mut body = text_response(); - body["choices"][0]["message"]["content"] = json!("{\"elements\":[]}"); - let server = json_server(body).await; - let result = chat(&server, "deepseek-reasoner") - .do_generate(&json_options(None)) - .await - .unwrap(); - assert!( - matches!(&result.content[0], GenerateContent::Text { text, .. } if text == "{\"elements\":[]}") - ); -} - -// ---- describe('assistant prefix completion') -------------------------------------- - -fn prefix_prompt(prefix_options: Value) -> LanguageModelPrompt { - vec![ - LanguageModelMessage::user_text("Complete this sentence."), - with_options( - LanguageModelMessage::Assistant { - content: vec![AssistantPart::Text(TextPart { - text: ("The answer is").into(), - provider_options: None, - })], - provider_options: None, - }, - json!({ "deepseek": prefix_options }), - ), - ] -} - -#[tokio::test] -async fn prefix_should_send_name_and_prefix_on_the_final_assistant_message() { - let server = json_server(text_response()).await; - let body = beta_chat(&server, "deepseek-chat") - .do_generate(&options_for(prefix_prompt( - json!({ "name": "assistant", "prefix": true }), - ))) - .await - .unwrap() - .request - .and_then(|r| r.body) - .unwrap(); - assert_eq!( - body["messages"], - json!([ - { "role": "user", "content": "Complete this sentence." }, - { "role": "assistant", "content": "The answer is", "name": "assistant", "prefix": true } - ]) - ); - assert_eq!(body["model"], "deepseek-chat"); -} - -#[tokio::test] -async fn prefix_should_reject_prefix_completion_with_the_default_base_url() { - let message = generate_error( - "deepseek-chat", - &options_for(vec![with_options( - LanguageModelMessage::Assistant { - content: vec![AssistantPart::Text(TextPart { - text: ("The answer is").into(), - provider_options: None, - })], - provider_options: None, - }, - json!({ "deepseek": { "prefix": true } }), - )]), - ) - .await; - assert!( - message.contains( - "DeepSeek assistant prefix completion requires a beta base URL ending in `/beta`." - ), - "{message}" - ); -} - -// Upstream emits provider error envelopes as error parts, including the first event. -async fn stream_error(data: &Value) -> aimux_core::error::ApiCallError { - let server = sse_server(vec![data_event(data)]).await; - let result = chat(&server, "deepseek-chat") - .do_stream(&options()) - .await - .unwrap(); - collect(result) - .await - .into_iter() - .find_map(|part| match part { - StreamPart::Error { - error: AiMuxError::ApiCall(error), - } => Some(*error), - _ => None, - }) - .expect("expected a provider error part") -} - -/// `deepSeekErrorSchema` as the chat model's failed-response handler -/// (deepseek@3.0.56 `deepseek-chat-api-types.ts:117-124`, -/// `deepseek-chat-language-model.ts:213-217`): `code` may be a number. -#[tokio::test] -async fn a_failed_response_reads_deepseeks_error_schema() { - let server = MockServer::start().await; - Mock::given(method("POST")) - .and(path_regex(".*/chat/completions$")) - .respond_with(ResponseTemplate::new(402).set_body_json(json!({ "error": { - "message": "Insufficient Balance", "type": "unknown_error", "param": null, "code": 4020 - } }))) - .mount(&server) - .await; - let Err(AiMuxError::ApiCall(error)) = - chat(&server, "deepseek-chat").do_generate(&options()).await - else { - panic!("expected an API call error"); - }; - assert_eq!(error.message, "Insufficient Balance"); - assert_eq!(error.provider_code.as_deref(), Some("4020")); - assert_eq!(error.status_code, Some(402)); -} - -#[tokio::test] -async fn stream_should_preserve_a_provider_error_envelope_in_stream_errors() { - let data = json!({ "error": { - "message": "Rate limit reached", "type": "rate_limit_error", "code": "rate_limit_exceeded" - } }); - let error = stream_error(&data).await; - assert_eq!(error.message, "Rate limit reached"); - assert_eq!(error.provider_code.as_deref(), Some("rate_limit_exceeded")); - assert_eq!(error.status_code, Some(429)); - assert!(error.is_retryable); - // upstream: `data` is the whole error envelope. - let envelope: Value = serde_json::from_str(error.response_body.as_deref().unwrap()).unwrap(); - assert_eq!(envelope, data); -} - -#[tokio::test] -async fn stream_should_classify_insufficient_quota_as_non_retryable() { - let data = json!({ "error": { - "message": "You exceeded your current quota.", "type": "rate_limit_error", - "code": "insufficient_quota" - } }); - let error = stream_error(&data).await; - assert_eq!(error.status_code, Some(429)); - assert!(!error.is_retryable); -} - -#[tokio::test] -async fn stream_should_preserve_the_provider_type_when_code_is_an_http_status() { - let data = json!({ "error": { - "message": "Rate limit reached", "type": "rate_limit_error", "code": "429" - } }); - let error = stream_error(&data).await; - assert_eq!(error.provider_code.as_deref(), Some("429")); - assert_eq!(error.status_code, Some(429)); - assert!(error.is_retryable); -} - -async fn stream_parts( - model_id: &str, - options: &CallOptions, - chunks: Vec, -) -> (Value, Vec) { - let server = sse_server(chunks).await; - let result = chat(&server, model_id).do_stream(options).await.unwrap(); - let body = result.request.clone().and_then(|r| r.body).unwrap(); - (body, collect(result).await) -} - -#[tokio::test] -async fn stream_text_should_send_model_id_settings_and_input() { - let mut options = options_for(vec![ - LanguageModelMessage::System { - content: ("You are a helpful assistant.").into(), - provider_options: None, - }, - LanguageModelMessage::user_text("Hello"), - ]); - options.temperature = Some(0.5); - options.top_p = Some(0.3); - let (body, _) = stream_parts("deepseek-chat", &options, text_chunks()).await; - assert_eq!( - body, - json!({ - "messages": [ - { "content": "You are a helpful assistant.", "role": "system" }, - { "content": "Hello", "role": "user" } - ], - "model": "deepseek-chat", - "stream": true, - "stream_options": { "include_usage": true }, - "temperature": 0.5, - "top_p": 0.3 - }) - ); -} - -#[tokio::test] -async fn stream_text_should_omit_deprecated_and_ineffective_sampling_options_in_default_v4_thinking_mode() - { - let mut options = options(); - options.temperature = Some(0.2); - options.top_p = Some(0.4); - options.frequency_penalty = Some(0.5); - options.presence_penalty = Some(0.6); - let (body, parts) = stream_parts("deepseek-v4-flash", &options, text_chunks()).await; - assert_eq!( - body, - json!({ - "model": "deepseek-v4-flash", - "messages": [{ "role": "user", "content": "Hello" }], - "stream": true, - "stream_options": { "include_usage": true } - }) - ); - assert_eq!( - stream_start_warnings(&parts), - warning_values(&[ - deprecated("frequencyPenalty"), - deprecated("presencePenalty"), - thinking_unsupported("temperature"), - thinking_unsupported("topP"), - ]) - ); -} - -#[tokio::test] -async fn stream_text_should_preserve_supported_sampling_options_when_v4_thinking_is_disabled() { - let mut options = with_provider_options( - options(), - json!({ "deepseek": { "thinking": { "type": "disabled" } } }), - ); - options.temperature = Some(0.2); - options.top_p = Some(0.4); - options.frequency_penalty = Some(0.5); - options.presence_penalty = Some(0.6); - let (body, parts) = stream_parts("deepseek-v4-flash", &options, text_chunks()).await; - assert_eq!( - body, - json!({ - "model": "deepseek-v4-flash", - "messages": [{ "role": "user", "content": "Hello" }], - "temperature": 0.2, - "top_p": 0.4, - "thinking": { "type": "disabled" }, - "stream": true, - "stream_options": { "include_usage": true } - }) - ); - assert_eq!( - stream_start_warnings(&parts), - warning_values(&[ - deprecated("frequencyPenalty"), - deprecated("presencePenalty") - ]) - ); -} - -#[tokio::test] -async fn stream_text_should_send_message_names() { - let name = |value: &str| json!({ "deepseek": { "name": value } }); - let options = options_for(vec![ - with_options( - LanguageModelMessage::System { - content: ("You are a helpful assistant.").into(), - provider_options: None, - }, - name("guide"), - ), - with_options(LanguageModelMessage::user_text("Hello"), name("alice")), - with_options( - LanguageModelMessage::Assistant { - content: vec![AssistantPart::Text(TextPart { - text: ("Hello, Alice.").into(), - provider_options: None, - })], - provider_options: None, - }, - name("assistant"), - ), - ]); - let (body, _) = stream_parts("deepseek-chat", &options, text_chunks()).await; - assert_eq!( - body["messages"], - json!([ - { "content": "You are a helpful assistant.", "name": "guide", "role": "system" }, - { "content": "Hello", "name": "alice", "role": "user" }, - { "content": "Hello, Alice.", "name": "assistant", "role": "assistant" } - ]) - ); -} - -#[tokio::test] -async fn stream_text_should_pass_provider_options_user_id_as_user_id() { - let options = with_provider_options( - options(), - json!({ "deepseek": { "userId": "tenant_123-user" } }), - ); - let (body, _) = stream_parts("deepseek-chat", &options, text_chunks()).await; - assert_eq!(body["user_id"], "tenant_123-user"); - assert_eq!(body["stream"], true); -} - -#[tokio::test] -async fn stream_text_should_stream_text() { - let (_, parts) = stream_parts("deepseek-chat", &options(), text_chunks()).await; - assert!(matches!(&parts[0], StreamPart::StreamStart { warnings } if warnings.is_empty())); - assert!(matches!( - &parts[1], - StreamPart::ResponseMetadata(ResponseMetadata { id, model_id, .. }) - if id.as_deref() == Some("c1") && model_id.as_deref() == Some("deepseek-chat") - )); - let deltas: Vec<&str> = parts - .iter() - .filter_map(|part| match part { - StreamPart::TextDelta { id, delta, .. } if id == "txt-0" => Some(delta.as_str()), - _ => None, - }) - .collect(); - assert_eq!(deltas, ["Hello", ", World!"]); - assert!( - parts - .iter() - .any(|p| matches!(p, StreamPart::TextStart { id, .. } if id == "txt-0")) - ); - assert!( - parts - .iter() - .any(|p| matches!(p, StreamPart::TextEnd { id, .. } if id == "txt-0")) - ); - match parts.last().unwrap() { - StreamPart::Finish { - finish_reason, - usage, - .. - } => { - assert_eq!(finish_reason.unified, FinishReasonUnified::Stop); - assert_eq!(finish_reason.raw.as_deref(), Some("stop")); - // usage with prompt-cache tokens - assert_eq!(usage.input_tokens.total, Some(13)); - assert_eq!(usage.input_tokens.cache_read, Some(5)); - assert_eq!(usage.input_tokens.no_cache, Some(8)); - assert_eq!(usage.output_tokens.total, Some(3)); - } - other => panic!("expected finish, got {other:?}"), - } - assert_eq!( - finish_metadata(&parts), - json!({ "deepseek": { - "promptCacheHitTokens": 5, - "promptCacheMissTokens": 8, - "responseObject": "chat.completion.chunk", - "choiceIndex": 0, - "messageRole": "assistant", - "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" - } }) - ); -} - -#[tokio::test] -async fn stream_text_should_include_the_repeated_system_fingerprint_in_provider_metadata() { - let (_, parts) = stream_parts("deepseek-chat", &options(), text_chunks()).await; - assert_eq!( - finish_metadata(&parts)["deepseek"]["systemFingerprint"], - "fp_eaab8d114b_prod0820_fp8_kvcache" - ); -} - -#[tokio::test] -async fn stream_text_should_keep_the_latest_non_null_system_fingerprint() { - let chunks = vec![ - "data: {\"system_fingerprint\":\"fp_initial\",\"choices\":[{\"delta\":{\"content\":\"OK\"},\"finish_reason\":null}],\"usage\":null}\n\n".to_string(), - "data: {\"system_fingerprint\":null,\"choices\":[{\"delta\":{},\"finish_reason\":null}],\"usage\":null}\n\n".to_string(), - "data: {\"system_fingerprint\":\"fp_latest\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":null}\n\n".to_string(), - ]; - let (_, parts) = stream_parts("deepseek-chat", &options(), chunks).await; - assert_eq!( - finish_metadata(&parts)["deepseek"]["systemFingerprint"], - "fp_latest" - ); -} - -#[tokio::test] -async fn stream_text_should_tolerate_a_null_or_missing_system_fingerprint() { - for fingerprint in [Some(Value::Null), None] { - let mut chunk = json!({ - "choices": [{ "delta": { "content": "OK" }, "finish_reason": "stop" }], - "usage": null - }); - if let Some(value) = fingerprint { - chunk["system_fingerprint"] = value; - } - let (_, parts) = stream_parts("deepseek-chat", &options(), vec![data_event(&chunk)]).await; - assert!( - finish_metadata(&parts)["deepseek"] - .get("systemFingerprint") - .is_none() - ); - } -} - -// ---- describe('reasoning') ------------------------------------------------------------- - -#[tokio::test] -async fn stream_reasoning_should_keep_reasoning_active_when_deltas_include_empty_tool_calls() { - let chunk = |delta: Value, finish: Value| { - data_event(&json!({ - "id": "chatcmpl-test", "object": "chat.completion.chunk", "created": 1, - "model": "test-model", - "choices": [{ "index": 0, "delta": delta, "finish_reason": finish }] - })) - }; - let chunks = vec![ - chunk( - json!({ "role": "assistant", "content": "", "reasoning_content": "Think ", "tool_calls": [] }), - Value::Null, - ), - chunk( - json!({ "content": "", "reasoning_content": "more...", "tool_calls": [] }), - Value::Null, - ), - chunk( - json!({ "content": "Hello", "reasoning_content": "", "tool_calls": [] }), - json!("stop"), - ), - ]; - let (_, parts) = stream_parts("deepseek-reasoner", &options(), chunks).await; - let reasoning: Vec = parts - .iter() - .filter_map(|part| match part { - StreamPart::ReasoningStart { id, .. } => Some(format!("start {id}")), - StreamPart::ReasoningDelta { id, delta, .. } => Some(format!("delta {id} {delta}")), - StreamPart::ReasoningEnd { id, .. } => Some(format!("end {id}")), - _ => None, - }) - .collect(); - assert_eq!( - reasoning, - [ - "start reasoning-0", - "delta reasoning-0 Think ", - "delta reasoning-0 more...", - "end reasoning-0" - ] - ); -} - -#[tokio::test] -async fn stream_reasoning_should_map_legacy_thinking_and_generic_reasoning_to_canonical_request_values() - { - let options = with_provider_options( - reasoning_options(ReasoningEffort::Medium), - json!({ "deepseek": { "thinking": { "type": "adaptive" } } }), - ); - let (body, parts) = stream_parts("deepseek-reasoner", &options, text_chunks()).await; - assert_eq!(body["thinking"], json!({ "type": "enabled" })); - assert_eq!(body["reasoning_effort"], "high"); - assert_eq!( - stream_start_warnings(&parts), - warning_values(&[ - compatibility( - "thinking.type", - "thinking.type \"adaptive\" is not a canonical DeepSeek value. mapped to \"enabled\"." - ), - compatibility( - "reasoning", - "reasoning \"medium\" is not directly supported by this model. mapped to effort \"high\"." - ), - ]) - ); -} - -#[tokio::test] -async fn stream_reasoning_should_stream_reasoning_before_text() { - let chunk = |delta: Value, finish: Value| { - data_event(&json!({ - "id": "c", "object": "chat.completion.chunk", "created": 1, "model": "deepseek-reasoner", - "choices": [{ "index": 0, "delta": delta, "finish_reason": finish }] - })) - }; - let chunks = vec![ - chunk( - json!({ "role": "assistant", "content": null, "reasoning_content": "Let me " }), - Value::Null, - ), - chunk( - json!({ "content": null, "reasoning_content": "think." }), - Value::Null, - ), - chunk(json!({ "content": "Answer" }), Value::Null), - chunk(json!({ "content": "" }), json!("stop")), - ]; - let (_, parts) = stream_parts("deepseek-reasoner", &options(), chunks).await; - let order: Vec<&str> = parts - .iter() - .filter_map(|part| match part { - StreamPart::ReasoningStart { .. } => Some("reasoning-start"), - StreamPart::ReasoningDelta { .. } => Some("reasoning-delta"), - StreamPart::ReasoningEnd { .. } => Some("reasoning-end"), - StreamPart::TextStart { .. } => Some("text-start"), - StreamPart::TextDelta { .. } => Some("text-delta"), - StreamPart::TextEnd { .. } => Some("text-end"), - _ => None, - }) - .collect(); - assert_eq!( - order, - [ - "reasoning-start", - "reasoning-delta", - "reasoning-delta", - "text-start", - "reasoning-end", - "text-delta", - "text-end" - ] - ); -} - -// ---- describe('logprobs') ---------------------------------------------------------------- - -#[tokio::test] -async fn stream_logprobs_should_send_logprobs_provider_options_and_collect_streamed_logprobs() { - let chunk = |choice: Value, usage: Value| { - data_event(&json!({ - "id": "c", "object": "chat.completion.chunk", "created": 1, "model": "deepseek-v4-flash", - "choices": [choice], "usage": usage - })) - }; - let chunks = vec![ - chunk( - json!({ "index": 0, "delta": { "role": "assistant", "reasoning_content": "Reasoning" }, - "logprobs": { "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] }, - "finish_reason": null }), - Value::Null, - ), - chunk( - json!({ "index": 0, "delta": { "content": "OK" }, - "logprobs": { "content": [logprob("OK", -0.00002467602, json!([79, 75]))] }, - "finish_reason": "stop" }), - json!({ "prompt_tokens": 9, "completion_tokens": 2, "total_tokens": 11, - "prompt_cache_hit_tokens": 0, "prompt_cache_miss_tokens": 9 }), - ), - ]; - let options = with_provider_options( - options(), - json!({ "deepseek": { "logprobs": true, "topLogprobs": 1 } }), - ); - let (body, parts) = stream_parts("deepseek-v4-flash", &options, chunks).await; - assert_eq!(body["logprobs"], true); - assert_eq!(body["top_logprobs"], 1); - assert_eq!( - finish_metadata(&parts), - json!({ "deepseek": { - "choiceIndex": 0, - "logprobs": { - "content": [logprob("OK", -0.00002467602, json!([79, 75]))], - "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] - }, - "messageRole": "assistant", - "promptCacheHitTokens": 0, - "promptCacheMissTokens": 9, - "responseObject": "chat.completion.chunk" - } }) - ); -} - -// ---- describe('tool call') ------------------------------------------------------------------ - -#[tokio::test] -async fn stream_tool_call_should_stream_tool_call() { - let chunk = |delta: Value, finish: Value| { - data_event(&json!({ - "id": "c", "object": "chat.completion.chunk", "created": 1, "model": "deepseek-reasoner", - "choices": [{ "index": 0, "delta": delta, "finish_reason": finish }] - })) - }; - let chunks = vec![ - chunk( - json!({ "role": "assistant", "reasoning_content": "Look it up." }), - Value::Null, - ), - chunk( - json!({ "tool_calls": [{ "index": 0, "id": "call_00_abc", "type": "function", - "function": { "name": "weather", "arguments": "" } }] }), - Value::Null, - ), - chunk( - json!({ "tool_calls": [{ "index": 0, "function": { "arguments": "{\"location\":" } }] }), - Value::Null, - ), - chunk( - json!({ "tool_calls": [{ "index": 0, "function": { "arguments": "\"San Francisco\"}" } }] }), - Value::Null, - ), - chunk(json!({ "content": "" }), json!("tool_calls")), - ]; - let (_, parts) = stream_parts("deepseek-reasoner", &tool_options(), chunks).await; - assert!(parts.iter().any(|p| matches!( - p, - StreamPart::ToolInputStart { id, tool_name, .. } if id == "call_00_abc" && tool_name == "weather" - ))); - let input: String = parts - .iter() - .filter_map(|p| match p { - StreamPart::ToolInputDelta { id, delta, .. } if id == "call_00_abc" => { - Some(delta.as_str()) + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should include the repeated system fingerprint in provider metadata + #[tokio::test] + async fn stream_text_should_include_the_repeated_system_fingerprint_in_provider_metadata() + { + let (_, parts) = stream_parts("deepseek-chat", &options(), text_chunks()).await; + assert_eq!( + finish_metadata(&parts)["deepseek"]["systemFingerprint"], + "fp_eaab8d114b_prod0820_fp8_kvcache" + ); } - _ => None, - }) - .collect(); - assert_eq!(input, "{\"location\":\"San Francisco\"}"); - assert!(parts.iter().any(|p| matches!( - p, - StreamPart::ToolCall(RawToolCall { tool_call_id, tool_name, input, .. }) - if tool_call_id == "call_00_abc" && tool_name == "weather" - && input == "{\"location\":\"San Francisco\"}" - ))); - assert!( - parts - .iter() - .any(|p| matches!(p, StreamPart::ReasoningEnd { .. })) - ); - match parts.last().unwrap() { - StreamPart::Finish { finish_reason, .. } => { - assert_eq!(finish_reason.unified, FinishReasonUnified::ToolCalls); - } - other => panic!("expected finish, got {other:?}"), - } - assert_eq!( - finish_metadata(&parts)["deepseek"]["toolCallTypes"], - json!(["function"]) - ); -} -// ---- describe('assistant prefix completion') ----------------------------------------------------- + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should keep the latest non-null system fingerprint + #[tokio::test] + async fn stream_text_should_keep_the_latest_non_null_system_fingerprint() { + let chunks = vec![ + "data: {\"system_fingerprint\":\"fp_initial\",\"choices\":[{\"delta\":{\"content\":\"OK\"},\"finish_reason\":null}],\"usage\":null}\n\n".to_string(), + "data: {\"system_fingerprint\":null,\"choices\":[{\"delta\":{},\"finish_reason\":null}],\"usage\":null}\n\n".to_string(), + "data: {\"system_fingerprint\":\"fp_latest\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":null}\n\n".to_string(), + ]; + let (_, parts) = stream_parts("deepseek-chat", &options(), chunks).await; + assert_eq!( + finish_metadata(&parts)["deepseek"]["systemFingerprint"], + "fp_latest" + ); + } -#[tokio::test] -async fn stream_prefix_should_send_prefix_true_on_the_final_assistant_message() { - let server = sse_server(text_chunks()).await; - let result = beta_chat(&server, "deepseek-chat") - .do_stream(&options_for(prefix_prompt(json!({ "prefix": true })))) - .await - .unwrap(); - let body = result.request.and_then(|r| r.body).unwrap(); - assert_eq!( - body["messages"], - json!([ - { "role": "user", "content": "Complete this sentence." }, - { "role": "assistant", "content": "The answer is", "prefix": true } - ]) - ); - assert_eq!(body["model"], "deepseek-chat"); - assert_eq!(body["stream"], true); -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › text › should tolerate a %s system fingerprint + #[tokio::test] + async fn stream_text_should_tolerate_a_null_or_missing_system_fingerprint() { + for fingerprint in [Some(Value::Null), None] { + let mut chunk = json!({ + "choices": [{ "delta": { "content": "OK" }, "finish_reason": "stop" }], + "usage": null + }); + if let Some(value) = fingerprint { + chunk["system_fingerprint"] = value; + } + let (_, parts) = + stream_parts("deepseek-chat", &options(), vec![data_event(&chunk)]).await; + assert!( + finish_metadata(&parts)["deepseek"] + .get("systemFingerprint") + .is_none() + ); + } + } + } -// =========================================================================== -// convert-to-deepseek-chat-messages.test.ts (through the request body) -// =========================================================================== + mod reasoning { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › reasoning › should keep reasoning active when deltas include empty tool calls + #[tokio::test] + async fn stream_reasoning_should_keep_reasoning_active_when_deltas_include_empty_tool_calls() + { + let chunk = |delta: Value, finish: Value| { + data_event(&json!({ + "id": "chatcmpl-test", "object": "chat.completion.chunk", "created": 1, + "model": "test-model", + "choices": [{ "index": 0, "delta": delta, "finish_reason": finish }] + })) + }; + let chunks = vec![ + chunk( + json!({ "role": "assistant", "content": "", "reasoning_content": "Think ", "tool_calls": [] }), + Value::Null, + ), + chunk( + json!({ "content": "", "reasoning_content": "more...", "tool_calls": [] }), + Value::Null, + ), + chunk( + json!({ "content": "Hello", "reasoning_content": "", "tool_calls": [] }), + json!("stop"), + ), + ]; + let (_, parts) = stream_parts("deepseek-reasoner", &options(), chunks).await; + let reasoning: Vec = parts + .iter() + .filter_map(|part| match part { + StreamPart::ReasoningStart { id, .. } => Some(format!("start {id}")), + StreamPart::ReasoningDelta { id, delta, .. } => { + Some(format!("delta {id} {delta}")) + } + StreamPart::ReasoningEnd { id, .. } => Some(format!("end {id}")), + _ => None, + }) + .collect(); + assert_eq!( + reasoning, + [ + "start reasoning-0", + "delta reasoning-0 Think ", + "delta reasoning-0 more...", + "end reasoning-0" + ] + ); + } -fn png_data() -> UserPart { - UserPart::File(FilePart { - data: FileData::Data { - data: FileBytes::Base64("AAECAw==".into()), - }, - media_type: "image/png".into(), - filename: None, - provider_options: None, - }) -} + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › reasoning › should map legacy thinking and generic reasoning to canonical request values + #[tokio::test] + async fn stream_reasoning_should_map_legacy_thinking_and_generic_reasoning_to_canonical_request_values() + { + let options = with_provider_options( + reasoning_options(ReasoningEffort::Medium), + json!({ "deepseek": { "thinking": { "type": "adaptive" } } }), + ); + let (body, parts) = + stream_parts("deepseek-reasoner", &options, text_chunks()).await; + assert_eq!(body["thinking"], json!({ "type": "enabled" })); + assert_eq!(body["reasoning_effort"], "high"); + assert_eq!( + stream_start_warnings(&parts), + warning_values(&[ + compatibility( + "thinking.type", + "thinking.type \"adaptive\" is not a canonical DeepSeek value. mapped to \"enabled\"." + ), + compatibility( + "reasoning", + "reasoning \"medium\" is not directly supported by this model. mapped to effort \"high\"." + ), + ]) + ); + } + } -fn file_with_options(mut part: UserPart, options: Value) -> UserPart { - if let UserPart::File(file) = &mut part { - file.provider_options = Some(serde_json::from_value(options).unwrap()); + mod logprobs { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › logprobs › should send logprobs provider options and collect streamed logprobs + #[tokio::test] + async fn stream_logprobs_should_send_logprobs_provider_options_and_collect_streamed_logprobs() + { + let chunk = |choice: Value, usage: Value| { + data_event(&json!({ + "id": "c", "object": "chat.completion.chunk", "created": 1, "model": "deepseek-v4-flash", + "choices": [choice], "usage": usage + })) + }; + let chunks = vec![ + chunk( + json!({ "index": 0, "delta": { "role": "assistant", "reasoning_content": "Reasoning" }, + "logprobs": { "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] }, + "finish_reason": null }), + Value::Null, + ), + chunk( + json!({ "index": 0, "delta": { "content": "OK" }, + "logprobs": { "content": [logprob("OK", -0.00002467602, json!([79, 75]))] }, + "finish_reason": "stop" }), + json!({ "prompt_tokens": 9, "completion_tokens": 2, "total_tokens": 11, + "prompt_cache_hit_tokens": 0, "prompt_cache_miss_tokens": 9 }), + ), + ]; + let options = with_provider_options( + options(), + json!({ "deepseek": { "logprobs": true, "topLogprobs": 1 } }), + ); + let (body, parts) = stream_parts("deepseek-v4-flash", &options, chunks).await; + assert_eq!(body["logprobs"], true); + assert_eq!(body["top_logprobs"], 1); + assert_eq!( + finish_metadata(&parts), + json!({ "deepseek": { + "choiceIndex": 0, + "logprobs": { + "content": [logprob("OK", -0.00002467602, json!([79, 75]))], + "reasoning_content": [logprob("Reasoning", -0.1, Value::Null)] + }, + "messageRole": "assistant", + "promptCacheHitTokens": 0, + "promptCacheMissTokens": 9, + "responseObject": "chat.completion.chunk" + } }) + ); + } + } + + mod assistant_prefix_completion { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/deepseek-chat-language-model.test.ts › DeepSeekChatLanguageModel › doStream › assistant prefix completion › should send prefix true on the final assistant message + #[tokio::test] + async fn stream_prefix_should_send_prefix_true_on_the_final_assistant_message() { + let server = sse_server(text_chunks()).await; + let result = beta_chat(&server, "deepseek-chat") + .do_stream(&options_for(prefix_prompt(json!({ "prefix": true })))) + .await + .unwrap(); + let body = result.request.and_then(|r| r.body).unwrap(); + assert_eq!( + body["messages"], + json!([ + { "role": "user", "content": "Complete this sentence." }, + { "role": "assistant", "content": "The answer is", "prefix": true } + ]) + ); + assert_eq!(body["model"], "deepseek-chat"); + assert_eq!(body["stream"], true); + } + } } - part } -// ---- describe('message names') ------------------------------------------------------------- - -#[tokio::test] -async fn convert_should_ignore_a_name_on_a_tool_message_with_an_unsupported_warning() { - let options = options_for(vec![with_options( - LanguageModelMessage::Tool { - content: vec![ToolPart::ToolResult(ToolResultPart { - tool_call_id: ("call-1").into(), - output: ToolResultOutput::Text { - value: "sunny".into(), +mod convert_to_deep_seek_chat_messages { + use super::*; + + mod message_names { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › message names › should ignore a name on a tool message with an unsupported warning + #[tokio::test] + async fn convert_should_ignore_a_name_on_a_tool_message_with_an_unsupported_warning() { + let options = options_for(vec![with_options( + LanguageModelMessage::Tool { + content: vec![ToolPart::ToolResult(ToolResultPart { + tool_call_id: ("call-1").into(), + output: ToolResultOutput::Text { + value: "sunny".into(), + provider_options: None, + }, + tool_name: "weather_tool".into(), + provider_options: None, + })], provider_options: None, }, - tool_name: "weather_tool".into(), - provider_options: None, - })], - provider_options: None, - }, - json!({ "deepseek": { "name": "weather_tool" } }), - )]); - let result = generate_result("deepseek-chat", &options).await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["messages"], - json!([{ "role": "tool", "tool_call_id": "call-1", "content": "sunny" }]) - ); - assert_eq!( - warning_values(&result.warnings), - warning_values(&[Warning::Unsupported { - feature: "message name on tool messages".to_string(), - details: None, - }]) - ); -} - -#[tokio::test] -async fn convert_should_reject_a_non_string_name() { - let options = options_for(vec![with_options( - LanguageModelMessage::user_text("Hello"), - json!({ "deepseek": { "name": 123 } }), - )]); - let message = generate_error("deepseek-chat", &options).await; - assert!(message.contains("invalid provider options"), "{message}"); -} + json!({ "deepseek": { "name": "weather_tool" } }), + )]); + let result = generate_result("deepseek-chat", &options).await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["messages"], + json!([{ "role": "tool", "tool_call_id": "call-1", "content": "sunny" }]) + ); + assert_eq!( + warning_values(&result.warnings), + warning_values(&[Warning::Unsupported { + feature: "message name on tool messages".to_string(), + details: None, + }]) + ); + } -// ---- describe('user messages') --------------------------------------------------------------- + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › message names › should reject a non-string name + #[tokio::test] + async fn convert_should_reject_a_non_string_name() { + let options = options_for(vec![with_options( + LanguageModelMessage::user_text("Hello"), + json!({ "deepseek": { "name": 123 } }), + )]); + let message = generate_error("deepseek-chat", &options).await; + assert!(message.contains("invalid provider options"), "{message}"); + } + } -#[tokio::test] -async fn convert_should_convert_messages_with_only_a_text_part_to_a_string_content() { - let messages = wire_messages( - "deepseek-chat", - vec![LanguageModelMessage::user_text("Hello")], - ) - .await; - assert_eq!(messages, [json!({ "role": "user", "content": "Hello" })]); -} + mod user_messages { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should convert messages with only a text part to a string content + #[tokio::test] + async fn convert_should_convert_messages_with_only_a_text_part_to_a_string_content() { + let messages = wire_messages( + "deepseek-chat", + vec![LanguageModelMessage::user_text("Hello")], + ) + .await; + assert_eq!(messages, [json!({ "role": "user", "content": "Hello" })]); + } -#[tokio::test] -async fn convert_should_convert_image_data_to_an_image_url_content_part() { - let messages = wire_messages( - "deepseek-chat", - vec![LanguageModelMessage::User { - content: vec![ - UserPart::Text(TextPart { - text: ("Hello").into(), + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should convert image data to an image URL content part + #[tokio::test] + async fn convert_should_convert_image_data_to_an_image_url_content_part() { + let messages = wire_messages( + "deepseek-chat", + vec![LanguageModelMessage::User { + content: vec![ + UserPart::Text(TextPart { + text: ("Hello").into(), + provider_options: None, + }), + png_data(), + ], provider_options: None, - }), - png_data(), - ], - provider_options: None, - }], - ) - .await; - assert_eq!( - messages, - [json!({ "role": "user", "content": [ + }], + ) + .await; + assert_eq!( + messages, + [json!({ "role": "user", "content": [ { "type": "text", "text": "Hello" }, { "type": "image_url", "image_url": { "url": "data:image/png;base64,AAECAw==" } } ] })] - ); -} + ); + } -#[tokio::test] -async fn convert_should_convert_an_image_url_to_an_image_url_content_part() { - let messages = wire_messages( - "deepseek-chat", - vec![LanguageModelMessage::User { - content: vec![ + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should convert an image URL to an image URL content part + #[tokio::test] + async fn convert_should_convert_an_image_url_to_an_image_url_content_part() { + let messages = wire_messages( + "deepseek-chat", + vec![LanguageModelMessage::User { + content: vec![ + UserPart::Text(TextPart { + text: ("Hello").into(), + provider_options: None, + }), + UserPart::File(FilePart { + data: FileData::Url { + url: ("https://example.com/image.png").into(), + original_url: None, + }, + media_type: ("image/png").into(), + filename: None, + provider_options: None, + }), + ], + provider_options: None, + }], + ) + .await; + assert_eq!( + messages, + [json!({ "role": "user", "content": [ + { "type": "text", "text": "Hello" }, + { "type": "image_url", "image_url": { "url": "https://example.com/image.png" } } + ] })] + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should pass imageDetail to image URL content parts + #[tokio::test] + async fn convert_should_pass_image_detail_to_image_url_content_parts() { + let messages = wire_messages( + "deepseek-v4-flash-vision-exp", + vec![LanguageModelMessage::User { + content: vec![file_with_options( + UserPart::File(FilePart { + data: FileData::Url { + url: ("https://example.com/image.webp").into(), + original_url: None, + }, + media_type: ("image/webp").into(), + filename: None, + provider_options: None, + }), + json!({ "deepseek": { "imageDetail": "low" } }), + )], + provider_options: None, + }], + ) + .await; + assert_eq!( + messages, + [json!({ "role": "user", "content": [ + { "type": "image_url", "image_url": { "url": "https://example.com/image.webp", "detail": "low" } } + ] })] + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should convert inline image data to file_data and preserve its filename + #[tokio::test] + async fn convert_should_convert_inline_image_data_to_file_data_and_preserve_its_filename() { + let part = UserPart::File(FilePart { + data: FileData::Data { + data: FileBytes::Base64("AAECAw==".to_string()), + }, + media_type: "image/jpg".to_string(), + filename: Some("sample.jpg".to_string()), + provider_options: Some( + provider_namespace("deepseek", json!({ "fileData": true })).unwrap(), + ), + }); + let messages = wire_messages( + "deepseek-v4-flash-vision-exp", + vec![LanguageModelMessage::User { + content: vec![part], + provider_options: None, + }], + ) + .await; + assert_eq!( + messages, + [json!({ "role": "user", "content": [ + { "type": "file", "file_data": "data:image/jpeg;base64,AAECAw==", "filename": "sample.jpg" } + ] })] + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should reject imageDetail together with fileData + #[tokio::test] + async fn convert_should_reject_image_detail_together_with_file_data() { + let part = file_with_options( + png_data(), + json!({ "deepseek": { "fileData": true, "imageDetail": "high" } }), + ); + let message = generate_error( + "deepseek-v4-flash-vision-exp", + &options_for(vec![LanguageModelMessage::User { + content: vec![part], + provider_options: None, + }]), + ) + .await; + assert!( + message.contains("DeepSeek `imageDetail` cannot be combined with `fileData`."), + "{message}" + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should reject image URLs longer than 8192 characters + #[tokio::test] + async fn convert_should_reject_image_urls_longer_than_8192_characters() { + let url = format!("https://example.com/{}", "a".repeat(8192)); + let message = generate_error( + "deepseek-v4-flash-vision-exp", + &options_for(vec![LanguageModelMessage::User { + content: vec![UserPart::File(FilePart { + data: FileData::Url { + url: (url), + original_url: None, + }, + media_type: ("image/png").into(), + filename: None, + provider_options: None, + })], + provider_options: None, + }]), + ) + .await; + assert!( + message.contains("DeepSeek image URLs must not exceed 8192 characters."), + "{message}" + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should reject unsupported image formats + #[tokio::test] + async fn convert_should_reject_unsupported_image_formats() { + let message = generate_error( + "deepseek-v4-flash-vision-exp", + &options_for(vec![LanguageModelMessage::User { + content: vec![UserPart::File(FilePart { + data: FileData::Data { + data: FileBytes::Base64(("AAECAw==").into()), + }, + media_type: ("image/svg+xml").into(), + filename: None, + provider_options: None, + })], + provider_options: None, + }]), + ) + .await; + assert!( + message.contains("DeepSeek supports JPEG, PNG, GIF, and WebP image inputs."), + "{message}" + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should convert an image provider reference to a file content part + #[tokio::test] + async fn convert_should_convert_an_image_provider_reference_to_a_file_content_part() { + let messages = wire_messages( + "deepseek-v4-flash-vision-exp", + vec![LanguageModelMessage::User { + content: vec![ UserPart::Text(TextPart { text: ("Hello").into(), provider_options: None, }), UserPart::File(FilePart { - data: FileData::Url { - url: ("https://example.com/image.png").into(), - original_url: None, + data: FileData::Reference { + reference: serde_json::from_value( + json!({ "deepseek": "file-api-deepseek", "openai": "file-openai" }), + ) + .unwrap(), }, media_type: ("image/png").into(), filename: None, provider_options: None, }), ], - provider_options: None, - }], - ) - .await; - assert_eq!( - messages, - [json!({ "role": "user", "content": [ + provider_options: None, + }], + ) + .await; + assert_eq!( + messages, + [json!({ "role": "user", "content": [ { "type": "text", "text": "Hello" }, - { "type": "image_url", "image_url": { "url": "https://example.com/image.png" } } + { "type": "file", "file_id": "file-api-deepseek" } ] })] + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should throw when an image reference has no DeepSeek identifier + #[tokio::test] + async fn convert_should_throw_when_an_image_reference_has_no_deepseek_identifier() { + let message = generate_error( + "deepseek-v4-flash-vision-exp", + &options_for(vec![LanguageModelMessage::User { + content: vec![UserPart::File(FilePart { + data: FileData::Reference { + reference: serde_json::from_value(json!({ "openai": "file-openai" })) + .unwrap(), + }, + media_type: ("image/png").into(), + filename: None, + provider_options: None, + })], + provider_options: None, + }]), + ) + .await; + assert!(message.contains("deepseek"), "{message}"); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › user messages › should warn about unsupported non-image file parts + #[tokio::test] + async fn convert_should_warn_about_unsupported_non_image_file_parts() { + let result = generate_result( + "deepseek-chat", + &options_for(vec![LanguageModelMessage::User { + content: vec![ + UserPart::Text(TextPart { + text: ("Hello").into(), + provider_options: None, + }), + UserPart::File(FilePart { + data: FileData::Data { + data: FileBytes::Base64(("AAECAw==").into()), + }, + media_type: ("application/pdf").into(), + filename: None, + provider_options: None, + }), + ], + provider_options: None, + }]), + ) + .await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["messages"], + json!([{ "role": "user", "content": "Hello" }]) + ); + assert_eq!( + warning_values(&result.warnings), + warning_values(&[Warning::Unsupported { + feature: "user message part type: file".to_string(), + details: None, + }]) + ); + } + } + + mod tool_calls { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › tool calls › should stringify arguments to tool calls + #[tokio::test] + async fn convert_should_stringify_arguments_to_tool_calls() { + let result = generate_result("deepseek-chat", &options_for(tool_turn(false))).await; + assert_eq!( + result.request.and_then(|r| r.body).unwrap()["messages"], + json!([ + // upstream sends the empty text as `content: ""`, not null. + { "role": "assistant", "content": "", "tool_calls": wire_tool_call() }, + { "role": "tool", "tool_call_id": "quux", "content": "{\"oof\":\"321rab\"}" } + ]) + ); + assert!(result.warnings.is_empty()); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › tool calls › should handle text output type in tool results + #[tokio::test] + async fn convert_should_handle_text_output_type_in_tool_results() { + let messages = wire_messages( + "deepseek-chat", + vec![ + LanguageModelMessage::Assistant { + content: vec![AssistantPart::ToolCall(ToolCallPart { + tool_call_id: ("call-1").into(), + tool_name: ("getWeather").into(), + input: json!({ "query": "weather" }), + provider_executed: None, + provider_options: None, + })], + provider_options: None, + }, + LanguageModelMessage::Tool { + content: vec![ToolPart::ToolResult(ToolResultPart { + tool_call_id: ("call-1").into(), + output: ToolResultOutput::Text { + value: "It is sunny today".into(), + provider_options: None, + }, + tool_name: "getWeather".into(), + provider_options: None, + })], + provider_options: None, + }, + ], + ) + .await; + assert_eq!( + messages[1], + json!({ "role": "tool", "tool_call_id": "call-1", "content": "It is sunny today" }) + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › tool calls › should support reasoning content in tool calls + #[tokio::test] + async fn convert_should_support_reasoning_content_in_tool_calls() { + let mut prompt = vec![LanguageModelMessage::user_text("Hello")]; + prompt.extend(tool_turn(true)); + let messages = wire_messages("deepseek-chat", prompt).await; + assert_eq!( + messages[1], + json!({ + "role": "assistant", "content": "", + "reasoning_content": "I think the tool will return the correct value.", + "tool_calls": wire_tool_call() + }) + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › tool calls › should filter out reasoning content from turns before the last user message + #[tokio::test] + async fn convert_should_filter_out_reasoning_content_from_turns_before_the_last_user_message() + { + let mut prompt = vec![LanguageModelMessage::user_text("Hello")]; + prompt.extend(tool_turn(true)); + prompt.push(LanguageModelMessage::user_text("Goodbye")); + let messages = wire_messages("deepseek-chat", prompt).await; + assert_eq!( + messages[1], + json!({ "role": "assistant", "content": "", "tool_calls": wire_tool_call() }) + ); + } + } + + mod deepseek_v4_thinking_mode { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › deepseek-v4 thinking mode › should preserve reasoning_content from prior turns for deepseek-v4 + #[tokio::test] + async fn convert_should_preserve_reasoning_content_from_prior_turns_for_deepseek_v4() { + let mut prompt = vec![LanguageModelMessage::user_text("Hello")]; + prompt.extend(tool_turn(true)); + prompt.push(LanguageModelMessage::user_text("Goodbye")); + let messages = wire_messages("deepseek-v4-pro", prompt).await; + assert_eq!( + messages[1], + json!({ + "role": "assistant", "content": "", + "reasoning_content": "I think the tool will return the correct value.", + "tool_calls": wire_tool_call() + }) + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › deepseek-v4 thinking mode › should preserve reasoning_content from prior turns for the deepseek-flash alias + #[tokio::test] + async fn convert_should_preserve_reasoning_content_from_prior_turns_for_the_deepseek_flash_alias() + { + let messages = wire_messages( + "deepseek-flash", + vec![ + LanguageModelMessage::user_text("Hello"), + LanguageModelMessage::Assistant { + content: vec![ + AssistantPart::Reasoning(ReasoningPart { + text: ("Prior-turn reasoning.").into(), + provider_options: None, + }), + AssistantPart::Text(TextPart { + text: ("Hi there").into(), + provider_options: None, + }), + ], + provider_options: None, + }, + LanguageModelMessage::user_text("Again"), + ], + ) + .await; + assert_eq!( + messages[1], + json!({ "role": "assistant", "content": "Hi there", "reasoning_content": "Prior-turn reasoning." }) + ); + } + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › deepseek-v4 thinking mode › should back-fill empty reasoning_content for deepseek-v4 assistant messages with no reasoning part + #[tokio::test] + async fn convert_should_back_fill_empty_reasoning_content_for_deepseek_v4_assistant_messages_with_no_reasoning_part() + { + let messages = wire_messages( + "deepseek-v4-pro", + vec![ + LanguageModelMessage::user_text("Hello"), + LanguageModelMessage::Assistant { + content: vec![AssistantPart::Text(TextPart { + text: ("Hi there").into(), + provider_options: None, + })], + provider_options: None, + }, + LanguageModelMessage::user_text("Again"), + ], + ) + .await; + assert_eq!( + messages[1], + json!({ "role": "assistant", "content": "Hi there", "reasoning_content": "" }) + ); + } + } + + mod assistant_prefix_completion { + use super::*; + + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › assistant prefix completion › should reject prefix completion on a non-assistant message + #[tokio::test] + async fn convert_should_reject_prefix_completion_on_a_non_assistant_message() { + let message = generate_error( + "deepseek-chat", + &options_for(vec![with_options( + LanguageModelMessage::user_text("Hello"), + json!({ "deepseek": { "prefix": true } }), + )]), + ) + .await; + assert!( + message.contains( + "DeepSeek assistant prefix completion requires `prefix: true` on an assistant message." + ), + "{message}" ); -} + } -#[tokio::test] -async fn convert_should_pass_image_detail_to_image_url_content_parts() { - let messages = wire_messages( - "deepseek-v4-flash-vision-exp", - vec![LanguageModelMessage::User { - content: vec![file_with_options( - UserPart::File(FilePart { - data: FileData::Url { - url: ("https://example.com/image.webp").into(), - original_url: None, + /// upstream: @ai-sdk/deepseek src/chat/convert-to-deepseek-chat-messages.test.ts › convertToDeepSeekChatMessages › assistant prefix completion › should reject prefix completion on a non-final assistant message + #[tokio::test] + async fn convert_should_reject_prefix_completion_on_a_non_final_assistant_message() { + let server = json_server(text_response()).await; + let prompt = vec![ + with_options( + LanguageModelMessage::Assistant { + content: vec![AssistantPart::Text(TextPart { + text: ("The answer is").into(), + provider_options: None, + })], + provider_options: None, }, - media_type: ("image/webp").into(), - filename: None, - provider_options: None, - }), - json!({ "deepseek": { "imageDetail": "low" } }), - )], + json!({ "deepseek": { "prefix": true } }), + ), + LanguageModelMessage::user_text("Continue"), + ]; + let error = beta_chat(&server, "deepseek-chat") + .do_generate(&options_for(prompt)) + .await + .unwrap_err(); + assert!( + error.to_string().contains( + "DeepSeek assistant prefix completion requires the prefixed assistant message to be the final message." + ), + "{error}" + ); + } + } +} + +mod prepare_tools { + use super::*; + + /// A tool with `strict: false` should produce `"strict": false` in the + /// serialized tool definition. + /// upstream: @ai-sdk/deepseek src/chat/deepseek-prepare-tools.test.ts › prepareTools › should pass through strict mode when strict is false + #[tokio::test] + async fn should_pass_through_strict_mode_when_strict_is_false() { + let tool = FunctionTool { + name: "testFunction".to_string(), + description: Some("A test function".to_string()), + input_schema: json!({ "type": "object", "properties": {} }), + strict: Some(false), provider_options: None, - }], - ) - .await; + input_examples: None, + }; + let mut options = options(); + options.tools = Some(vec![Tool::from(tool)]); + let body = generate_body("deepseek-chat", &options).await; + + assert_eq!( + body["tools"], + json!([{ + "type": "function", + "function": { + "description": "A test function", + "name": "testFunction", + "parameters": { "type": "object", "properties": {} }, + "strict": false + } + }]) + ); + } + + /// A tool without `strict` set should NOT have a `"strict"` field in the + /// serialized tool definition. + /// upstream: @ai-sdk/deepseek src/chat/deepseek-prepare-tools.test.ts › prepareTools › should not include strict mode when strict is undefined + #[tokio::test] + async fn should_not_include_strict_mode_when_strict_is_undefined() { + let tool = FunctionTool { + name: "testFunction".to_string(), + description: Some("A test function".to_string()), + input_schema: json!({ "type": "object", "properties": {} }), + strict: None, + provider_options: None, + input_examples: None, + }; + let mut options = options(); + options.tools = Some(vec![Tool::from(tool)]); + let body = generate_body("deepseek-chat", &options).await; + + assert_eq!( + body["tools"], + json!([{ + "type": "function", + "function": { + "description": "A test function", + "name": "testFunction", + "parameters": { "type": "object", "properties": {} } + } + }]) + ); + // Verify strict is absent. + assert!( + body["tools"][0]["function"].get("strict").is_none(), + "strict should be absent" + ); + } +} + +// ---- Tests without a matching upstream case (aimux-own, or a partial port) ---- + +#[tokio::test] +async fn text_should_send_max_tokens_and_stop_sequences() { + let mut options = options(); + options.max_output_tokens = Some(64); + options.stop_sequences = Some(vec!["END".to_string()]); + let body = generate_body("deepseek-chat", &options).await; + assert_eq!(body["max_tokens"], 64); + assert_eq!(body["stop"], json!(["END"])); + assert!(body.get("max_completion_tokens").is_none()); +} + +#[tokio::test] +async fn text_should_not_send_unknown_provider_options() { + // upstream: `deepseekLanguageModelChatOptions` is a zod object, which + // strips keys it does not declare. + let options = + with_provider_options(options(), json!({ "deepseek": { "user": "u1", "foo": 1 } })); + let body = generate_body("deepseek-chat", &options).await; + assert!(body.get("user").is_none() && body.get("foo").is_none()); +} + +#[tokio::test] +async fn text_should_extract_text_content() { + let result = generate_result("deepseek-chat", &options()).await; + assert_eq!(result.content.len(), 1); + assert!( + matches!(&result.content[0], GenerateContent::Text { text, .. } if text == "Hello, World!") + ); + assert_eq!(result.finish_reason.unified, FinishReasonUnified::Stop); + assert_eq!(result.finish_reason.raw.as_deref(), Some("stop")); + assert_eq!(result.usage.input_tokens.total, Some(13)); + assert_eq!(result.usage.output_tokens.total, Some(300)); + assert_eq!( + result.response.as_ref().and_then(|r| r.id.as_deref()), + Some("00f10ecd-60b3-4707-b5db-e4bcadf7aea1") + ); assert_eq!( - messages, - [json!({ "role": "user", "content": [ - { "type": "image_url", "image_url": { "url": "https://example.com/image.webp", "detail": "low" } } - ] })] + result.response.as_ref().and_then(|r| r.model_id.as_deref()), + Some("deepseek-chat") ); } #[tokio::test] -async fn convert_should_convert_inline_image_data_to_file_data_and_preserve_its_filename() { - let part = UserPart::File(FilePart { - data: FileData::Data { - data: FileBytes::Base64("AAECAw==".to_string()), - }, - media_type: "image/jpg".to_string(), - filename: Some("sample.jpg".to_string()), - provider_options: Some( - provider_namespace("deepseek", json!({ "fileData": true })).unwrap(), - ), +async fn text_should_report_usage_with_prompt_cache_tokens() { + // upstream convert-to-deepseek-usage.ts: cache hits are the cache-read tokens. + let mut body = text_response(); + body["usage"] = json!({ + "prompt_tokens": 100, "completion_tokens": 20, "total_tokens": 120, + "prompt_cache_hit_tokens": 70, "prompt_cache_miss_tokens": 30, + "completion_tokens_details": { "reasoning_tokens": 5 } }); - let messages = wire_messages( - "deepseek-v4-flash-vision-exp", - vec![LanguageModelMessage::User { - content: vec![part], - provider_options: None, - }], - ) - .await; - assert_eq!( - messages, - [json!({ "role": "user", "content": [ - { "type": "file", "file_data": "data:image/jpeg;base64,AAECAw==", "filename": "sample.jpg" } - ] })] - ); + let server = json_server(body).await; + let usage = chat(&server, "deepseek-chat") + .do_generate(&options()) + .await + .unwrap() + .usage; + assert_eq!(usage.input_tokens.total, Some(100)); + assert_eq!(usage.input_tokens.cache_read, Some(70)); + assert_eq!(usage.input_tokens.no_cache, Some(30)); + assert_eq!(usage.output_tokens.total, Some(20)); + assert_eq!(usage.output_tokens.reasoning, Some(5)); + assert_eq!(usage.output_tokens.text, Some(15)); + assert_eq!(usage.raw.unwrap()["prompt_cache_hit_tokens"], 70); } #[tokio::test] -async fn convert_should_reject_image_detail_together_with_file_data() { - let part = file_with_options( - png_data(), - json!({ "deepseek": { "fileData": true, "imageDetail": "high" } }), - ); - let message = generate_error( - "deepseek-v4-flash-vision-exp", - &options_for(vec![LanguageModelMessage::User { - content: vec![part], - provider_options: None, - }]), - ) - .await; - assert!( - message.contains("DeepSeek `imageDetail` cannot be combined with `fileData`."), - "{message}" +async fn text_should_report_the_provider_metadata() { + // upstream doGenerate: promptCacheHitTokens, promptCacheMissTokens, + // responseObject, choiceIndex, messageRole, systemFingerprint. + let result = generate_result("deepseek-chat", &options()).await; + assert_eq!( + serde_json::to_value(result.provider_metadata.unwrap()).unwrap(), + json!({ "deepseek": { + "promptCacheHitTokens": 0, + "promptCacheMissTokens": 13, + "responseObject": "chat.completion", + "choiceIndex": 0, + "messageRole": "assistant", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" + } }) ); } #[tokio::test] -async fn convert_should_reject_image_urls_longer_than_8192_characters() { - let url = format!("https://example.com/{}", "a".repeat(8192)); - let message = generate_error( - "deepseek-v4-flash-vision-exp", - &options_for(vec![LanguageModelMessage::User { - content: vec![UserPart::File(FilePart { - data: FileData::Url { - url: (url), - original_url: None, - }, - media_type: ("image/png").into(), - filename: None, - provider_options: None, - })], - provider_options: None, - }]), - ) - .await; +async fn reasoning_should_extract_reasoning_before_text() { + let server = json_server(reasoning_response()).await; + let result = chat(&server, "deepseek-reasoner") + .do_generate(&options()) + .await + .unwrap(); + assert_eq!(result.content.len(), 2); assert!( - message.contains("DeepSeek image URLs must not exceed 8192 characters."), - "{message}" + matches!(&result.content[0], GenerateContent::Reasoning(ReasoningOutput { text, .. }) if text == "Let me count the letters.") + ); + assert!( + matches!(&result.content[1], GenerateContent::Text { text, .. } if text == "There are 3 r's in strawberry.") ); + assert_eq!(result.usage.output_tokens.reasoning, Some(10)); + assert_eq!(result.usage.output_tokens.text, Some(20)); } #[tokio::test] -async fn convert_should_reject_unsupported_image_formats() { - let message = generate_error( - "deepseek-v4-flash-vision-exp", - &options_for(vec![LanguageModelMessage::User { - content: vec![UserPart::File(FilePart { - data: FileData::Data { - data: FileBytes::Base64(("AAECAw==").into()), - }, - media_type: ("image/svg+xml").into(), - filename: None, - provider_options: None, - })], - provider_options: None, - }]), - ) - .await; - assert!( - message.contains("DeepSeek supports JPEG, PNG, GIF, and WebP image inputs."), - "{message}" - ); +async fn reasoning_should_not_read_the_reasoning_field() { + // upstream deepseekChatResponseSchema only declares `reasoning_content`. + let mut body = reasoning_response(); + let message = body["choices"][0]["message"].as_object_mut().unwrap(); + let reasoning = message.remove("reasoning_content").unwrap(); + message.insert("reasoning".to_string(), reasoning); + let server = json_server(body).await; + let result = chat(&server, "deepseek-reasoner") + .do_generate(&options()) + .await + .unwrap(); + assert_eq!(result.content.len(), 1); + assert!(matches!(&result.content[0], GenerateContent::Text { .. })); } #[tokio::test] -async fn convert_should_convert_an_image_provider_reference_to_a_file_content_part() { - let messages = wire_messages( - "deepseek-v4-flash-vision-exp", - vec![LanguageModelMessage::User { - content: vec![ - UserPart::Text(TextPart { - text: ("Hello").into(), - provider_options: None, - }), - UserPart::File(FilePart { - data: FileData::Reference { - reference: serde_json::from_value( - json!({ "deepseek": "file-api-deepseek", "openai": "file-openai" }), - ) - .unwrap(), - }, - media_type: ("image/png").into(), - filename: None, - provider_options: None, - }), - ], - provider_options: None, - }], - ) - .await; +async fn top_level_reasoning_none_should_keep_the_temperature() { + // thinking is disabled, so temperature applies and is not warned about. + let mut options = reasoning_options(ReasoningEffort::None); + options.temperature = Some(0.4); + let result = generate_result("deepseek-reasoner", &options).await; assert_eq!( - messages, - [json!({ "role": "user", "content": [ - { "type": "text", "text": "Hello" }, - { "type": "file", "file_id": "file-api-deepseek" } - ] })] + result.request.and_then(|r| r.body).unwrap()["temperature"], + 0.4 ); + assert!(result.warnings.is_empty()); } #[tokio::test] -async fn convert_should_throw_when_an_image_reference_has_no_deepseek_identifier() { - let message = generate_error( - "deepseek-v4-flash-vision-exp", - &options_for(vec![LanguageModelMessage::User { - content: vec![UserPart::File(FilePart { - data: FileData::Reference { - reference: serde_json::from_value(json!({ "openai": "file-openai" })).unwrap(), - }, - media_type: ("image/png").into(), - filename: None, - provider_options: None, - })], - provider_options: None, - }]), +async fn top_level_reasoning_provider_default_sends_neither_thinking_nor_effort() { + let body = generate_body( + "deepseek-reasoner", + &reasoning_options(ReasoningEffort::ProviderDefault), ) .await; - assert!(message.contains("deepseek"), "{message}"); + assert!(body.get("thinking").is_none() && body.get("reasoning_effort").is_none()); } #[tokio::test] -async fn convert_should_warn_about_unsupported_non_image_file_parts() { - let result = generate_result( - "deepseek-chat", - &options_for(vec![LanguageModelMessage::User { - content: vec![ - UserPart::Text(TextPart { - text: ("Hello").into(), - provider_options: None, - }), - UserPart::File(FilePart { - data: FileData::Data { - data: FileBytes::Base64(("AAECAw==").into()), - }, - media_type: ("application/pdf").into(), - filename: None, - provider_options: None, - }), - ], - provider_options: None, - }]), - ) - .await; - assert_eq!( - result.request.and_then(|r| r.body).unwrap()["messages"], - json!([{ "role": "user", "content": "Hello" }]) - ); +async fn tool_call_should_send_the_tool_choice() { + use aimux_core::options::LanguageModelV4ToolChoice; + let mut options = tool_options(); + options.tool_choice = Some(LanguageModelV4ToolChoice::Tool { + tool_name: "weather".to_string(), + }); assert_eq!( - warning_values(&result.warnings), - warning_values(&[Warning::Unsupported { - feature: "user message part type: file".to_string(), - details: None, - }]) + generate_body("deepseek-reasoner", &options).await["tool_choice"], + json!({ "type": "function", "function": { "name": "weather" } }) ); -} - -// ---- describe('tool calls') ------------------------------------------------------------------ - -fn tool_turn(reasoning: bool) -> Vec { - let mut assistant = vec![]; - if reasoning { - assistant.push(AssistantPart::Reasoning(ReasoningPart { - text: ("I think the tool will return the correct value.").into(), - provider_options: None, - })); - } - assistant.push(AssistantPart::ToolCall(ToolCallPart { - tool_call_id: ("quux").into(), - tool_name: ("thwomp").into(), - input: json!({ "foo": "bar123" }), - provider_executed: None, - provider_options: None, - })); - vec![ - LanguageModelMessage::Assistant { - content: assistant, - provider_options: None, - }, - LanguageModelMessage::Tool { - content: vec![ToolPart::ToolResult(ToolResultPart { - tool_call_id: ("quux").into(), - output: ToolResultOutput::Json { - value: json!({ "oof": "321rab" }), - provider_options: None, - }, - tool_name: "thwomp".into(), - provider_options: None, - })], - provider_options: None, - }, - ] -} - -fn wire_tool_call() -> Value { - json!([{ - "id": "quux", "type": "function", - "function": { "name": "thwomp", "arguments": "{\"foo\":\"bar123\"}" } - }]) -} - -#[tokio::test] -async fn convert_should_stringify_arguments_to_tool_calls() { - let result = generate_result("deepseek-chat", &options_for(tool_turn(false))).await; + options.tool_choice = Some(LanguageModelV4ToolChoice::Required); assert_eq!( - result.request.and_then(|r| r.body).unwrap()["messages"], - json!([ - // upstream sends the empty text as `content: ""`, not null. - { "role": "assistant", "content": "", "tool_calls": wire_tool_call() }, - { "role": "tool", "tool_call_id": "quux", "content": "{\"oof\":\"321rab\"}" } - ]) + generate_body("deepseek-reasoner", &options).await["tool_choice"], + "required" ); - assert!(result.warnings.is_empty()); } #[tokio::test] -async fn convert_should_handle_text_output_type_in_tool_results() { - let messages = wire_messages( - "deepseek-chat", - vec![ - LanguageModelMessage::Assistant { - content: vec![AssistantPart::ToolCall(ToolCallPart { - tool_call_id: ("call-1").into(), - tool_name: ("getWeather").into(), - input: json!({ "query": "weather" }), - provider_executed: None, - provider_options: None, - })], - provider_options: None, - }, - LanguageModelMessage::Tool { - content: vec![ToolPart::ToolResult(ToolResultPart { - tool_call_id: ("call-1").into(), - output: ToolResultOutput::Text { - value: "It is sunny today".into(), - provider_options: None, - }, - tool_name: "getWeather".into(), - provider_options: None, - })], - provider_options: None, - }, - ], - ) - .await; +async fn tool_call_should_warn_about_provider_defined_tools() { + use aimux_core::tool::ProviderTool; + let mut options = options(); + options.tools = Some(vec![Tool::Provider(ProviderTool { + id: "test.search".parse().unwrap(), + name: "search".to_string(), + args: serde_json::Map::new(), + supports_deferred_results: None, + })]); + let result = generate_result("deepseek-chat", &options).await; assert_eq!( - messages[1], - json!({ "role": "tool", "tool_call_id": "call-1", "content": "It is sunny today" }) + warning_values(&result.warnings), + warning_values(&[Warning::Unsupported { + feature: "provider-defined tool test.search".to_string(), + details: None, + }]) ); -} - -#[tokio::test] -async fn convert_should_support_reasoning_content_in_tool_calls() { - let mut prompt = vec![LanguageModelMessage::user_text("Hello")]; - prompt.extend(tool_turn(true)); - let messages = wire_messages("deepseek-chat", prompt).await; - assert_eq!( - messages[1], - json!({ - "role": "assistant", "content": "", - "reasoning_content": "I think the tool will return the correct value.", - "tool_calls": wire_tool_call() - }) + assert!( + result.request.and_then(|r| r.body).unwrap()["tools"] + .as_array() + .unwrap() + .is_empty() ); } #[tokio::test] -async fn convert_should_filter_out_reasoning_content_from_turns_before_the_last_user_message() { - let mut prompt = vec![LanguageModelMessage::user_text("Hello")]; - prompt.extend(tool_turn(true)); - prompt.push(LanguageModelMessage::user_text("Goodbye")); - let messages = wire_messages("deepseek-chat", prompt).await; +async fn tool_call_should_extract_tool_call_content() { + let server = json_server(tool_call_response()).await; + let result = chat(&server, "deepseek-reasoner") + .do_generate(&tool_options()) + .await + .unwrap(); + assert!( + matches!(&result.content[0], GenerateContent::Reasoning(ReasoningOutput { text, .. }) if text == "I should look up the weather.") + ); + assert!(matches!( + &result.content[1], + GenerateContent::ToolCall(RawToolCall { tool_call_id, tool_name, input, .. }) + if tool_call_id == "call_00_abc" && tool_name == "weather" + && input == "{\"location\":\"San Francisco\"}" + )); + assert_eq!(result.content.len(), 2); + assert_eq!(result.finish_reason.unified, FinishReasonUnified::ToolCalls); assert_eq!( - messages[1], - json!({ "role": "assistant", "content": "", "tool_calls": wire_tool_call() }) + result.provider_metadata.unwrap()["deepseek"]["toolCallTypes"], + json!(["function"]) ); } -// ---- describe('deepseek-v4 thinking mode') ------------------------------------------------------- +#[tokio::test] +async fn tool_call_should_generate_an_id_when_the_server_sends_none() { + let mut body = tool_call_response(); + body["choices"][0]["message"]["tool_calls"][0]["id"] = Value::Null; + let server = json_server(body).await; + let result = chat(&server, "deepseek-reasoner") + .do_generate(&tool_options()) + .await + .unwrap(); + assert!(matches!( + &result.content[1], + GenerateContent::ToolCall(RawToolCall { tool_call_id, .. }) if !tool_call_id.is_empty() + )); +} #[tokio::test] -async fn convert_should_preserve_reasoning_content_from_prior_turns_for_deepseek_v4() { - let mut prompt = vec![LanguageModelMessage::user_text("Hello")]; - prompt.extend(tool_turn(true)); - prompt.push(LanguageModelMessage::user_text("Goodbye")); - let messages = wire_messages("deepseek-v4-pro", prompt).await; - assert_eq!( - messages[1], - json!({ - "role": "assistant", "content": "", - "reasoning_content": "I think the tool will return the correct value.", - "tool_calls": wire_tool_call() - }) +async fn json_response_format_should_extract_text_content() { + let mut body = text_response(); + body["choices"][0]["message"]["content"] = json!("{\"elements\":[]}"); + let server = json_server(body).await; + let result = chat(&server, "deepseek-reasoner") + .do_generate(&json_options(None)) + .await + .unwrap(); + assert!( + matches!(&result.content[0], GenerateContent::Text { text, .. } if text == "{\"elements\":[]}") ); } +/// `deepSeekErrorSchema` as the chat model's failed-response handler +/// (deepseek@3.0.56 `deepseek-chat-api-types.ts:117-124`, +/// `deepseek-chat-language-model.ts:213-217`): `code` may be a number. #[tokio::test] -async fn convert_should_preserve_reasoning_content_from_prior_turns_for_the_deepseek_flash_alias() { - let messages = wire_messages( - "deepseek-flash", - vec![ - LanguageModelMessage::user_text("Hello"), - LanguageModelMessage::Assistant { - content: vec![ - AssistantPart::Reasoning(ReasoningPart { - text: ("Prior-turn reasoning.").into(), - provider_options: None, - }), - AssistantPart::Text(TextPart { - text: ("Hi there").into(), - provider_options: None, - }), - ], - provider_options: None, - }, - LanguageModelMessage::user_text("Again"), - ], - ) - .await; - assert_eq!( - messages[1], - json!({ "role": "assistant", "content": "Hi there", "reasoning_content": "Prior-turn reasoning." }) - ); +async fn a_failed_response_reads_deepseeks_error_schema() { + let server = MockServer::start().await; + Mock::given(method("POST")) + .and(path_regex(".*/chat/completions$")) + .respond_with(ResponseTemplate::new(402).set_body_json(json!({ "error": { + "message": "Insufficient Balance", "type": "unknown_error", "param": null, "code": 4020 + } }))) + .mount(&server) + .await; + let Err(AiMuxError::ApiCall(error)) = + chat(&server, "deepseek-chat").do_generate(&options()).await + else { + panic!("expected an API call error"); + }; + assert_eq!(error.message, "Insufficient Balance"); + assert_eq!(error.provider_code.as_deref(), Some("4020")); + assert_eq!(error.status_code, Some(402)); } #[tokio::test] -async fn convert_should_back_fill_empty_reasoning_content_for_deepseek_v4_assistant_messages_with_no_reasoning_part() - { - let messages = wire_messages( - "deepseek-v4-pro", - vec![ - LanguageModelMessage::user_text("Hello"), - LanguageModelMessage::Assistant { - content: vec![AssistantPart::Text(TextPart { - text: ("Hi there").into(), - provider_options: None, - })], - provider_options: None, - }, - LanguageModelMessage::user_text("Again"), - ], - ) - .await; +async fn stream_text_should_stream_text() { + let (_, parts) = stream_parts("deepseek-chat", &options(), text_chunks()).await; + assert!(matches!(&parts[0], StreamPart::StreamStart { warnings } if warnings.is_empty())); + assert!(matches!( + &parts[1], + StreamPart::ResponseMetadata(ResponseMetadata { id, model_id, .. }) + if id.as_deref() == Some("c1") && model_id.as_deref() == Some("deepseek-chat") + )); + let deltas: Vec<&str> = parts + .iter() + .filter_map(|part| match part { + StreamPart::TextDelta { id, delta, .. } if id == "txt-0" => Some(delta.as_str()), + _ => None, + }) + .collect(); + assert_eq!(deltas, ["Hello", ", World!"]); + assert!( + parts + .iter() + .any(|p| matches!(p, StreamPart::TextStart { id, .. } if id == "txt-0")) + ); + assert!( + parts + .iter() + .any(|p| matches!(p, StreamPart::TextEnd { id, .. } if id == "txt-0")) + ); + match parts.last().unwrap() { + StreamPart::Finish { + finish_reason, + usage, + .. + } => { + assert_eq!(finish_reason.unified, FinishReasonUnified::Stop); + assert_eq!(finish_reason.raw.as_deref(), Some("stop")); + // usage with prompt-cache tokens + assert_eq!(usage.input_tokens.total, Some(13)); + assert_eq!(usage.input_tokens.cache_read, Some(5)); + assert_eq!(usage.input_tokens.no_cache, Some(8)); + assert_eq!(usage.output_tokens.total, Some(3)); + } + other => panic!("expected finish, got {other:?}"), + } assert_eq!( - messages[1], - json!({ "role": "assistant", "content": "Hi there", "reasoning_content": "" }) + finish_metadata(&parts), + json!({ "deepseek": { + "promptCacheHitTokens": 5, + "promptCacheMissTokens": 8, + "responseObject": "chat.completion.chunk", + "choiceIndex": 0, + "messageRole": "assistant", + "systemFingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache" + } }) ); } -// ---- describe('assistant prefix completion') ----------------------------------------------------- - #[tokio::test] -async fn convert_should_reject_prefix_completion_on_a_non_assistant_message() { - let message = generate_error( - "deepseek-chat", - &options_for(vec![with_options( - LanguageModelMessage::user_text("Hello"), - json!({ "deepseek": { "prefix": true } }), - )]), - ) - .await; - assert!( - message.contains( - "DeepSeek assistant prefix completion requires `prefix: true` on an assistant message." +async fn stream_reasoning_should_stream_reasoning_before_text() { + let chunk = |delta: Value, finish: Value| { + data_event(&json!({ + "id": "c", "object": "chat.completion.chunk", "created": 1, "model": "deepseek-reasoner", + "choices": [{ "index": 0, "delta": delta, "finish_reason": finish }] + })) + }; + let chunks = vec![ + chunk( + json!({ "role": "assistant", "content": null, "reasoning_content": "Let me " }), + Value::Null, ), - "{message}" + chunk( + json!({ "content": null, "reasoning_content": "think." }), + Value::Null, + ), + chunk(json!({ "content": "Answer" }), Value::Null), + chunk(json!({ "content": "" }), json!("stop")), + ]; + let (_, parts) = stream_parts("deepseek-reasoner", &options(), chunks).await; + let order: Vec<&str> = parts + .iter() + .filter_map(|part| match part { + StreamPart::ReasoningStart { .. } => Some("reasoning-start"), + StreamPart::ReasoningDelta { .. } => Some("reasoning-delta"), + StreamPart::ReasoningEnd { .. } => Some("reasoning-end"), + StreamPart::TextStart { .. } => Some("text-start"), + StreamPart::TextDelta { .. } => Some("text-delta"), + StreamPart::TextEnd { .. } => Some("text-end"), + _ => None, + }) + .collect(); + assert_eq!( + order, + [ + "reasoning-start", + "reasoning-delta", + "reasoning-delta", + "text-start", + "reasoning-end", + "text-delta", + "text-end" + ] ); } #[tokio::test] -async fn convert_should_reject_prefix_completion_on_a_non_final_assistant_message() { - let server = json_server(text_response()).await; - let prompt = vec![ - with_options( - LanguageModelMessage::Assistant { - content: vec![AssistantPart::Text(TextPart { - text: ("The answer is").into(), - provider_options: None, - })], - provider_options: None, - }, - json!({ "deepseek": { "prefix": true } }), +async fn stream_tool_call_should_stream_tool_call() { + let chunk = |delta: Value, finish: Value| { + data_event(&json!({ + "id": "c", "object": "chat.completion.chunk", "created": 1, "model": "deepseek-reasoner", + "choices": [{ "index": 0, "delta": delta, "finish_reason": finish }] + })) + }; + let chunks = vec![ + chunk( + json!({ "role": "assistant", "reasoning_content": "Look it up." }), + Value::Null, + ), + chunk( + json!({ "tool_calls": [{ "index": 0, "id": "call_00_abc", "type": "function", + "function": { "name": "weather", "arguments": "" } }] }), + Value::Null, ), - LanguageModelMessage::user_text("Continue"), + chunk( + json!({ "tool_calls": [{ "index": 0, "function": { "arguments": "{\"location\":" } }] }), + Value::Null, + ), + chunk( + json!({ "tool_calls": [{ "index": 0, "function": { "arguments": "\"San Francisco\"}" } }] }), + Value::Null, + ), + chunk(json!({ "content": "" }), json!("tool_calls")), ]; - let error = beta_chat(&server, "deepseek-chat") - .do_generate(&options_for(prompt)) - .await - .unwrap_err(); + let (_, parts) = stream_parts("deepseek-reasoner", &tool_options(), chunks).await; + assert!(parts.iter().any(|p| matches!( + p, + StreamPart::ToolInputStart { id, tool_name, .. } if id == "call_00_abc" && tool_name == "weather" + ))); + let input: String = parts + .iter() + .filter_map(|p| match p { + StreamPart::ToolInputDelta { id, delta, .. } if id == "call_00_abc" => { + Some(delta.as_str()) + } + _ => None, + }) + .collect(); + assert_eq!(input, "{\"location\":\"San Francisco\"}"); + assert!(parts.iter().any(|p| matches!( + p, + StreamPart::ToolCall(RawToolCall { tool_call_id, tool_name, input, .. }) + if tool_call_id == "call_00_abc" && tool_name == "weather" + && input == "{\"location\":\"San Francisco\"}" + ))); assert!( - error.to_string().contains( - "DeepSeek assistant prefix completion requires the prefixed assistant message to be the final message." - ), - "{error}" + parts + .iter() + .any(|p| matches!(p, StreamPart::ReasoningEnd { .. })) + ); + match parts.last().unwrap() { + StreamPart::Finish { finish_reason, .. } => { + assert_eq!(finish_reason.unified, FinishReasonUnified::ToolCalls); + } + other => panic!("expected finish, got {other:?}"), + } + assert_eq!( + finish_metadata(&parts)["deepseek"]["toolCallTypes"], + json!(["function"]) ); }