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