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;
65pub(crate) mod chat_render;
66mod deepseek_v4;
67pub(crate) mod 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 native_qwen_tool_template: bool,
87 #[allow(dead_code)]
89 chat_template: String,
90 jinja_env: minijinja::Environment<'static>,
92 openai_jinja_env: Option<minijinja::Environment<'static>>,
95}
96
97pub struct StreamingDecoder<'a> {
100 inner: tokenizers::DecodeStream<
101 'a,
102 tokenizers::models::ModelWrapper,
103 tokenizers::normalizers::NormalizerWrapper,
104 tokenizers::pre_tokenizers::PreTokenizerWrapper,
105 tokenizers::processors::PostProcessorWrapper,
106 tokenizers::decoders::DecoderWrapper,
107 >,
108}
109
110impl StreamingDecoder<'_> {
111 pub fn step(&mut self, id: u32) -> Result<Option<String>> {
113 self.inner
114 .step(id)
115 .map_err(|e| anyhow::anyhow!("Streaming decode error: {e}"))
116 }
117}
118
119#[cfg(test)]
120mod tests;