spark_server/
tokenizer.rs1use anyhow::Result;
10use tokenizers::Tokenizer;
11
12fn normalize_tool_call_arguments(messages: &[serde_json::Value]) -> Vec<serde_json::Value> {
20 let mut total_parsed = 0usize;
21 let mut total_seen = 0usize;
22 let out: Vec<_> = messages
23 .iter()
24 .map(|msg| {
25 let mut msg = msg.clone();
26 let Some(tool_calls) = msg.get_mut("tool_calls").and_then(|v| v.as_array_mut()) else {
27 return msg;
28 };
29 for tc in tool_calls.iter_mut() {
30 let Some(function) = tc.get_mut("function") else {
31 continue;
32 };
33 let Some(args) = function.get_mut("arguments") else {
34 continue;
35 };
36 total_seen += 1;
37 let parsed_owned = if let Some(s) = args.as_str() {
38 serde_json::from_str::<serde_json::Value>(s).ok()
39 } else {
40 None
41 };
42 if let Some(parsed) = parsed_owned {
43 *args = parsed;
44 total_parsed += 1;
45 }
46 }
50 msg
51 })
52 .collect();
53 if total_seen > 0 {
54 tracing::debug!(
55 "F76 normalize: {}/{} tool_call arguments parsed string→dict",
56 total_parsed,
57 total_seen,
58 );
59 }
60 out
61}
62
63mod chat_impl;
65mod chat_render;
66mod deepseek_v4;
67mod jinja_helpers;
68mod message_preprocess;
69
70pub(crate) use message_preprocess::{
71 autoclose_assistant_think, remap_developer_role, resolve_think_control,
72};
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75enum ChatEncoding {
76 Jinja,
77 DeepseekV4,
78}
79
80pub struct ChatTokenizer {
81 tokenizer: Tokenizer,
82 eos_token_id: u32,
83 supports_thinking: bool,
84 chat_encoding: ChatEncoding,
85 #[allow(dead_code)]
87 chat_template: String,
88 jinja_env: minijinja::Environment<'static>,
90 openai_jinja_env: Option<minijinja::Environment<'static>>,
93}
94
95pub struct StreamingDecoder<'a> {
98 inner: tokenizers::DecodeStream<
99 'a,
100 tokenizers::models::ModelWrapper,
101 tokenizers::normalizers::NormalizerWrapper,
102 tokenizers::pre_tokenizers::PreTokenizerWrapper,
103 tokenizers::processors::PostProcessorWrapper,
104 tokenizers::decoders::DecoderWrapper,
105 >,
106}
107
108impl StreamingDecoder<'_> {
109 pub fn step(&mut self, id: u32) -> Result<Option<String>> {
111 self.inner
112 .step(id)
113 .map_err(|e| anyhow::anyhow!("Streaming decode error: {e}"))
114 }
115}
116
117#[cfg(test)]
118mod tests;