Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions aimux-providers/layout.toml
Original file line number Diff line number Diff line change
Expand Up @@ -931,35 +931,35 @@ package = "@ai-sdk/deepseek"

[[deepseek.files]]
upstream = "src/chat/convert-to-deepseek-chat-messages.ts"
rust = "deepseek/convert.rs"
rust = "deepseek/chat/convert_to_chat_messages.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/chat/convert-to-deepseek-usage.ts"
rust = "deepseek/usage.rs"
rust = "deepseek/chat/convert_to_usage.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/chat/deepseek-chat-api-types.ts"
rust = "deepseek/types.rs"
rust = "deepseek/chat/chat_api_types.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/chat/deepseek-chat-language-model-options.ts"
rust = "deepseek/options.rs"
rust = "deepseek/chat/chat_language_model_options.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/chat/deepseek-chat-language-model.ts"
rust = "deepseek/model.rs"
rust = "deepseek/chat/chat_language_model.rs"
status = "mapped"

[deepseek.files.tests]
Expand All @@ -971,14 +971,14 @@ ts-only = [

[[deepseek.files]]
upstream = "src/chat/deepseek-file-part-options.ts"
rust = "deepseek/options.rs"
rust = "deepseek/chat/file_part_options.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/chat/deepseek-prepare-tools.ts"
rust = "deepseek/prepare_tools.rs"
rust = "deepseek/chat/prepare_tools.rs"
status = "mapped"

[deepseek.files.tests]
Expand All @@ -988,28 +988,28 @@ ts-only = [

[[deepseek.files]]
upstream = "src/chat/get-response-metadata.ts"
rust = "deepseek/model.rs"
rust = "deepseek/chat/chat_language_model.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/chat/is-deepseek-v4-model.ts"
rust = "deepseek/is_v4_model.rs"
rust = "deepseek/chat/is_v4_model.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/chat/map-deepseek-finish-reason.ts"
rust = "deepseek/finish_reason.rs"
rust = "deepseek/chat/map_finish_reason.rs"
status = "mapped"

[deepseek.files.tests]

[[deepseek.files]]
upstream = "src/deepseek-provider.ts"
rust = "deepseek/mod.rs"
rust = "deepseek/provider.rs"
status = "mapped"

[deepseek.files.tests]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ use aimux_core::stream_part::StreamPart;
use aimux_core::types::{FinishReason, ReasoningEffort, ResponseMetadata, Warning};
use aimux_provider_utils::{Transformer, generate_id, pipe_through};

use super::convert::convert_to_deepseek_chat_messages;
use super::finish_reason::map_deepseek_finish_reason;
use super::chat_api_types::{ChatChunk, ChatResponse};
use super::chat_language_model_options::{
ProviderReasoningEffort, ThinkingType, parse_chat_options,
};
use super::convert_to_chat_messages::convert_to_deepseek_chat_messages;
use super::convert_to_usage::convert_deepseek_usage;
use super::is_v4_model::is_deepseek_v4_model;
use super::options::{ProviderReasoningEffort, ThinkingType, parse_chat_options};
use super::map_finish_reason::map_deepseek_finish_reason;
use super::prepare_tools::prepare_tools;
use super::types::{ChatChunk, ChatResponse};
use super::usage::convert_deepseek_usage;
use crate::shared::EndpointConfig;
use crate::stream::{
ChatToolCalls, Controller, Emit, FINISH_ERROR, FINISH_OTHER, StreamContext, ToolCallDelta,
Expand Down Expand Up @@ -373,7 +375,7 @@ impl LanguageModel for DeepSeekChatLanguageModel {
exchange.request(exchange.url("/chat/completions"), options),
body.clone(),
aimux_provider_utils::create_json_response_handler::<ChatResponse>(),
super::types::deepseek_failed_response_handler(),
super::chat_api_types::deepseek_failed_response_handler(),
)
.await?;

Expand Down Expand Up @@ -492,7 +494,7 @@ impl LanguageModel for DeepSeekChatLanguageModel {
exchange.request(endpoint.clone(), options),
body.clone(),
aimux_provider_utils::create_event_source_response_handler::<Value>(),
super::types::deepseek_failed_response_handler(),
super::chat_api_types::deepseek_failed_response_handler(),
)
.await?;
let response_headers = resp.response_headers;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! The providerOptions of the DeepSeek chat model
//! (`deepseek-chat-language-model-options.ts`, `deepseek-file-part-options.ts`).
//! (`deepseek-chat-language-model-options.ts`).
//!
//! They are read from the namespace named by the provider (`deepseek`).

Expand Down Expand Up @@ -78,17 +78,6 @@ pub(crate) struct DeepSeekMessageOptions {
pub prefix: Option<bool>,
}

/// The `providerOptions` of a file part.
#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DeepSeekFilePartOptions {
/// How DeepSeek processes an image sent as an `image_url` part
/// (`low`, `high`, `original`, `auto`).
pub image_detail: Option<String>,
/// Send inline image data as a `file` part instead of an `image_url`.
pub file_data: Option<bool>,
}

// An optional schema field may be absent, but an explicit null is invalid.
fn deserialize_optional<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
Expand All @@ -100,7 +89,7 @@ where

/// The options of `namespace` in a providerOptions value; no namespace is the
/// defaults.
fn parse_namespace<T: Default + for<'de> Deserialize<'de>>(
pub(super) fn parse_namespace<T: Default + for<'de> Deserialize<'de>>(
namespace: Option<&JsonObject>,
name: &str,
) -> Result<T, AiMuxError> {
Expand All @@ -115,7 +104,7 @@ fn parse_namespace<T: Default + for<'de> Deserialize<'de>>(
}
}

fn invalid(name: &str, message: &str) -> AiMuxError {
pub(super) fn invalid(name: &str, message: &str) -> AiMuxError {
AiMuxError::invalid_argument(format!(
"invalid provider options for \"{name}\": {message}"
))
Expand Down Expand Up @@ -182,31 +171,3 @@ pub(crate) fn parse_message_options(
}
Ok(options)
}

/// The options of a file part.
///
/// # Errors
///
/// `InvalidArgument` when `imageDetail` is not a known value or `fileData` is
/// not `true`.
pub(crate) fn parse_file_part_options(
provider_options: Option<&SharedProviderOptions>,
name: &str,
) -> Result<DeepSeekFilePartOptions, AiMuxError> {
let options: DeepSeekFilePartOptions =
parse_namespace(provider_options.and_then(|all| all.get(name)), name)?;
if options.file_data == Some(false) {
return Err(invalid(name, "fileData must be true"));
}
if options
.image_detail
.as_deref()
.is_some_and(|detail| !["low", "high", "original", "auto"].contains(&detail))
{
return Err(invalid(
name,
"imageDetail must be low, high, original or auto",
));
}
Ok(options)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use aimux_core::shared::{FileBytes, FileData};
use aimux_core::types::Warning;
use aimux_provider_utils::resolve_full_media_type;

use super::chat_language_model_options::parse_message_options;
use super::file_part_options::parse_file_part_options;
use super::is_v4_model::is_deepseek_v4_model;
use super::options::{parse_file_part_options, parse_message_options};

const SUPPORTED_IMAGE_MEDIA_TYPES: [&str; 5] = [
"image/gif",
Expand Down
47 changes: 47 additions & 0 deletions aimux-providers/src/deepseek/chat/file_part_options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//! The providerOptions of a file part (`deepseek-file-part-options.ts`).

use serde::Deserialize;

use aimux_core::error::AiMuxError;
use aimux_core::shared::SharedProviderOptions;

use super::chat_language_model_options::{invalid, parse_namespace};

/// The `providerOptions` of a file part.
#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DeepSeekFilePartOptions {
/// How DeepSeek processes an image sent as an `image_url` part
/// (`low`, `high`, `original`, `auto`).
pub image_detail: Option<String>,
/// Send inline image data as a `file` part instead of an `image_url`.
pub file_data: Option<bool>,
}

/// The options of a file part.
///
/// # Errors
///
/// `InvalidArgument` when `imageDetail` is not a known value or `fileData` is
/// not `true`.
pub(crate) fn parse_file_part_options(
provider_options: Option<&SharedProviderOptions>,
name: &str,
) -> Result<DeepSeekFilePartOptions, AiMuxError> {
let options: DeepSeekFilePartOptions =
parse_namespace(provider_options.and_then(|all| all.get(name)), name)?;
if options.file_data == Some(false) {
return Err(invalid(name, "fileData must be true"));
}
if options
.image_detail
.as_deref()
.is_some_and(|detail| !["low", "high", "original", "auto"].contains(&detail))
{
return Err(invalid(
name,
"imageDetail must be low, high, original or auto",
));
}
Ok(options)
}
15 changes: 15 additions & 0 deletions aimux-providers/src/deepseek/chat/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! `src/chat/` of `@ai-sdk/deepseek`.

mod chat_api_types;
mod chat_language_model;
mod chat_language_model_options;
pub(super) mod convert_to_chat_messages;
pub(super) mod convert_to_usage;
mod file_part_options;
pub(super) mod is_v4_model;
mod map_finish_reason;
pub(super) mod prepare_tools;

pub(crate) use chat_api_types::deepseek_failed_response_handler;
pub(crate) use chat_language_model::DeepSeekChatConfig;
pub use chat_language_model::DeepSeekChatLanguageModel;
Loading
Loading