llama_cpp_4/context/params/mod.rs
1//! A safe wrapper around `llama_context_params`.
2//!
3//! Use [`LlamaContextParams`] to configure context size, batching, KV layout,
4//! `RoPE` / `YaRN` scaling, flash attention, per-sequence samplers, and pairing
5//! with another context (`ctx_other`).
6mod advanced;
7mod types;
8
9pub use types::*;
10
11use std::num::NonZeroU32;
12use std::pin::Pin;
13
14use thiserror::Error;
15
16use super::tensor_transaction::{
17 tensor_transaction_callback, tensor_transaction_decode_begin, tensor_transaction_decode_end,
18 TensorTransactions,
19};
20use crate::sampling::LlamaSampler;
21
22/// Error returned when [`LlamaContextParams::try_clone`] cannot duplicate state.
23#[derive(Debug, Error, PartialEq, Eq)]
24pub enum ParamsCloneError {
25 /// Per-sequence sampler chains cannot be duplicated.
26 #[error("cannot clone params that own per-sequence sampler chains")]
27 SamplerChains,
28 /// Owned tensor transaction handlers cannot be duplicated.
29 #[error("cannot clone params that own tensor transactions")]
30 TensorTransactions,
31}
32
33/// Builder for [`llama_context_params`](llama_cpp_sys_4::llama_context_params).
34///
35/// Construct with [`Default::default()`], chain `with_*` setters, then pass the
36/// value to [`crate::model::LlamaModel::new_context`]. Getter methods mirror
37/// the fields that exist on the underlying C struct.
38///
39/// # Sampler ownership
40///
41/// [`Self::with_sampler_seq_configs`] stores owned [`LlamaSampler`] chains inside
42/// this struct until the context is created. [`Clone`] clears sampler configs
43/// because the underlying chains cannot be duplicated safely.
44///
45/// # Examples
46///
47/// ```rust
48/// # use std::num::NonZeroU32;
49/// use llama_cpp_4::context::params::LlamaContextParams;
50///
51/// let ctx_params = LlamaContextParams::default()
52/// .with_n_ctx(NonZeroU32::new(2048));
53///
54/// assert_eq!(ctx_params.n_ctx(), NonZeroU32::new(2048));
55/// ```
56#[derive(Debug)]
57#[allow(
58 missing_docs,
59 clippy::struct_excessive_bools,
60 clippy::module_name_repetitions
61)]
62pub struct LlamaContextParams {
63 pub(crate) context_params: llama_cpp_sys_4::llama_context_params,
64 /// When `true`, the `TurboQuant` attention rotation (PR #21038) will be
65 /// disabled for any context created from these params.
66 pub(crate) attn_rot_disabled: bool,
67 /// Keeps sampler chains alive while `context_params.samplers` points at them.
68 owned_samplers: Vec<LlamaSampler>,
69 sampler_configs: Vec<llama_cpp_sys_4::llama_sampler_seq_config>,
70 pub(crate) tensor_transactions: Option<Pin<Box<TensorTransactions>>>,
71}
72
73impl LlamaContextParams {
74 /// Set the side of the context
75 ///
76 /// # Examples
77 ///
78 /// ```rust
79 /// # use std::num::NonZeroU32;
80 /// use llama_cpp_4::context::params::LlamaContextParams;
81 /// let params = LlamaContextParams::default();
82 /// let params = params.with_n_ctx(NonZeroU32::new(2048));
83 /// assert_eq!(params.n_ctx(), NonZeroU32::new(2048));
84 /// ```
85 #[must_use]
86 pub fn with_n_ctx(mut self, n_ctx: Option<NonZeroU32>) -> Self {
87 self.context_params.n_ctx = n_ctx.map_or(0, std::num::NonZeroU32::get);
88 self
89 }
90
91 /// Get the size of the context.
92 ///
93 /// [`None`] if the context size is specified by the model and not the context.
94 ///
95 /// # Examples
96 ///
97 /// ```rust
98 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
99 /// assert_eq!(params.n_ctx(), std::num::NonZeroU32::new(512));
100 #[must_use]
101 pub fn n_ctx(&self) -> Option<NonZeroU32> {
102 NonZeroU32::new(self.context_params.n_ctx)
103 }
104
105 /// Set the maximum number of independent sequence states in the context.
106 ///
107 /// This maps to llama.cpp's `llama_context_params.n_seq_max` and must match
108 /// the highest sequence id used by batched decoding.
109 ///
110 /// # Examples
111 ///
112 /// ```rust
113 /// use llama_cpp_4::context::params::LlamaContextParams;
114 /// let params = LlamaContextParams::default()
115 /// .with_n_seq_max(16);
116 /// assert_eq!(params.n_seq_max(), 16);
117 /// ```
118 #[must_use]
119 pub fn with_n_seq_max(mut self, n_seq_max: u32) -> Self {
120 self.context_params.n_seq_max = n_seq_max.max(1);
121 self
122 }
123
124 /// Get the configured maximum number of independent sequence states.
125 #[must_use]
126 pub fn n_seq_max(&self) -> u32 {
127 self.context_params.n_seq_max
128 }
129
130 /// Set the `n_batch`
131 ///
132 /// # Examples
133 ///
134 /// ```rust
135 /// # use std::num::NonZeroU32;
136 /// use llama_cpp_4::context::params::LlamaContextParams;
137 /// let params = LlamaContextParams::default()
138 /// .with_n_batch(2048);
139 /// assert_eq!(params.n_batch(), 2048);
140 /// ```
141 #[must_use]
142 pub fn with_n_batch(mut self, n_batch: u32) -> Self {
143 self.context_params.n_batch = n_batch;
144 self
145 }
146
147 /// Get the `n_batch`
148 ///
149 /// # Examples
150 ///
151 /// ```rust
152 /// use llama_cpp_4::context::params::LlamaContextParams;
153 /// let params = LlamaContextParams::default();
154 /// assert_eq!(params.n_batch(), 2048);
155 /// ```
156 #[must_use]
157 pub fn n_batch(&self) -> u32 {
158 self.context_params.n_batch
159 }
160
161 /// Set the `n_ubatch`
162 ///
163 /// # Examples
164 ///
165 /// ```rust
166 /// # use std::num::NonZeroU32;
167 /// use llama_cpp_4::context::params::LlamaContextParams;
168 /// let params = LlamaContextParams::default()
169 /// .with_n_ubatch(512);
170 /// assert_eq!(params.n_ubatch(), 512);
171 /// ```
172 #[must_use]
173 pub fn with_n_ubatch(mut self, n_ubatch: u32) -> Self {
174 self.context_params.n_ubatch = n_ubatch;
175 self
176 }
177
178 /// Get the `n_ubatch`
179 ///
180 /// # Examples
181 ///
182 /// ```rust
183 /// use llama_cpp_4::context::params::LlamaContextParams;
184 /// let params = LlamaContextParams::default();
185 /// assert_eq!(params.n_ubatch(), 512);
186 /// ```
187 #[must_use]
188 pub fn n_ubatch(&self) -> u32 {
189 self.context_params.n_ubatch
190 }
191
192 /// Set the context type (e.g. [`LlamaContextType::Mtp`] for the draft context in
193 /// [`crate::mtp::MtpSession`]).
194 #[must_use]
195 pub fn with_ctx_type(mut self, ctx_type: LlamaContextType) -> Self {
196 self.context_params.ctx_type = ctx_type.into();
197 self
198 }
199
200 /// Get the configured context type.
201 #[must_use]
202 pub fn ctx_type(&self) -> LlamaContextType {
203 self.context_params.ctx_type.into()
204 }
205
206 /// Set the number of recurrent-state snapshots per sequence (MTP rollback).
207 ///
208 /// Must be `>=` [`MtpSessionConfig::n_draft_max`](crate::mtp::MtpSessionConfig::n_draft_max)
209 /// on the draft context. See [`crate::mtp`].
210 #[must_use]
211 pub fn with_n_rs_seq(mut self, n_rs_seq: u32) -> Self {
212 self.context_params.n_rs_seq = n_rs_seq;
213 self
214 }
215
216 /// Get the number of recurrent-state snapshots per sequence used for MTP rollback.
217 #[must_use]
218 pub fn n_rs_seq(&self) -> u32 {
219 self.context_params.n_rs_seq
220 }
221
222 /// Set the `offload_kqv` parameter to control offloading KV cache & KQV ops to GPU
223 ///
224 /// # Examples
225 ///
226 /// ```rust
227 /// use llama_cpp_4::context::params::LlamaContextParams;
228 /// let params = LlamaContextParams::default()
229 /// .with_offload_kqv(false);
230 /// assert_eq!(params.offload_kqv(), false);
231 /// ```
232 #[must_use]
233 pub fn with_offload_kqv(mut self, enabled: bool) -> Self {
234 self.context_params.offload_kqv = enabled;
235 self
236 }
237
238 /// Get the `offload_kqv` parameter
239 ///
240 /// # Examples
241 ///
242 /// ```rust
243 /// use llama_cpp_4::context::params::LlamaContextParams;
244 /// let params = LlamaContextParams::default();
245 /// assert_eq!(params.offload_kqv(), true);
246 /// ```
247 #[must_use]
248 pub fn offload_kqv(&self) -> bool {
249 self.context_params.offload_kqv
250 }
251
252 /// Set the type of rope scaling.
253 ///
254 /// # Examples
255 ///
256 /// ```rust
257 /// use llama_cpp_4::context::params::{LlamaContextParams, RopeScalingType};
258 /// let params = LlamaContextParams::default()
259 /// .with_rope_scaling_type(RopeScalingType::Linear);
260 /// assert_eq!(params.rope_scaling_type(), RopeScalingType::Linear);
261 /// ```
262 #[must_use]
263 pub fn with_rope_scaling_type(mut self, rope_scaling_type: RopeScalingType) -> Self {
264 self.context_params.rope_scaling_type = i32::from(rope_scaling_type);
265 self
266 }
267
268 /// Get the type of rope scaling.
269 ///
270 /// # Examples
271 ///
272 /// ```rust
273 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
274 /// assert_eq!(params.rope_scaling_type(), llama_cpp_4::context::params::RopeScalingType::Unspecified);
275 /// ```
276 #[must_use]
277 pub fn rope_scaling_type(&self) -> RopeScalingType {
278 RopeScalingType::from(self.context_params.rope_scaling_type)
279 }
280
281 /// Set the rope frequency base.
282 ///
283 /// # Examples
284 ///
285 /// ```rust
286 /// use llama_cpp_4::context::params::LlamaContextParams;
287 /// let params = LlamaContextParams::default()
288 /// .with_rope_freq_base(0.5);
289 /// assert_eq!(params.rope_freq_base(), 0.5);
290 /// ```
291 #[must_use]
292 pub fn with_rope_freq_base(mut self, rope_freq_base: f32) -> Self {
293 self.context_params.rope_freq_base = rope_freq_base;
294 self
295 }
296
297 /// Get the rope frequency base.
298 ///
299 /// # Examples
300 ///
301 /// ```rust
302 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
303 /// assert_eq!(params.rope_freq_base(), 0.0);
304 /// ```
305 #[must_use]
306 pub fn rope_freq_base(&self) -> f32 {
307 self.context_params.rope_freq_base
308 }
309
310 /// Set the rope frequency scale.
311 ///
312 /// # Examples
313 ///
314 /// ```rust
315 /// use llama_cpp_4::context::params::LlamaContextParams;
316 /// let params = LlamaContextParams::default()
317 /// .with_rope_freq_scale(0.5);
318 /// assert_eq!(params.rope_freq_scale(), 0.5);
319 /// ```
320 #[must_use]
321 pub fn with_rope_freq_scale(mut self, rope_freq_scale: f32) -> Self {
322 self.context_params.rope_freq_scale = rope_freq_scale;
323 self
324 }
325
326 /// Get the rope frequency scale.
327 ///
328 /// # Examples
329 ///
330 /// ```rust
331 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
332 /// assert_eq!(params.rope_freq_scale(), 0.0);
333 /// ```
334 #[must_use]
335 pub fn rope_freq_scale(&self) -> f32 {
336 self.context_params.rope_freq_scale
337 }
338
339 /// Get the number of threads.
340 ///
341 /// # Examples
342 ///
343 /// ```rust
344 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
345 /// assert_eq!(params.n_threads(), 4);
346 /// ```
347 #[must_use]
348 pub fn n_threads(&self) -> i32 {
349 self.context_params.n_threads
350 }
351
352 /// Get the number of threads allocated for batches.
353 ///
354 /// # Examples
355 ///
356 /// ```rust
357 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
358 /// assert_eq!(params.n_threads_batch(), 4);
359 /// ```
360 #[must_use]
361 pub fn n_threads_batch(&self) -> i32 {
362 self.context_params.n_threads_batch
363 }
364
365 /// Set the number of threads.
366 ///
367 /// # Examples
368 ///
369 /// ```rust
370 /// use llama_cpp_4::context::params::LlamaContextParams;
371 /// let params = LlamaContextParams::default()
372 /// .with_n_threads(8);
373 /// assert_eq!(params.n_threads(), 8);
374 /// ```
375 #[must_use]
376 pub fn with_n_threads(mut self, n_threads: i32) -> Self {
377 self.context_params.n_threads = n_threads;
378 self
379 }
380
381 /// Set the number of threads allocated for batches.
382 ///
383 /// # Examples
384 ///
385 /// ```rust
386 /// use llama_cpp_4::context::params::LlamaContextParams;
387 /// let params = LlamaContextParams::default()
388 /// .with_n_threads_batch(8);
389 /// assert_eq!(params.n_threads_batch(), 8);
390 /// ```
391 #[must_use]
392 pub fn with_n_threads_batch(mut self, n_threads: i32) -> Self {
393 self.context_params.n_threads_batch = n_threads;
394 self
395 }
396
397 /// Check whether embeddings are enabled
398 ///
399 /// # Examples
400 ///
401 /// ```rust
402 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
403 /// assert!(!params.embeddings());
404 /// ```
405 #[must_use]
406 pub fn embeddings(&self) -> bool {
407 self.context_params.embeddings
408 }
409
410 /// Enable the use of embeddings
411 ///
412 /// # Examples
413 ///
414 /// ```rust
415 /// use llama_cpp_4::context::params::LlamaContextParams;
416 /// let params = LlamaContextParams::default()
417 /// .with_embeddings(true);
418 /// assert!(params.embeddings());
419 /// ```
420 #[must_use]
421 pub fn with_embeddings(mut self, embedding: bool) -> Self {
422 self.context_params.embeddings = embedding;
423 self
424 }
425
426 /// Set the evaluation callback.
427 ///
428 /// # Examples
429 ///
430 /// ```no_run
431 /// extern "C" fn cb_eval_fn(
432 /// t: *mut llama_cpp_sys_4::ggml_tensor,
433 /// ask: bool,
434 /// user_data: *mut std::ffi::c_void,
435 /// ) -> bool {
436 /// false
437 /// }
438 ///
439 /// use llama_cpp_4::context::params::LlamaContextParams;
440 /// let params = LlamaContextParams::default().with_cb_eval(Some(cb_eval_fn));
441 /// ```
442 #[must_use]
443 pub fn with_cb_eval(
444 mut self,
445 cb_eval: llama_cpp_sys_4::ggml_backend_sched_eval_callback,
446 ) -> Self {
447 self.context_params.cb_eval = cb_eval;
448 self
449 }
450
451 /// Set the evaluation callback user data.
452 ///
453 /// # Examples
454 ///
455 /// ```no_run
456 /// use llama_cpp_4::context::params::LlamaContextParams;
457 /// let params = LlamaContextParams::default();
458 /// let user_data = std::ptr::null_mut();
459 /// let params = params.with_cb_eval_user_data(user_data);
460 /// ```
461 #[must_use]
462 pub fn with_cb_eval_user_data(mut self, cb_eval_user_data: *mut std::ffi::c_void) -> Self {
463 self.context_params.cb_eval_user_data = cb_eval_user_data;
464 self
465 }
466
467 /// Attach a [`TensorCapture`](super::tensor_capture::TensorCapture) to
468 /// intercept intermediate tensor outputs during [`crate::LlamaContext::decode`].
469 ///
470 /// Sets `cb_eval` to copy tensors matching the capture filter (layer outputs,
471 /// named nodes, prefix, or all). After `decode()`, read results from the
472 /// capture — see [`crate::TensorCapture`] and [`crate::context::tensor_capture`].
473 ///
474 /// The capture must outlive the context. Call
475 /// [`TensorCapture::clear`](crate::TensorCapture::clear) before reusing it
476 /// on another batch. Prefer [`Self::with_tensor_transactions`], which
477 /// transfers owned pinned callback state into the context.
478 ///
479 /// # Safety
480 ///
481 /// The caller must keep `capture` at a stable address until after the
482 /// resulting context is dropped. It must not be accessed concurrently with
483 /// any context operation that can invoke the callback. The reference
484 /// accepted here does not remain borrowed by the returned params.
485 ///
486 /// # Example
487 ///
488 /// ```no_run
489 /// use llama_cpp_4::prelude::*;
490 ///
491 /// fn main() {
492 /// let backend = LlamaBackend::init().unwrap();
493 /// let model = LlamaModel::load_from_file(
494 /// &backend,
495 /// "model.gguf",
496 /// &LlamaModelParams::default(),
497 /// )
498 /// .unwrap();
499 ///
500 /// let mut capture = TensorCapture::for_layers(&[13, 20, 27]);
501 /// let ctx_params = unsafe {
502 /// LlamaContextParams::default().with_tensor_capture(&mut capture)
503 /// };
504 /// let _ctx = model.new_context(&backend, ctx_params).unwrap();
505 /// }
506 /// ```
507 #[must_use]
508 pub unsafe fn with_tensor_capture(
509 self,
510 capture: &mut super::tensor_capture::TensorCapture,
511 ) -> Self {
512 self.with_cb_eval(Some(super::tensor_capture::tensor_capture_callback))
513 .with_cb_eval_user_data(
514 std::ptr::from_mut::<super::tensor_capture::TensorCapture>(capture)
515 .cast::<std::ffi::c_void>(),
516 )
517 }
518
519 /// Attaches bounded owned tensor transactions to the context.
520 ///
521 /// The transaction state is pinned before its address is installed in the
522 /// native callback parameters. On successful context creation ownership
523 /// moves into [`crate::LlamaContext`] and remains there until after
524 /// `llama_free`.
525 ///
526 /// # Panics
527 ///
528 /// Panics if the linked `libllama` was not built with the decode-lifecycle
529 /// hooks patch — an ABI mismatch that would otherwise silently disable the
530 /// hooks or misread the context-params struct.
531 #[must_use]
532 pub fn with_tensor_transactions(mut self, transactions: TensorTransactions) -> Self {
533 // ABI guard: this symbol is defined only in a libllama built with the
534 // decode-lifecycle-hooks patch (0004). Referencing it makes an
535 // unpatched or ABI-mismatched prebuilt fail at link time — and, if it
536 // somehow linked, this assert fails — rather than silently dropping the
537 // hooks or reading a struct with a different layout.
538 assert_eq!(
539 unsafe { llama_cpp_sys_4::llama_cpp_rs_decode_hooks_abi_v1() },
540 1,
541 "libllama is missing the decode-hook ABI patch (0004)",
542 );
543
544 let mut transactions = Box::pin(transactions);
545 let user_data = std::ptr::from_mut(transactions.as_mut().get_mut()).cast();
546 self.context_params.cb_eval = Some(tensor_transaction_callback);
547 self.context_params.cb_eval_user_data = user_data;
548 self.context_params.cb_decode_begin = Some(tensor_transaction_decode_begin);
549 self.context_params.cb_decode_end = Some(tensor_transaction_decode_end);
550 self.tensor_transactions = Some(transactions);
551 self
552 }
553
554 /// Set the storage type for the **K** (key) KV cache tensors.
555 ///
556 /// The default is `GgmlType::F16`. Quantized types like `GgmlType::Q5_0`
557 /// or `GgmlType::Q4_0` reduce VRAM usage significantly; combining them with
558 /// `TurboQuant` attention rotation (the default) keeps quality high.
559 ///
560 /// # Examples
561 ///
562 /// ```rust
563 /// use llama_cpp_4::context::params::LlamaContextParams;
564 /// use llama_cpp_4::quantize::GgmlType;
565 /// let params = LlamaContextParams::default()
566 /// .with_cache_type_k(GgmlType::Q5_0);
567 /// ```
568 #[must_use]
569 pub fn with_cache_type_k(mut self, ty: crate::quantize::GgmlType) -> Self {
570 self.context_params.type_k = ty as llama_cpp_sys_4::ggml_type;
571 self
572 }
573
574 /// Get the K-cache storage type.
575 #[must_use]
576 pub fn cache_type_k(&self) -> llama_cpp_sys_4::ggml_type {
577 self.context_params.type_k
578 }
579
580 /// Set the storage type for the **V** (value) KV cache tensors.
581 ///
582 /// See [`with_cache_type_k`](Self::with_cache_type_k) for details.
583 ///
584 /// # Examples
585 ///
586 /// ```rust
587 /// use llama_cpp_4::context::params::LlamaContextParams;
588 /// use llama_cpp_4::quantize::GgmlType;
589 /// let params = LlamaContextParams::default()
590 /// .with_cache_type_v(GgmlType::Q5_0);
591 /// ```
592 #[must_use]
593 pub fn with_cache_type_v(mut self, ty: crate::quantize::GgmlType) -> Self {
594 self.context_params.type_v = ty as llama_cpp_sys_4::ggml_type;
595 self
596 }
597
598 /// Get the V-cache storage type.
599 #[must_use]
600 pub fn cache_type_v(&self) -> llama_cpp_sys_4::ggml_type {
601 self.context_params.type_v
602 }
603
604 /// Control the `TurboQuant` attention-rotation feature (llama.cpp PR #21038).
605 ///
606 /// By default, llama.cpp applies a Hadamard rotation to Q/K/V tensors
607 /// before writing them into the KV cache. This significantly improves
608 /// quantized KV-cache quality at near-zero overhead, and is enabled
609 /// automatically for models whose head dimension is a power of two.
610 ///
611 /// Set `disabled = true` to opt out (equivalent to `LLAMA_ATTN_ROT_DISABLE=1`).
612 /// The env-var is applied just before the context is created and restored
613 /// afterwards, so this is safe to call from a single thread.
614 ///
615 /// # Examples
616 ///
617 /// ```rust
618 /// use llama_cpp_4::context::params::LlamaContextParams;
619 /// // Disable rotation for this context only:
620 /// let params = LlamaContextParams::default().with_attn_rot_disabled(true);
621 /// assert!(params.attn_rot_disabled());
622 /// ```
623 #[must_use]
624 pub fn with_attn_rot_disabled(mut self, disabled: bool) -> Self {
625 self.attn_rot_disabled = disabled;
626 self
627 }
628
629 /// Returns `true` if `TurboQuant` attention rotation is disabled for this context.
630 ///
631 /// ```rust
632 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
633 /// assert!(!params.attn_rot_disabled());
634 /// ```
635 #[must_use]
636 pub fn attn_rot_disabled(&self) -> bool {
637 self.attn_rot_disabled
638 }
639
640 /// Set the type of pooling.
641 ///
642 /// # Examples
643 ///
644 /// ```rust
645 /// use llama_cpp_4::context::params::{LlamaContextParams, LlamaPoolingType};
646 /// let params = LlamaContextParams::default()
647 /// .with_pooling_type(LlamaPoolingType::Last);
648 /// assert_eq!(params.pooling_type(), LlamaPoolingType::Last);
649 /// ```
650 #[must_use]
651 pub fn with_pooling_type(mut self, pooling_type: LlamaPoolingType) -> Self {
652 self.context_params.pooling_type = i32::from(pooling_type);
653 self
654 }
655
656 /// Get the type of pooling.
657 ///
658 /// # Examples
659 ///
660 /// ```rust
661 /// let params = llama_cpp_4::context::params::LlamaContextParams::default();
662 /// assert_eq!(params.pooling_type(), llama_cpp_4::context::params::LlamaPoolingType::Unspecified);
663 /// ```
664 #[must_use]
665 pub fn pooling_type(&self) -> LlamaPoolingType {
666 LlamaPoolingType::from(self.context_params.pooling_type)
667 }
668
669 /// Clone these params, failing when sampler chains are attached.
670 ///
671 /// Prefer this over [`Clone::clone`] when you need to detect dropped sampler
672 /// configuration.
673 ///
674 /// # Errors
675 ///
676 /// Returns [`ParamsCloneError::SamplerChains`] when per-sequence sampler
677 /// chains are attached and cannot be duplicated, or
678 /// [`ParamsCloneError::TensorTransactions`] when an owned callback program
679 /// is attached.
680 pub fn try_clone(&self) -> Result<Self, ParamsCloneError> {
681 if !self.sampler_configs.is_empty() {
682 return Err(ParamsCloneError::SamplerChains);
683 }
684 if self.tensor_transactions.is_some() {
685 return Err(ParamsCloneError::TensorTransactions);
686 }
687 Ok(self.clone())
688 }
689}
690
691/// Default parameters for `LlamaContext`. (as defined in llama.cpp by `llama_context_default_params`)
692/// ```
693/// # use std::num::NonZeroU32;
694/// use llama_cpp_4::context::params::{LlamaContextParams, RopeScalingType};
695/// let params = LlamaContextParams::default();
696/// assert_eq!(params.n_ctx(), NonZeroU32::new(512), "n_ctx should be 512");
697/// assert_eq!(params.rope_scaling_type(), RopeScalingType::Unspecified);
698/// ```
699impl Default for LlamaContextParams {
700 fn default() -> Self {
701 let context_params = unsafe { llama_cpp_sys_4::llama_context_default_params() };
702 Self {
703 context_params,
704 attn_rot_disabled: false,
705 owned_samplers: Vec::new(),
706 sampler_configs: Vec::new(),
707 tensor_transactions: None,
708 }
709 }
710}
711
712/// Duplicate context params for reuse.
713///
714/// Sampler chains attached via [`LlamaContextParams::with_sampler_seq_configs`]
715/// are **not** cloned — the copy clears `samplers` / `n_samplers` because the
716/// underlying C chains cannot be duplicated safely.
717impl Clone for LlamaContextParams {
718 fn clone(&self) -> Self {
719 let mut context_params = self.context_params;
720 // Sampler chains cannot be duplicated here; cloned params omit them.
721 context_params.samplers = std::ptr::null_mut();
722 context_params.n_samplers = 0;
723 if self.tensor_transactions.is_some() {
724 context_params.cb_eval = None;
725 context_params.cb_eval_user_data = std::ptr::null_mut();
726 context_params.cb_decode_begin = None;
727 context_params.cb_decode_end = None;
728 }
729 Self {
730 context_params,
731 attn_rot_disabled: self.attn_rot_disabled,
732 owned_samplers: Vec::new(),
733 sampler_configs: Vec::new(),
734 tensor_transactions: None,
735 }
736 }
737}