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