Skip to main content

kernel/model/
window.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! How much of a conversation one model can be given at once.
7//! The part `crates/kernel/spec/Model.lean` specifies this module with the
8//! rest of `kernel::model`.
9
10use std::num::NonZeroU64;
11
12use serde::{Deserialize, Serialize};
13
14/// The most tokens one model reads in a single call, prompt and reply
15/// together.
16///
17/// **Zero is unrepresentable, and absence is not zero.** Were a window
18/// nobody stated and a window of zero the same value, the context
19/// reminder would measure a conversation against nothing and report
20/// every session as full. A figure nobody registered is
21/// carried as `None` all the way to the reminder, which then stays
22/// silent, and every layer in between is spared the rule that zero is
23/// special.
24///
25/// A separate type from [`Ceiling`](crate::Ceiling) although both are
26/// non-zero token counts: one bounds what the model may read and the
27/// other bounds what it may write, and a call that swapped them would
28/// compile.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
30#[serde(transparent)]
31#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
32pub struct Window(NonZeroU64);
33
34impl Window {
35    /// `None` for zero, which is not a window.
36    #[must_use]
37    pub const fn new(tokens: u64) -> Option<Window> {
38        match NonZeroU64::new(tokens) {
39            Some(tokens) => Some(Window(tokens)),
40            None => None,
41        }
42    }
43
44    #[must_use]
45    pub const fn get(self) -> u64 {
46        self.0.get()
47    }
48}
49
50impl std::fmt::Display for Window {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        write!(f, "{}", self.0.get())
53    }
54}
55
56#[cfg(test)]
57#[allow(clippy::unwrap_used, clippy::expect_used, reason = "test code")]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn a_window_of_zero_is_no_window_at_all() {
63        assert_eq!(Window::new(0), None);
64        assert_eq!(Window::new(200_000).unwrap().get(), 200_000);
65    }
66
67    #[test]
68    fn a_window_travels_as_the_bare_number_and_absence_as_null() {
69        let stated = serde_json::to_string(&Window::new(128_000)).unwrap();
70        assert_eq!(stated, "128000");
71        let absent = serde_json::to_string(&Option::<Window>::None).unwrap();
72        assert_eq!(absent, "null");
73        assert_eq!(
74            serde_json::from_str::<Option<Window>>("128000").unwrap(),
75            Window::new(128_000)
76        );
77    }
78
79    /// Zero on the wire is refused rather than read as "no window":
80    /// the encoding of absence is `null`, and a second encoding of it
81    /// would be a second authority for what unstated means.
82    #[test]
83    fn zero_on_the_wire_is_refused_rather_than_read_as_absence() {
84        assert!(serde_json::from_str::<Window>("0").is_err());
85    }
86}