chuk-ai-session-manager 0.7__py3-none-any.whl → 0.8__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.
Files changed (46) hide show
  1. chuk_ai_session_manager/__init__.py +84 -40
  2. chuk_ai_session_manager/api/__init__.py +1 -1
  3. chuk_ai_session_manager/api/simple_api.py +53 -59
  4. chuk_ai_session_manager/exceptions.py +31 -17
  5. chuk_ai_session_manager/guards/__init__.py +118 -0
  6. chuk_ai_session_manager/guards/bindings.py +217 -0
  7. chuk_ai_session_manager/guards/cache.py +163 -0
  8. chuk_ai_session_manager/guards/manager.py +819 -0
  9. chuk_ai_session_manager/guards/models.py +498 -0
  10. chuk_ai_session_manager/guards/ungrounded.py +159 -0
  11. chuk_ai_session_manager/infinite_conversation.py +86 -79
  12. chuk_ai_session_manager/memory/__init__.py +247 -0
  13. chuk_ai_session_manager/memory/artifacts_bridge.py +469 -0
  14. chuk_ai_session_manager/memory/context_packer.py +347 -0
  15. chuk_ai_session_manager/memory/fault_handler.py +507 -0
  16. chuk_ai_session_manager/memory/manifest.py +307 -0
  17. chuk_ai_session_manager/memory/models.py +1084 -0
  18. chuk_ai_session_manager/memory/mutation_log.py +186 -0
  19. chuk_ai_session_manager/memory/pack_cache.py +206 -0
  20. chuk_ai_session_manager/memory/page_table.py +275 -0
  21. chuk_ai_session_manager/memory/prefetcher.py +192 -0
  22. chuk_ai_session_manager/memory/tlb.py +247 -0
  23. chuk_ai_session_manager/memory/vm_prompts.py +238 -0
  24. chuk_ai_session_manager/memory/working_set.py +574 -0
  25. chuk_ai_session_manager/models/__init__.py +21 -9
  26. chuk_ai_session_manager/models/event_source.py +3 -1
  27. chuk_ai_session_manager/models/event_type.py +10 -1
  28. chuk_ai_session_manager/models/session.py +103 -68
  29. chuk_ai_session_manager/models/session_event.py +69 -68
  30. chuk_ai_session_manager/models/session_metadata.py +9 -10
  31. chuk_ai_session_manager/models/session_run.py +21 -22
  32. chuk_ai_session_manager/models/token_usage.py +76 -76
  33. chuk_ai_session_manager/procedural_memory/__init__.py +70 -0
  34. chuk_ai_session_manager/procedural_memory/formatter.py +407 -0
  35. chuk_ai_session_manager/procedural_memory/manager.py +523 -0
  36. chuk_ai_session_manager/procedural_memory/models.py +371 -0
  37. chuk_ai_session_manager/sample_tools.py +79 -46
  38. chuk_ai_session_manager/session_aware_tool_processor.py +27 -16
  39. chuk_ai_session_manager/session_manager.py +238 -197
  40. chuk_ai_session_manager/session_prompt_builder.py +163 -111
  41. chuk_ai_session_manager/session_storage.py +45 -52
  42. {chuk_ai_session_manager-0.7.dist-info → chuk_ai_session_manager-0.8.dist-info}/METADATA +78 -2
  43. chuk_ai_session_manager-0.8.dist-info/RECORD +45 -0
  44. {chuk_ai_session_manager-0.7.dist-info → chuk_ai_session_manager-0.8.dist-info}/WHEEL +1 -1
  45. chuk_ai_session_manager-0.7.dist-info/RECORD +0 -22
  46. {chuk_ai_session_manager-0.7.dist-info → chuk_ai_session_manager-0.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,307 @@
1
+ # chuk_ai_session_manager/memory/manifest.py
2
+ """
3
+ Manifest Builder for AI Virtual Memory.
4
+
5
+ The ManifestBuilder generates the VM:MANIFEST_JSON block - a machine-readable
6
+ index of all pages available to the model. This tells the model what exists
7
+ and where, enabling informed page_fault decisions.
8
+
9
+ Design principles:
10
+ - Machine-readable: Strict JSON for reliable parsing
11
+ - Discovery-focused: Hints help find relevant pages, not provide evidence
12
+ - Policy-aware: Includes fault limits and preferences
13
+ - Pydantic-native: All models are BaseModel subclasses
14
+ - No magic strings: Uses enums for all categorical values
15
+ """
16
+
17
+ from typing import Callable, Dict, List, Optional
18
+
19
+ from pydantic import BaseModel, Field
20
+
21
+ from .models import (
22
+ ALL_COMPRESSION_LEVELS,
23
+ CompressionLevel,
24
+ MemoryPage,
25
+ Modality,
26
+ PageTableEntry,
27
+ StorageTier,
28
+ )
29
+ from .page_table import PageTable
30
+
31
+
32
+ class WorkingSetEntry(BaseModel):
33
+ """Entry for a page in the working set (already mapped)."""
34
+
35
+ page_id: str
36
+ modality: str
37
+ level: int = Field(..., description="Compression level (0-3)")
38
+ tokens_est: int
39
+ importance: float = 0.5
40
+
41
+
42
+ class AvailablePageEntry(BaseModel):
43
+ """Entry for a page available for loading (not yet mapped)."""
44
+
45
+ page_id: str
46
+ modality: str
47
+ tier: str = Field(..., description="Current storage tier")
48
+ levels: List[int] = Field(
49
+ default_factory=lambda: list(ALL_COMPRESSION_LEVELS),
50
+ description="Available compression levels",
51
+ )
52
+ hint: str = Field(default="", description="Discovery hint (NOT evidence)")
53
+
54
+
55
+ class ManifestPolicies(BaseModel):
56
+ """Policies governing VM behavior."""
57
+
58
+ faults_allowed: bool = True
59
+ max_faults_per_turn: int = 2
60
+ upgrade_budget_tokens: int = 4096
61
+ prefer_levels: List[int] = Field(
62
+ default_factory=lambda: [
63
+ CompressionLevel.ABSTRACT.value,
64
+ CompressionLevel.REDUCED.value,
65
+ CompressionLevel.FULL.value,
66
+ ],
67
+ description="Preference order for compression levels",
68
+ )
69
+
70
+
71
+ class VMManifest(BaseModel):
72
+ """
73
+ Complete VM manifest for inclusion in developer message.
74
+
75
+ This is the machine-readable counterpart to VM:CONTEXT.
76
+ """
77
+
78
+ session_id: str
79
+ working_set: List[WorkingSetEntry] = Field(default_factory=list)
80
+ available_pages: List[AvailablePageEntry] = Field(default_factory=list)
81
+ policies: ManifestPolicies = Field(default_factory=ManifestPolicies)
82
+
83
+ def to_json(self, indent: Optional[int] = None) -> str:
84
+ """Serialize to JSON string."""
85
+ return self.model_dump_json(indent=indent)
86
+
87
+ def to_wrapped_json(self, indent: Optional[int] = None) -> str:
88
+ """Serialize wrapped with VM:MANIFEST_JSON tags."""
89
+ json_str = self.to_json(indent=indent)
90
+ return f"<VM:MANIFEST_JSON>\n{json_str}\n</VM:MANIFEST_JSON>"
91
+
92
+
93
+ class ManifestBuilder(BaseModel):
94
+ """
95
+ Builds VM manifests from PageTable state.
96
+
97
+ Usage:
98
+ builder = ManifestBuilder()
99
+ manifest = builder.build(
100
+ session_id="sess_123",
101
+ page_table=page_table,
102
+ working_set_ids=["msg_1", "msg_2"],
103
+ hint_generator=lambda e: f"message about {e.modality}"
104
+ )
105
+ """
106
+
107
+ # Default policies
108
+ default_policies: ManifestPolicies = Field(default_factory=ManifestPolicies)
109
+
110
+ # Maximum available pages to include
111
+ max_available_pages: int = Field(
112
+ default=50, description="Limit available_pages to prevent manifest bloat"
113
+ )
114
+
115
+ def build(
116
+ self,
117
+ session_id: str,
118
+ page_table: PageTable,
119
+ working_set_ids: List[str],
120
+ working_set_tokens: Optional[Dict[str, int]] = None,
121
+ working_set_importance: Optional[Dict[str, float]] = None,
122
+ hint_generator: Optional[Callable[[PageTableEntry], str]] = None,
123
+ policies: Optional[ManifestPolicies] = None,
124
+ ) -> VMManifest:
125
+ """
126
+ Build a complete VM manifest.
127
+
128
+ Args:
129
+ session_id: Session identifier
130
+ page_table: PageTable with all page entries
131
+ working_set_ids: Page IDs currently in working set (L0)
132
+ working_set_tokens: Optional token counts per page
133
+ working_set_importance: Optional importance scores per page
134
+ hint_generator: Optional function(PageTableEntry) -> str for hints
135
+ policies: Optional policy overrides
136
+
137
+ Returns:
138
+ VMManifest ready for serialization
139
+ """
140
+ working_set: List[WorkingSetEntry] = []
141
+ available_pages: List[AvailablePageEntry] = []
142
+
143
+ working_set_tokens = working_set_tokens or {}
144
+ working_set_importance = working_set_importance or {}
145
+
146
+ # Build working set entries
147
+ for page_id in working_set_ids:
148
+ entry = page_table.lookup(page_id)
149
+ if entry:
150
+ ws_entry = WorkingSetEntry(
151
+ page_id=page_id,
152
+ modality=entry.modality.value,
153
+ level=entry.compression_level,
154
+ tokens_est=working_set_tokens.get(
155
+ page_id, entry.size_tokens or 100
156
+ ),
157
+ importance=working_set_importance.get(page_id, 0.5),
158
+ )
159
+ working_set.append(ws_entry)
160
+
161
+ # Build available pages (everything not in working set)
162
+ available_count = 0
163
+ for page_id, entry in page_table.entries.items():
164
+ if page_id in working_set_ids:
165
+ continue
166
+
167
+ if available_count >= self.max_available_pages:
168
+ break
169
+
170
+ # Generate hint
171
+ hint = ""
172
+ if hint_generator:
173
+ try:
174
+ hint = hint_generator(entry)
175
+ except Exception:
176
+ hint = ""
177
+
178
+ available_entry = AvailablePageEntry(
179
+ page_id=page_id,
180
+ modality=entry.modality.value,
181
+ tier=entry.tier.value,
182
+ levels=ALL_COMPRESSION_LEVELS,
183
+ hint=hint,
184
+ )
185
+ available_pages.append(available_entry)
186
+ available_count += 1
187
+
188
+ return VMManifest(
189
+ session_id=session_id,
190
+ working_set=working_set,
191
+ available_pages=available_pages,
192
+ policies=policies or self.default_policies,
193
+ )
194
+
195
+ def build_from_pages(
196
+ self,
197
+ session_id: str,
198
+ working_set_pages: List[MemoryPage],
199
+ available_entries: List[PageTableEntry],
200
+ hint_generator: Optional[Callable[[PageTableEntry], str]] = None,
201
+ policies: Optional[ManifestPolicies] = None,
202
+ ) -> VMManifest:
203
+ """
204
+ Build manifest directly from page objects (alternative API).
205
+
206
+ Args:
207
+ session_id: Session identifier
208
+ working_set_pages: MemoryPage objects in working set
209
+ available_entries: PageTableEntry objects for available pages
210
+ hint_generator: Optional function(PageTableEntry) -> str
211
+ policies: Optional policy overrides
212
+
213
+ Returns:
214
+ VMManifest
215
+ """
216
+ working_set: List[WorkingSetEntry] = []
217
+ available_pages: List[AvailablePageEntry] = []
218
+
219
+ # Build working set from pages
220
+ for page in working_set_pages:
221
+ ws_entry = WorkingSetEntry(
222
+ page_id=page.page_id,
223
+ modality=page.modality.value
224
+ if hasattr(page.modality, "value")
225
+ else str(page.modality),
226
+ level=page.compression_level
227
+ if isinstance(page.compression_level, int)
228
+ else page.compression_level.value,
229
+ tokens_est=page.size_tokens or page.estimate_tokens(),
230
+ importance=page.importance,
231
+ )
232
+ working_set.append(ws_entry)
233
+
234
+ # Build available pages
235
+ working_set_ids = {p.page_id for p in working_set_pages}
236
+ for entry in available_entries[: self.max_available_pages]:
237
+ if entry.page_id in working_set_ids:
238
+ continue
239
+
240
+ hint = ""
241
+ if hint_generator:
242
+ try:
243
+ hint = hint_generator(entry)
244
+ except Exception:
245
+ hint = ""
246
+
247
+ available_entry = AvailablePageEntry(
248
+ page_id=entry.page_id,
249
+ modality=entry.modality.value
250
+ if hasattr(entry.modality, "value")
251
+ else str(entry.modality),
252
+ tier=entry.tier.value
253
+ if hasattr(entry.tier, "value")
254
+ else str(entry.tier),
255
+ levels=ALL_COMPRESSION_LEVELS,
256
+ hint=hint,
257
+ )
258
+ available_pages.append(available_entry)
259
+
260
+ return VMManifest(
261
+ session_id=session_id,
262
+ working_set=working_set,
263
+ available_pages=available_pages,
264
+ policies=policies or self.default_policies,
265
+ )
266
+
267
+
268
+ # Hint type constants
269
+ class HintType:
270
+ """Constants for hint types in manifest generation."""
271
+
272
+ RECENT = "recent"
273
+ STORED = "stored"
274
+ ARCHIVED = "archived"
275
+ SUMMARY = "summary"
276
+ EXCERPT = "excerpt"
277
+ CONTENT = "content"
278
+
279
+
280
+ def generate_simple_hint(entry: PageTableEntry) -> str:
281
+ """
282
+ Simple hint generator based on page metadata.
283
+
284
+ This is a basic implementation - real systems would use
285
+ summaries, embeddings, or other content-aware hints.
286
+ """
287
+ parts: List[str] = []
288
+
289
+ # Modality
290
+ if entry.modality != Modality.TEXT:
291
+ parts.append(entry.modality.value)
292
+
293
+ # Tier (indicates recency/importance)
294
+ if entry.tier == StorageTier.L2:
295
+ parts.append(HintType.RECENT)
296
+ elif entry.tier == StorageTier.L3:
297
+ parts.append(HintType.STORED)
298
+ elif entry.tier == StorageTier.L4:
299
+ parts.append(HintType.ARCHIVED)
300
+
301
+ # Compression level
302
+ if entry.compression_level == CompressionLevel.ABSTRACT:
303
+ parts.append(HintType.SUMMARY)
304
+ elif entry.compression_level == CompressionLevel.REDUCED:
305
+ parts.append(HintType.EXCERPT)
306
+
307
+ return " ".join(parts) if parts else HintType.CONTENT