mod gguf; #[cfg(target_os = "macos")] mod kvstore; #[cfg(target_os = "macos")] mod metal; mod tokenizer; mod validation; #[cfg(target_os = "macos")] use crate::metrics::{KvLookup, Metrics}; use crate::model::ModelChoice; use crate::settings::TurnSettings; use crate::settings::{EngineSettings, ReasoningMode}; use gguf::{F16, F32, Gguf, I32, IQ2_XXS, Q2_K, Q4_0, Q4_K, Q5_K, Q6_K, Q8_0, Tensor, Value}; #[cfg(target_os = "macos")] use kvstore::{KvStore, StoreReason}; use sha2::{Digest, Sha256}; use std::path::{Path, PathBuf}; #[cfg(target_os = "macos")] use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; #[cfg(target_os = "macos")] use std::time::Instant; use tokenizer::Tokenizer; use validation::{validate_dspark, validate_main}; pub(crate) use validation::validate_model_artifact; #[cfg(target_os = "macos")] pub(crate) use kvstore::sweep_unreachable as sweep_transient_cache; #[cfg(target_os = "macos")] pub(crate) use metal::configure_sources as configure_metal_sources; const DENSE: &[u32] = &[Q8_0, Q4_K, Q4_0]; const ROUTED: &[u32] = &[Q8_0, IQ2_XXS, Q2_K, Q4_K, Q5_K, Q6_K]; const PLAIN: &[u32] = &[F16, F32]; const DSPARK_DENSE: &[u32] = &[F16, F32, Q8_0]; #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum ModelFamily { DeepSeek, Glm, } #[derive(Clone, Copy)] struct Shape { model: ModelChoice, family: ModelFamily, layers: u32, embd: u64, vocab: u64, heads: u64, head_kv: u64, head_dim: u64, value_dim: u64, rot: u64, out_groups: u64, lora_q: u64, lora_o: u64, experts: u64, experts_used: u64, expert_shared: u64, ff_expert: u64, ff_dense: u64, hash_layers: u32, sliding_window: u64, indexer_heads: u64, indexer_head_dim: u64, indexer_top_k: u64, hc: u64, hc_sinkhorn: u64, nextn: u32, leading_dense: u32, kv_lora: u64, key_mla: u64, value_mla: u64, rms_epsilon: f32, hc_epsilon: f32, expert_weight_scale: f32, swiglu_clamp: f32, rope_base: f32, rope_scale: f32, rope_beta_fast: f32, rope_beta_slow: f32, compress_rope_base: f32, original_context: u64, } const FLASH: Shape = Shape { model: ModelChoice::DeepSeekV4Flash, family: ModelFamily::DeepSeek, layers: 43, embd: 4096, vocab: 129_280, heads: 64, head_kv: 1, head_dim: 512, value_dim: 512, rot: 64, out_groups: 8, lora_q: 1024, lora_o: 1024, experts: 256, experts_used: 6, expert_shared: 1, ff_expert: 2048, ff_dense: 0, hash_layers: 3, sliding_window: 128, indexer_heads: 64, indexer_head_dim: 128, indexer_top_k: 512, hc: 4, hc_sinkhorn: 20, nextn: 0, leading_dense: 0, kv_lora: 0, key_mla: 0, value_mla: 0, rms_epsilon: 1.0e-6, hc_epsilon: 1.0e-6, expert_weight_scale: 1.5, swiglu_clamp: 10.0, rope_base: 10_000.0, rope_scale: 16.0, rope_beta_fast: 32.0, rope_beta_slow: 1.0, compress_rope_base: 160_000.0, original_context: 65_536, }; const PRO: Shape = Shape { model: ModelChoice::DeepSeekV4Pro, layers: 61, embd: 7168, heads: 128, out_groups: 16, lora_q: 1536, experts: 384, ff_expert: 3072, indexer_top_k: 1024, expert_weight_scale: 2.5, ..FLASH }; const GLM: Shape = Shape { model: ModelChoice::Glm52, family: ModelFamily::Glm, layers: 79, embd: 6144, vocab: 154_880, heads: 64, head_kv: 1, head_dim: 576, value_dim: 512, rot: 64, out_groups: 0, lora_q: 2048, lora_o: 0, experts: 256, experts_used: 8, expert_shared: 1, ff_expert: 2048, ff_dense: 12_288, hash_layers: 0, sliding_window: 0, indexer_heads: 32, indexer_head_dim: 128, indexer_top_k: 2048, hc: 0, hc_sinkhorn: 0, nextn: 1, leading_dense: 3, kv_lora: 512, key_mla: 256, value_mla: 256, rms_epsilon: 1.0e-5, hc_epsilon: 0.0, expert_weight_scale: 2.5, swiglu_clamp: 0.0, rope_base: 8_000_000.0, rope_scale: 1.0, rope_beta_fast: 0.0, rope_beta_slow: 0.0, compress_rope_base: 0.0, original_context: 1_048_576, }; pub(crate) struct Model { main: Gguf, support: Option, shape: Shape, tokenizer: Tokenizer, } #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct ModelSummary { pub(crate) model: ModelChoice, pub(crate) mapped_bytes: u64, pub(crate) tensor_count: usize, pub(crate) vocabulary_size: usize, pub(crate) support_loaded: bool, } impl Model { #[allow(dead_code)] pub(crate) fn open(settings: &EngineSettings) -> Result { let mut model = Self::open_main(&settings.artifacts.model, settings.model)?; if let Some(path) = &settings.artifacts.mtp { let support = Gguf::open(path)?; validate_dspark(&support, &model.shape)?; model.support = Some(support); } Ok(model) } fn open_main(path: &Path, expected: ModelChoice) -> Result { let main = Gguf::open(path)?; let shape = validate_main(&main, expected)?; let tokenizer = Tokenizer::load(&main, shape.family)?; if tokenizer.vocab_size() != shape.vocab as usize { return Err(format!( "tokenizer has {} entries, expected {}", tokenizer.vocab_size(), shape.vocab )); } Ok(Self { main, support: None, shape, tokenizer, }) } pub(crate) fn summary(&self) -> ModelSummary { ModelSummary { model: self.shape.model, mapped_bytes: self.main.len() + self.support.as_ref().map_or(0, Gguf::len), tensor_count: self.main.tensors.len() + self .support .as_ref() .map_or(0, |support| support.tensors.len()), vocabulary_size: self.tokenizer.vocab_size(), support_loaded: self.support.is_some(), } } pub(crate) fn tokenize(&self, text: &str) -> Vec { self.tokenizer.tokenize(text) } pub(crate) fn render_prompt( &self, system: &str, prompt: &str, reasoning: ReasoningMode, ) -> Vec { self.tokenizer.encode_chat(system, prompt, reasoning) } fn render_conversation( &self, system: &str, messages: &[ChatTurn], reasoning: ReasoningMode, ) -> Vec { self.tokenizer .encode_conversation(system, messages, reasoning) } fn render_continuation( &self, prompt: &str, reasoning: ReasoningMode, skip_previous_eos: bool, ) -> Vec { self.tokenizer .encode_continuation(prompt, reasoning, skip_previous_eos) } pub(crate) fn token_bytes(&self, token: i32) -> Option> { self.tokenizer.token_bytes(token) } pub(crate) fn eos_token(&self) -> i32 { self.tokenizer.eos() } pub(crate) fn is_stop_token(&self, token: i32) -> bool { self.tokenizer.is_stop(token) } pub(crate) fn is_think_start_token(&self, token: i32) -> bool { self.tokenizer.is_think_start(token) } pub(crate) fn is_think_end_token(&self, token: i32) -> bool { self.tokenizer.is_think_end(token) } pub(crate) fn is_stop_token_for_reasoning(&self, token: i32, reasoning: ReasoningMode) -> bool { self.is_stop_token(token) || (reasoning == ReasoningMode::Direct && (self.is_think_start_token(token) || self.is_think_end_token(token))) } pub(crate) fn tensor_data(&self, name: &str) -> Result<&[u8], String> { self.main.tensor_data(name) } } #[cfg(target_os = "macos")] pub(crate) struct Generator { executor: metal::Executor, checkpoint: Option, /// Token frontier of the last transient store, so continued checkpoints are /// spaced like ds4's `continued_last_store_tokens`. last_store_tokens: u32, metrics: Arc, } #[derive(Clone)] pub(crate) struct ChatTurn { pub(crate) user: bool, pub(crate) tool: bool, pub(crate) skip_previous_eos: bool, pub(crate) reasoning: Option, pub(crate) reasoning_complete: bool, pub(crate) content: String, } pub(crate) struct GenerationOutput { pub(crate) message: ChatTurn, pub(crate) prompt_tokens: u32, pub(crate) cached_tokens: u32, pub(crate) completion_tokens: u32, pub(crate) finish_reason: &'static str, pub(crate) previous_checkpoint_bytes: Option, pub(crate) checkpoint_bytes: u64, } #[cfg(target_os = "macos")] impl Generator { pub(crate) fn open(settings: &EngineSettings, metrics: Arc) -> Result { if settings.model != ModelChoice::DeepSeekV4Flash { return Err("local generation currently supports DeepSeek V4 Flash only".into()); } if settings.speculative.dspark || settings.ssd.enabled || settings.steering.file.is_some() { return Err( "DSpark, SSD streaming, and steering are not yet available in the Rust executor" .into(), ); } let model = Model::open(settings)?; let executor = metal::Executor::open( model, settings.context_tokens.max(1) as u32, settings.execution.quality, settings.execution.prefill_chunk, )?; Ok(Self { executor, checkpoint: None, last_store_tokens: 0, metrics, }) } pub(crate) fn summary(&self) -> ModelSummary { self.executor.model().summary() } pub(crate) fn generate( &mut self, checkpoint: &Path, messages: &[ChatTurn], settings: &TurnSettings, cancelled: &AtomicBool, mut emit: impl FnMut(bool, String), mut progress: impl FnMut(u32, u32, Option), ) -> Result { let history = messages .split_last() .map_or(messages, |(_, history)| history); self.select_checkpoint( checkpoint, conversation_tag(&settings.system_prompt, settings.reasoning_mode, history), )?; let (mut output, prompt_complete) = self.generate_inner(messages, settings, cancelled, &mut emit, &mut progress)?; let mut completed = messages.to_vec(); completed.push(output.message.clone()); output.previous_checkpoint_bytes = std::fs::metadata(checkpoint).ok().map(|item| item.len()); self.save_checkpoint( checkpoint, if prompt_complete { conversation_tag(&settings.system_prompt, settings.reasoning_mode, &completed) } else { [0; 32] }, )?; output.checkpoint_bytes = std::fs::metadata(checkpoint) .map(|item| item.len()) .unwrap_or(0); Ok(output) } pub(crate) fn generate_transient( &mut self, directory: &Path, messages: &[ChatTurn], settings: &TurnSettings, cancelled: &AtomicBool, mut emit: impl FnMut(bool, String), mut progress: impl FnMut(u32, u32, Option), ) -> Result { let history = messages .split_last() .map_or(messages, |(_, history)| history); let store = KvStore::open(directory, settings.kv_cache.budget_bytes)?; let history_key = conversation_key(&settings.system_prompt, settings.reasoning_mode, history); let history_tag: [u8; 32] = Sha256::digest(&history_key).into(); let mut previous_checkpoint = self.checkpoint.clone(); if self.executor.checkpoint_tag() != history_tag { if let Some(entry) = store.find(&history_key, self.executor.context()) { if self.select_checkpoint(&entry.checkpoint, entry.tag)? { store.touch(&entry)?; self.last_store_tokens = entry.tokens; previous_checkpoint = Some(entry.checkpoint); } else { store.discard(&entry); self.last_store_tokens = 0; previous_checkpoint = None; } } else { self.executor.reset()?; self.checkpoint = None; self.last_store_tokens = 0; previous_checkpoint = None; self.metrics.kv_lookup(KvLookup::Miss); } } else { self.metrics.kv_lookup(KvLookup::MemoryHit); } let (mut output, prompt_complete) = self.generate_inner(messages, settings, cancelled, &mut emit, &mut progress)?; let mut completed = messages.to_vec(); completed.push(output.message.clone()); output.previous_checkpoint_bytes = previous_checkpoint .as_deref() .and_then(|path| std::fs::metadata(path).ok()) .map(|item| item.len()); if prompt_complete { let completed_key = conversation_key(&settings.system_prompt, settings.reasoning_mode, &completed); let completed_tag: [u8; 32] = Sha256::digest(&completed_key).into(); if !settings.kv_cache.stores( self.executor.position(), history.is_empty(), self.last_store_tokens, ) { // A gated store still leaves the finished conversation in the // live KV, so mark it and drop the stale file association. self.executor.note_checkpoint_tag(completed_tag); self.checkpoint = None; return Ok(output); } let completed_checkpoint = store.checkpoint_path(&completed_key); self.save_checkpoint(&completed_checkpoint, completed_tag)?; let retained = store.record( &completed_checkpoint, &completed_key, completed_tag, self.executor.position(), self.executor.context(), if history.is_empty() { StoreReason::Cold } else { StoreReason::Continued }, )?; output.checkpoint_bytes = retained .then(|| std::fs::metadata(&completed_checkpoint).ok()) .flatten() .map_or(0, |item| item.len()); if retained { self.last_store_tokens = self.executor.position(); } self.checkpoint = retained.then_some(completed_checkpoint); } Ok(output) } fn select_checkpoint( &mut self, checkpoint: &Path, expected_tag: [u8; 32], ) -> Result { if self.checkpoint.as_deref() == Some(checkpoint) { let found = self.executor.checkpoint_tag() == expected_tag; self.metrics.kv_lookup(if found { KvLookup::MemoryHit } else { KvLookup::Miss }); return Ok(found); } self.executor.reset()?; self.metrics.kv_read_started(); let started = Instant::now(); let loaded = self .executor .load_checkpoint(checkpoint, &mut |bytes| self.metrics.kv_read_bytes(bytes)); self.metrics .kv_read_finished(started.elapsed(), loaded.is_err()); let found = matches!(loaded, Ok(true)) && self.executor.checkpoint_tag() == expected_tag; let lookup = match loaded { Ok(true) if found => KvLookup::DiskHit, Ok(true) | Ok(false) => KvLookup::Miss, Err(_) => { self.executor.reset()?; let _ = std::fs::remove_file(checkpoint); KvLookup::Invalid } }; self.metrics.kv_lookup(lookup); self.checkpoint = Some(checkpoint.to_owned()); Ok(found) } fn save_checkpoint(&mut self, checkpoint: &Path, tag: [u8; 32]) -> Result<(), String> { self.metrics.kv_write_started(); let started = Instant::now(); let result = self .executor .save_checkpoint(checkpoint, tag, &mut |bytes| { self.metrics.kv_write_bytes(bytes); }); self.metrics .kv_write_finished(started.elapsed(), result.is_err()); result } fn generate_inner( &mut self, messages: &[ChatTurn], settings: &TurnSettings, cancelled: &AtomicBool, emit: &mut impl FnMut(bool, String), progress: &mut impl FnMut(u32, u32, Option), ) -> Result<(GenerationOutput, bool), String> { let tokens = match messages.split_last() { Some((latest, history)) if latest.user && self.executor.checkpoint_tag() == conversation_tag( &settings.system_prompt, settings.reasoning_mode, history, ) => { let mut tokens = self.executor.tokens().to_vec(); tokens.extend(self.executor.model().render_continuation( &latest.content, settings.reasoning_mode, latest.skip_previous_eos, )); tokens } _ => self.executor.model().render_conversation( &settings.system_prompt, messages, settings.reasoning_mode, ), }; if tokens.is_empty() { return Err("the rendered prompt is empty".into()); } let max_context = self.executor.context() as usize; if tokens.len() >= max_context { return Err(format!( "Prompt has {} tokens, but the configured context size is {max_context} tokens", tokens.len() )); } let reused = self.executor.align_prompt(&tokens)?; self.metrics.kv_prefix_reused(reused); progress(self.executor.position(), self.executor.context(), None); let mut rng = Rng::new(settings.seed.unwrap_or(0x4453_3453_4552_5645)); let mut reasoning = settings.reasoning_mode != ReasoningMode::Direct; let mut generated = ChatTurn { user: false, tool: false, skip_previous_eos: false, reasoning: reasoning.then(String::new), reasoning_complete: !reasoning, content: String::new(), }; let mut emitted_reasoning = 0; let mut emitted_content = 0; let mut pending_utf8 = Vec::new(); let prompt_tokens = tokens.len(); let suffix = &tokens[reused..]; let completed = if (reused == 0 && tokens.len() > 1) || suffix.len() >= 4 { let context = self.executor.context(); self.executor.prefill(suffix, |used| { progress(used, context, None); !cancelled.load(Ordering::Relaxed) })? } else { let mut completed = 0; for &token in suffix { if cancelled.load(Ordering::Relaxed) { break; } self.executor.eval(token)?; completed += 1; progress(self.executor.position(), self.executor.context(), None); } completed }; if completed != suffix.len() { return Ok(( GenerationOutput { message: generated, prompt_tokens: prompt_tokens as u32, cached_tokens: reused as u32, completion_tokens: 0, finish_reason: "stop", previous_checkpoint_bytes: None, checkpoint_bytes: 0, }, false, )); } progress(self.executor.position(), self.executor.context(), Some(0.0)); let generation_started = Instant::now(); let mut generated_tokens = 0_u32; for _ in 0..settings .max_generated_tokens .max(0) .min((max_context - self.executor.position() as usize) as i32) { if cancelled.load(Ordering::Relaxed) { append_generated_bytes(&mut generated, reasoning, &mut pending_utf8, &[], true); flush_generated( &mut generated, &mut emitted_reasoning, &mut emitted_content, &settings.stops, emit, ); return Ok(( GenerationOutput { message: generated, prompt_tokens: prompt_tokens as u32, cached_tokens: reused as u32, completion_tokens: generated_tokens, finish_reason: "stop", previous_checkpoint_bytes: None, checkpoint_bytes: 0, }, true, )); } let token = sample( self.executor.logits(), settings.temperature, settings.top_p, settings.min_p, settings.top_k, &mut rng, ); if self .executor .model() .is_stop_token_for_reasoning(token, settings.reasoning_mode) { append_generated_bytes(&mut generated, reasoning, &mut pending_utf8, &[], true); flush_generated( &mut generated, &mut emitted_reasoning, &mut emitted_content, &settings.stops, emit, ); return Ok(( GenerationOutput { message: generated, prompt_tokens: prompt_tokens as u32, cached_tokens: reused as u32, completion_tokens: generated_tokens, finish_reason: "stop", previous_checkpoint_bytes: None, checkpoint_bytes: 0, }, true, )); } if self.executor.model().is_think_start_token(token) { append_generated_bytes(&mut generated, reasoning, &mut pending_utf8, &[], true); reasoning = true; generated.reasoning.get_or_insert_default(); } else if self.executor.model().is_think_end_token(token) { append_generated_bytes(&mut generated, reasoning, &mut pending_utf8, &[], true); if let Some(reasoning_text) = &mut generated.reasoning && emit_safe_text( reasoning_text, &mut emitted_reasoning, &settings.stops, true, true, emit, ) { return Ok(( GenerationOutput { message: generated, prompt_tokens: prompt_tokens as u32, cached_tokens: reused as u32, completion_tokens: generated_tokens + 1, finish_reason: "stop", previous_checkpoint_bytes: None, checkpoint_bytes: 0, }, false, )); } reasoning = false; generated.reasoning_complete = true; emit(false, String::new()); } else if let Some(bytes) = self.executor.model().token_bytes(token) { append_generated_bytes(&mut generated, reasoning, &mut pending_utf8, &bytes, false); let stopped = if reasoning { let text = generated.reasoning.get_or_insert_default(); emit_safe_text( text, &mut emitted_reasoning, &settings.stops, false, true, emit, ) } else { generated.reasoning_complete = true; emit_safe_text( &mut generated.content, &mut emitted_content, &settings.stops, false, false, emit, ) }; if stopped { return Ok(( GenerationOutput { message: generated, prompt_tokens: prompt_tokens as u32, cached_tokens: reused as u32, completion_tokens: generated_tokens + 1, finish_reason: "stop", previous_checkpoint_bytes: None, checkpoint_bytes: 0, }, false, )); } } self.executor.eval(token)?; generated_tokens += 1; progress( self.executor.position(), self.executor.context(), Some( generated_tokens as f32 / generation_started.elapsed().as_secs_f32().max(1.0e-6), ), ); } append_generated_bytes(&mut generated, reasoning, &mut pending_utf8, &[], true); flush_generated( &mut generated, &mut emitted_reasoning, &mut emitted_content, &settings.stops, emit, ); Ok(( GenerationOutput { message: generated, prompt_tokens: prompt_tokens as u32, cached_tokens: reused as u32, completion_tokens: generated_tokens, finish_reason: "length", previous_checkpoint_bytes: None, checkpoint_bytes: 0, }, true, )) } } #[cfg(target_os = "macos")] fn append_generated_bytes( generated: &mut ChatTurn, reasoning: bool, pending: &mut Vec, bytes: &[u8], final_flush: bool, ) { let text = if reasoning { generated.reasoning.get_or_insert_default() } else { &mut generated.content }; pending.extend_from_slice(bytes); loop { match std::str::from_utf8(pending) { Ok(valid) => { text.push_str(valid); pending.clear(); return; } Err(error) => { let valid = error.valid_up_to(); text.push_str(std::str::from_utf8(&pending[..valid]).unwrap()); pending.drain(..valid); match error.error_len() { Some(length) => { text.push('\u{fffd}'); pending.drain(..length); } None if final_flush => { text.push_str(&String::from_utf8_lossy(pending)); pending.clear(); return; } None => return, } } } } } #[cfg(target_os = "macos")] fn flush_generated( generated: &mut ChatTurn, emitted_reasoning: &mut usize, emitted_content: &mut usize, stops: &[String], emit: &mut impl FnMut(bool, String), ) { if let Some(reasoning) = &mut generated.reasoning { let _ = emit_safe_text(reasoning, emitted_reasoning, stops, true, true, emit); } let _ = emit_safe_text( &mut generated.content, emitted_content, stops, true, false, emit, ); } #[cfg(target_os = "macos")] fn emit_safe_text( text: &mut String, emitted: &mut usize, stops: &[String], final_flush: bool, reasoning: bool, emit: &mut impl FnMut(bool, String), ) -> bool { let stop = stops .iter() .filter_map(|stop| { text[*emitted..] .find(stop) .map(|position| *emitted + position) }) .min(); if let Some(stop) = stop { if stop > *emitted { emit(reasoning, text[*emitted..stop].to_owned()); } text.truncate(stop); *emitted = stop; return true; } let hold = if final_flush { 0 } else { stops .iter() .map(|stop| stop.len().saturating_sub(1)) .max() .unwrap_or(0) }; let mut safe = text.len().saturating_sub(hold); while safe > *emitted && !text.is_char_boundary(safe) { safe -= 1; } if safe > *emitted { emit(reasoning, text[*emitted..safe].to_owned()); *emitted = safe; } false } #[cfg(target_os = "macos")] fn conversation_key(system: &str, reasoning: ReasoningMode, messages: &[ChatTurn]) -> Vec { fn text(output: &mut Vec, value: &str) { output.extend_from_slice(&(value.len() as u64).to_le_bytes()); output.extend_from_slice(value.as_bytes()); } let mut output = b"DS4Server chat checkpoint v3".to_vec(); text(&mut output, system); output.push(match reasoning { ReasoningMode::Direct => 0, ReasoningMode::High => 1, ReasoningMode::Max => 2, }); for message in messages { output.push(u8::from(message.user)); output.push(u8::from(message.tool)); output.push(u8::from(message.skip_previous_eos)); match &message.reasoning { Some(reasoning) => { output.push(1); text(&mut output, reasoning); } None => output.push(0), } output.push(u8::from(message.reasoning_complete)); text(&mut output, &message.content); } output } #[cfg(target_os = "macos")] fn conversation_tag(system: &str, reasoning: ReasoningMode, messages: &[ChatTurn]) -> [u8; 32] { Sha256::digest(conversation_key(system, reasoning, messages)).into() } #[cfg(target_os = "macos")] fn sample( logits: &[f32], temperature: f32, top_p: f32, min_p: f32, top_k: i32, rng: &mut Rng, ) -> i32 { if temperature <= 0.0 { return logits .iter() .enumerate() .max_by(|a, b| a.1.total_cmp(b.1)) .map_or(0, |(index, _)| index as i32); } let maximum = logits .iter() .copied() .filter(|value| value.is_finite()) .fold(f32::NEG_INFINITY, f32::max); if !maximum.is_finite() { return 0; } let top_p = if top_p <= 0.0 || top_p > 1.0 { 1.0 } else { top_p }; let min_p = min_p.max(0.0); let mut probabilities: Vec<(usize, f32)> = logits .iter() .enumerate() .filter(|(_, logit)| logit.is_finite()) .map(|(index, logit)| (index, ((*logit - maximum) / temperature).exp())) .filter(|(_, probability)| *probability >= min_p) .collect(); if probabilities.is_empty() { return logits .iter() .enumerate() .max_by(|a, b| a.1.total_cmp(b.1)) .map_or(0, |(index, _)| index as i32); } if top_p < 1.0 || top_k > 0 { probabilities.sort_unstable_by(|a, b| b.1.total_cmp(&a.1).then_with(|| a.0.cmp(&b.0))); if top_k > 0 { probabilities.truncate(probabilities.len().min(top_k as usize)); } } if top_p < 1.0 { let total: f32 = probabilities .iter() .map(|(_, probability)| probability) .sum(); let mut kept = 0.0; let count = probabilities .iter() .position(|(_, probability)| { kept += *probability; kept / total >= top_p }) .map_or(probabilities.len(), |index| index + 1); probabilities.truncate(count); } let kept_total: f32 = probabilities.iter().map(|(_, p)| p).sum(); let mut choice = rng.unit() * kept_total; for (token, probability) in &probabilities { choice -= probability; if choice <= 0.0 { return *token as i32; } } probabilities.last().map_or(0, |(token, _)| *token as i32) } #[cfg(target_os = "macos")] struct Rng(u64); #[cfg(target_os = "macos")] impl Rng { fn new(seed: u64) -> Self { Self(seed.max(1)) } fn unit(&mut self) -> f32 { let mut value = self.0; if value == 0 { value = 0x9e37_79b9_7f4a_7c15; } value ^= value >> 12; value ^= value << 25; value ^= value >> 27; self.0 = value; let value = value.wrapping_mul(0x2545_f491_4f6c_dd1d); ((value >> 40) & 0xff_ffff) as f32 / 16_777_216.0 } } #[cfg(all(test, target_os = "macos"))] mod sampling_tests { use super::*; #[test] fn zero_temperature_is_greedy() { let mut rng = Rng::new(1); assert_eq!(sample(&[1.0, 4.0, 2.0], 0.0, 1.0, 0.0, 0, &mut rng), 1); } #[test] fn top_k_and_stream_stops_are_applied_before_output() { let mut rng = Rng::new(1); assert_eq!(sample(&[1.0, 4.0, 2.0], 1.0, 1.0, 0.0, 1, &mut rng), 1); let mut text = "hello STOP hidden".to_owned(); let mut emitted = 0; let mut chunks = Vec::new(); assert!(emit_safe_text( &mut text, &mut emitted, &["STOP".into()], false, false, &mut |_, chunk| chunks.push(chunk), )); assert_eq!(text, "hello "); assert_eq!(chunks, ["hello "]); } #[test] fn split_utf8_token_bytes_are_joined_before_decoding() { let mut generated = ChatTurn { user: false, tool: false, skip_previous_eos: false, reasoning: None, reasoning_complete: true, content: String::new(), }; let mut pending = Vec::new(); append_generated_bytes(&mut generated, false, &mut pending, &[0xf0, 0x9f], false); assert!(generated.content.is_empty()); append_generated_bytes(&mut generated, false, &mut pending, &[0x98, 0x8a], false); assert_eq!(generated.content, "😊"); assert!(pending.is_empty()); } #[test] fn checkpoint_tag_covers_the_canonical_chat_state() { let mut messages = vec![ChatTurn { user: true, tool: false, skip_previous_eos: false, reasoning: None, reasoning_complete: true, content: "Hello".into(), }]; let tag = conversation_tag("System", ReasoningMode::High, &messages); assert_eq!( tag, conversation_tag("System", ReasoningMode::High, &messages) ); assert_ne!( tag, conversation_tag("Changed", ReasoningMode::High, &messages) ); assert_ne!( tag, conversation_tag("System", ReasoningMode::Direct, &messages) ); messages[0].skip_previous_eos = true; assert_ne!( tag, conversation_tag("System", ReasoningMode::High, &messages) ); let prefix = conversation_key("System", ReasoningMode::High, &messages); messages.push(ChatTurn { user: false, tool: false, skip_previous_eos: false, reasoning: Some("because".into()), reasoning_complete: true, content: "Hi".into(), }); assert!(conversation_key("System", ReasoningMode::High, &messages).starts_with(&prefix)); } #[test] #[ignore = "requires the 80 GiB Flash checkpoint and Apple Metal"] fn metal_executes_real_flash_token() { configure_metal_sources().unwrap(); let path = Path::new(env!("CARGO_MANIFEST_DIR")).join( "../ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf", ); let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash).unwrap(); let tokens = model.render_prompt( "You are a helpful assistant", "Hello", ReasoningMode::Direct, ); assert_eq!(tokens.len(), 10); let mut executor = metal::Executor::open(model, 32_768, false, 0).unwrap(); assert_eq!(executor.context(), 32_768); for &token in &tokens { executor.eval(token).unwrap(); } assert!(executor.logits().iter().all(|logit| logit.is_finite())); let argmax = executor .logits() .iter() .enumerate() .max_by(|a, b| a.1.total_cmp(b.1)) .unwrap(); eprintln!( "Rust logits: argmax={} value={} logit0={}", argmax.0, argmax.1, executor.logits()[0] ); assert_eq!(argmax.0, 19_923); assert!((executor.logits()[0] - -7.675_424).abs() < 0.1); let next = argmax.0 as i32; let checkpoint = std::env::temp_dir().join(format!("ds4-rust-kv-{}.bin", std::process::id())); executor .save_checkpoint(&checkpoint, [7; 32], &mut |_| {}) .unwrap(); executor.eval(next).unwrap(); let continued_logit = executor.logits()[0]; let continued_argmax = executor .logits() .iter() .enumerate() .max_by(|a, b| a.1.total_cmp(b.1)) .unwrap() .0; drop(executor); let model = Model::open_main(&path, ModelChoice::DeepSeekV4Flash).unwrap(); let mut restored = metal::Executor::open(model, 32_768, false, 0).unwrap(); assert!(restored.load_checkpoint(&checkpoint, &mut |_| {}).unwrap()); assert_eq!(restored.position(), tokens.len() as u32); assert_eq!(restored.tokens(), tokens); assert_eq!(restored.checkpoint_tag(), [7; 32]); restored.eval(next).unwrap(); assert_eq!( restored .logits() .iter() .enumerate() .max_by(|a, b| a.1.total_cmp(b.1)) .unwrap() .0, continued_argmax ); assert!((restored.logits()[0] - continued_logit).abs() < 1.0e-5); std::fs::remove_file(checkpoint).unwrap(); } }