1use phf::phf_map;
15
16pub static KEY_ABBREV: phf::Map<&'static str, &'static str> = phf_map! {
25 "content" => "c", "model" => "M", "temperature" => "T", "max_tokens" => "x", "stream" => "s", "stop" => "S", "top_p" => "p", "frequency_penalty" => "f", "presence_penalty" => "P", "function_call" => "fc", "arguments" => "a", "tool_calls" => "tc", "tool_choice" => "tx", "response_format" => "rf", "logit_bias" => "lb", "logprobs" => "lp", "top_logprobs" => "tlp", "choices" => "C", "finish_reason" => "fr", "prompt_tokens" => "pt", "completion_tokens" => "ct","total_tokens" => "tt", "delta" => "D", "system_fingerprint" => "sf", "error" => "E", };
53
54pub static KEY_EXPAND: phf::Map<&'static str, &'static str> = phf_map! {
56 "c" => "content",
57 "M" => "model",
58 "T" => "temperature",
59 "x" => "max_tokens",
60 "s" => "stream",
61 "S" => "stop",
62 "p" => "top_p",
63 "f" => "frequency_penalty",
64 "P" => "presence_penalty",
65 "fc" => "function_call",
66 "a" => "arguments",
67 "tc" => "tool_calls",
68 "tx" => "tool_choice",
69 "rf" => "response_format",
70 "lb" => "logit_bias",
71 "lp" => "logprobs",
72 "tlp" => "top_logprobs",
73 "C" => "choices",
74 "fr" => "finish_reason",
75 "pt" => "prompt_tokens",
76 "ct" => "completion_tokens",
77 "tt" => "total_tokens",
78 "D" => "delta",
79 "sf" => "system_fingerprint",
80 "E" => "error",
81};
82
83pub static ROLE_ABBREV: phf::Map<&'static str, &'static str> = phf_map! {
88 "system" => "S", "assistant" => "A", "function" => "F", "tool" => "T", };
93
94pub static ROLE_EXPAND: phf::Map<&'static str, &'static str> = phf_map! {
96 "S" => "system",
97 "A" => "assistant",
98 "F" => "function",
99 "T" => "tool",
100};
101
102pub static MODEL_ABBREV: phf::Map<&'static str, &'static str> = phf_map! {
109 "gpt-4o" => "g4o", "gpt-4o-mini" => "g4om", "gpt-4-turbo" => "g4t", "gpt-4" => "g4", "gpt-3.5-turbo" => "g35t", "llama-3.1-405b" => "l31405", "llama-3.1-70b" => "l3170", "llama-3.1-8b" => "l318", "llama-3.3-70b" => "l3370", "mistral-large-latest" => "mll", "mistral-small-latest" => "msl", "mixtral-8x7b" => "mx87", "mixtral-8x22b" => "mx822", "deepseek-v3" => "dv3", "deepseek-r1" => "dr1", "deepseek-coder" => "dc", "qwen-2.5-72b" => "q2572", "qwen-2.5-32b" => "q2532", "qwen-2.5-coder-32b" => "qc32", };
134
135pub static MODEL_EXPAND: phf::Map<&'static str, &'static str> = phf_map! {
137 "g4o" => "gpt-4o",
139 "g4om" => "gpt-4o-mini",
140 "g4t" => "gpt-4-turbo",
141 "g4" => "gpt-4",
142 "g35t" => "gpt-3.5-turbo",
143 "l31405" => "llama-3.1-405b",
145 "l3170" => "llama-3.1-70b",
146 "l318" => "llama-3.1-8b",
147 "l3370" => "llama-3.3-70b",
148 "mll" => "mistral-large-latest",
150 "msl" => "mistral-small-latest",
151 "mx87" => "mixtral-8x7b",
152 "mx822" => "mixtral-8x22b",
153 "dv3" => "deepseek-v3",
155 "dr1" => "deepseek-r1",
156 "dc" => "deepseek-coder",
157 "q2572" => "qwen-2.5-72b",
159 "q2532" => "qwen-2.5-32b",
160 "qc32" => "qwen-2.5-coder-32b",
161};
162
163pub static PATTERN_ABBREV: &[(&str, &str)] = &[
170 (r#"{"role":"user","content":""#, "\u{0001}"),
172 (r#"{"role":"assistant","content":""#, "\u{0002}"),
173 (r#"{"role":"system","content":""#, "\u{0003}"),
174 (r#"{"role":"tool","content":""#, "\u{0004}"),
175 (r#"{"index":0,"delta":{"#, "\u{0005}"),
177 (r#"{"index":0,"message":{"#, "\u{0006}"),
178 (r#""finish_reason":"stop""#, "\u{0007}"),
180 (r#""finish_reason":"length""#, "\u{0008}"),
181 (r#""finish_reason":"tool_calls""#, "\u{0009}"),
182 (r#"{"type":"function","function":{"#, "\u{000A}"),
184 (r#""choices":[{"#, "\u{000B}"),
186 (r#"{"messages":["#, "\u{000C}"),
187 (r#"],"model":""#, "\u{000D}"),
188];
189
190pub static PATTERN_EXPAND: &[(&str, &str)] = &[
192 ("\u{0001}", r#"{"role":"user","content":""#),
193 ("\u{0002}", r#"{"role":"assistant","content":""#),
194 ("\u{0003}", r#"{"role":"system","content":""#),
195 ("\u{0004}", r#"{"role":"tool","content":""#),
196 ("\u{0005}", r#"{"index":0,"delta":{"#),
197 ("\u{0006}", r#"{"index":0,"message":{"#),
198 ("\u{0007}", r#""finish_reason":"stop""#),
199 ("\u{0008}", r#""finish_reason":"length""#),
200 ("\u{0009}", r#""finish_reason":"tool_calls""#),
201 ("\u{000A}", r#"{"type":"function","function":{"#),
202 ("\u{000B}", r#""choices":[{"#),
203 ("\u{000C}", r#"{"messages":["#),
204 ("\u{000D}", r#"],"model":""#),
205];
206
207pub fn is_default_value(key: &str, value: &serde_json::Value) -> bool {
209 use serde_json::Value;
210
211 match (key, value) {
212 ("temperature" | "T", Value::Number(n)) => {
213 n.as_f64().map(|f| (f - 1.0).abs() < 0.001).unwrap_or(false)
214 },
215 ("top_p" | "p", Value::Number(n)) => {
216 n.as_f64().map(|f| (f - 1.0).abs() < 0.001).unwrap_or(false)
217 },
218 ("n", Value::Number(n)) => n.as_i64() == Some(1),
219 ("stream" | "s", Value::Bool(b)) => !b,
220 ("frequency_penalty" | "f", Value::Number(n)) => {
221 n.as_i64() == Some(0) || n.as_f64() == Some(0.0)
222 },
223 ("presence_penalty" | "P", Value::Number(n)) => {
224 n.as_i64() == Some(0) || n.as_f64() == Some(0.0)
225 },
226 ("logit_bias" | "lb", Value::Object(m)) => m.is_empty(),
227 ("stop" | "S", Value::Null) => true,
228 _ => false,
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 #[test]
237 fn test_key_roundtrip() {
238 for (full, abbrev) in KEY_ABBREV.entries() {
239 assert_eq!(
240 KEY_EXPAND.get(*abbrev),
241 Some(full),
242 "Key '{full}' -> '{abbrev}' doesn't round-trip"
243 );
244 }
245 }
246
247 #[test]
248 fn test_role_roundtrip() {
249 for (full, abbrev) in ROLE_ABBREV.entries() {
250 assert_eq!(
251 ROLE_EXPAND.get(*abbrev),
252 Some(full),
253 "Role '{full}' -> '{abbrev}' doesn't round-trip"
254 );
255 }
256 }
257
258 #[test]
259 fn test_model_roundtrip() {
260 for (full, abbrev) in MODEL_ABBREV.entries() {
261 assert_eq!(
262 MODEL_EXPAND.get(*abbrev),
263 Some(full),
264 "Model '{full}' -> '{abbrev}' doesn't round-trip"
265 );
266 }
267 }
268
269 #[test]
270 fn test_pattern_roundtrip() {
271 for (pattern, abbrev) in PATTERN_ABBREV {
272 let expanded = PATTERN_EXPAND
273 .iter()
274 .find(|(a, _)| a == abbrev)
275 .map(|(_, p)| *p);
276 assert_eq!(
277 expanded,
278 Some(*pattern),
279 "Pattern '{pattern}' -> '{abbrev:?}' doesn't round-trip"
280 );
281 }
282 }
283
284 #[test]
285 fn test_default_detection() {
286 use serde_json::json;
287
288 assert!(is_default_value("temperature", &json!(1.0)));
289 assert!(!is_default_value("temperature", &json!(0.7)));
290 assert!(is_default_value("stream", &json!(false)));
291 assert!(!is_default_value("stream", &json!(true)));
292 assert!(is_default_value("n", &json!(1)));
293 assert!(!is_default_value("n", &json!(2)));
294 }
295}