chuk-ai-session-manager 0.7.1__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.1.dist-info → chuk_ai_session_manager-0.8.dist-info}/METADATA +79 -3
  43. chuk_ai_session_manager-0.8.dist-info/RECORD +45 -0
  44. {chuk_ai_session_manager-0.7.1.dist-info → chuk_ai_session_manager-0.8.dist-info}/WHEEL +1 -1
  45. chuk_ai_session_manager-0.7.1.dist-info/RECORD +0 -22
  46. {chuk_ai_session_manager-0.7.1.dist-info → chuk_ai_session_manager-0.8.dist-info}/top_level.txt +0 -0
@@ -5,9 +5,10 @@ InfiniteConversationManager for handling conversations that exceed token limits.
5
5
  This module provides support for managing conversations that span multiple
6
6
  session segments, with automatic summarization and context building.
7
7
  """
8
+
8
9
  from __future__ import annotations
9
10
  from enum import Enum
10
- from typing import List, Dict, Any, Optional, Callable, Tuple, Union
11
+ from typing import List, Dict, Any, Callable, Tuple
11
12
  import logging
12
13
 
13
14
  from chuk_ai_session_manager.models.session import Session
@@ -24,29 +25,30 @@ logger = logging.getLogger(__name__)
24
25
 
25
26
  class SummarizationStrategy(str, Enum):
26
27
  """Different strategies for summarizing conversation segments."""
27
- BASIC = "basic" # General overview of the conversation
28
- KEY_POINTS = "key_points" # Focus on key information points
29
- TOPIC_BASED = "topic_based" # Organize by topics discussed
28
+
29
+ BASIC = "basic" # General overview of the conversation
30
+ KEY_POINTS = "key_points" # Focus on key information points
31
+ TOPIC_BASED = "topic_based" # Organize by topics discussed
30
32
  QUERY_FOCUSED = "query_focused" # Focus on user's questions
31
33
 
32
34
 
33
35
  class InfiniteConversationManager:
34
36
  """
35
37
  Manages conversations that can theoretically be infinite in length.
36
-
38
+
37
39
  This manager automatically segments conversations that exceed token limits
38
40
  by creating a chain of sessions with summaries that provide context.
39
41
  """
40
-
42
+
41
43
  def __init__(
42
44
  self,
43
45
  token_threshold: int = 3000,
44
46
  max_turns_per_segment: int = 20,
45
- summarization_strategy: SummarizationStrategy = SummarizationStrategy.BASIC
47
+ summarization_strategy: SummarizationStrategy = SummarizationStrategy.BASIC,
46
48
  ):
47
49
  """
48
50
  Initialize the infinite conversation manager.
49
-
51
+
50
52
  Args:
51
53
  token_threshold: Maximum tokens before creating a new segment
52
54
  max_turns_per_segment: Maximum conversation turns per segment
@@ -55,42 +57,42 @@ class InfiniteConversationManager:
55
57
  self.token_threshold = token_threshold
56
58
  self.max_turns_per_segment = max_turns_per_segment
57
59
  self.summarization_strategy = summarization_strategy
58
-
60
+
59
61
  async def process_message(
60
62
  self,
61
63
  session_id: str,
62
64
  message: str,
63
65
  source: EventSource,
64
66
  llm_callback: LLMCallbackAsync,
65
- model: str = "gpt-3.5-turbo"
67
+ model: str = "gpt-3.5-turbo",
66
68
  ) -> str:
67
69
  """
68
70
  Process a new message in the conversation.
69
-
71
+
70
72
  This method:
71
73
  1. Adds the message to the current session
72
74
  2. Checks if token threshold is exceeded
73
75
  3. If needed, creates a summary and starts a new session
74
-
76
+
75
77
  Args:
76
78
  session_id: ID of the current session
77
79
  message: The message content
78
80
  source: Source of the message (USER or LLM)
79
81
  llm_callback: Async callback for LLM calls
80
82
  model: The model to use for token counting
81
-
83
+
82
84
  Returns:
83
85
  The current session ID (may be a new one if threshold was exceeded)
84
86
  """
85
87
  # Get the store
86
88
  backend = get_backend()
87
89
  store = ChukSessionsStore(backend)
88
-
90
+
89
91
  # Get the current session
90
92
  session = await store.get(session_id)
91
93
  if not session:
92
94
  raise ValueError(f"Session {session_id} not found")
93
-
95
+
94
96
  # Add the message to the session
95
97
  event = await SessionEvent.create_with_tokens(
96
98
  message=message,
@@ -98,175 +100,181 @@ class InfiniteConversationManager:
98
100
  completion=message if source == EventSource.LLM else "",
99
101
  model=model,
100
102
  source=source,
101
- type=EventType.MESSAGE
103
+ type=EventType.MESSAGE,
102
104
  )
103
105
  await session.add_event_and_save(event)
104
-
106
+
105
107
  # Check if we've exceeded the token threshold
106
108
  if await self._should_create_new_segment(session):
107
- logger.info(f"Token threshold exceeded for session {session_id}. Creating new segment.")
108
-
109
+ logger.info(
110
+ f"Token threshold exceeded for session {session_id}. Creating new segment."
111
+ )
112
+
109
113
  # Create a summary of the current session
110
114
  summary = await self._create_summary(session, llm_callback)
111
-
115
+
112
116
  # Add the summary to the current session
113
117
  summary_event = SessionEvent(
114
- message=summary,
115
- source=EventSource.SYSTEM,
116
- type=EventType.SUMMARY
118
+ message=summary, source=EventSource.SYSTEM, type=EventType.SUMMARY
117
119
  )
118
120
  await session.add_event_and_save(summary_event)
119
-
121
+
120
122
  # Create a new session with the current as parent
121
123
  new_session = await Session.create(parent_id=session_id)
122
-
124
+
123
125
  # Return the new session ID
124
126
  return new_session.id
125
-
127
+
126
128
  # No new segment needed, return the current session ID
127
129
  return session_id
128
-
130
+
129
131
  async def _should_create_new_segment(self, session: Session) -> bool:
130
132
  """
131
133
  Determine if we should create a new session segment.
132
-
134
+
133
135
  Args:
134
136
  session: The current session
135
-
137
+
136
138
  Returns:
137
139
  True if a new segment should be created
138
140
  """
139
141
  # Check token count
140
142
  if session.total_tokens >= self.token_threshold:
141
143
  return True
142
-
144
+
143
145
  # Check turn count
144
146
  message_events = [e for e in session.events if e.type == EventType.MESSAGE]
145
147
  if len(message_events) >= self.max_turns_per_segment:
146
148
  return True
147
-
149
+
148
150
  return False
149
-
151
+
150
152
  async def _create_summary(
151
- self,
152
- session: Session,
153
- llm_callback: LLMCallbackAsync
153
+ self, session: Session, llm_callback: LLMCallbackAsync
154
154
  ) -> str:
155
155
  """
156
156
  Create a summary of the session.
157
-
157
+
158
158
  Args:
159
159
  session: The session to summarize
160
160
  llm_callback: Async callback for LLM calls
161
-
161
+
162
162
  Returns:
163
163
  A summary string
164
164
  """
165
165
  # Get message events
166
166
  message_events = [e for e in session.events if e.type == EventType.MESSAGE]
167
-
167
+
168
168
  # Create a conversation history for the LLM
169
169
  messages = []
170
-
170
+
171
171
  # Add system prompt based on summarization strategy
172
172
  system_prompt = self._get_summarization_prompt()
173
173
  messages.append({"role": "system", "content": system_prompt})
174
-
174
+
175
175
  # Add the conversation history
176
176
  for event in message_events:
177
177
  role = "user" if event.source == EventSource.USER else "assistant"
178
178
  content = event.message
179
179
  messages.append({"role": role, "content": content})
180
-
180
+
181
181
  # Call the LLM to generate a summary
182
182
  summary = await llm_callback(messages)
183
183
  return summary
184
-
184
+
185
185
  def _get_summarization_prompt(self) -> str:
186
186
  """
187
187
  Get the prompt for summarization based on the selected strategy.
188
-
188
+
189
189
  Returns:
190
190
  A prompt string
191
191
  """
192
192
  if self.summarization_strategy == SummarizationStrategy.BASIC:
193
193
  return "Please provide a concise summary of this conversation. Focus on the main topic and key information exchanged."
194
-
194
+
195
195
  elif self.summarization_strategy == SummarizationStrategy.KEY_POINTS:
196
196
  return "Summarize this conversation by identifying and listing the key points discussed. Focus on the most important information exchanged."
197
-
197
+
198
198
  elif self.summarization_strategy == SummarizationStrategy.TOPIC_BASED:
199
199
  return "Create a summary of this conversation organized by topics discussed. Identify the main subject areas and the key points within each."
200
-
200
+
201
201
  elif self.summarization_strategy == SummarizationStrategy.QUERY_FOCUSED:
202
202
  return "Summarize this conversation by focusing on the user's main questions and the key answers provided. Prioritize what the user was seeking to learn."
203
-
203
+
204
204
  else:
205
205
  return "Please provide a brief summary of this conversation."
206
-
206
+
207
207
  async def build_context_for_llm(
208
- self,
209
- session_id: str,
210
- max_messages: int = 10,
211
- include_summaries: bool = True
208
+ self, session_id: str, max_messages: int = 10, include_summaries: bool = True
212
209
  ) -> List[Dict[str, str]]:
213
210
  """
214
211
  Build context for an LLM call from the current session and its ancestors.
215
-
212
+
216
213
  Args:
217
214
  session_id: ID of the current session
218
215
  max_messages: Maximum number of recent messages to include
219
216
  include_summaries: Whether to include summaries from parent sessions
220
-
217
+
221
218
  Returns:
222
219
  A list of messages suitable for an LLM call
223
220
  """
224
221
  # Get the store
225
222
  backend = get_backend()
226
223
  store = ChukSessionsStore(backend)
227
-
224
+
228
225
  # Get the current session
229
226
  session = await store.get(session_id)
230
227
  if not session:
231
228
  raise ValueError(f"Session {session_id} not found")
232
-
229
+
233
230
  # Initialize context
234
231
  context = []
235
-
232
+
236
233
  # Add summaries from ancestor sessions if requested
237
234
  if include_summaries:
238
235
  # Get all ancestors
239
236
  ancestors = await session.ancestors()
240
-
237
+
241
238
  # Get summaries from ancestors (most distant to most recent)
242
239
  summaries = []
243
240
  for ancestor in ancestors:
244
241
  summary_event = next(
245
- (e for e in reversed(ancestor.events) if e.type == EventType.SUMMARY),
246
- None
242
+ (
243
+ e
244
+ for e in reversed(ancestor.events)
245
+ if e.type == EventType.SUMMARY
246
+ ),
247
+ None,
247
248
  )
248
249
  if summary_event:
249
250
  summaries.append(summary_event.message)
250
-
251
+
251
252
  # If we have summaries, add them as a system message
252
253
  if summaries:
253
- context.append({
254
- "role": "system",
255
- "content": "Previous conversation context: " + " ".join(summaries)
256
- })
257
-
254
+ context.append(
255
+ {
256
+ "role": "system",
257
+ "content": "Previous conversation context: "
258
+ + " ".join(summaries),
259
+ }
260
+ )
261
+
258
262
  # Get recent messages from the current session
259
263
  message_events = [e for e in session.events if e.type == EventType.MESSAGE]
260
- recent_messages = message_events[-max_messages:] if len(message_events) > max_messages else message_events
261
-
264
+ recent_messages = (
265
+ message_events[-max_messages:]
266
+ if len(message_events) > max_messages
267
+ else message_events
268
+ )
269
+
262
270
  # Add messages to context
263
271
  for event in recent_messages:
264
272
  role = "user" if event.source == EventSource.USER else "assistant"
265
273
  content = event.message
266
274
  context.append({"role": role, "content": content})
267
-
275
+
268
276
  return context
269
-
277
+
270
278
  async def get_session_chain(self, session_id: str) -> List[Session]:
271
279
  """
272
280
  Return sessions from root → … → current.
@@ -287,33 +295,32 @@ class InfiniteConversationManager:
287
295
  return ancestors + [session]
288
296
 
289
297
  async def get_full_conversation_history(
290
- self,
291
- session_id: str
298
+ self, session_id: str
292
299
  ) -> List[Tuple[str, EventSource, str]]:
293
300
  """
294
301
  Get the full conversation history across all session segments.
295
-
302
+
296
303
  Args:
297
304
  session_id: ID of the current session
298
-
305
+
299
306
  Returns:
300
307
  A list of (role, source, content) tuples representing the conversation
301
308
  """
302
309
  # Get the session chain
303
310
  sessions = await self.get_session_chain(session_id)
304
-
311
+
305
312
  # Initialize history
306
313
  history = []
307
-
314
+
308
315
  # Process each session in the chain
309
316
  for session in sessions:
310
317
  # Get message events from this session
311
318
  message_events = [e for e in session.events if e.type == EventType.MESSAGE]
312
-
319
+
313
320
  # Add to history
314
321
  for event in message_events:
315
322
  role = "user" if event.source == EventSource.USER else "assistant"
316
323
  content = event.message
317
324
  history.append((role, event.source, content))
318
-
319
- return history
325
+
326
+ return history
@@ -0,0 +1,247 @@
1
+ # chuk_ai_session_manager/memory/__init__.py
2
+ """
3
+ AI Virtual Memory subsystem.
4
+
5
+ This module implements OS-style virtual memory semantics for AI context management:
6
+ - Pages: Atomic units of content (text, images, audio, video)
7
+ - Working set: Currently mapped pages in context window
8
+ - Page faults: Loading content from lower tiers on demand
9
+ - Eviction: Moving pages to lower tiers under pressure
10
+ - Compression: Multi-resolution representations per page
11
+
12
+ Design principles:
13
+ - Async-native: All I/O operations are async
14
+ - Pydantic-native: All models are BaseModel subclasses
15
+ - No magic strings: Uses enums and constants throughout
16
+ """
17
+
18
+ from .models import (
19
+ # Enums
20
+ Actor,
21
+ Affinity,
22
+ CompressionLevel,
23
+ ContextPrefix,
24
+ FaultConfidenceThreshold,
25
+ FaultReason,
26
+ MessageRole,
27
+ Modality,
28
+ MutationType,
29
+ PageType,
30
+ StorageTier,
31
+ ToolType,
32
+ VMMode,
33
+ # Constants
34
+ ALL_COMPRESSION_LEVELS,
35
+ MEMORY_PAGE_MIME_TYPE,
36
+ VM_CHECKPOINT_MIME_TYPE,
37
+ # Stats Models
38
+ CombinedPageTableStats,
39
+ FaultMetrics,
40
+ PageTableStats,
41
+ StorageStats,
42
+ TLBStats,
43
+ WorkingSetStats,
44
+ # Content Models
45
+ AudioContent,
46
+ FaultEffects,
47
+ FormattedPage,
48
+ ImageContent,
49
+ PageContent,
50
+ PageData,
51
+ PageMeta,
52
+ SearchResultEntry,
53
+ StructuredContent,
54
+ TextContent,
55
+ VideoContent,
56
+ # Tool Definition Models
57
+ ToolDefinition,
58
+ ToolFunction,
59
+ ToolParameter,
60
+ ToolParameters,
61
+ # Core Models
62
+ MemoryPage,
63
+ PageTableEntry,
64
+ TokenBudget,
65
+ VMMetrics,
66
+ # Fault Policy Models
67
+ FaultPolicy,
68
+ FaultRecord,
69
+ # Mutation Log Models
70
+ PageMutation,
71
+ # Memory ABI Models
72
+ MemoryABI,
73
+ PageManifestEntry,
74
+ # UX Metrics Models
75
+ RecallAttempt,
76
+ UserExperienceMetrics,
77
+ )
78
+ from .page_table import PageTable
79
+ from .tlb import PageTLB, TLBWithPageTable
80
+ from .working_set import (
81
+ AntiThrashPolicy,
82
+ PinnedSet,
83
+ WorkingSetConfig,
84
+ WorkingSetManager,
85
+ )
86
+ from .pack_cache import ContextPackCache, PackedContext as CachedPackedContext
87
+ from .mutation_log import ContextSnapshot, MutationLogLite
88
+ from .prefetcher import SimplePrefetcher, ToolUsagePattern
89
+ from .context_packer import ContextPacker, ContextPackerConfig, PackedContext
90
+ from .manifest import (
91
+ AvailablePageEntry,
92
+ HintType,
93
+ ManifestBuilder,
94
+ ManifestPolicies,
95
+ VMManifest,
96
+ WorkingSetEntry,
97
+ generate_simple_hint,
98
+ )
99
+ from .fault_handler import (
100
+ FaultResult,
101
+ PageFaultHandler,
102
+ PageSearchHandler,
103
+ SearchResult,
104
+ VMToolError,
105
+ VMToolResult,
106
+ )
107
+ from .artifacts_bridge import (
108
+ ArtifactsBridge,
109
+ CheckpointEntry,
110
+ CheckpointManifest,
111
+ CheckpointMetadata,
112
+ InMemoryBackend,
113
+ PageMetadata,
114
+ )
115
+ from .vm_prompts import (
116
+ PAGE_FAULT_TOOL,
117
+ SEARCH_PAGES_TOOL,
118
+ VM_PASSIVE_PROMPT,
119
+ VM_PROMPTS,
120
+ VM_RELAXED_PROMPT,
121
+ VM_STRICT_PROMPT,
122
+ VM_TOOL_DEFINITIONS,
123
+ VM_TOOLS,
124
+ build_vm_developer_message,
125
+ get_prompt_for_mode,
126
+ get_vm_tools,
127
+ get_vm_tools_as_dicts,
128
+ )
129
+
130
+ __all__ = [
131
+ # Enums
132
+ "Actor",
133
+ "Affinity",
134
+ "CompressionLevel",
135
+ "ContextPrefix",
136
+ "FaultConfidenceThreshold",
137
+ "FaultReason",
138
+ "MessageRole",
139
+ "Modality",
140
+ "MutationType",
141
+ "PageType",
142
+ "StorageTier",
143
+ "ToolType",
144
+ "VMMode",
145
+ # Constants
146
+ "ALL_COMPRESSION_LEVELS",
147
+ "MEMORY_PAGE_MIME_TYPE",
148
+ "VM_CHECKPOINT_MIME_TYPE",
149
+ # Stats Models
150
+ "CombinedPageTableStats",
151
+ "FaultMetrics",
152
+ "PageTableStats",
153
+ "StorageStats",
154
+ "TLBStats",
155
+ "WorkingSetStats",
156
+ # Content Models
157
+ "AudioContent",
158
+ "FaultEffects",
159
+ "FormattedPage",
160
+ "ImageContent",
161
+ "PageContent",
162
+ "PageData",
163
+ "PageMeta",
164
+ "SearchResultEntry",
165
+ "StructuredContent",
166
+ "TextContent",
167
+ "VideoContent",
168
+ # Tool Definition Models
169
+ "ToolDefinition",
170
+ "ToolFunction",
171
+ "ToolParameter",
172
+ "ToolParameters",
173
+ # Core Models
174
+ "MemoryPage",
175
+ "PageTableEntry",
176
+ "TokenBudget",
177
+ "VMMetrics",
178
+ # Fault Policy Models
179
+ "FaultPolicy",
180
+ "FaultRecord",
181
+ # Mutation Log Models
182
+ "PageMutation",
183
+ # Memory ABI Models
184
+ "MemoryABI",
185
+ "PageManifestEntry",
186
+ # UX Metrics Models
187
+ "RecallAttempt",
188
+ "UserExperienceMetrics",
189
+ # Data Structures
190
+ "PageTable",
191
+ "PageTLB",
192
+ "TLBWithPageTable",
193
+ # Working Set
194
+ "AntiThrashPolicy",
195
+ "PinnedSet",
196
+ "WorkingSetConfig",
197
+ "WorkingSetManager",
198
+ # Context Pack Cache
199
+ "CachedPackedContext",
200
+ "ContextPackCache",
201
+ # Mutation Log
202
+ "ContextSnapshot",
203
+ "MutationLogLite",
204
+ # Prefetcher
205
+ "SimplePrefetcher",
206
+ "ToolUsagePattern",
207
+ # Context Packing
208
+ "ContextPacker",
209
+ "ContextPackerConfig",
210
+ "PackedContext",
211
+ # Manifest
212
+ "AvailablePageEntry",
213
+ "HintType",
214
+ "ManifestBuilder",
215
+ "ManifestPolicies",
216
+ "VMManifest",
217
+ "WorkingSetEntry",
218
+ "generate_simple_hint",
219
+ # Fault Handling
220
+ "FaultResult",
221
+ "PageFaultHandler",
222
+ "PageSearchHandler",
223
+ "SearchResult",
224
+ "VMToolError",
225
+ "VMToolResult",
226
+ # Storage
227
+ "ArtifactsBridge",
228
+ "CheckpointEntry",
229
+ "CheckpointManifest",
230
+ "CheckpointMetadata",
231
+ "InMemoryBackend",
232
+ "PageMetadata",
233
+ # Prompts
234
+ "PAGE_FAULT_TOOL",
235
+ "SEARCH_PAGES_TOOL",
236
+ "VM_PASSIVE_PROMPT",
237
+ "VM_PROMPTS",
238
+ "VM_RELAXED_PROMPT",
239
+ "VM_STRICT_PROMPT",
240
+ "VM_TOOL_DEFINITIONS",
241
+ "VM_TOOLS",
242
+ # Builders
243
+ "build_vm_developer_message",
244
+ "get_prompt_for_mode",
245
+ "get_vm_tools",
246
+ "get_vm_tools_as_dicts",
247
+ ]