Skip to main content

sim_lib_openai_server/storage/
memory.rs

1use std::collections::BTreeMap;
2
3use sim_kernel::{ContentId, Result};
4
5use crate::{
6    content_id::{content_id_for_expr, request_content_id},
7    objects::{GatewayEvent, GatewayRequest, GatewayResponse, GatewayRun},
8    storage::{
9        GatewayBatch, GatewayFile, GatewayResponseObjectStore, GatewayStateStore, GatewayStore,
10        GatewayThread, GatewayThreadMessage, GatewayVectorStore, StoredGatewayResponse,
11    },
12};
13
14/// Snapshot of how many records of each kind a gateway store currently holds.
15#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
16pub struct GatewayStoreCounts {
17    /// Number of stored requests.
18    pub request_count: usize,
19    /// Number of stored runs.
20    pub run_count: usize,
21    /// Number of stored events.
22    pub event_count: usize,
23    /// Number of stored responses.
24    pub response_count: usize,
25    /// Number of stored response objects.
26    pub response_object_count: usize,
27    /// Number of stored file records.
28    pub file_count: usize,
29    /// Number of stored file byte blobs.
30    pub file_bytes_count: usize,
31    /// Number of stored batches.
32    pub batch_count: usize,
33    /// Number of stored threads.
34    pub thread_count: usize,
35    /// Total number of stored thread messages across all threads.
36    pub thread_message_count: usize,
37    /// Number of stored vector stores.
38    pub vector_store_count: usize,
39}
40
41/// In-memory gateway store backed by [`BTreeMap`]s.
42///
43/// Implements [`GatewayStore`], [`GatewayResponseObjectStore`], and
44/// [`GatewayStateStore`]. Intended for tests and single-process use; nothing is
45/// persisted beyond the process.
46#[derive(Clone, Debug, Default)]
47pub struct MemoryGatewayStore {
48    requests: BTreeMap<ContentId, GatewayRequest>,
49    runs: BTreeMap<ContentId, GatewayRun>,
50    events: BTreeMap<ContentId, GatewayEvent>,
51    responses: BTreeMap<ContentId, GatewayResponse>,
52    response_objects: BTreeMap<String, StoredGatewayResponse>,
53    files: BTreeMap<String, GatewayFile>,
54    file_bytes: BTreeMap<String, Vec<u8>>,
55    batches: BTreeMap<String, GatewayBatch>,
56    threads: BTreeMap<String, GatewayThread>,
57    thread_messages: BTreeMap<String, Vec<GatewayThreadMessage>>,
58    vector_stores: BTreeMap<String, GatewayVectorStore>,
59}
60
61impl MemoryGatewayStore {
62    /// Creates an empty in-memory store.
63    pub fn new() -> Self {
64        Self::default()
65    }
66
67    /// Stores a request under its derived content id and returns that id.
68    pub fn put_request_content(&mut self, request: GatewayRequest) -> Result<ContentId> {
69        let id = request_content_id(&request)?;
70        self.put_request(id.clone(), request)?;
71        Ok(id)
72    }
73
74    /// Stores a run under its derived content id and returns that id.
75    pub fn put_run_content(&mut self, run: GatewayRun) -> Result<ContentId> {
76        let id = content_id_for_expr(&run.to_expr())?;
77        self.put_run(id.clone(), run)?;
78        Ok(id)
79    }
80
81    /// Stores an event under its derived content id and returns that id.
82    pub fn put_event_content(&mut self, event: GatewayEvent) -> Result<ContentId> {
83        let id = content_id_for_expr(&event.to_expr())?;
84        self.put_event(id.clone(), event)?;
85        Ok(id)
86    }
87
88    /// Stores a response under its derived content id and returns that id.
89    pub fn put_response_content(&mut self, response: GatewayResponse) -> Result<ContentId> {
90        let id = content_id_for_expr(&response.to_expr())?;
91        self.put_response(id.clone(), response)?;
92        Ok(id)
93    }
94
95    /// Returns a snapshot of the current record counts.
96    pub fn counts(&self) -> GatewayStoreCounts {
97        GatewayStoreCounts {
98            request_count: self.requests.len(),
99            run_count: self.runs.len(),
100            event_count: self.events.len(),
101            response_count: self.responses.len(),
102            response_object_count: self.response_objects.len(),
103            file_count: self.files.len(),
104            file_bytes_count: self.file_bytes.len(),
105            batch_count: self.batches.len(),
106            thread_count: self.threads.len(),
107            thread_message_count: self.thread_messages.values().map(Vec::len).sum(),
108            vector_store_count: self.vector_stores.len(),
109        }
110    }
111
112    /// Returns all stored requests paired with their content ids.
113    pub fn requests(&self) -> Vec<(ContentId, GatewayRequest)> {
114        self.requests
115            .iter()
116            .map(|(id, request)| (id.clone(), request.clone()))
117            .collect()
118    }
119
120    /// Returns all stored runs paired with their content ids.
121    pub fn runs(&self) -> Vec<(ContentId, GatewayRun)> {
122        self.runs
123            .iter()
124            .map(|(id, run)| (id.clone(), run.clone()))
125            .collect()
126    }
127
128    /// Returns the run (with its content id) whose run id matches `run_id`.
129    pub fn run_by_id(&self, run_id: &str) -> Option<(ContentId, GatewayRun)> {
130        self.runs
131            .iter()
132            .find_map(|(id, run)| (run.id() == run_id).then(|| (id.clone(), run.clone())))
133    }
134
135    /// Returns all stored events paired with their content ids.
136    pub fn events(&self) -> Vec<(ContentId, GatewayEvent)> {
137        self.events
138            .iter()
139            .map(|(id, event)| (id.clone(), event.clone()))
140            .collect()
141    }
142}
143
144impl GatewayStore for MemoryGatewayStore {
145    fn put_request(&mut self, id: ContentId, request: GatewayRequest) -> Result<()> {
146        self.requests.insert(id, request);
147        Ok(())
148    }
149
150    fn request(&self, id: &ContentId) -> Option<GatewayRequest> {
151        self.requests.get(id).cloned()
152    }
153
154    fn put_run(&mut self, id: ContentId, run: GatewayRun) -> Result<()> {
155        self.runs.insert(id, run);
156        Ok(())
157    }
158
159    fn run(&self, id: &ContentId) -> Option<GatewayRun> {
160        self.runs.get(id).cloned()
161    }
162
163    fn put_event(&mut self, id: ContentId, event: GatewayEvent) -> Result<()> {
164        self.events.insert(id, event);
165        Ok(())
166    }
167
168    fn event(&self, id: &ContentId) -> Option<GatewayEvent> {
169        self.events.get(id).cloned()
170    }
171
172    fn put_response(&mut self, id: ContentId, response: GatewayResponse) -> Result<()> {
173        self.responses.insert(id, response);
174        Ok(())
175    }
176
177    fn response(&self, id: &ContentId) -> Option<GatewayResponse> {
178        self.responses.get(id).cloned()
179    }
180}
181
182impl GatewayResponseObjectStore for MemoryGatewayStore {
183    fn put_response_object(&mut self, response: StoredGatewayResponse) -> Result<()> {
184        self.responses
185            .insert(response.content_id().clone(), response.response().clone());
186        self.response_objects
187            .insert(response.response_id().to_owned(), response);
188        Ok(())
189    }
190
191    fn response_object(&self, response_id: &str) -> Option<StoredGatewayResponse> {
192        self.response_objects.get(response_id).cloned()
193    }
194}
195
196impl GatewayStateStore for MemoryGatewayStore {
197    fn put_file(&mut self, file: GatewayFile, bytes: Vec<u8>) -> Result<()> {
198        self.file_bytes.insert(file.id().to_owned(), bytes);
199        self.files.insert(file.id().to_owned(), file);
200        Ok(())
201    }
202
203    fn file(&self, file_id: &str) -> Option<GatewayFile> {
204        self.files.get(file_id).cloned()
205    }
206
207    fn file_bytes(&self, file_id: &str) -> Option<Vec<u8>> {
208        self.file_bytes.get(file_id).cloned()
209    }
210
211    fn put_batch(&mut self, batch: GatewayBatch) -> Result<()> {
212        self.batches.insert(batch.id().to_owned(), batch);
213        Ok(())
214    }
215
216    fn batch(&self, batch_id: &str) -> Option<GatewayBatch> {
217        self.batches.get(batch_id).cloned()
218    }
219
220    fn put_thread(&mut self, thread: GatewayThread) -> Result<()> {
221        self.threads.insert(thread.id().to_owned(), thread);
222        Ok(())
223    }
224
225    fn thread(&self, thread_id: &str) -> Option<GatewayThread> {
226        self.threads.get(thread_id).cloned()
227    }
228
229    fn put_thread_message(&mut self, message: GatewayThreadMessage) -> Result<()> {
230        self.thread_messages
231            .entry(message.thread_id().to_owned())
232            .or_default()
233            .push(message);
234        Ok(())
235    }
236
237    fn thread_messages(&self, thread_id: &str) -> Vec<GatewayThreadMessage> {
238        self.thread_messages
239            .get(thread_id)
240            .cloned()
241            .unwrap_or_default()
242    }
243
244    fn put_vector_store(&mut self, vector_store: GatewayVectorStore) -> Result<()> {
245        self.vector_stores
246            .insert(vector_store.id().to_owned(), vector_store);
247        Ok(())
248    }
249
250    fn vector_store(&self, vector_store_id: &str) -> Option<GatewayVectorStore> {
251        self.vector_stores.get(vector_store_id).cloned()
252    }
253}