Skip to main content

meerkat_runtime/
service_ext.rs

1//! SessionServiceRuntimeExt — v9 runtime extension for SessionService.
2//!
3//! This trait extends the existing SessionService with runtime-specific
4//! operations. It lives in meerkat-runtime (NOT in core) to maintain
5//! the separation: core owns SessionService, runtime owns runtime extensions.
6
7use meerkat_core::lifecycle::{InputId, RunId};
8use meerkat_core::types::SessionId;
9
10use crate::accept::AcceptOutcome;
11use crate::completion::CompletionHandle;
12use crate::input::Input;
13use crate::input_state::StoredInputState;
14use crate::meerkat_machine_types::{
15    ImageOperationRoutingRequest, ImageOperationRoutingResult, SessionLlmReconfigureReport,
16    SessionLlmReconfigureRequest, SwitchTurnRequest,
17};
18use crate::runtime_state::RuntimeState;
19use crate::terminal_status::{
20    InteractionSelector, InteractionTerminalReport, RunTerminalReport, Sourced,
21};
22use crate::traits::{ResetReport, RetireReport, RuntimeDriverError};
23
24/// v9 runtime extensions for SessionService.
25///
26/// This branch is runtime-backed only: every implementation is a v9
27/// runtime surface, so the methods below are unconditionally available.
28#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
29#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
30pub trait SessionServiceRuntimeExt: Send + Sync {
31    /// Accept an input for a session.
32    async fn accept_input(
33        &self,
34        session_id: &SessionId,
35        input: Input,
36    ) -> Result<AcceptOutcome, RuntimeDriverError>;
37
38    /// Accept an input and optionally return a completion handle that resolves
39    /// when the admitted work reaches a terminal runtime outcome.
40    async fn accept_input_with_completion(
41        &self,
42        session_id: &SessionId,
43        input: Input,
44    ) -> Result<(AcceptOutcome, Option<CompletionHandle>), RuntimeDriverError>;
45
46    /// Get the runtime state for a session.
47    async fn runtime_state(
48        &self,
49        session_id: &SessionId,
50    ) -> Result<RuntimeState, RuntimeDriverError>;
51
52    /// Get the runtime-owned resolved LLM capability surface for a session.
53    async fn resolved_session_llm_capabilities(
54        &self,
55        _session_id: &SessionId,
56    ) -> Result<Option<crate::meerkat_machine_types::SessionLlmCapabilitySurface>, RuntimeDriverError>
57    {
58        Err(RuntimeDriverError::Internal(
59            "resolved session llm capabilities are not implemented by this runtime adapter".into(),
60        ))
61    }
62
63    /// Retire a session's runtime.
64    async fn retire_runtime(
65        &self,
66        session_id: &SessionId,
67    ) -> Result<RetireReport, RuntimeDriverError>;
68
69    /// Reset a session's runtime.
70    async fn reset_runtime(
71        &self,
72        session_id: &SessionId,
73    ) -> Result<ResetReport, RuntimeDriverError>;
74
75    /// Get the state of a specific input, bundled with its DSL-owned seed
76    /// (phase / run association / boundary sequence).
77    async fn input_state(
78        &self,
79        session_id: &SessionId,
80        input_id: &InputId,
81    ) -> Result<Option<StoredInputState>, RuntimeDriverError>;
82
83    /// Resolve a caller-supplied idempotency key to its admitted input and
84    /// return that input's stored state (terminal outcome, last run id,
85    /// boundary sequence).
86    ///
87    /// This is the durable reconciliation query for interrupted work: the
88    /// machine-owned idempotency binding and the input's terminal facts
89    /// survive restart (persistent runtimes re-enter them on recovery), so
90    /// after re-registering a session a host can ask "did the interaction I
91    /// submitted under this key reach a terminal state, and which?" without
92    /// keeping its own run journal. Read-only: never registers a binding.
93    async fn input_state_by_idempotency_key(
94        &self,
95        session_id: &SessionId,
96        idempotency_key: &str,
97    ) -> Result<Option<StoredInputState>, RuntimeDriverError>;
98
99    /// Durable terminal-status query for one interaction.
100    ///
101    /// Registered sessions answer from live DSL truth; unregistered sessions
102    /// on a machine with a persistent RuntimeStore answer from the durably
103    /// committed input-state witnesses WITHOUT reviving the runtime. A
104    /// never-admitted session id fails typed `NotFound`; unregistered
105    /// sessions on a store-less (ephemeral) machine keep the `NotReady`
106    /// class. `Ok(None)` means the session is known but no input matches the
107    /// selector.
108    async fn interaction_terminal_status(
109        &self,
110        session_id: &SessionId,
111        selector: InteractionSelector,
112    ) -> Result<Option<Sourced<InteractionTerminalReport>>, RuntimeDriverError>;
113
114    /// Durable terminal-status query for a run.
115    ///
116    /// Evaluates the input-state witnesses whose `last_run_id` references
117    /// `run_id` (live snapshot when registered, durable store rows
118    /// otherwise) through the canonical pure evaluator. An unknown run on a
119    /// known session reports `NoDurableWitness` — callers must not read that
120    /// as `Failed` (re-staging rebinds `last_run_id`).
121    async fn run_terminal_status(
122        &self,
123        session_id: &SessionId,
124        run_id: &RunId,
125    ) -> Result<Sourced<RunTerminalReport>, RuntimeDriverError>;
126
127    /// List all active (non-terminal) inputs for a session.
128    async fn list_active_inputs(
129        &self,
130        session_id: &SessionId,
131    ) -> Result<Vec<InputId>, RuntimeDriverError>;
132
133    /// Canonically reconfigure the LLM identity for a registered live session.
134    async fn reconfigure_session_llm_identity(
135        &self,
136        session_id: &SessionId,
137        request: SessionLlmReconfigureRequest,
138    ) -> Result<SessionLlmReconfigureReport, RuntimeDriverError>;
139
140    async fn configure_model_routing_baseline(
141        &self,
142        _session_id: &SessionId,
143        _baseline_model: meerkat_core::lifecycle::run_primitive::ModelId,
144        _realtime_capable: bool,
145    ) -> Result<(), RuntimeDriverError> {
146        Err(RuntimeDriverError::Internal(
147            "model routing baseline is not supported by this runtime adapter".into(),
148        ))
149    }
150
151    async fn session_model_routing_status(
152        &self,
153        _session_id: &SessionId,
154    ) -> Result<meerkat_core::image_generation::SessionModelRoutingStatus, RuntimeDriverError> {
155        Err(RuntimeDriverError::Internal(
156            "model routing status is not supported by this runtime adapter".into(),
157        ))
158    }
159
160    async fn request_switch_turn(
161        &self,
162        _session_id: &SessionId,
163        _request: SwitchTurnRequest,
164    ) -> Result<meerkat_core::image_generation::SwitchTurnControlResult, RuntimeDriverError> {
165        Err(RuntimeDriverError::Internal(
166            "switch_turn is not supported by this runtime adapter".into(),
167        ))
168    }
169
170    async fn admit_model_routing_assistant_turn(
171        &self,
172        _session_id: &SessionId,
173    ) -> Result<(), RuntimeDriverError> {
174        Err(RuntimeDriverError::Internal(
175            "model routing turn admission is not supported by this runtime adapter".into(),
176        ))
177    }
178
179    async fn begin_image_operation(
180        &self,
181        _session_id: &SessionId,
182        _request: ImageOperationRoutingRequest,
183    ) -> Result<ImageOperationRoutingResult, RuntimeDriverError> {
184        Err(RuntimeDriverError::Internal(
185            "image operation routing is not supported by this runtime adapter".into(),
186        ))
187    }
188
189    async fn deny_image_operation_plan(
190        &self,
191        _session_id: &SessionId,
192        _operation_id: meerkat_core::image_generation::ImageOperationId,
193        _reason: meerkat_core::image_generation::ImageOperationDenialReason,
194    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
195        Err(RuntimeDriverError::Internal(
196            "image operation plan denial is not supported by this runtime adapter".into(),
197        ))
198    }
199
200    async fn activate_image_operation_override(
201        &self,
202        _session_id: &SessionId,
203        _operation_id: meerkat_core::image_generation::ImageOperationId,
204    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
205        Err(RuntimeDriverError::Internal(
206            "image operation activation is not supported by this runtime adapter".into(),
207        ))
208    }
209
210    async fn classify_image_operation_terminal(
211        &self,
212        _session_id: &SessionId,
213        _operation_id: meerkat_core::image_generation::ImageOperationId,
214        _observation: meerkat_core::image_generation::ImageProviderTerminalObservation,
215        _provider_text: meerkat_core::image_generation::ProviderTextDisposition,
216    ) -> Result<meerkat_core::image_generation::ImageOperationTerminalClass, RuntimeDriverError>
217    {
218        Err(RuntimeDriverError::Internal(
219            "image operation terminal classification is not supported by this runtime adapter"
220                .into(),
221        ))
222    }
223
224    async fn complete_image_operation(
225        &self,
226        _session_id: &SessionId,
227        _operation_id: meerkat_core::image_generation::ImageOperationId,
228        _terminal: meerkat_core::image_generation::ImageOperationTerminalClass,
229    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
230        Err(RuntimeDriverError::Internal(
231            "image operation completion is not supported by this runtime adapter".into(),
232        ))
233    }
234
235    async fn restore_image_operation_override(
236        &self,
237        _session_id: &SessionId,
238        _operation_id: meerkat_core::image_generation::ImageOperationId,
239    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
240        Err(RuntimeDriverError::Internal(
241            "image operation restore is not supported by this runtime adapter".into(),
242        ))
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use super::*;
249
250    // Verify trait is object-safe
251    fn _assert_object_safe(_: &dyn SessionServiceRuntimeExt) {}
252}