contextos-memory-runtime 1.0.0rc2__py3-none-any.whl
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.
- contextos/__init__.py +3 -0
- contextos/__main__.py +6 -0
- contextos/api/__init__.py +1 -0
- contextos/api/routes/__init__.py +1 -0
- contextos/api/routes/desktop.py +322 -0
- contextos/api/routes/ingest.py +17 -0
- contextos/api/routes/memories.py +84 -0
- contextos/api/routes/models.py +81 -0
- contextos/api/routes/retrieval.py +89 -0
- contextos/api/routes/system.py +216 -0
- contextos/api/server.py +195 -0
- contextos/benchmarks/__init__.py +1 -0
- contextos/benchmarks/compilation.py +245 -0
- contextos/benchmarks/connectors.py +423 -0
- contextos/benchmarks/explainability.py +103 -0
- contextos/benchmarks/final.py +406 -0
- contextos/benchmarks/graph.py +310 -0
- contextos/benchmarks/graph_adversarial.py +525 -0
- contextos/benchmarks/mcp.py +324 -0
- contextos/benchmarks/model_routing.py +203 -0
- contextos/benchmarks/optimization.py +305 -0
- contextos/benchmarks/rescue_integration.py +127 -0
- contextos/benchmarks/retrieval.py +266 -0
- contextos/benchmarks/temporal.py +377 -0
- contextos/benchmarks/temporal_hotpath.py +76 -0
- contextos/benchmarks/terminal.py +62 -0
- contextos/cli/__init__.py +1 -0
- contextos/cli/app.py +932 -0
- contextos/cli/dashboard.py +174 -0
- contextos/cli/formatters.py +299 -0
- contextos/config/__init__.py +1 -0
- contextos/config/settings.py +160 -0
- contextos/connectors/__init__.py +6 -0
- contextos/connectors/fake.py +11 -0
- contextos/connectors/json_import.py +125 -0
- contextos/connectors/local_files.py +102 -0
- contextos/connectors/manager.py +293 -0
- contextos/connectors/models.py +62 -0
- contextos/connectors/protocols.py +11 -0
- contextos/core/__init__.py +103 -0
- contextos/core/enums.py +489 -0
- contextos/core/exceptions.py +293 -0
- contextos/core/models.py +1147 -0
- contextos/core/protocols.py +549 -0
- contextos/daemon/__init__.py +1 -0
- contextos/daemon/manager.py +510 -0
- contextos/daemon/state.py +127 -0
- contextos/daemon/wiring.py +296 -0
- contextos/demo.py +217 -0
- contextos/embedding/__init__.py +1 -0
- contextos/embedding/deterministic.py +76 -0
- contextos/embedding/sentence_transformers.py +80 -0
- contextos/mcp/__init__.py +5 -0
- contextos/mcp/server.py +269 -0
- contextos/providers/__init__.py +13 -0
- contextos/providers/fake.py +217 -0
- contextos/providers/ollama.py +297 -0
- contextos/providers/openai_compatible.py +337 -0
- contextos/services/__init__.py +1 -0
- contextos/services/compilation.py +535 -0
- contextos/services/explainability.py +553 -0
- contextos/services/extraction.py +311 -0
- contextos/services/graph.py +524 -0
- contextos/services/graph_retrieval.py +143 -0
- contextos/services/ingestion.py +143 -0
- contextos/services/inspection.py +174 -0
- contextos/services/memory.py +291 -0
- contextos/services/model_service.py +409 -0
- contextos/services/optimization.py +426 -0
- contextos/services/privacy.py +331 -0
- contextos/services/retrieval.py +302 -0
- contextos/services/retrieval_index.py +88 -0
- contextos/services/router.py +302 -0
- contextos/services/secret_scanner.py +207 -0
- contextos/services/telemetry_query.py +102 -0
- contextos/services/temporal.py +500 -0
- contextos/services/token_counter.py +222 -0
- contextos/storage/__init__.py +1 -0
- contextos/storage/connector_repo.py +67 -0
- contextos/storage/database.py +497 -0
- contextos/storage/event_repo.py +137 -0
- contextos/storage/graph_repo.py +228 -0
- contextos/storage/lexical/__init__.py +1 -0
- contextos/storage/lexical/bm25.py +134 -0
- contextos/storage/memory_repo.py +589 -0
- contextos/storage/relation_repo.py +80 -0
- contextos/storage/telemetry_repo.py +481 -0
- contextos/storage/vector/__init__.py +1 -0
- contextos/storage/vector/in_memory.py +162 -0
- contextos_memory_runtime-1.0.0rc2.dist-info/METADATA +143 -0
- contextos_memory_runtime-1.0.0rc2.dist-info/RECORD +93 -0
- contextos_memory_runtime-1.0.0rc2.dist-info/WHEEL +4 -0
- contextos_memory_runtime-1.0.0rc2.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"""Domain-specific exceptions for ContextOS.
|
|
2
|
+
|
|
3
|
+
All exceptions inherit from ContextOSError so callers can catch
|
|
4
|
+
the entire hierarchy with a single except clause when needed.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ContextOSError(Exception):
|
|
9
|
+
"""Base exception for all ContextOS errors."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# --- Lifecycle Errors ---
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class InvalidTransitionError(ContextOSError):
|
|
16
|
+
"""Raised when a memory lifecycle transition is not allowed."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, memory_id: str, from_status: str, to_status: str) -> None:
|
|
19
|
+
self.memory_id = memory_id
|
|
20
|
+
self.from_status = from_status
|
|
21
|
+
self.to_status = to_status
|
|
22
|
+
super().__init__(
|
|
23
|
+
f"Invalid transition for memory {memory_id}: "
|
|
24
|
+
f"{from_status} → {to_status}"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class MemoryNotFoundError(ContextOSError):
|
|
29
|
+
"""Raised when a memory ID does not exist."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, memory_id: str) -> None:
|
|
32
|
+
self.memory_id = memory_id
|
|
33
|
+
super().__init__(f"Memory not found: {memory_id}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DuplicateMemoryError(ContextOSError):
|
|
37
|
+
"""Raised when a memory ID is already stored."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, memory_id: str) -> None:
|
|
40
|
+
self.memory_id = memory_id
|
|
41
|
+
super().__init__(f"Memory ID already exists: {memory_id}")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class EventNotFoundError(ContextOSError):
|
|
45
|
+
"""Raised when an event ID does not exist."""
|
|
46
|
+
|
|
47
|
+
def __init__(self, event_id: str) -> None:
|
|
48
|
+
self.event_id = event_id
|
|
49
|
+
super().__init__(f"Event not found: {event_id}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# --- Ingestion Errors ---
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class SecretDetectedError(ContextOSError):
|
|
56
|
+
"""Raised when the secret scanner detects sensitive content in strict mode."""
|
|
57
|
+
|
|
58
|
+
def __init__(self, secret_types: list[str], message: str = "") -> None:
|
|
59
|
+
self.secret_types = secret_types
|
|
60
|
+
detail = f"Detected secrets: {', '.join(secret_types)}"
|
|
61
|
+
if message:
|
|
62
|
+
detail += f". {message}"
|
|
63
|
+
super().__init__(detail)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class IngestionError(ContextOSError):
|
|
67
|
+
"""Raised when the ingestion pipeline fails."""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ExtractionError(ContextOSError):
|
|
71
|
+
"""Raised when memory extraction from raw text fails."""
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# --- Storage Errors ---
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class StorageError(ContextOSError):
|
|
78
|
+
"""Base exception for storage-layer failures."""
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class DatabaseError(StorageError):
|
|
82
|
+
"""Raised for SQLite database errors."""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class VectorStoreError(StorageError):
|
|
86
|
+
"""Raised for vector store errors."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class IndexError(StorageError):
|
|
90
|
+
"""Raised for BM25 index errors."""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ConcurrencyError(StorageError):
|
|
94
|
+
"""Raised when an optimistic concurrency check fails (version mismatch)."""
|
|
95
|
+
|
|
96
|
+
def __init__(self, memory_id: str, expected_version: int, actual_version: int) -> None:
|
|
97
|
+
self.memory_id = memory_id
|
|
98
|
+
self.expected_version = expected_version
|
|
99
|
+
self.actual_version = actual_version
|
|
100
|
+
super().__init__(
|
|
101
|
+
f"Concurrency conflict for memory {memory_id}: "
|
|
102
|
+
f"expected version {expected_version}, found {actual_version}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class MigrationError(StorageError):
|
|
107
|
+
"""Raised when a database migration fails."""
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# --- Retrieval/Compilation Errors ---
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class RetrievalError(ContextOSError):
|
|
114
|
+
"""Raised when the retrieval pipeline fails."""
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class CompilationError(ContextOSError):
|
|
118
|
+
"""Raised when context compilation fails."""
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class TokenBudgetExceededError(CompilationError):
|
|
122
|
+
"""Raised when no meaningful context fits within the token budget."""
|
|
123
|
+
|
|
124
|
+
def __init__(self, budget: int, minimum_required: int) -> None:
|
|
125
|
+
self.budget = budget
|
|
126
|
+
self.minimum_required = minimum_required
|
|
127
|
+
super().__init__(
|
|
128
|
+
f"Token budget {budget} is too small. "
|
|
129
|
+
f"Minimum required: {minimum_required}"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# --- Embedding Errors ---
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class EmbeddingError(ContextOSError):
|
|
137
|
+
"""Raised when embedding generation fails."""
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class EmbeddingModelNotLoadedError(EmbeddingError):
|
|
141
|
+
"""Raised when the embedding model is not available."""
|
|
142
|
+
|
|
143
|
+
def __init__(self, model_name: str) -> None:
|
|
144
|
+
self.model_name = model_name
|
|
145
|
+
super().__init__(f"Embedding model not loaded: {model_name}")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# --- Daemon Errors ---
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class DaemonError(ContextOSError):
|
|
152
|
+
"""Base exception for daemon management errors."""
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class DaemonAlreadyRunningError(DaemonError):
|
|
156
|
+
"""Raised when attempting to start a daemon that is already running."""
|
|
157
|
+
|
|
158
|
+
def __init__(self, pid: int) -> None:
|
|
159
|
+
self.pid = pid
|
|
160
|
+
super().__init__(f"ContextOS daemon is already running (PID: {pid})")
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class DaemonNotRunningError(DaemonError):
|
|
164
|
+
"""Raised when attempting to interact with a daemon that is not running."""
|
|
165
|
+
|
|
166
|
+
def __init__(self) -> None:
|
|
167
|
+
super().__init__("ContextOS daemon is not running. Start it with: contextos start")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class DaemonLockTimeoutError(DaemonError):
|
|
171
|
+
"""Raised when acquiring the daemon lifecycle lock times out."""
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# --- Configuration Errors ---
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class ConfigError(ContextOSError):
|
|
178
|
+
"""Raised for configuration-related errors."""
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class ConfigKeyError(ConfigError):
|
|
182
|
+
"""Raised when a configuration key is invalid."""
|
|
183
|
+
|
|
184
|
+
def __init__(self, key: str) -> None:
|
|
185
|
+
self.key = key
|
|
186
|
+
super().__init__(f"Unknown configuration key: {key}")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# --- Model Runtime & Routing Errors (Phase 9) ---
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class ModelRuntimeError(ContextOSError):
|
|
193
|
+
"""Base exception for all model runtime, provider, and router errors."""
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class ProviderUnavailableError(ModelRuntimeError):
|
|
197
|
+
"""Raised when a requested provider runtime is unreachable or unhealthy."""
|
|
198
|
+
|
|
199
|
+
def __init__(self, provider_id: str, message: str = "") -> None:
|
|
200
|
+
self.provider_id = provider_id
|
|
201
|
+
detail = f"Provider '{provider_id}' is unavailable"
|
|
202
|
+
if message:
|
|
203
|
+
detail += f": {message}"
|
|
204
|
+
super().__init__(detail)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class ModelUnavailableError(ModelRuntimeError):
|
|
208
|
+
"""Raised when a requested model is not offered or disabled by the provider."""
|
|
209
|
+
|
|
210
|
+
def __init__(self, model_id: str, provider_id: str = "") -> None:
|
|
211
|
+
self.model_id = model_id
|
|
212
|
+
self.provider_id = provider_id
|
|
213
|
+
msg = f"Model '{model_id}' is unavailable"
|
|
214
|
+
if provider_id:
|
|
215
|
+
msg += f" on provider '{provider_id}'"
|
|
216
|
+
super().__init__(msg)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class ContextWindowExceededError(ModelRuntimeError):
|
|
220
|
+
"""Raised when prompt and context exceed the provider/model context window."""
|
|
221
|
+
|
|
222
|
+
def __init__(
|
|
223
|
+
self,
|
|
224
|
+
model_id: str,
|
|
225
|
+
required_tokens: int,
|
|
226
|
+
context_window: int,
|
|
227
|
+
prompt_tokens: int = 0,
|
|
228
|
+
compiled_context_tokens: int = 0,
|
|
229
|
+
reserved_output_tokens: int = 0,
|
|
230
|
+
) -> None:
|
|
231
|
+
self.model_id = model_id
|
|
232
|
+
self.required_tokens = required_tokens
|
|
233
|
+
self.context_window = context_window
|
|
234
|
+
self.prompt_tokens = prompt_tokens
|
|
235
|
+
self.compiled_context_tokens = compiled_context_tokens
|
|
236
|
+
self.reserved_output_tokens = reserved_output_tokens
|
|
237
|
+
super().__init__(
|
|
238
|
+
f"Context window exceeded for model '{model_id}': "
|
|
239
|
+
f"required {required_tokens} tokens (prompt: {prompt_tokens}, "
|
|
240
|
+
f"context: {compiled_context_tokens}, reserved output: {reserved_output_tokens}), "
|
|
241
|
+
f"but context window is {context_window} tokens."
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class ProviderTimeoutError(ModelRuntimeError):
|
|
246
|
+
"""Raised when a provider request exceeds its allotted timeout."""
|
|
247
|
+
|
|
248
|
+
def __init__(self, provider_id: str, timeout_seconds: float) -> None:
|
|
249
|
+
self.provider_id = provider_id
|
|
250
|
+
self.timeout_seconds = timeout_seconds
|
|
251
|
+
super().__init__(
|
|
252
|
+
f"Provider '{provider_id}' timed out after {timeout_seconds:.1f} seconds"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class ProviderAuthenticationError(ModelRuntimeError):
|
|
257
|
+
"""Raised when provider authentication fails. Never echoes credentials."""
|
|
258
|
+
|
|
259
|
+
def __init__(self, provider_id: str, message: str = "Authentication failed") -> None:
|
|
260
|
+
self.provider_id = provider_id
|
|
261
|
+
super().__init__(f"Provider '{provider_id}' authentication error: {message}")
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class ProviderRateLimitError(ModelRuntimeError):
|
|
265
|
+
"""Raised when provider returns a rate limit / 429 response."""
|
|
266
|
+
|
|
267
|
+
def __init__(self, provider_id: str, retry_after: float | None = None) -> None:
|
|
268
|
+
self.provider_id = provider_id
|
|
269
|
+
self.retry_after = retry_after
|
|
270
|
+
msg = f"Provider '{provider_id}' rate limit reached"
|
|
271
|
+
if retry_after is not None:
|
|
272
|
+
msg += f" (retry after {retry_after:.1f}s)"
|
|
273
|
+
super().__init__(msg)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class MalformedProviderResponseError(ModelRuntimeError):
|
|
277
|
+
"""Raised when provider returns an unparseable or unexpected payload structure."""
|
|
278
|
+
|
|
279
|
+
def __init__(self, provider_id: str, reason: str = "") -> None:
|
|
280
|
+
self.provider_id = provider_id
|
|
281
|
+
msg = f"Malformed response from provider '{provider_id}'"
|
|
282
|
+
if reason:
|
|
283
|
+
msg += f": {reason}"
|
|
284
|
+
super().__init__(msg)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class RoutingFailureError(ModelRuntimeError):
|
|
288
|
+
"""Raised when the router cannot select a model under current policy and constraints."""
|
|
289
|
+
|
|
290
|
+
def __init__(self, policy: str, reason: str) -> None:
|
|
291
|
+
self.policy = policy
|
|
292
|
+
self.reason = reason
|
|
293
|
+
super().__init__(f"Routing failure under policy '{policy}': {reason}")
|