stratus-engine 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stratus_engine-0.2.0/LICENSE +21 -0
- stratus_engine-0.2.0/PKG-INFO +313 -0
- stratus_engine-0.2.0/README.md +269 -0
- stratus_engine-0.2.0/pyproject.toml +35 -0
- stratus_engine-0.2.0/setup.cfg +4 -0
- stratus_engine-0.2.0/src/stratus_engine/__init__.py +57 -0
- stratus_engine-0.2.0/src/stratus_engine/config.py +66 -0
- stratus_engine-0.2.0/src/stratus_engine/core/__init__.py +4 -0
- stratus_engine-0.2.0/src/stratus_engine/core/engine.py +138 -0
- stratus_engine-0.2.0/src/stratus_engine/core/models.py +118 -0
- stratus_engine-0.2.0/src/stratus_engine/core/protocols.py +14 -0
- stratus_engine-0.2.0/src/stratus_engine/embeddings.py +59 -0
- stratus_engine-0.2.0/src/stratus_engine/evaluation/__init__.py +4 -0
- stratus_engine-0.2.0/src/stratus_engine/evaluation/benchmarks.py +88 -0
- stratus_engine-0.2.0/src/stratus_engine/evaluation/datasets.py +21 -0
- stratus_engine-0.2.0/src/stratus_engine/extraction/__init__.py +3 -0
- stratus_engine-0.2.0/src/stratus_engine/extraction/extractors.py +142 -0
- stratus_engine-0.2.0/src/stratus_engine/metrics.py +88 -0
- stratus_engine-0.2.0/src/stratus_engine/openai_chat.py +68 -0
- stratus_engine-0.2.0/src/stratus_engine/planning/__init__.py +3 -0
- stratus_engine-0.2.0/src/stratus_engine/planning/planners.py +95 -0
- stratus_engine-0.2.0/src/stratus_engine/providers/__init__.py +3 -0
- stratus_engine-0.2.0/src/stratus_engine/providers/adapters.py +82 -0
- stratus_engine-0.2.0/src/stratus_engine/retrieval/__init__.py +3 -0
- stratus_engine-0.2.0/src/stratus_engine/retrieval/rankers.py +93 -0
- stratus_engine-0.2.0/src/stratus_engine/storage/__init__.py +7 -0
- stratus_engine-0.2.0/src/stratus_engine/storage/memories/__init__.py +4 -0
- stratus_engine-0.2.0/src/stratus_engine/storage/memories/chroma.py +132 -0
- stratus_engine-0.2.0/src/stratus_engine/storage/memories/memory.py +82 -0
- stratus_engine-0.2.0/src/stratus_engine/storage/sessions/__init__.py +3 -0
- stratus_engine-0.2.0/src/stratus_engine/storage/sessions/adapters.py +142 -0
- stratus_engine-0.2.0/src/stratus_engine.egg-info/PKG-INFO +313 -0
- stratus_engine-0.2.0/src/stratus_engine.egg-info/SOURCES.txt +40 -0
- stratus_engine-0.2.0/src/stratus_engine.egg-info/dependency_links.txt +1 -0
- stratus_engine-0.2.0/src/stratus_engine.egg-info/requires.txt +36 -0
- stratus_engine-0.2.0/src/stratus_engine.egg-info/top_level.txt +1 -0
- stratus_engine-0.2.0/tests/test_chroma_retrieval.py +23 -0
- stratus_engine-0.2.0/tests/test_config.py +9 -0
- stratus_engine-0.2.0/tests/test_engine.py +81 -0
- stratus_engine-0.2.0/tests/test_evaluation.py +14 -0
- stratus_engine-0.2.0/tests/test_planner.py +29 -0
- stratus_engine-0.2.0/tests/test_retrieval.py +37 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aagam Chhajer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stratus-engine
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Two-layer memory infrastructure for LLM applications.
|
|
5
|
+
Keywords: llm,memory,rag,vector-database,agents
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Intended Audience :: Developers
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: pydantic>=2.7
|
|
15
|
+
Provides-Extra: mongo
|
|
16
|
+
Requires-Dist: pymongo>=4.8; extra == "mongo"
|
|
17
|
+
Provides-Extra: vector
|
|
18
|
+
Requires-Dist: chromadb>=0.5.0; extra == "vector"
|
|
19
|
+
Provides-Extra: openai
|
|
20
|
+
Requires-Dist: openai>=1.40.0; extra == "openai"
|
|
21
|
+
Requires-Dist: tiktoken>=0.7.0; extra == "openai"
|
|
22
|
+
Requires-Dist: python-dotenv>=1.0; extra == "openai"
|
|
23
|
+
Provides-Extra: anthropic
|
|
24
|
+
Requires-Dist: anthropic>=0.40.0; extra == "anthropic"
|
|
25
|
+
Provides-Extra: all
|
|
26
|
+
Requires-Dist: anthropic>=0.40.0; extra == "all"
|
|
27
|
+
Requires-Dist: chromadb>=0.5.0; extra == "all"
|
|
28
|
+
Requires-Dist: openai>=1.40.0; extra == "all"
|
|
29
|
+
Requires-Dist: pymongo>=4.8; extra == "all"
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0; extra == "all"
|
|
31
|
+
Requires-Dist: tiktoken>=0.7.0; extra == "all"
|
|
32
|
+
Provides-Extra: demo
|
|
33
|
+
Requires-Dist: chromadb>=0.5.0; extra == "demo"
|
|
34
|
+
Requires-Dist: openai>=1.40.0; extra == "demo"
|
|
35
|
+
Requires-Dist: pymongo>=4.8; extra == "demo"
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == "demo"
|
|
37
|
+
Requires-Dist: python-dotenv>=1.0; extra == "demo"
|
|
38
|
+
Requires-Dist: tiktoken>=0.7.0; extra == "demo"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
42
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
# Stratus Engine
|
|
46
|
+
|
|
47
|
+
Stratus Engine is a pragmatic memory layer for LLM applications. The MVP keeps
|
|
48
|
+
active conversations in MongoDB, promotes only useful facts into long-term
|
|
49
|
+
memory in Chroma, and warms relevant context when a session is reopened.
|
|
50
|
+
|
|
51
|
+
The point is simple: do not make vector search behave like a chat log. Keep the
|
|
52
|
+
active session close, then send only valuable extracted memories to the long-term
|
|
53
|
+
vector store.
|
|
54
|
+
|
|
55
|
+
## Install and use
|
|
56
|
+
|
|
57
|
+
Install the minimal, dependency-free core:
|
|
58
|
+
|
|
59
|
+
```powershell
|
|
60
|
+
pip install stratus-engine
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or install a backend combination from source:
|
|
64
|
+
|
|
65
|
+
```powershell
|
|
66
|
+
pip install -e ".[mongo,vector,openai]"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The public API starts with one factory:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from stratus_engine import StratusConfig, create_engine
|
|
73
|
+
|
|
74
|
+
engine = create_engine() # local, in-memory, no API key or Docker needed
|
|
75
|
+
session = engine.create_session("user_123", title="Product assistant")
|
|
76
|
+
|
|
77
|
+
engine.append_user_message(session.id, "I prefer React for dashboards.")
|
|
78
|
+
engine.extract_memories(session.id)
|
|
79
|
+
|
|
80
|
+
context = engine.build_context(session.id, "What frontend preference do I have?")
|
|
81
|
+
print(context.as_prompt_sections())
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Switch to persisted sessions and Chroma vector memory without changing the
|
|
85
|
+
application flow:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
engine = create_engine(StratusConfig(
|
|
89
|
+
session_backend="mongo",
|
|
90
|
+
memory_backend="chroma",
|
|
91
|
+
use_openai=True,
|
|
92
|
+
))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
For advanced setup, import the storage and provider adapters directly. The
|
|
96
|
+
factory is the stable plug-and-play path; the internal modules are intentionally
|
|
97
|
+
more configurable and may evolve faster.
|
|
98
|
+
|
|
99
|
+
## The Private Kitchen Analogy
|
|
100
|
+
|
|
101
|
+
Think of the LLM as a chef serving a customer. The temporary memory layer is
|
|
102
|
+
the kitchen: active conversation context and likely-useful memories are kept
|
|
103
|
+
close for fast service. The permanent vector database is the warehouse: it
|
|
104
|
+
stores durable facts that are available when needed.
|
|
105
|
+
|
|
106
|
+
When a session reopens, Stratus prepares the kitchen by running intelligent
|
|
107
|
+
warmup queries and moving relevant memories into the temporary layer. If a new
|
|
108
|
+
request needs something that is not already there, the engine makes an ad-hoc
|
|
109
|
+
trip to permanent memory—like fetching a special ingredient from the
|
|
110
|
+
warehouse. This keeps vector search useful without making it the default path
|
|
111
|
+
for every message.
|
|
112
|
+
|
|
113
|
+
## Current MVP
|
|
114
|
+
|
|
115
|
+
- MongoDB session layer for active conversations
|
|
116
|
+
- Structured memory extraction from user messages
|
|
117
|
+
- Chroma vector DB adapter for long-term memories
|
|
118
|
+
- Optional OpenAI embeddings and live answer generation
|
|
119
|
+
- Session reopen cache warming with predefined queries
|
|
120
|
+
- Context assembly that prefers active session state before ad-hoc recall
|
|
121
|
+
- Metrics for estimated context tokens, retrieved memories, and relevance
|
|
122
|
+
- Benchmark script for vector-search reduction
|
|
123
|
+
- Runnable local demo and tests
|
|
124
|
+
|
|
125
|
+
## Quick Start
|
|
126
|
+
|
|
127
|
+
```powershell
|
|
128
|
+
python -m venv .venv
|
|
129
|
+
.\.venv\Scripts\Activate.ps1
|
|
130
|
+
pip install -e ".[dev]"
|
|
131
|
+
python examples/demo.py
|
|
132
|
+
python examples/benchmark.py
|
|
133
|
+
pytest
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For an LLM-powered demo, copy `.env.example` to `.env`, add your
|
|
137
|
+
`OPENAI_API_KEY`, and run `python examples/live_openai_demo.py`. The offline
|
|
138
|
+
tests and local demo do not require an API key.
|
|
139
|
+
|
|
140
|
+
The default warmup planner is deterministic and derives retrieval intents from
|
|
141
|
+
the session. You can opt into `OpenAIWarmupPlanner` when you want the model to
|
|
142
|
+
produce more nuanced, structured retrieval plans; the engine keeps the
|
|
143
|
+
deterministic planner as a safe fallback.
|
|
144
|
+
|
|
145
|
+
## Model providers
|
|
146
|
+
|
|
147
|
+
The engine is provider-agnostic. The memory pipeline depends on small Python
|
|
148
|
+
protocols, while model and embedding clients are optional adapters.
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from stratus_engine import OllamaConversationClient
|
|
152
|
+
|
|
153
|
+
llm = OllamaConversationClient(model="llama3.2")
|
|
154
|
+
result = llm.respond(prompt="What do you remember?", context=context)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Available adapters include OpenAI, Anthropic Claude, and local Ollama. Ollama
|
|
158
|
+
requires a running Ollama server and a pulled model; Claude requires
|
|
159
|
+
`pip install -e ".[anthropic]"`. The deterministic local mode remains useful
|
|
160
|
+
for tests and demos without any model provider.
|
|
161
|
+
|
|
162
|
+
## Package layout
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
stratus_engine/
|
|
166
|
+
├── core/ public engine and domain models
|
|
167
|
+
├── storage/ MongoDB, Chroma, and in-memory adapters
|
|
168
|
+
├── providers/ model and embedding integrations
|
|
169
|
+
├── retrieval/ candidate ranking and deduplication
|
|
170
|
+
├── extraction/ memory extraction strategies
|
|
171
|
+
└── planning/ dynamic session warmup planning
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Chroma retrieval is intentionally staged: it fetches a wider candidate pool,
|
|
175
|
+
combines vector similarity with lexical coverage and memory quality, applies
|
|
176
|
+
recency/access signals, removes near-duplicate facts, and only then returns the
|
|
177
|
+
final context. This is durable-memory retrieval, not a naive every-message RAG
|
|
178
|
+
loop.
|
|
179
|
+
|
|
180
|
+
## Evaluation and comparison
|
|
181
|
+
|
|
182
|
+
Run the reproducible local comparison:
|
|
183
|
+
|
|
184
|
+
```powershell
|
|
185
|
+
python examples/evaluate_architectures.py
|
|
186
|
+
python examples/end_to_end_simulation.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The evaluation compares three explicit strategies:
|
|
190
|
+
|
|
191
|
+
| Strategy | What it does | Main tradeoff |
|
|
192
|
+
| --- | --- | --- |
|
|
193
|
+
| `full_context` | Sends every durable fact on every turn | High context cost, no retrieval calls |
|
|
194
|
+
| `naive_retrieval` | Runs retrieval for every turn | More retrieval calls and noisy context |
|
|
195
|
+
| `hybrid_warmup` | Warms likely facts once and gates ad-hoc recall | More orchestration, lower repeated retrieval |
|
|
196
|
+
|
|
197
|
+
The pack reports recall, vector-call count, and estimated context tokens. It is
|
|
198
|
+
intentionally small and inspectable so contributors can understand every case.
|
|
199
|
+
It is not presented as a universal benchmark. Production evaluations should add
|
|
200
|
+
domain-specific conversations, adversarial queries, stale facts, conflicting
|
|
201
|
+
facts, multilingual data, and human or LLM-judged answer quality.
|
|
202
|
+
|
|
203
|
+
The end-to-end simulation shows the complete lifecycle offline: session writes,
|
|
204
|
+
durable memory promotion, engine recreation, login-time warmup, continued work,
|
|
205
|
+
retrieval traces, and context analytics. Its traced in-memory store can be
|
|
206
|
+
replaced with `ChromaLongTermMemoryStore` without changing the engine flow.
|
|
207
|
+
|
|
208
|
+
For a live interactive version, run:
|
|
209
|
+
|
|
210
|
+
```powershell
|
|
211
|
+
python examples/live_session_simulation.py --provider openai
|
|
212
|
+
python examples/live_session_simulation.py --provider ollama --model llama3.2
|
|
213
|
+
python examples/live_session_simulation.py --provider offline
|
|
214
|
+
python examples/live_session_simulation.py --provider openai --backend chroma
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The live simulation recreates the engine after seed memories are promoted, then
|
|
218
|
+
accepts your questions and prints the actual model response plus retrieval
|
|
219
|
+
reason, warmed memories, recalled memories, estimated tokens, and relevance.
|
|
220
|
+
Use `--backend chroma` with the Docker Chroma service to exercise a real vector
|
|
221
|
+
database; the default `memory` backend is faster for repeatable local demos.
|
|
222
|
+
|
|
223
|
+
## Docker Services
|
|
224
|
+
|
|
225
|
+
Start MongoDB and Chroma:
|
|
226
|
+
|
|
227
|
+
```powershell
|
|
228
|
+
docker compose up -d mongo chroma
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Chroma Vector Demo
|
|
232
|
+
|
|
233
|
+
This uses MongoDB for sessions and Chroma for long-term memory. It uses local
|
|
234
|
+
hash embeddings, so it does not need an OpenAI key.
|
|
235
|
+
|
|
236
|
+
```powershell
|
|
237
|
+
pip install -e ".[mongo,vector,dev]"
|
|
238
|
+
python examples/chroma_demo.py
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Live OpenAI Demo
|
|
242
|
+
|
|
243
|
+
This uses MongoDB, Chroma, OpenAI embeddings, and an OpenAI chat completion. It
|
|
244
|
+
prints context metrics and API token usage.
|
|
245
|
+
|
|
246
|
+
Create a local `.env` file with `OPENAI_API_KEY` set to your key. The live demo
|
|
247
|
+
loads that file automatically, or you can set the variable in the current
|
|
248
|
+
PowerShell session before running it.
|
|
249
|
+
|
|
250
|
+
```powershell
|
|
251
|
+
pip install -e ".[demo]"
|
|
252
|
+
$env:OPENAI_API_KEY = "your_api_key_here"
|
|
253
|
+
python examples/live_openai_demo.py
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Benchmark
|
|
257
|
+
|
|
258
|
+
The benchmark compares naive retrieval, where every prompt would run vector
|
|
259
|
+
search, against Stratus's gated recall.
|
|
260
|
+
|
|
261
|
+
```powershell
|
|
262
|
+
python examples/benchmark.py
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
It prints vector-search reduction, average estimated context tokens, average
|
|
266
|
+
memory relevance, and a prompt-level trace.
|
|
267
|
+
|
|
268
|
+
## Programmatic Usage
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
from stratus_engine import (
|
|
272
|
+
ChromaLongTermMemoryStore,
|
|
273
|
+
MongoSessionStore,
|
|
274
|
+
OpenAIEmbeddingProvider,
|
|
275
|
+
StratusEngine,
|
|
276
|
+
analyze_context,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
engine = StratusEngine(
|
|
280
|
+
session_store=MongoSessionStore("mongodb://localhost:27017"),
|
|
281
|
+
memory_store=ChromaLongTermMemoryStore(
|
|
282
|
+
host="localhost",
|
|
283
|
+
port=8000,
|
|
284
|
+
embedding_provider=OpenAIEmbeddingProvider(),
|
|
285
|
+
),
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
session = engine.create_session("user_123", title="Demo")
|
|
289
|
+
engine.append_user_message(session.id, "I prefer React over Angular.")
|
|
290
|
+
engine.extract_memories(session.id)
|
|
291
|
+
engine.reopen_session(session.id)
|
|
292
|
+
|
|
293
|
+
context = engine.build_context(session.id, "What frontend preference do I have?")
|
|
294
|
+
metrics = analyze_context("What frontend preference do I have?", context)
|
|
295
|
+
print(context.as_prompt_sections())
|
|
296
|
+
print(metrics)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Demo Story
|
|
300
|
+
|
|
301
|
+
The demo shows five important behaviors:
|
|
302
|
+
|
|
303
|
+
1. Active conversation context is read from the session layer.
|
|
304
|
+
2. Useful facts are extracted into structured memories.
|
|
305
|
+
3. Chroma retrieves long-term memories.
|
|
306
|
+
4. Reopening a session warms relevant context before the user asks anything.
|
|
307
|
+
5. Metrics show token footprint and retrieval relevance.
|
|
308
|
+
|
|
309
|
+
## Design Direction
|
|
310
|
+
|
|
311
|
+
Next steps are intentionally narrow: replace the heuristic extractor with an
|
|
312
|
+
LLM-backed extractor, add background extraction, and add a small evaluation set
|
|
313
|
+
that proves latency, recall quality, and reduced vector-search usage.
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Stratus Engine
|
|
2
|
+
|
|
3
|
+
Stratus Engine is a pragmatic memory layer for LLM applications. The MVP keeps
|
|
4
|
+
active conversations in MongoDB, promotes only useful facts into long-term
|
|
5
|
+
memory in Chroma, and warms relevant context when a session is reopened.
|
|
6
|
+
|
|
7
|
+
The point is simple: do not make vector search behave like a chat log. Keep the
|
|
8
|
+
active session close, then send only valuable extracted memories to the long-term
|
|
9
|
+
vector store.
|
|
10
|
+
|
|
11
|
+
## Install and use
|
|
12
|
+
|
|
13
|
+
Install the minimal, dependency-free core:
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
pip install stratus-engine
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or install a backend combination from source:
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
pip install -e ".[mongo,vector,openai]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The public API starts with one factory:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from stratus_engine import StratusConfig, create_engine
|
|
29
|
+
|
|
30
|
+
engine = create_engine() # local, in-memory, no API key or Docker needed
|
|
31
|
+
session = engine.create_session("user_123", title="Product assistant")
|
|
32
|
+
|
|
33
|
+
engine.append_user_message(session.id, "I prefer React for dashboards.")
|
|
34
|
+
engine.extract_memories(session.id)
|
|
35
|
+
|
|
36
|
+
context = engine.build_context(session.id, "What frontend preference do I have?")
|
|
37
|
+
print(context.as_prompt_sections())
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Switch to persisted sessions and Chroma vector memory without changing the
|
|
41
|
+
application flow:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
engine = create_engine(StratusConfig(
|
|
45
|
+
session_backend="mongo",
|
|
46
|
+
memory_backend="chroma",
|
|
47
|
+
use_openai=True,
|
|
48
|
+
))
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For advanced setup, import the storage and provider adapters directly. The
|
|
52
|
+
factory is the stable plug-and-play path; the internal modules are intentionally
|
|
53
|
+
more configurable and may evolve faster.
|
|
54
|
+
|
|
55
|
+
## The Private Kitchen Analogy
|
|
56
|
+
|
|
57
|
+
Think of the LLM as a chef serving a customer. The temporary memory layer is
|
|
58
|
+
the kitchen: active conversation context and likely-useful memories are kept
|
|
59
|
+
close for fast service. The permanent vector database is the warehouse: it
|
|
60
|
+
stores durable facts that are available when needed.
|
|
61
|
+
|
|
62
|
+
When a session reopens, Stratus prepares the kitchen by running intelligent
|
|
63
|
+
warmup queries and moving relevant memories into the temporary layer. If a new
|
|
64
|
+
request needs something that is not already there, the engine makes an ad-hoc
|
|
65
|
+
trip to permanent memory—like fetching a special ingredient from the
|
|
66
|
+
warehouse. This keeps vector search useful without making it the default path
|
|
67
|
+
for every message.
|
|
68
|
+
|
|
69
|
+
## Current MVP
|
|
70
|
+
|
|
71
|
+
- MongoDB session layer for active conversations
|
|
72
|
+
- Structured memory extraction from user messages
|
|
73
|
+
- Chroma vector DB adapter for long-term memories
|
|
74
|
+
- Optional OpenAI embeddings and live answer generation
|
|
75
|
+
- Session reopen cache warming with predefined queries
|
|
76
|
+
- Context assembly that prefers active session state before ad-hoc recall
|
|
77
|
+
- Metrics for estimated context tokens, retrieved memories, and relevance
|
|
78
|
+
- Benchmark script for vector-search reduction
|
|
79
|
+
- Runnable local demo and tests
|
|
80
|
+
|
|
81
|
+
## Quick Start
|
|
82
|
+
|
|
83
|
+
```powershell
|
|
84
|
+
python -m venv .venv
|
|
85
|
+
.\.venv\Scripts\Activate.ps1
|
|
86
|
+
pip install -e ".[dev]"
|
|
87
|
+
python examples/demo.py
|
|
88
|
+
python examples/benchmark.py
|
|
89
|
+
pytest
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
For an LLM-powered demo, copy `.env.example` to `.env`, add your
|
|
93
|
+
`OPENAI_API_KEY`, and run `python examples/live_openai_demo.py`. The offline
|
|
94
|
+
tests and local demo do not require an API key.
|
|
95
|
+
|
|
96
|
+
The default warmup planner is deterministic and derives retrieval intents from
|
|
97
|
+
the session. You can opt into `OpenAIWarmupPlanner` when you want the model to
|
|
98
|
+
produce more nuanced, structured retrieval plans; the engine keeps the
|
|
99
|
+
deterministic planner as a safe fallback.
|
|
100
|
+
|
|
101
|
+
## Model providers
|
|
102
|
+
|
|
103
|
+
The engine is provider-agnostic. The memory pipeline depends on small Python
|
|
104
|
+
protocols, while model and embedding clients are optional adapters.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from stratus_engine import OllamaConversationClient
|
|
108
|
+
|
|
109
|
+
llm = OllamaConversationClient(model="llama3.2")
|
|
110
|
+
result = llm.respond(prompt="What do you remember?", context=context)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Available adapters include OpenAI, Anthropic Claude, and local Ollama. Ollama
|
|
114
|
+
requires a running Ollama server and a pulled model; Claude requires
|
|
115
|
+
`pip install -e ".[anthropic]"`. The deterministic local mode remains useful
|
|
116
|
+
for tests and demos without any model provider.
|
|
117
|
+
|
|
118
|
+
## Package layout
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
stratus_engine/
|
|
122
|
+
├── core/ public engine and domain models
|
|
123
|
+
├── storage/ MongoDB, Chroma, and in-memory adapters
|
|
124
|
+
├── providers/ model and embedding integrations
|
|
125
|
+
├── retrieval/ candidate ranking and deduplication
|
|
126
|
+
├── extraction/ memory extraction strategies
|
|
127
|
+
└── planning/ dynamic session warmup planning
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Chroma retrieval is intentionally staged: it fetches a wider candidate pool,
|
|
131
|
+
combines vector similarity with lexical coverage and memory quality, applies
|
|
132
|
+
recency/access signals, removes near-duplicate facts, and only then returns the
|
|
133
|
+
final context. This is durable-memory retrieval, not a naive every-message RAG
|
|
134
|
+
loop.
|
|
135
|
+
|
|
136
|
+
## Evaluation and comparison
|
|
137
|
+
|
|
138
|
+
Run the reproducible local comparison:
|
|
139
|
+
|
|
140
|
+
```powershell
|
|
141
|
+
python examples/evaluate_architectures.py
|
|
142
|
+
python examples/end_to_end_simulation.py
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The evaluation compares three explicit strategies:
|
|
146
|
+
|
|
147
|
+
| Strategy | What it does | Main tradeoff |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| `full_context` | Sends every durable fact on every turn | High context cost, no retrieval calls |
|
|
150
|
+
| `naive_retrieval` | Runs retrieval for every turn | More retrieval calls and noisy context |
|
|
151
|
+
| `hybrid_warmup` | Warms likely facts once and gates ad-hoc recall | More orchestration, lower repeated retrieval |
|
|
152
|
+
|
|
153
|
+
The pack reports recall, vector-call count, and estimated context tokens. It is
|
|
154
|
+
intentionally small and inspectable so contributors can understand every case.
|
|
155
|
+
It is not presented as a universal benchmark. Production evaluations should add
|
|
156
|
+
domain-specific conversations, adversarial queries, stale facts, conflicting
|
|
157
|
+
facts, multilingual data, and human or LLM-judged answer quality.
|
|
158
|
+
|
|
159
|
+
The end-to-end simulation shows the complete lifecycle offline: session writes,
|
|
160
|
+
durable memory promotion, engine recreation, login-time warmup, continued work,
|
|
161
|
+
retrieval traces, and context analytics. Its traced in-memory store can be
|
|
162
|
+
replaced with `ChromaLongTermMemoryStore` without changing the engine flow.
|
|
163
|
+
|
|
164
|
+
For a live interactive version, run:
|
|
165
|
+
|
|
166
|
+
```powershell
|
|
167
|
+
python examples/live_session_simulation.py --provider openai
|
|
168
|
+
python examples/live_session_simulation.py --provider ollama --model llama3.2
|
|
169
|
+
python examples/live_session_simulation.py --provider offline
|
|
170
|
+
python examples/live_session_simulation.py --provider openai --backend chroma
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The live simulation recreates the engine after seed memories are promoted, then
|
|
174
|
+
accepts your questions and prints the actual model response plus retrieval
|
|
175
|
+
reason, warmed memories, recalled memories, estimated tokens, and relevance.
|
|
176
|
+
Use `--backend chroma` with the Docker Chroma service to exercise a real vector
|
|
177
|
+
database; the default `memory` backend is faster for repeatable local demos.
|
|
178
|
+
|
|
179
|
+
## Docker Services
|
|
180
|
+
|
|
181
|
+
Start MongoDB and Chroma:
|
|
182
|
+
|
|
183
|
+
```powershell
|
|
184
|
+
docker compose up -d mongo chroma
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Chroma Vector Demo
|
|
188
|
+
|
|
189
|
+
This uses MongoDB for sessions and Chroma for long-term memory. It uses local
|
|
190
|
+
hash embeddings, so it does not need an OpenAI key.
|
|
191
|
+
|
|
192
|
+
```powershell
|
|
193
|
+
pip install -e ".[mongo,vector,dev]"
|
|
194
|
+
python examples/chroma_demo.py
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Live OpenAI Demo
|
|
198
|
+
|
|
199
|
+
This uses MongoDB, Chroma, OpenAI embeddings, and an OpenAI chat completion. It
|
|
200
|
+
prints context metrics and API token usage.
|
|
201
|
+
|
|
202
|
+
Create a local `.env` file with `OPENAI_API_KEY` set to your key. The live demo
|
|
203
|
+
loads that file automatically, or you can set the variable in the current
|
|
204
|
+
PowerShell session before running it.
|
|
205
|
+
|
|
206
|
+
```powershell
|
|
207
|
+
pip install -e ".[demo]"
|
|
208
|
+
$env:OPENAI_API_KEY = "your_api_key_here"
|
|
209
|
+
python examples/live_openai_demo.py
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Benchmark
|
|
213
|
+
|
|
214
|
+
The benchmark compares naive retrieval, where every prompt would run vector
|
|
215
|
+
search, against Stratus's gated recall.
|
|
216
|
+
|
|
217
|
+
```powershell
|
|
218
|
+
python examples/benchmark.py
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
It prints vector-search reduction, average estimated context tokens, average
|
|
222
|
+
memory relevance, and a prompt-level trace.
|
|
223
|
+
|
|
224
|
+
## Programmatic Usage
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
from stratus_engine import (
|
|
228
|
+
ChromaLongTermMemoryStore,
|
|
229
|
+
MongoSessionStore,
|
|
230
|
+
OpenAIEmbeddingProvider,
|
|
231
|
+
StratusEngine,
|
|
232
|
+
analyze_context,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
engine = StratusEngine(
|
|
236
|
+
session_store=MongoSessionStore("mongodb://localhost:27017"),
|
|
237
|
+
memory_store=ChromaLongTermMemoryStore(
|
|
238
|
+
host="localhost",
|
|
239
|
+
port=8000,
|
|
240
|
+
embedding_provider=OpenAIEmbeddingProvider(),
|
|
241
|
+
),
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
session = engine.create_session("user_123", title="Demo")
|
|
245
|
+
engine.append_user_message(session.id, "I prefer React over Angular.")
|
|
246
|
+
engine.extract_memories(session.id)
|
|
247
|
+
engine.reopen_session(session.id)
|
|
248
|
+
|
|
249
|
+
context = engine.build_context(session.id, "What frontend preference do I have?")
|
|
250
|
+
metrics = analyze_context("What frontend preference do I have?", context)
|
|
251
|
+
print(context.as_prompt_sections())
|
|
252
|
+
print(metrics)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Demo Story
|
|
256
|
+
|
|
257
|
+
The demo shows five important behaviors:
|
|
258
|
+
|
|
259
|
+
1. Active conversation context is read from the session layer.
|
|
260
|
+
2. Useful facts are extracted into structured memories.
|
|
261
|
+
3. Chroma retrieves long-term memories.
|
|
262
|
+
4. Reopening a session warms relevant context before the user asks anything.
|
|
263
|
+
5. Metrics show token footprint and retrieval relevance.
|
|
264
|
+
|
|
265
|
+
## Design Direction
|
|
266
|
+
|
|
267
|
+
Next steps are intentionally narrow: replace the heuristic extractor with an
|
|
268
|
+
LLM-backed extractor, add background extraction, and add a small evaluation set
|
|
269
|
+
that proves latency, recall quality, and reduced vector-search usage.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "stratus-engine"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Two-layer memory infrastructure for LLM applications."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = ["pydantic>=2.7"]
|
|
8
|
+
keywords = ["llm", "memory", "rag", "vector-database", "agents"]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 3 - Alpha",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
mongo = ["pymongo>=4.8"]
|
|
19
|
+
vector = ["chromadb>=0.5.0"]
|
|
20
|
+
openai = ["openai>=1.40.0", "tiktoken>=0.7.0", "python-dotenv>=1.0"]
|
|
21
|
+
anthropic = ["anthropic>=0.40.0"]
|
|
22
|
+
all = ["anthropic>=0.40.0", "chromadb>=0.5.0", "openai>=1.40.0", "pymongo>=4.8", "python-dotenv>=1.0", "tiktoken>=0.7.0"]
|
|
23
|
+
demo = ["chromadb>=0.5.0", "openai>=1.40.0", "pymongo>=4.8", "pytest>=8.0", "python-dotenv>=1.0", "tiktoken>=0.7.0"]
|
|
24
|
+
dev = ["build>=1.2", "pytest>=8.0", "twine>=5.0"]
|
|
25
|
+
|
|
26
|
+
[build-system]
|
|
27
|
+
requires = ["setuptools>=69"]
|
|
28
|
+
build-backend = "setuptools.build_meta"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
where = ["src"]
|
|
32
|
+
|
|
33
|
+
[tool.pytest.ini_options]
|
|
34
|
+
pythonpath = ["src"]
|
|
35
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from stratus_engine.core.engine import StratusEngine
|
|
2
|
+
from stratus_engine.config import StratusConfig, create_engine
|
|
3
|
+
from stratus_engine.embeddings import HashEmbeddingProvider, OpenAIEmbeddingProvider
|
|
4
|
+
from stratus_engine.extraction.extractors import HeuristicMemoryExtractor, OpenAIMemoryExtractor
|
|
5
|
+
from stratus_engine.storage.memories.memory import InMemoryLongTermMemoryStore
|
|
6
|
+
from stratus_engine.metrics import ContextMetrics, analyze_context, estimate_tokens
|
|
7
|
+
from stratus_engine.core.models import ContextBundle, Memory, MemoryType, Message, Role, Session
|
|
8
|
+
from stratus_engine.openai_chat import ChatResult, OpenAIConversationClient
|
|
9
|
+
from stratus_engine.providers.adapters import (
|
|
10
|
+
AnthropicConversationClient,
|
|
11
|
+
OllamaConversationClient,
|
|
12
|
+
OllamaEmbeddingProvider,
|
|
13
|
+
)
|
|
14
|
+
from stratus_engine.core.protocols import ChatProvider, MemoryExtractor
|
|
15
|
+
from stratus_engine.retrieval.rankers import ProductionMemoryRanker, RetrievalCandidate
|
|
16
|
+
from stratus_engine.planning.planners import (
|
|
17
|
+
HeuristicWarmupPlanner,
|
|
18
|
+
OpenAIWarmupPlanner,
|
|
19
|
+
WarmupPlan,
|
|
20
|
+
)
|
|
21
|
+
from stratus_engine.storage.sessions.adapters import InMemorySessionStore, MongoSessionStore
|
|
22
|
+
from stratus_engine.storage.memories.chroma import ChromaLongTermMemoryStore
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"ChatResult",
|
|
26
|
+
"ChatProvider",
|
|
27
|
+
"AnthropicConversationClient",
|
|
28
|
+
"ChromaLongTermMemoryStore",
|
|
29
|
+
"ContextBundle",
|
|
30
|
+
"ContextMetrics",
|
|
31
|
+
"StratusConfig",
|
|
32
|
+
"HashEmbeddingProvider",
|
|
33
|
+
"HeuristicMemoryExtractor",
|
|
34
|
+
"HeuristicWarmupPlanner",
|
|
35
|
+
"InMemoryLongTermMemoryStore",
|
|
36
|
+
"InMemorySessionStore",
|
|
37
|
+
"Memory",
|
|
38
|
+
"MemoryType",
|
|
39
|
+
"MemoryExtractor",
|
|
40
|
+
"Message",
|
|
41
|
+
"MongoSessionStore",
|
|
42
|
+
"OpenAIConversationClient",
|
|
43
|
+
"OpenAIEmbeddingProvider",
|
|
44
|
+
"OpenAIMemoryExtractor",
|
|
45
|
+
"OpenAIWarmupPlanner",
|
|
46
|
+
"OllamaConversationClient",
|
|
47
|
+
"OllamaEmbeddingProvider",
|
|
48
|
+
"ProductionMemoryRanker",
|
|
49
|
+
"RetrievalCandidate",
|
|
50
|
+
"Role",
|
|
51
|
+
"Session",
|
|
52
|
+
"StratusEngine",
|
|
53
|
+
"WarmupPlan",
|
|
54
|
+
"analyze_context",
|
|
55
|
+
"create_engine",
|
|
56
|
+
"estimate_tokens",
|
|
57
|
+
]
|