Skip to main content

everruns_runtime/
backends.rs

1// Public backend contract for the embedded runtime.
2// Decision: runtime extends core's read-only traits with the minimal write
3// operations needed for seeding and message persistence. Trait upcasting +
4// blanket `Arc<T>: T` impls in core let the runtime forward to atoms without
5// shim wrappers.
6
7use crate::in_memory::{InMemorySessionStorageStore, InMemorySessionStore};
8use async_trait::async_trait;
9use everruns_core::agent::Agent;
10use everruns_core::error::Result;
11use everruns_core::events::Event;
12use everruns_core::harness::Harness;
13use everruns_core::in_memory::{
14    InMemoryAgentStore, InMemoryEventEmitter, InMemoryHarnessStore, InMemoryLlmProviderStore,
15    InMemoryMessageRetriever,
16};
17use everruns_core::message::Message;
18use everruns_core::message_retriever::{InputMessage, MessageRetriever};
19use everruns_core::session::Session;
20use everruns_core::traits::{
21    AgentStore, EventEmitter, HarnessStore, LlmProviderStore, ModelWithProvider, SessionMutator,
22    SessionStorageStore, SessionStore, UserConnectionResolver,
23};
24use everruns_core::typed_id::SessionId;
25use std::sync::Arc;
26
27/// Agent store contract for runtime seeding and lookup.
28#[async_trait]
29pub trait RuntimeAgentStore: AgentStore + Send + Sync {
30    /// Insert or replace an agent definition.
31    async fn add_agent(&self, agent: Agent) -> Result<()>;
32}
33
34/// Harness store contract for runtime seeding and lookup.
35#[async_trait]
36pub trait RuntimeHarnessStore: HarnessStore + Send + Sync {
37    /// Insert or replace a harness definition.
38    async fn add_harness(&self, harness: Harness) -> Result<()>;
39}
40
41/// Session store contract for runtime seeding, lookup, and mutation.
42#[async_trait]
43pub trait RuntimeSessionStore: SessionStore + SessionMutator + Send + Sync {
44    /// Insert or replace a session definition.
45    async fn add_session(&self, session: Session) -> Result<()>;
46}
47
48/// Message store contract for runtime persistence and lookup.
49#[async_trait]
50pub trait RuntimeMessageStore: MessageRetriever + Send + Sync {
51    /// Store a new input message and return the generated message record.
52    async fn add_input_message(
53        &self,
54        session_id: SessionId,
55        input: InputMessage,
56    ) -> Result<Message>;
57
58    /// Persist an existing message record.
59    async fn store_message(&self, session_id: SessionId, message: Message) -> Result<()>;
60}
61
62/// Provider store contract for runtime lookup and default-model configuration.
63#[async_trait]
64pub trait RuntimeProviderStore: LlmProviderStore + Send + Sync {
65    /// Set the runtime default model.
66    async fn set_default_model(&self, model: ModelWithProvider) -> Result<()>;
67}
68
69/// Event sink that supports emission and optional collection.
70///
71/// Every `EventBus` is an `EventEmitter`. Embedders that want to inspect
72/// emitted events override `collected_events`; production hosts inherit the
73/// no-op default.
74#[async_trait]
75pub trait EventBus: EventEmitter {
76    /// Return all collected events. Defaults to an empty `Vec` for buses
77    /// that do not retain events.
78    async fn collected_events(&self) -> Vec<Event> {
79        Vec::new()
80    }
81}
82
83#[async_trait]
84impl<T: EventBus + ?Sized> EventBus for Arc<T> {
85    async fn collected_events(&self) -> Vec<Event> {
86        (**self).collected_events().await
87    }
88}
89
90/// Non-filesystem backend bundle supplied to the embedded runtime.
91///
92/// Use this when you want the public runtime orchestration but your own store
93/// implementations instead of the built-in in-memory ones. Session filesystem
94/// selection is always resolved from `PlatformDefinition`.
95#[derive(Clone)]
96pub struct RuntimeBackends {
97    /// Harness definitions available to the runtime.
98    pub harness_store: Arc<dyn RuntimeHarnessStore>,
99    /// Agent definitions available to the runtime.
100    pub agent_store: Arc<dyn RuntimeAgentStore>,
101    /// Session records and mutable session metadata.
102    pub session_store: Arc<dyn RuntimeSessionStore>,
103    /// Conversation message persistence and retrieval.
104    pub message_store: Arc<dyn RuntimeMessageStore>,
105    /// Model/provider resolution and default-model configuration.
106    pub provider_store: Arc<dyn RuntimeProviderStore>,
107    /// Event sink (emit + optional collection).
108    pub event_bus: Arc<dyn EventBus>,
109    /// Session key/value + secret storage backend.
110    pub storage_store: Arc<dyn SessionStorageStore>,
111    /// Optional resolver for user connection tokens (e.g. GitHub, Daytona).
112    ///
113    /// When set, the runtime exposes it through `ToolContext.connection_resolver`
114    /// so connection-aware capabilities can resolve tokens lazily at tool time.
115    /// `None` (the default) leaves the resolver unset, matching prior behavior.
116    /// There is no in-memory default because a connection resolver implies a
117    /// real credential source the embedder must supply.
118    pub connection_resolver: Option<Arc<dyn UserConnectionResolver>>,
119}
120
121impl RuntimeBackends {
122    /// Backend bundle with in-memory implementations for every store.
123    ///
124    /// Suitable for tests, examples, and the default runtime configuration.
125    /// Use the chainable `with_*` setters to override individual stores.
126    pub fn in_memory() -> Self {
127        let event_bus = Arc::new(InMemoryEventEmitter::new());
128        Self {
129            harness_store: Arc::new(InMemoryHarnessStore::new()),
130            agent_store: Arc::new(InMemoryAgentStore::new()),
131            session_store: Arc::new(InMemorySessionStore::new()),
132            message_store: Arc::new(InMemoryMessageRetriever::new()),
133            provider_store: Arc::new(InMemoryLlmProviderStore::new()),
134            event_bus,
135            storage_store: Arc::new(InMemorySessionStorageStore::new()),
136            connection_resolver: None,
137        }
138    }
139
140    pub fn with_harness_store(mut self, store: Arc<dyn RuntimeHarnessStore>) -> Self {
141        self.harness_store = store;
142        self
143    }
144
145    pub fn with_agent_store(mut self, store: Arc<dyn RuntimeAgentStore>) -> Self {
146        self.agent_store = store;
147        self
148    }
149
150    pub fn with_session_store(mut self, store: Arc<dyn RuntimeSessionStore>) -> Self {
151        self.session_store = store;
152        self
153    }
154
155    pub fn with_message_store(mut self, store: Arc<dyn RuntimeMessageStore>) -> Self {
156        self.message_store = store;
157        self
158    }
159
160    pub fn with_provider_store(mut self, store: Arc<dyn RuntimeProviderStore>) -> Self {
161        self.provider_store = store;
162        self
163    }
164
165    pub fn with_event_bus(mut self, bus: Arc<dyn EventBus>) -> Self {
166        self.event_bus = bus;
167        self
168    }
169
170    pub fn with_storage_store(mut self, store: Arc<dyn SessionStorageStore>) -> Self {
171        self.storage_store = store;
172        self
173    }
174
175    /// Supply a resolver for user connection tokens (e.g. GitHub, Daytona).
176    ///
177    /// The runtime forwards it into `ToolContext` so connection-aware
178    /// capabilities resolve tokens lazily at tool execution time.
179    pub fn with_connection_resolver(mut self, resolver: Arc<dyn UserConnectionResolver>) -> Self {
180        self.connection_resolver = Some(resolver);
181        self
182    }
183}
184
185#[async_trait]
186impl RuntimeAgentStore for InMemoryAgentStore {
187    async fn add_agent(&self, agent: Agent) -> Result<()> {
188        InMemoryAgentStore::add_agent(self, agent).await;
189        Ok(())
190    }
191}
192
193#[async_trait]
194impl RuntimeHarnessStore for InMemoryHarnessStore {
195    async fn add_harness(&self, harness: Harness) -> Result<()> {
196        InMemoryHarnessStore::add_harness(self, harness).await;
197        Ok(())
198    }
199}
200
201#[async_trait]
202impl RuntimeSessionStore for InMemorySessionStore {
203    async fn add_session(&self, session: Session) -> Result<()> {
204        InMemorySessionStore::add_session(self, session).await;
205        Ok(())
206    }
207}
208
209#[async_trait]
210impl RuntimeMessageStore for InMemoryMessageRetriever {
211    async fn add_input_message(
212        &self,
213        session_id: SessionId,
214        input: InputMessage,
215    ) -> Result<Message> {
216        self.add(session_id, input).await
217    }
218
219    async fn store_message(&self, session_id: SessionId, message: Message) -> Result<()> {
220        self.store(session_id, message).await
221    }
222}
223
224#[async_trait]
225impl RuntimeProviderStore for InMemoryLlmProviderStore {
226    async fn set_default_model(&self, model: ModelWithProvider) -> Result<()> {
227        InMemoryLlmProviderStore::set_default_model(self, model).await;
228        Ok(())
229    }
230}
231
232#[async_trait]
233impl EventBus for InMemoryEventEmitter {
234    async fn collected_events(&self) -> Vec<Event> {
235        InMemoryEventEmitter::events(self).await
236    }
237}