mod assembly;
mod builder;
pub(crate) mod causal;
mod config_ops;
mod effect;
mod environment;
mod error;
mod host;
mod in_memory_store;
mod io;
mod lifecycle;
mod observation;
mod process;
mod process_work_runner;
mod process_worker;
mod queued_work_runner;
mod session_api;
mod session_manager;
mod session_ops;
mod state;
#[cfg(test)]
pub(crate) mod tests;
mod turn_boundary;
mod turn_commit_draft;
mod turn_driver;
mod turn_graph_editor;
mod turn_loop;
mod turn_queue;
mod usage;
use std::any::Any;
use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use std::sync::Mutex as StdMutex;
use std::sync::atomic::{AtomicBool, Ordering};
use tokio::sync::{Mutex, mpsc};
use tokio_util::sync::CancellationToken;
use crate::llm::types::{
LlmOutputPart, LlmProviderTraceEvent, LlmProviderTraceSender, LlmRequest, LlmResponse,
LlmStreamEvent, LlmUsage,
};
use crate::plugin::{
CheckpointHookContext, PrepareTurnRequest, SessionConfigChangedContext, SessionRelation,
};
use crate::sansio::{LlmCallError, Response};
use crate::session_model::{
Message, MessageRole, Part, PartKind, PruneState, RuntimeSessionPolicy, SessionEvent,
SessionPolicy, TokenUsage, fresh_message_id, make_error_event, reassign_part_ids, shared_parts,
transport_stream_events,
};
use crate::{
CheckpointKind, PersistentRuntimeServices, PluginActionInvokeError, PromptHookContext,
RuntimeServices, SandboxMessage, Session, SessionCreateRequest, SessionError, SessionHandle,
SessionSnapshot, SessionStartPoint, ToolCallRecord, TurnFinish, TurnOutcome, TurnStop,
};
use crate::{Effect, TurnMachine};
use host::*;
use session_manager::*;
use turn_boundary::*;
use turn_commit_draft::*;
use turn_driver::*;
pub(crate) const RUNTIME_TURN_LEASE_TTL_MS: u64 = 15 * 60 * 1000;
pub use lash_sansio::PromptUsage;
use assembly::{
LlmDebugText, LlmDebugToolCall, LlmStreamAccumulator, LlmStreamDebugState, LlmStreamEventLog,
LlmStreamState, LlmStreamSummary, TurnAssembler,
};
#[cfg(test)]
#[allow(unused_imports)]
use assembly::{classify_output_state, sanitize_assistant_output};
pub use builder::EmbeddedRuntimeBuilder;
pub use causal::process_event_invocation;
pub(crate) use causal::tool_retry_sleep_invocation;
pub(crate) use effect::RuntimeEffectControllerHandle;
pub use effect::{
CausalRef, EffectHost, EffectScope, InlineEffectHost, InlineRuntimeEffectController,
LlmAttachmentSpec, LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, RuntimeEffectCommand,
RuntimeEffectController, RuntimeEffectControllerError, RuntimeEffectEnvelope,
RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome, RuntimeInvocation,
RuntimeReplay, RuntimeScope, RuntimeSubject, ScopedEffectController,
};
pub use environment::{ParkedSession, Residency, RuntimeEnvironment, RuntimeEnvironmentBuilder};
pub use error::{DurableStoreFacet, RuntimeError, RuntimeErrorCode};
pub use host::{EmbeddedRuntimeHost, ProcessRuntimeHost, RuntimeHostConfig};
pub use in_memory_store::{InMemorySessionStore, InMemorySessionStoreFactory};
use io::normalize_input_items;
pub use observation::{RuntimeHandle, RuntimeObservation};
#[cfg(any(test, feature = "testing"))]
pub use process::TestLocalProcessRegistry;
pub use process::{
DefaultProcessCancelAbility, ObservedProcess, ObservedProcessEvent, ObservedWorkItem,
PROCESS_LEASE_SCHEMA_VERSION, PreparedProcessEventAppend, ProcessAwaitOutput,
ProcessCancelAbility, ProcessCancelAllRequest, ProcessCancelRequest, ProcessCancelSource,
ProcessCancelSummary, ProcessDefinitionSelector, ProcessDefinitionSummary, ProcessEvent,
ProcessEventAppendRequest, ProcessEventAppendResult, ProcessEventSemantics,
ProcessEventSemanticsSpec, ProcessEventType, ProcessExecutionContext, ProcessExternalRef,
ProcessHandleDescriptor, ProcessHandleGrant, ProcessHandleGrantEntry, ProcessHandleSummary,
ProcessId, ProcessInput, ProcessLease, ProcessLeaseCompletion, ProcessLifecycleStatus,
ProcessListFilter, ProcessListMode, ProcessOpScope, ProcessProvenance, ProcessRecord,
ProcessRegistration, ProcessRegistry, ProcessScope, ProcessScopeId, ProcessService,
ProcessSessionDeleteReport, ProcessStartGrant, ProcessStartOptions, ProcessStartRequest,
ProcessStatus, ProcessStatusFilter, ProcessTerminalSemantics, ProcessTerminalSpec,
ProcessTerminalState, ProcessValueSelector, ProcessWake, ProcessWakeDedupeKey,
ProcessWakeDelivery, ProcessWakeSpec, ProcessWorkObserver, ProcessWorkSnapshot,
UnavailableProcessService, current_epoch_ms, epoch_ms_from_system_time,
lashlang_process_event_types, materialize_process_event_semantics,
prepare_process_event_append, prepare_process_registration, process_event_payload_hash,
process_wake_delivery, process_wake_input_from_event_payload, process_wake_turn_cause,
process_wake_turn_text, require_event_replay, system_time_from_epoch_ms,
};
pub use process_work_runner::{
InlineProcessRunHandle, ProcessRunHandle, ProcessWorkDriver, ProcessWorkPoke, ProcessWorkRunner,
};
pub use process_worker::{DurableProcessWorker, DurableProcessWorkerConfig};
pub use queued_work_runner::{
QueuedWorkPoke, QueuedWorkRunHandle, QueuedWorkRunOutcome, QueuedWorkRunRequest,
QueuedWorkRunner,
};
pub use session_manager::DirectCompletionClient;
pub use state::RuntimeSessionState;
use state::{
append_session_nodes_to_state, apply_residency_on_load, apply_session_checkpoint,
apply_session_head, normalize_session_graph, open_agent_frame_in_state,
};
pub use turn_loop::ensure_durable_effect_input;
pub use turn_queue::{
DeliveryPolicy, MergeKey, QUEUED_WORK_CLAIM_TTL_MS, QueuedCheckpointWork, QueuedTurnWork,
QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim, QueuedWorkClaimBoundary,
QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload, SessionCommand, SessionCommandReceipt,
SlotPolicy, process_wake_batch_draft,
};
pub use usage::{
SessionUsageReport, TokenLedgerEntry, UsageReportRow, UsageTotals, diff_token_ledger,
diff_usage_reports,
};
use usage::{merge_ledger_entry, merge_usage_delta_entries, normalize_prompt_usage};
#[doc(hidden)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RuntimeTurnPhase {
ContextTransform,
BeforeTurnHooks,
PromptBuild,
EffectLoop,
FinalizeTurn,
PersistTurn,
FinalCommit,
PostPersistHooks,
}
#[doc(hidden)]
pub trait RuntimeTurnPhaseProbe: Send + Sync {
fn begin(&self, phase: RuntimeTurnPhase);
fn end(&self, phase: RuntimeTurnPhase);
fn begin_named(&self, _phase: &str) {}
fn end_named(&self, _phase: &str) {}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum InputItem {
Text { text: String },
ImageRef { id: String },
}
impl InputItem {
pub fn text(text: impl Into<String>) -> Self {
Self::Text { text: text.into() }
}
pub fn image_ref(id: impl Into<String>) -> Self {
Self::ImageRef { id: id.into() }
}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct TurnInput {
pub items: Vec<InputItem>,
#[serde(default)]
pub image_blobs: HashMap<String, Vec<u8>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub protocol_turn_options: Option<crate::ProtocolTurnOptions>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace_turn_id: Option<String>,
#[serde(skip)]
pub protocol_extension: Option<ProtocolTurnExtensionHandle>,
#[serde(skip)]
pub turn_context: TurnContext,
}
impl TurnInput {
pub fn empty() -> Self {
Self::items(std::iter::empty())
}
pub fn text(text: impl Into<String>) -> Self {
Self::items([InputItem::text(text)])
}
pub fn items(items: impl IntoIterator<Item = InputItem>) -> Self {
Self {
items: items.into_iter().collect(),
image_blobs: HashMap::new(),
protocol_turn_options: None,
trace_turn_id: None,
protocol_extension: None,
turn_context: TurnContext::default(),
}
}
pub fn with_image_blob(mut self, id: impl Into<String>, bytes: Vec<u8>) -> Self {
self.image_blobs.insert(id.into(), bytes);
self
}
pub fn with_image_blobs<I, K>(mut self, image_blobs: I) -> Self
where
I: IntoIterator<Item = (K, Vec<u8>)>,
K: Into<String>,
{
self.image_blobs.extend(
image_blobs
.into_iter()
.map(|(id, bytes)| (id.into(), bytes)),
);
self
}
pub fn with_image_ref(mut self, id: impl Into<String>, bytes: Vec<u8>) -> Self {
let id = id.into();
self.items.push(InputItem::image_ref(id.clone()));
self.image_blobs.insert(id, bytes);
self
}
pub fn with_protocol_turn_options(mut self, options: crate::ProtocolTurnOptions) -> Self {
self.protocol_turn_options = Some(options);
self
}
pub fn with_trace_turn_id(mut self, trace_turn_id: impl Into<String>) -> Self {
self.trace_turn_id = Some(trace_turn_id.into());
self
}
}
#[derive(Clone, Default)]
pub struct LiveTurnInputs {
inputs: HashMap<&'static str, Arc<dyn Any + Send + Sync>>,
}
impl LiveTurnInputs {
fn insert<T>(&mut self, plugin_id: &'static str, input: T)
where
T: Send + Sync + 'static,
{
self.inputs.insert(plugin_id, Arc::new(input));
}
fn get<T>(&self, plugin_id: &'static str) -> Option<&T>
where
T: 'static,
{
self.inputs
.get(plugin_id)
.and_then(|input| input.downcast_ref::<T>())
}
fn contains(&self, plugin_id: &'static str) -> bool {
self.inputs.contains_key(plugin_id)
}
fn is_empty(&self) -> bool {
self.inputs.is_empty()
}
pub fn plugin_ids(&self) -> Vec<&'static str> {
self.inputs.keys().copied().collect()
}
pub(crate) fn durable_effect_rejection(&self) -> Result<(), RuntimeError> {
if self.is_empty() {
return Ok(());
}
Err(RuntimeError::new(
RuntimeErrorCode::DurableEffectLivePluginInput,
"durable effect hosts do not support live TurnContext plugin inputs; encode replayable data in protocol_turn_options or persisted plugin state",
))
}
}
#[derive(Clone, Default)]
pub struct TurnContext {
plugin_inputs: LiveTurnInputs,
provider: Option<crate::ProviderHandle>,
model: Option<crate::ModelSpec>,
prompt: crate::PromptLayer,
}
impl TurnContext {
pub fn new() -> Self {
Self::default()
}
pub fn insert_plugin_input<T>(&mut self, plugin_id: &'static str, input: T)
where
T: Send + Sync + 'static,
{
self.plugin_inputs.insert(plugin_id, input);
}
pub fn set_provider(&mut self, provider: crate::ProviderHandle) {
self.provider = Some(provider);
}
pub fn provider(&self) -> Option<&crate::ProviderHandle> {
self.provider.as_ref()
}
pub fn set_model(&mut self, model: crate::ModelSpec) {
self.model = Some(model);
}
pub fn model_spec(&self) -> Option<&crate::ModelSpec> {
self.model.as_ref()
}
pub fn plugin_input<T>(&self, plugin_id: &'static str) -> Option<&T>
where
T: 'static,
{
self.plugin_inputs.get(plugin_id)
}
pub fn has_plugin_input(&self, plugin_id: &'static str) -> bool {
self.plugin_inputs.contains(plugin_id)
}
pub fn has_live_plugin_inputs(&self) -> bool {
!self.plugin_inputs.is_empty()
}
pub fn live_plugin_input_ids(&self) -> Vec<&'static str> {
self.plugin_inputs.plugin_ids()
}
pub(crate) fn live_plugin_inputs(&self) -> &LiveTurnInputs {
&self.plugin_inputs
}
pub fn set_prompt_template(&mut self, template: crate::PromptTemplate) {
self.prompt.template = Some(template);
}
pub fn add_prompt_contribution(&mut self, contribution: crate::PromptContribution) {
self.prompt.add_contribution(contribution);
}
pub fn replace_prompt_slot(
&mut self,
slot: crate::PromptSlot,
contributions: impl IntoIterator<Item = crate::PromptContribution>,
) {
self.prompt.replace_slot(slot, contributions);
}
pub fn clear_prompt_slot(&mut self, slot: crate::PromptSlot) {
self.prompt.clear_slot(slot);
}
pub fn set_prompt_layer(&mut self, prompt: crate::PromptLayer) {
self.prompt = prompt;
}
pub fn prompt_layer(&self) -> &crate::PromptLayer {
&self.prompt
}
}
impl fmt::Debug for TurnContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TurnContext")
.field("plugin_inputs", &self.plugin_inputs.plugin_ids())
.field("has_provider", &self.provider.is_some())
.field("has_model", &self.model.is_some())
.field("has_prompt_layer", &(!self.prompt.is_empty()))
.finish()
}
}
#[derive(Clone)]
pub struct ProtocolTurnExtensionHandle(Arc<dyn ProtocolTurnExtension>);
impl ProtocolTurnExtensionHandle {
pub fn new(extension: impl ProtocolTurnExtension + 'static) -> Self {
Self(Arc::new(extension))
}
pub fn as_any(&self) -> &dyn Any {
self.0.as_any()
}
pub fn prompt_contributions(&self) -> Vec<crate::PromptContribution> {
self.0.prompt_contributions()
}
}
impl fmt::Debug for ProtocolTurnExtensionHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("ProtocolTurnExtensionHandle(..)")
}
}
pub trait ProtocolTurnExtension: Send + Sync {
fn as_any(&self) -> &dyn Any;
fn prompt_contributions(&self) -> Vec<crate::PromptContribution> {
Vec::new()
}
}
#[derive(Clone)]
pub struct ProtocolSessionExtensionHandle(Arc<dyn ProtocolSessionExtension>);
impl ProtocolSessionExtensionHandle {
pub fn new(extension: impl ProtocolSessionExtension + 'static) -> Self {
Self(Arc::new(extension))
}
pub fn as_any(&self) -> &dyn Any {
self.0.as_any()
}
}
impl fmt::Debug for ProtocolSessionExtensionHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("ProtocolSessionExtensionHandle(..)")
}
}
pub trait ProtocolSessionExtension: Send + Sync {
fn as_any(&self) -> &dyn Any;
}
#[derive(Clone, Debug)]
pub(super) enum NormalizedItem {
Text(String),
Image(crate::AttachmentRef),
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct AssistantOutput {
pub safe_text: String,
pub raw_text: String,
pub state: OutputState,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum OutputState {
Usable,
EmptyOutput,
TracebackOnly,
RecoveredFromError,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct CodeOutputRecord {
pub output: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct ExecutionSummary {
#[serde(default)]
pub had_tool_calls: bool,
#[serde(default)]
pub had_code_execution: bool,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct TurnIssue {
pub kind: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub terminal_reason: Option<crate::LlmTerminalReason>,
pub message: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub raw: Option<String>,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct AssembledTurn {
pub state: SessionSnapshot,
pub outcome: crate::TurnOutcome,
pub assistant_output: AssistantOutput,
pub execution: ExecutionSummary,
#[serde(default)]
pub token_usage: TokenUsage,
#[serde(default)]
pub children_usage: Vec<TokenLedgerEntry>,
#[serde(default)]
pub tool_calls: Vec<ToolCallRecord>,
#[serde(default)]
pub errors: Vec<TurnIssue>,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct AgentFrameRun {
pub turns: Vec<AssembledTurn>,
}
impl AgentFrameRun {
pub fn final_turn(&self) -> Option<&AssembledTurn> {
self.turns.last()
}
pub fn into_final_turn(mut self) -> Option<AssembledTurn> {
self.turns.pop()
}
pub fn frame_switch_count(&self) -> usize {
self.turns
.iter()
.filter(|turn| matches!(turn.outcome, crate::TurnOutcome::AgentFrameSwitch { .. }))
.count()
}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct TerminationPolicy {
#[serde(default)]
pub treat_missing_done_as_failure: bool,
}
impl Default for TerminationPolicy {
fn default() -> Self {
Self {
treat_missing_done_as_failure: true,
}
}
}
#[async_trait::async_trait]
pub trait EventSink: Send + Sync {
fn is_noop(&self) -> bool {
false
}
async fn emit(&self, event: SessionEvent);
}
pub struct NoopEventSink;
pub static NOOP_EVENT_SINK: NoopEventSink = NoopEventSink;
#[async_trait::async_trait]
impl EventSink for NoopEventSink {
fn is_noop(&self) -> bool {
true
}
async fn emit(&self, _event: SessionEvent) {}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct TurnActivityId(pub String);
impl TurnActivityId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn fresh() -> Self {
Self(uuid::Uuid::new_v4().to_string())
}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct TurnActivity {
pub id: TurnActivityId,
pub correlation_id: TurnActivityId,
#[serde(flatten)]
pub event: TurnEvent,
}
impl TurnActivity {
pub fn new(correlation_id: TurnActivityId, event: TurnEvent) -> Self {
Self {
id: TurnActivityId::fresh(),
correlation_id,
event,
}
}
pub fn independent(event: TurnEvent) -> Self {
let correlation_id = TurnActivityId::fresh();
Self::new(correlation_id, event)
}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
pub enum TurnEvent {
QueuedWorkStarted {
boundary: crate::QueuedWorkClaimBoundary,
batch_ids: Vec<String>,
causes: Vec<crate::TurnCause>,
},
ModelRequestStarted {
protocol_iteration: usize,
},
AssistantProseDelta {
text: String,
},
ReasoningDelta {
text: String,
},
CodeBlockStarted {
language: String,
code: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
graph_key: Option<String>,
},
CodeBlockCompleted {
language: String,
output: String,
error: Option<String>,
success: bool,
duration_ms: u64,
tool_call_ids: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
graph_key: Option<String>,
},
ToolCallStarted {
call_id: Option<String>,
name: String,
args: serde_json::Value,
},
ToolCallCompleted {
call_id: Option<String>,
name: String,
args: serde_json::Value,
output: crate::ToolCallOutput,
duration_ms: u64,
},
SubmittedValue {
value: serde_json::Value,
},
ToolValue {
tool_name: String,
value: serde_json::Value,
},
Usage {
protocol_iteration: usize,
usage: TokenUsage,
cumulative: TokenUsage,
},
ChildUsage {
session_id: String,
source: String,
model: String,
protocol_iteration: usize,
usage: TokenUsage,
cumulative: TokenUsage,
},
RetryStatus {
wait_seconds: u64,
attempt: usize,
max_attempts: usize,
reason: String,
},
PluginRuntime {
plugin_id: String,
event: crate::PluginRuntimeEvent,
},
QueuedInputAccepted {
checkpoint: crate::CheckpointKind,
inputs: Vec<crate::AcceptedInjectedTurnInput>,
},
QueuedMessagesCommitted {
messages: Vec<crate::PluginMessage>,
checkpoint: crate::CheckpointKind,
},
Error {
message: String,
},
}
#[async_trait::async_trait]
pub trait TurnActivitySink: Send + Sync {
fn is_noop(&self) -> bool {
false
}
async fn emit(&self, activity: TurnActivity);
}
pub struct NoopTurnActivitySink;
pub static NOOP_TURN_ACTIVITY_SINK: NoopTurnActivitySink = NoopTurnActivitySink;
#[async_trait::async_trait]
impl TurnActivitySink for NoopTurnActivitySink {
fn is_noop(&self) -> bool {
true
}
async fn emit(&self, _activity: TurnActivity) {}
}
pub struct TurnOptions<'a> {
events: Option<&'a dyn EventSink>,
turn_events: Option<&'a dyn TurnActivitySink>,
scoped_effect_controller: ScopedEffectController<'a>,
cancel: CancellationToken,
}
impl<'a> TurnOptions<'a> {
pub fn new(
cancel: CancellationToken,
scoped_effect_controller: ScopedEffectController<'a>,
) -> Self {
Self {
events: None,
turn_events: None,
scoped_effect_controller,
cancel,
}
}
pub fn with_events(mut self, events: &'a dyn EventSink) -> Self {
self.events = Some(events);
self
}
pub fn with_turn_events(mut self, turn_events: &'a dyn TurnActivitySink) -> Self {
self.turn_events = Some(turn_events);
self
}
pub(crate) fn events_or_noop(&self) -> &'a dyn EventSink {
self.events.unwrap_or(&NOOP_EVENT_SINK)
}
pub(crate) fn turn_events_or_noop(&self) -> &'a dyn TurnActivitySink {
self.turn_events.unwrap_or(&NOOP_TURN_ACTIVITY_SINK)
}
pub(crate) fn effect_scope_id(&self) -> &str {
self.scoped_effect_controller.scope_id()
}
pub(crate) fn scoped_effect_controller(&self) -> ScopedEffectController<'a> {
self.scoped_effect_controller.clone()
}
}
enum RuntimeStreamEvent {
Session(SessionEvent),
Turn(TurnActivity),
}
#[derive(Clone)]
pub struct SessionStoreCreateRequest {
pub session_id: String,
pub relation: SessionRelation,
pub policy: SessionPolicy,
}
impl SessionStoreCreateRequest {
pub fn parent_session_id(&self) -> Option<&str> {
self.relation.parent_session_id()
}
}
#[async_trait::async_trait]
pub trait SessionStoreFactory: Send + Sync {
fn durability_tier(&self) -> crate::DurabilityTier {
crate::DurabilityTier::Inline
}
async fn create_store(
&self,
request: &SessionStoreCreateRequest,
) -> Result<Arc<dyn crate::store::RuntimePersistence>, String>;
async fn delete_session(&self, session_id: &str) -> Result<(), String>;
}
pub struct LashRuntime {
pub(in crate::runtime) session: Option<Session>,
pub(in crate::runtime) policy: SessionPolicy,
pub(in crate::runtime) host: RuntimeHost,
pub(in crate::runtime) services: RuntimeServices,
pub(in crate::runtime) state: RuntimeSessionState,
pub(in crate::runtime) runtime_scope_id: Arc<str>,
pub(in crate::runtime) managed_sessions: Arc<Mutex<HashMap<String, RuntimeHandle>>>,
pub(in crate::runtime) managed_turns: Arc<Mutex<HashMap<String, ManagedSessionTurn>>>,
pub(in crate::runtime) protocol_turn_options: crate::ProtocolTurnOptions,
pub(in crate::runtime) shared_token_ledger: Arc<std::sync::Mutex<Vec<TokenLedgerEntry>>>,
pub(in crate::runtime) process_sync_needed: Arc<AtomicBool>,
pub(in crate::runtime) turn_phase_probe: Option<Arc<dyn RuntimeTurnPhaseProbe>>,
pub(in crate::runtime) residency: Residency,
}