Skip to main content

rig_core/serve/
recorder.rs

1//! Runtime-independent recording of handler dispatches and consumer delivery.
2//!
3//! ```
4//! use rig_core::serve::Origin;
5//!
6//! let origin = Origin::default();
7//! assert!(origin.parent.is_none());
8//! ```
9
10use crate::{
11    effect::{EffectId, EffectKind, HandlerDescriptor, HandlerKey, Outcome},
12    error::ErrorReport,
13    streaming::{Item, StreamEvent},
14    wasm_compat::{WasmCompatSend, WasmCompatSync},
15};
16
17/// Recorded parent dispatch and stable program scope identifier, without live
18/// runtime handles.
19#[derive(Clone, Debug, Default, PartialEq, Eq)]
20pub struct Origin {
21    /// The dispatch this one was made from, if a handler made it.
22    pub parent: Option<EffectId>,
23    /// The scope of the program that made it, if its dispatcher was scoped.
24    pub scope: Option<std::sync::Arc<str>>,
25}
26
27/// What a driver tells about the dispatches it serves. A driver calls
28/// [`handlers`](Self::handlers) once when recording starts,
29/// [`begin`](Self::begin) as each dispatch is handed to its handler,
30/// [`event`](Self::event) for every streamed event when
31/// [`keep_events`](Self::keep_events) says so, and
32/// [`resolve`](Self::resolve) when the outcome is known. A recorder is
33/// shared between the driver and its owner, so every method takes `&self`;
34/// it rides in the dispatch observer and uses the platform compatibility bounds.
35pub trait Recorder: WasmCompatSend + WasmCompatSync + 'static {
36    /// Optional provider-observation context for a dispatch after [`Self::begin`].
37    /// Keep this runtime-only; observations do not belong in the effect log.
38    /// Return the same logical context when asked again for the same dispatch.
39    /// An explicit invocation context on the dispatch takes precedence.
40    fn adapter_context(&self, _id: EffectId) -> Option<crate::observe::AdapterContext> {
41        None
42    }
43    /// Declare that this runtime records consumer-visible delivery boundaries.
44    /// Handler-only recorders may ignore this optional scheduling metadata.
45    fn begin_delivery_tracking(&self) {}
46    /// A transition at the consumer boundary, after collection rather than
47    /// when a handler produces a value. Order within a batch is call order.
48    fn delivery(&self, _delivery: crate::effect::Delivery) {}
49    /// This recording includes visibility outside the runtime's supported
50    /// observation boundary and cannot prove policy-visible replay.
51    fn unsupported_delivery(&self, _reason: &str) {}
52    /// Handlers the driver serves: those registered when recording started,
53    /// then each one installed later, as it is installed. A key described
54    /// again is the same handler re-registered; the latest description
55    /// stands.
56    fn handlers(&self, handlers: Vec<HandlerDescriptor>);
57    /// A dispatch begins: its id, the key it was routed to, the effect, and
58    /// where it came from (its parent and scope).
59    fn begin(&self, id: EffectId, key: HandlerKey, kind: EffectKind, origin: Origin);
60    /// Removes a begun dispatch decided by a layer before handler execution.
61    /// Replay reruns layer decisions rather than recording them as handler outcomes.
62    fn discard(&self, id: EffectId);
63    /// Replaces the recorded request with a same-family layer patch, so it
64    /// reflects the request served by the innermost handler.
65    fn patch(&self, id: EffectId, kind: EffectKind);
66    /// Whether streamed items are wanted verbatim ([`Self::event`]).
67    fn keep_events(&self) -> bool;
68    /// One streamed item of `id`.
69    fn event(&self, id: EffectId, item: &Item<StreamEvent>);
70    /// An error item at its original position in a kept stream. Unlike the
71    /// folded outcome, this includes errors after an earlier terminal item.
72    fn stream_error(&self, _id: EffectId, _error: &ErrorReport) {}
73    /// Who the streamed reply of `id` is from, before its first item, when
74    /// [`keep_events`](Self::keep_events) says so.
75    fn origin(&self, id: EffectId, origin: &crate::message::Origin);
76    /// Explicitly published tool output, delivered before `resolve`. A driver
77    /// snapshots it without consuming the caller's published context.
78    fn tool_output(&self, id: EffectId, output: crate::tool::ToolResultContext);
79    /// The outcome of `id`.
80    fn resolve(&self, id: EffectId, outcome: Result<Outcome, ErrorReport>);
81}