Skip to main content

rhema_transcript/
lib.rs

1//! The bounded view over an unbounded session.
2//!
3//! Every step sends `session.history.clone()` (SPEC.md §4): cost grows
4//! with the session, and the context window ends the session that
5//! outgrows it. This crate splits what was fused. The **log** — the
6//! caller's `Session` — stays complete; the **view** — what a request
7//! carries — is a projection built per request under a byte budget.
8//! Old messages are represented by the stepped compaction block,
9//! nothing is deleted anywhere, and `zoom` is the model's way back to
10//! any original.
11//!
12//! - [`tree`] — the slot algebra: message ranges `(id, n)`
13//! - [`summary`] — the extractive line text: heads and counts, no
14//!   model calls
15//! - [`compact`] — the stepped compaction engine: the append-only
16//!   block, the summarizer seam, the model worker
17//! - [`view`] — the request view: the provider decorator, the mirror,
18//!   the budget, the benchmark stats
19//! - [`zoom`] — the `zoom` tool
20//!
21//! The design is `specs/rhema-transcript.md`.
22
23#![forbid(unsafe_code)]
24
25pub mod compact;
26pub mod summary;
27pub mod tree;
28pub mod view;
29pub mod zoom;
30
31pub use compact::{ModelSummarizer, PendingSummary, Section, SectionOrigin, Summarizer};
32pub use view::{
33    LogContent, SkillText, Transcript, TranscriptSettings, TranscriptStats, TranscriptView,
34    UsageBreakdown, WorkerOutcome,
35};
36pub use zoom::{ZOOM_MAX_BYTES, Zoom};
37
38use std::sync::{Arc, Mutex};
39
40/// Wires a transcript over `inner`: the view decorator plus the `zoom`
41/// resolver, sharing one mirror. A consumer that builds its own
42/// [`rhema_core::Agent`] sends the wrapped provider through to the
43/// builder and overlays the resolver over its tool chain; the coding
44/// agent does both in its constructor when its config enables the
45/// transcript.
46///
47/// The mirror starts empty; the first request fills it. Sections keep
48/// their extractive stand-ins — pass a summarizer to
49/// [`attach_with_summarizer`] for the model fill.
50pub fn attach(
51    inner: Arc<dyn rhema_core::ModelProvider>,
52    settings: TranscriptSettings,
53) -> (Arc<dyn rhema_core::ModelProvider>, Zoom) {
54    let (provider, zoom, _mirror) = attach_with_summarizer(inner, settings, None);
55    (provider, zoom)
56}
57
58/// [`attach`] with the compaction's model fill: `summarizer` rewrites
59/// each new section's extractive stand-in into a dense block at flush
60/// time. `None` is the extractive-only compaction. Returns the mirror
61/// too, for a driver that reports the benchmark stats.
62pub fn attach_with_summarizer(
63    inner: Arc<dyn rhema_core::ModelProvider>,
64    settings: TranscriptSettings,
65    summarizer: Option<Arc<dyn Summarizer>>,
66) -> (
67    Arc<dyn rhema_core::ModelProvider>,
68    Zoom,
69    Arc<Mutex<Transcript>>,
70) {
71    let transcript = Arc::new(Mutex::new(Transcript::new(settings)));
72    let view = match summarizer {
73        Some(summarizer) => TranscriptView::with_summarizer(inner, transcript.clone(), summarizer),
74        None => TranscriptView::new(inner, transcript.clone()),
75    };
76    let zoom = Zoom::new(transcript.clone());
77    (Arc::new(view), zoom, transcript)
78}