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