Skip to main content

wire/answer/
sessions.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//! The stretches of one room, newest first: where each began, how, its
7//! runs and its last line (`crates/wire/spec/Answer/Sessions.lean` §8-71).
8
9use kernel::{Address, Effort, Origin, Seq, TimeMs};
10use serde::{Deserialize, Serialize};
11
12use crate::command::Carry;
13
14/// How many stretches one answer lists. A bound on the size of an answer
15/// on the wire, not a machine reading: the page that reads it shows a
16/// room's recent stretches, and `earlier` says how many more there are.
17pub const SESSIONS_MAX: usize = 64;
18
19/// How many characters of a stretch's last reply [`SessionLine::preview`]
20/// carries. A bound on the answer, not on what a page shows: the page cuts
21/// again to the width it has (`crates/wire/spec/Answer/Sessions.lean` D27).
22pub const SESSION_PREVIEW_MAX: usize = 240;
23
24/// One room's stretches, newest first, and how many older ones the answer
25/// leaves out. `room` echoes the question, which the wire carries no id
26/// for.
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
29pub struct SessionsAnswer {
30    pub room: Address,
31    pub sessions: Vec<SessionLine>,
32    pub earlier: u64,
33}
34
35/// One stretch of a room, each field read off a line the Ledger files
36/// under the room's address.
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
39pub struct SessionLine {
40    /// The stretch's first line: its `session_opened`, or the room's first
41    /// `run_started` when dispatching opened the room.
42    pub began: Seq,
43    pub start: SessionStart,
44    /// The runs started in this stretch.
45    pub runs: u64,
46    /// The last line of this stretch filed under the room's address, and
47    /// its time: the room's slice ends there (`crates/storage/Spec.lean` §8-24).
48    pub last: Seq,
49    pub at: TimeMs,
50    /// The name the last `session_named` for this stretch gave it; `None`
51    /// when it has none, and a page shows the room's address.
52    #[serde(default)]
53    pub name: Option<String>,
54    /// The model the stretch's last run called.
55    #[serde(default)]
56    pub model: Option<String>,
57    /// The effort the stretch's last run froze; `None` when it left the
58    /// provider to choose, and on lines written before the key existed.
59    #[serde(default)]
60    pub effort: Option<Effort>,
61    /// The worktree the stretch's last run was lent.
62    #[serde(default)]
63    pub workspace: Option<String>,
64    /// The start of the stretch's last reply, at most
65    /// [`SESSION_PREVIEW_MAX`] characters.
66    #[serde(default)]
67    pub preview: Option<String>,
68}
69
70/// How a stretch began.
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
72#[serde(rename_all = "snake_case")]
73#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
74pub enum SessionStart {
75    /// Dispatching into the room opened it; no `session_opened` was
76    /// written. `by` is who dispatched, as that first `run_started`
77    /// records it; `None` for a line written before the key existed (D40).
78    Dispatched {
79        #[cfg_attr(feature = "schema", schemars(with = "Option<String>"))]
80        by: Option<kernel::event::Who>,
81    },
82    /// `/new`: what crossed from the stretch before - `Handoff` when the
83    /// previous stretch's handoff travelled - and the run line it branched
84    /// from, when it is a branch.
85    Opened { carry: Carry, from: Option<Origin> },
86}