Skip to main content

everruns_host/
backends.rs

1// Public backend contract for the embedded host.
2// Seeding stores remain writable host configuration. Conversation history is
3// different: canonical events are the only write path and EventHistory is the
4// rebuildable read projection.
5
6use crate::SessionMutator;
7use crate::events::{EventLog, EventSink, InMemoryEventLog, NoopEventSink};
8use crate::in_memory::{
9    InMemoryAgentStore, InMemoryCompactionCheckpointStore, InMemoryHarnessStore,
10    InMemoryProviderStore, InMemorySessionStorageStore, InMemorySessionStore,
11};
12use async_trait::async_trait;
13use everruns_core::agent_definition::AgentDefinition;
14use everruns_core::harness_definition::HarnessDefinition;
15use everruns_core::session::ExecutionSession;
16use everruns_core::session_task::SessionTaskRegistry;
17use everruns_core::{
18    connection_services::UserConnectionResolver, execution_loading::AgentStore,
19    execution_loading::HarnessStore, execution_loading::SessionStore,
20    provider_resolution::ProviderStore, session_services::SessionScheduleStore,
21    session_services::SessionStorageStore,
22};
23use everruns_provider::error::Result;
24use everruns_provider::model_spec::ModelSpec;
25use everruns_provider::typed_id::HarnessId;
26use std::sync::Arc;
27
28/// Factory producing a per-org [`SessionScheduleStore`]. Embedders that have a
29/// single global store can ignore the `org_id` argument and return the same
30/// `Arc` every time.
31pub type ScheduleStoreFactory = Arc<dyn Fn(i64) -> Arc<dyn SessionScheduleStore> + Send + Sync>;
32
33/// Agent store contract for runtime seeding and lookup.
34///
35/// Seeds portable [`AgentDefinition`] values (EVE-877): the embedded host
36/// carries no stored Agent persistence records.
37#[async_trait]
38pub trait RuntimeAgentStore: AgentStore + Send + Sync {
39    /// Insert or replace an agent definition.
40    async fn add_agent(&self, agent: AgentDefinition) -> Result<()>;
41}
42
43/// Harness store contract for runtime seeding and lookup.
44///
45/// Seeds portable [`HarnessDefinition`] values under an embedder-chosen id
46/// (EVE-881): the embedded host carries no stored Harness persistence records.
47#[async_trait]
48pub trait RuntimeHarnessStore: HarnessStore + Send + Sync {
49    /// Insert or replace a harness definition under the given id.
50    async fn add_harness(&self, harness_id: HarnessId, harness: HarnessDefinition) -> Result<()>;
51}
52
53/// Session store contract for runtime seeding, lookup, and mutation.
54///
55/// Seeds portable [`ExecutionSession`] values (EVE-882): the embedded host
56/// carries no stored Session persistence records.
57#[async_trait]
58pub trait RuntimeSessionStore: SessionStore + SessionMutator + Send + Sync {
59    /// Insert or replace a session's portable execution view.
60    async fn add_session(&self, session: ExecutionSession) -> Result<()>;
61}
62
63/// Provider store contract for runtime lookup and default-model configuration.
64#[async_trait]
65pub trait RuntimeProviderStore: ProviderStore + Send + Sync {
66    /// Set the runtime default credential-free model selection.
67    async fn set_default_model_spec(&self, model: ModelSpec) -> Result<()>;
68}
69
70/// Non-filesystem backend bundle supplied to an execution host.
71///
72/// Use this when you want the public runtime orchestration but your own store
73/// implementations instead of the built-in in-memory ones. Session filesystem
74/// selection is always resolved from `HostComposition`.
75#[derive(Clone)]
76pub struct HostBackends {
77    /// Optional shared fenced journal for native asynchronous tool execution.
78    pub native_async_store: Option<Arc<dyn everruns_core::native_async_store::NativeAsyncStore>>,
79    /// Harness definitions available to the runtime.
80    pub harness_store: Arc<dyn RuntimeHarnessStore>,
81    /// Agent definitions available to the runtime.
82    pub agent_store: Arc<dyn RuntimeAgentStore>,
83    /// Session records and mutable session metadata.
84    pub session_store: Arc<dyn RuntimeSessionStore>,
85    /// Coherent canonical event log. This is the sole conversation write path.
86    pub event_log: Arc<dyn EventLog>,
87    /// Durable replacement context used to reconstruct compacted model input.
88    pub compaction_checkpoint_store: Arc<dyn everruns_core::CompactionCheckpointStore>,
89    /// Model/provider resolution and default-model configuration.
90    pub provider_store: Arc<dyn RuntimeProviderStore>,
91    /// Optional, non-blocking live observation sink notified after commit.
92    pub event_sink: Arc<dyn EventSink>,
93    /// Session key/value + secret storage backend.
94    pub storage_store: Arc<dyn SessionStorageStore>,
95    /// Optional resolver for user connection tokens (e.g. GitHub, Daytona).
96    ///
97    /// When set, the runtime exposes it through `ToolContext.connection_resolver`
98    /// so connection-aware capabilities can resolve tokens lazily at tool time.
99    /// `None` (the default) leaves the resolver unset, matching prior behavior.
100    /// There is no in-memory default because a connection resolver implies a
101    /// real credential source the embedder must supply.
102    pub connection_resolver: Option<Arc<dyn UserConnectionResolver>>,
103    /// Optional session-task registry injected into the act path so background
104    /// tools, subagents, and monitors persist their lifecycle. `None` (the
105    /// default) leaves `RuntimeHostAdapter::session_task_registry` returning
106    /// `None`, matching prior in-memory behavior.
107    pub session_task_registry: Option<Arc<dyn SessionTaskRegistry>>,
108    /// Optional per-org schedule store factory. `None` (the default) leaves
109    /// `RuntimeHostAdapter::schedule_store` returning `None`.
110    pub schedule_store_factory: Option<ScheduleStoreFactory>,
111    /// Optional higher-level typed services supplied to tool contexts.
112    pub tool_context_extensions_factory: Option<crate::ToolContextExtensionsFactory>,
113    /// Optional neutral subagent delegate supplied by a higher-level host.
114    pub subagent_delegate_factory: Option<crate::SubagentDelegateFactory>,
115    /// Optional higher-level tool augmentation policy.
116    pub tool_augmentor: Option<Arc<dyn crate::HostToolAugmentor>>,
117}
118
119impl HostBackends {
120    /// Backend bundle with in-memory implementations for every store.
121    ///
122    /// Suitable for tests, examples, and the default runtime configuration.
123    /// Use the chainable `with_*` setters to override individual stores.
124    pub fn in_memory() -> Self {
125        Self {
126            harness_store: Arc::new(InMemoryHarnessStore::new()),
127            agent_store: Arc::new(InMemoryAgentStore::new()),
128            session_store: Arc::new(InMemorySessionStore::new()),
129            event_log: Arc::new(InMemoryEventLog::new()),
130            native_async_store: None,
131            compaction_checkpoint_store: Arc::new(InMemoryCompactionCheckpointStore::default()),
132            provider_store: Arc::new(InMemoryProviderStore::new()),
133            event_sink: Arc::new(NoopEventSink),
134            storage_store: Arc::new(InMemorySessionStorageStore::new()),
135            connection_resolver: None,
136            session_task_registry: None,
137            schedule_store_factory: None,
138            tool_context_extensions_factory: None,
139            subagent_delegate_factory: None,
140            tool_augmentor: None,
141        }
142    }
143
144    pub fn with_harness_store(mut self, store: Arc<dyn RuntimeHarnessStore>) -> Self {
145        self.harness_store = store;
146        self
147    }
148
149    pub fn with_agent_store(mut self, store: Arc<dyn RuntimeAgentStore>) -> Self {
150        self.agent_store = store;
151        self
152    }
153
154    pub fn with_session_store(mut self, store: Arc<dyn RuntimeSessionStore>) -> Self {
155        self.session_store = store;
156        self
157    }
158
159    /// Replace the coherent canonical event log.
160    pub fn with_event_log(mut self, log: Arc<dyn EventLog>) -> Self {
161        self.event_log = log;
162        self
163    }
164
165    pub fn with_native_async_store(
166        mut self,
167        store: Arc<dyn everruns_core::native_async_store::NativeAsyncStore>,
168    ) -> Self {
169        self.native_async_store = Some(store);
170        self
171    }
172
173    pub fn with_compaction_checkpoint_store(
174        mut self,
175        store: Arc<dyn everruns_core::CompactionCheckpointStore>,
176    ) -> Self {
177        self.compaction_checkpoint_store = store;
178        self
179    }
180
181    pub fn with_provider_store(mut self, store: Arc<dyn RuntimeProviderStore>) -> Self {
182        self.provider_store = store;
183        self
184    }
185
186    /// Install a non-blocking post-commit observation sink.
187    pub fn with_event_sink(mut self, sink: Arc<dyn EventSink>) -> Self {
188        self.event_sink = sink;
189        self
190    }
191
192    pub fn with_storage_store(mut self, store: Arc<dyn SessionStorageStore>) -> Self {
193        self.storage_store = store;
194        self
195    }
196
197    /// Supply a resolver for user connection tokens (e.g. GitHub, Daytona).
198    ///
199    /// The runtime forwards it into `ToolContext` so connection-aware
200    /// capabilities resolve tokens lazily at tool execution time.
201    pub fn with_connection_resolver(mut self, resolver: Arc<dyn UserConnectionResolver>) -> Self {
202        self.connection_resolver = Some(resolver);
203        self
204    }
205
206    /// Inject a session-task registry so background tools / subagents / monitors
207    /// persist their lifecycle through the act path. Additive: leaving this unset
208    /// keeps the prior behavior (the adapter returns `None`).
209    pub fn with_session_task_registry(mut self, registry: Arc<dyn SessionTaskRegistry>) -> Self {
210        self.session_task_registry = Some(registry);
211        self
212    }
213
214    /// Inject a per-org schedule store factory. The closure is invoked with the
215    /// internal org id each time the act path needs a schedule store.
216    pub fn with_schedule_store_factory(mut self, factory: ScheduleStoreFactory) -> Self {
217        self.schedule_store_factory = Some(factory);
218        self
219    }
220
221    /// Inject type-erased tool services supplied by a higher-level host.
222    pub fn with_tool_context_extensions_factory(
223        mut self,
224        factory: crate::ToolContextExtensionsFactory,
225    ) -> Self {
226        self.tool_context_extensions_factory = Some(factory);
227        self
228    }
229
230    /// Inject a neutral subagent delegate supplied by a higher-level host.
231    pub fn with_subagent_delegate_factory(
232        mut self,
233        factory: crate::SubagentDelegateFactory,
234    ) -> Self {
235        self.subagent_delegate_factory = Some(factory);
236        self
237    }
238
239    /// Inject higher-level turn-dependent tools.
240    pub fn with_tool_augmentor(mut self, augmentor: Arc<dyn crate::HostToolAugmentor>) -> Self {
241        self.tool_augmentor = Some(augmentor);
242        self
243    }
244}
245
246#[async_trait]
247impl RuntimeAgentStore for InMemoryAgentStore {
248    async fn add_agent(&self, agent: AgentDefinition) -> Result<()> {
249        InMemoryAgentStore::add_agent(self, agent).await;
250        Ok(())
251    }
252}
253
254#[async_trait]
255impl RuntimeHarnessStore for InMemoryHarnessStore {
256    async fn add_harness(&self, harness_id: HarnessId, harness: HarnessDefinition) -> Result<()> {
257        InMemoryHarnessStore::add_harness(self, harness_id, harness).await;
258        Ok(())
259    }
260}
261
262#[async_trait]
263impl RuntimeSessionStore for InMemorySessionStore {
264    async fn add_session(&self, session: ExecutionSession) -> Result<()> {
265        InMemorySessionStore::add_session(self, session).await;
266        Ok(())
267    }
268}
269
270#[async_trait]
271impl RuntimeProviderStore for InMemoryProviderStore {
272    async fn set_default_model_spec(&self, model: ModelSpec) -> Result<()> {
273        InMemoryProviderStore::set_default_model_spec(self, model).await;
274        Ok(())
275    }
276}