1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Owns retained Episode/action views and transient history-fragment encoding, not activation.
//! Views borrow validated checkpoint data; encoding is model data, not authority or a checkpoint.
mod context;
mod encoding;
pub use context::InitialProjection;
pub use encoding::ProjectionError;
use crate::{
boundary::Exit, command::CommandView, episode::Episode, format::Id32, graph::RestoredAgent,
memory::Memory, receipt::ReceiptView,
};
/// Deterministic checkpoint history/current-chain view, independent of provider transcripts.
/// Definition history zero hides completed Episodes only; mandatory retained bytes and
/// the current chain remain intact. This is not a complete ModelRequest: policy/tools,
/// new prepared input, live working memory, RAM trajectory and combined context-byte
/// accounting belong to the later context/activation composition.
#[derive(Clone, Copy)]
pub struct HistoryProjection<'a> {
restored: &'a RestoredAgent,
}
impl<'a> HistoryProjection<'a> {
pub fn new(restored: &'a RestoredAgent) -> Self {
Self { restored }
}
/// Completed Episodes, oldest to newest, without shrinking the promised window.
pub fn completed(self) -> impl Iterator<Item = EpisodeProjection<'a>> {
let enabled = self.restored.definition().limits().history_episodes != 0;
self.restored
.history()
.filter(move |_| enabled)
.map(move |episode| EpisodeProjection {
restored: self.restored,
episode,
})
}
/// Open checkpoint chain, if any. A final pending Command has no recorded Receipt yet.
/// This does not invent a result or join an unadmitted new ActivationInput.
pub fn current(self) -> Option<EpisodeProjection<'a>> {
self.restored
.current_episode()
.map(|episode| EpisodeProjection {
restored: self.restored,
episode,
})
}
}
/// One retained Episode's entry/latest memory and ordered commands/terminal results.
#[derive(Clone, Copy)]
pub struct EpisodeProjection<'a> {
restored: &'a RestoredAgent,
episode: &'a Episode,
}
impl<'a> EpisodeProjection<'a> {
pub fn id(self) -> Id32 {
self.episode.id()
}
pub fn closed(self) -> bool {
self.episode.closed()
}
pub fn entry_memory(self) -> Option<&'a Memory> {
self.episode.entry_memory_link().map(|cid| {
self.restored
.memory_block(cid)
.expect("restored entry Memory")
})
}
/// Final memory for a completed Episode; latest checkpoint memory for an open one.
/// A memory-disabled profile returns None, never synthetic empty planes.
pub fn latest_memory(self) -> Option<&'a Memory> {
let cid = self
.episode
.boundaries()
.last()
.expect("restored nonempty Episode");
self.restored
.boundary(cid)
.expect("restored Boundary")
.memory_link()
.map(|cid| {
self.restored
.memory_block(cid)
.expect("restored Boundary Memory")
})
}
pub fn actions(self) -> impl Iterator<Item = ActionProjection<'a>> {
let mut boundaries = self.episode.boundaries().peekable();
core::iter::from_fn(move || loop {
let cid = boundaries.next()?;
let boundary = self.restored.boundary(cid).expect("restored Boundary");
let Exit::AwaitAction(command) = boundary.exit() else {
continue;
};
let receipt = boundaries.peek().map(|next| {
let next = self
.restored
.boundary(*next)
.expect("restored next Boundary");
self.restored
.input(next.input_link())
.expect("restored next input")
.receipt_bytes()
.expect("restored action-result Receipt")
});
return Some(ActionProjection { command, receipt });
})
}
}
/// Exact validated embedded records, borrowed from the Command Boundary and following
/// ActivationInput. The final no_op is not another action; its input still supplies
/// the previous Command's Receipt. Closed Episodes have Some receipt for every action.
/// Raw records retain runtime metadata; model-facing normalization is a separate step.
#[derive(Clone, Copy)]
pub struct ActionProjection<'a> {
command: &'a [u8],
receipt: Option<&'a [u8]>,
}
impl<'a> ActionProjection<'a> {
/// Borrow schema-owned typed fields without copying or revalidating the retained payload.
pub fn command(self) -> CommandView<'a> {
CommandView::from_validated(self.command)
}
pub fn receipt(self) -> Option<ReceiptView<'a>> {
self.receipt.map(ReceiptView::from_validated)
}
pub fn command_bytes(self) -> &'a [u8] {
self.command
}
pub fn receipt_bytes(self) -> Option<&'a [u8]> {
self.receipt
}
}