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}