async_dashscope/operation/
validate.rs1use crate::operation::request::RequestTrait;
2use crate::{
3 error::{DashScopeError, Result},
4 operation::{common::Parameters, embeddings::EmbeddingsParameters},
5};
6
7pub enum ModelValidator {
13 Default,
15 NotSupportResultFormatText,
17 NotSupportEnableThinking,
19 NotSupportToolCall,
20 NotSupportJsonOutput,
21 DimensionNotMatch,
23 OnlyStreaming,
24}
25
26pub trait Validator<T> {
27 #[allow(clippy::result_large_err)]
29 fn validate<R: RequestTrait<P = T> + ?Sized>(&self, params: &R) -> Result<()>;
30}
31
32impl Validator<EmbeddingsParameters> for ModelValidator {
33 fn validate<R: RequestTrait<P = EmbeddingsParameters> + ?Sized>(
34 &self,
35 params: &R,
36 ) -> Result<()> {
37 match self {
38 ModelValidator::DimensionNotMatch => {
39 if let Some(p) = params.parameters() {
45 let valid_dimensions = match params.model() {
46 "text-embedding-v1" | "text-embedding-v2" => {
47 vec![1536]
48 }
49 "text-embedding-v3" => {
50 vec![1024, 768, 512, 256, 128, 64]
51 }
52 "text-embedding-v4" => {
53 vec![2048, 1536, 1024, 768, 512, 256, 128, 64]
54 }
55 _ => vec![], };
57 if let Some(dimension) = p.dimension {
58 if !valid_dimensions.contains(&dimension) {
59 return Err(DashScopeError::InvalidArgument(format!(
60 "Invalid dimension: {} for model: {}",
61 dimension,
62 params.model()
63 )));
64 }
65 }
66 }
67 Ok(())
68 }
69 _ => Ok(()),
70 }
71 }
72}
73impl Validator<Parameters> for ModelValidator {
74 fn validate<R: RequestTrait<P = Parameters> + ?Sized>(&self, params: &R) -> Result<()> {
75 match self {
76 ModelValidator::Default => {
77 Ok(())
79 }
80 ModelValidator::NotSupportResultFormatText => {
81 if let Some(p) = params.parameters() {
83 if let Some(format) = &p.result_format {
84 if format == "text" {
85 return Err(DashScopeError::InvalidArgument(
86 "deepseek-r1 does not support result_format = text".into(),
87 ));
88 }
89 }
90 }
91 Ok(())
92 }
93 ModelValidator::NotSupportEnableThinking => {
94 if let Some(p) = params.parameters() {
95 if let Some(thinking) = p.enable_thinking {
96 if thinking {
97 return Err(DashScopeError::InvalidArgument(
98 "The model does not support enable_thinking = true".into(),
99 ));
100 }
101 }
102 }
103 Ok(())
104 }
105 ModelValidator::NotSupportJsonOutput => {
106 if let Some(p) = params.parameters() {
107 if let Some(response_format) = p.response_format.as_ref() {
108 if response_format.type_ == "json_object" {
109 return Err(DashScopeError::InvalidArgument(
110 "The model does not support response_format=json_object".into(),
111 ));
112 }
113 }
114 }
115 Ok(())
116 }
117
118 ModelValidator::NotSupportToolCall => {
119 if let Some(p) = params.parameters() {
120 if p.tools.is_some() {
121 return Err(DashScopeError::InvalidArgument(
122 "The model does not support tool call".into(),
123 ));
124 }
125 }
126 Ok(())
127 }
128
129 ModelValidator::OnlyStreaming => {
130 if let Some(p) = params.parameters() {
131 #[allow(deprecated)]
132 if p.incremental_output == Some(false) {
133 return Err(DashScopeError::InvalidArgument(
134 "The model does not support streaming".into(),
135 ));
136 }
137 }
138
139 Ok(())
140 }
141
142 _ => Ok(()),
143 }
144 }
145}
146
147pub(crate) fn check_model_parameters(model: &str) -> Vec<ModelValidator> {
157 match model {
158 "deepseek-r1" => vec![
159 ModelValidator::NotSupportResultFormatText,
160 ModelValidator::NotSupportJsonOutput,
161 ],
162 "qwen-vl" | "qwen-audio" => vec![ModelValidator::NotSupportToolCall],
163 "Moonshot-Kimi-K2-Instruct" => vec![
164 ModelValidator::NotSupportEnableThinking,
165 ModelValidator::NotSupportResultFormatText,
166 ModelValidator::NotSupportJsonOutput,
167 ModelValidator::NotSupportToolCall,
168 ],
169 "text-embedding-v4" | "text-embedding-v3" | "text-embedding-v2" | "text-embedding-v1" => {
170 vec![ModelValidator::DimensionNotMatch]
171 }
172 "qwen-mt-image" => {
173 vec![ModelValidator::Default]
174 }
175 "glm-4.6" | "glm-4.5" | "glm-4.5-air" => {
176 vec![ModelValidator::OnlyStreaming]
177 }
178 _ => vec![ModelValidator::Default],
179 }
180}