Slot
Slot<C, O> is the container that parent modalities use to hold child components in one of two states: Cold (cached output) or Hot (live, fully operational). It implements Component, so the parent’s compilation pipeline treats both states uniformly.
Definition
Section titled “Definition”pub enum Slot<C, O> { Cold(O), Hot(Arc<Mutex<C>>),}| Variant | Contents | Behavior |
|---|---|---|
Cold(O) | Cached compiled output | Returns the cached value on compile(). Zero cost, no recompilation. |
Hot(Arc<Mutex<C>>) | Live child behind Arc<Mutex> | Delegates compile() to the inner component. Arc<Mutex> allows independent locking for recursive generation (each child runs its own agent thread). |
Component Implementation
Section titled “Component Implementation”Slot implements Component by branching on the variant. Hot locks the Arc<Mutex> before delegating:
impl<C, O> Component for Slot<C, O>where C: Component<Output = O>, O: Clone + Send + Sync + 'static,{ type Metadata = C::Metadata; type Output = O;
fn properties(&self) -> Vec<PropertySchema> { match self { Slot::Hot(c) => c.lock().properties(), Slot::Cold(_) => Vec::new(), } }
fn compile( &self, metadata: &Self::Metadata, values: &HashMap<String, PropertyValue>, ) -> Result<Self::Output, CompileError> { match self { Slot::Hot(c) => c.lock().compile(metadata, values), Slot::Cold(o) => Ok(o.clone()), } }}- Cold returns the cached output directly. No metadata or values are consulted.
- Hot locks the mutex, then delegates to the inner component’s
compile(). ForSession<Whiteboard, ...>, this returns the session’s already-compiled output.
Slot does not implement Reducer. The parent Session’s ReduceIntent impl locks the Hot child’s Arc<Mutex<Session>> and calls dispatch() directly. Dispatching to a Cold slot is an error — it must be warmed first.
Usage in Parent Modalities
Section titled “Usage in Parent Modalities”LessonPlan holds its whiteboard children as a HashMap of Slots:
pub struct LessonPlan { rt: Runtime<Self>, children: HashMap<String, Slot<Session<Whiteboard>, Vec<WhiteboardElement>>>,}The concrete type is Slot<Session<Whiteboard>, Vec<WhiteboardElement>> (Session<Whiteboard> uses the default I = SessionIntent<WhiteboardIntent>):
C= full child session with its own Doc, cache, effects, and AI subagentO=Vec<WhiteboardElement>, the whiteboard’s compiled output
Hot/Cold Lifecycle
Section titled “Hot/Cold Lifecycle”stateDiagram-v2 [*] --> Cold: Session opens Cold --> Hot: WarmChild Hot --> Cold: Session persists on close Hot --> Hot: Child dispatch
state Cold { [*] --> cached_output: Cached from parent synced state } state Hot { [*] --> child_session: Full Session with Doc + cache }1. Open — all children start Cold
Section titled “1. Open — all children start Cold”When a parent session opens, all children begin as Cold with cached output from the parent’s synced state (or empty output for new placements). This is the zero-cost default.
2. Warm — promote Cold to Hot
Section titled “2. Warm — promote Cold to Hot”When Dart navigates to a slide, it dispatches ParentSessionIntent::WarmChild { id }:
WarmChild { id } => { fx.spawn(move |svc, sender| { let bytes = svc.backend.load(&id).unwrap(); sender.send(Command::Feedback( ParentSessionFeedback::ChildWarmed { id, bytes } )); });}The async load completes, and the feedback handler creates a full Hot session from the loaded bytes.
3. Dispatch — interact with Hot children
Section titled “3. Dispatch — interact with Hot children”Child intents route through ParentSessionIntent::Child { id, intent }:
Child { id, intent } => { let child_id = id.unwrap_or_else(|| { state.modality.selected_child_id().unwrap().to_string() }); match state.modality.children_mut().get_mut(&child_id) { Some(Slot::Hot(child_session)) => { child_session.dispatch(Command::Intent(intent)); } Some(Slot::Cold(_)) => { /* error: must warm first */ } None => { /* error: unknown child */ } }}The Hot child runs its own full reduce cycle (drain, reduce, send, lifecycle, spawn). The parent then invalidates the cache for that placement and runs its own lifecycle (recompile, emit).
4. Close — persist and cool down
Section titled “4. Close — persist and cool down”On session close, Hot sessions export their docs. The parent can store the compiled output back as Cold for the next open.
Compilation Behavior
Section titled “Compilation Behavior”During parent compilation, Slot’s Component::compile() is called for every child placement:
| Child State | Compilation Cost | What Happens |
|---|---|---|
| Cold | O(1) clone | Returns cached output. No hash check needed. |
| Hot | Delegates to Session | Session’s compile() returns its already-compiled output (computed during dispatch lifecycle). |
For a LessonPlan with 20 slides where 1 is Hot and 19 are Cold: the Hot slide returns its cached output from the last dispatch, and the 19 Cold slides each return their stored output. Total recompilation: zero (unless the Hot slide’s output changed).