chuk-ai-session-manager 0.1.1__py3-none-any.whl → 0.2__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.
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chuk-ai-session-manager
3
- Version: 0.1.1
3
+ Version: 0.2
4
4
  Summary: Session manager for AI applications
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: aiofiles>=24.1.0
8
+ Requires-Dist: chuk-sessions>=0.3
8
9
  Requires-Dist: chuk-tool-processor>=0.4.1
9
10
  Requires-Dist: pydantic>=2.11.3
10
11
  Provides-Extra: tiktoken
@@ -70,10 +71,10 @@ This isn't just a demo framework - it's designed for production AI applications
70
71
 
71
72
  ```python
72
73
  import asyncio
73
- from chuk_ai_session_manager.models.session import Session
74
+ from chuk_ai_session_manager.session import Session
74
75
  from chuk_ai_session_manager.models.session_event import SessionEvent
75
76
  from chuk_ai_session_manager.models.event_source import EventSource
76
- from chuk_ai_session_manager.storage import SessionStoreProvider, InMemorySessionStore
77
+ from chuk_ai_session_manager.chuk_sessions_storage import get_backend, ChukSessionsStore, InMemorySessionStore
77
78
 
78
79
  async def main():
79
80
  # Set up storage
@@ -116,8 +117,8 @@ import asyncio
116
117
  import json
117
118
  from openai import AsyncOpenAI
118
119
  from chuk_tool_processor.registry import initialize
119
- from chuk_ai_session_manager.models.session import Session
120
- from chuk_ai_session_manager.storage import SessionStoreProvider, InMemorySessionStore
120
+ from chuk_ai_session_manager.session import Session
121
+ from chuk_ai_session_manager.chuk_sessions_storage import get_backend, ChukSessionsStore, InMemorySessionStore
121
122
 
122
123
  # Import tools - auto-registers via decorators
123
124
  from your_tools import sample_tools
@@ -160,7 +161,7 @@ asyncio.run(openai_integration_demo())
160
161
 
161
162
  ### In-Memory (Default)
162
163
  ```python
163
- from chuk_ai_session_manager.storage import InMemorySessionStore, SessionStoreProvider
164
+ from chuk_ai_session_manager.chuk_sessions_storage import InMemorySessionStore, SessionStoreProvider
164
165
 
165
166
  # Great for testing or single-process applications
166
167
  store = InMemorySessionStore()
@@ -169,7 +170,7 @@ SessionStoreProvider.set_store(store)
169
170
 
170
171
  ### File Storage
171
172
  ```python
172
- from chuk_ai_session_manager.storage.providers.file import create_file_session_store
173
+ from chuk_ai_session_manager.chuk_sessions_storage.providers.file import create_file_session_store
173
174
 
174
175
  # Persistent JSON file storage with async I/O
175
176
  store = await create_file_session_store(directory="./sessions")
@@ -178,7 +179,7 @@ SessionStoreProvider.set_store(store)
178
179
 
179
180
  ### Redis Storage
180
181
  ```python
181
- from chuk_ai_session_manager.storage.providers.redis import create_redis_session_store
182
+ from chuk_ai_session_manager.chuk_sessions_storage.providers.redis import create_redis_session_store
182
183
 
183
184
  # Distributed storage for production with TTL
184
185
  store = await create_redis_session_store(
@@ -0,0 +1,23 @@
1
+ chuk_ai_session_manager/__init__.py,sha256=0a8NezasrQJe2jm-1pZpzqPI-JCnrPNGTRLKDPRtyuk,11009
2
+ chuk_ai_session_manager/exceptions.py,sha256=WqrrUZuOAiUmz7tKnSnk0y222U_nV9a8LyaXLayn2fg,4420
3
+ chuk_ai_session_manager/infinite_conversation.py,sha256=7j3caMnsX27M5rjj4oOkqiy_2AfcupWwsAWRflnKiSo,12092
4
+ chuk_ai_session_manager/sample_tools.py,sha256=yZDM-ast5lv0YVHcd3GTxBMcJd7zuNkUhZPVIb06G0c,8155
5
+ chuk_ai_session_manager/session_aware_tool_processor.py,sha256=iVe3d-qfp5QGkdNrgfZeRYoOjd8nLZ0g6K7HW1thFE8,7274
6
+ chuk_ai_session_manager/session_prompt_builder.py,sha256=-ZTUczYh5emToInp4TRCj9FvF4CECyn45YHYKoWzmxE,17328
7
+ chuk_ai_session_manager/session_storage.py,sha256=HqzYDtwx4zN5an1zJmSZc56BpyD3KjT3IWonIpmnVXQ,5790
8
+ chuk_ai_session_manager/api/__init__.py,sha256=Lo_BoDW2rSn0Zw-CbjahOxc6ykjjTpucxHZo5FA2Gnc,41
9
+ chuk_ai_session_manager/api/simple_api.py,sha256=N2Y0b7JkQsWLCvU1uGyAfYTGqyyCmG26X2PnKt3vux4,12040
10
+ chuk_ai_session_manager/models/__init__.py,sha256=H1rRuDQDRf821JPUWUn5Zgwvc5BAqcEGekkHEmX-IgE,1167
11
+ chuk_ai_session_manager/models/event_source.py,sha256=mn_D16sXMa6nAX-5BzssygJPz6VF24GRe-3IaH7bTnI,196
12
+ chuk_ai_session_manager/models/event_type.py,sha256=TPPvAz-PlXVtrwXDNVFVnhdt1yEfgDGmKDGt8ArYcTk,275
13
+ chuk_ai_session_manager/models/session.py,sha256=Txnmqd5SmiMz6acur_zL5MiFHJjKqU2se895p7_zUNQ,11781
14
+ chuk_ai_session_manager/models/session_event.py,sha256=YPDbymduF42LLHtAv_k_kqlWF68vnth5J_HM4q-bOyI,5896
15
+ chuk_ai_session_manager/models/session_metadata.py,sha256=KFG7lc_E0BQTP2OD9Y529elVGJXppDUMqz8vVONW0rw,1510
16
+ chuk_ai_session_manager/models/session_run.py,sha256=uhMM4-WSrqOUsiWQPnyakInd-foZhxI-YnSHSWiZZwE,4369
17
+ chuk_ai_session_manager/models/token_usage.py,sha256=pnsNDMew9ToUqkRCIz1TADnHC5aKnautdLD4trCA6Zg,11121
18
+ chuk_ai_session_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ chuk_ai_session_manager/utils/status_display_utils.py,sha256=id4TIE0VSq3thvDd4wKIyk3kBr_bUMqrtXmOI9CD8r8,19231
20
+ chuk_ai_session_manager-0.2.dist-info/METADATA,sha256=jucZml2QT7GsqdM8I4U5I7uBm8pdWtrS2dNdvWYoxvc,16465
21
+ chuk_ai_session_manager-0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
+ chuk_ai_session_manager-0.2.dist-info/top_level.txt,sha256=5RinqD0v-niHuLYePUREX4gEWTlrpgtUg0RfexVRBMk,24
23
+ chuk_ai_session_manager-0.2.dist-info/RECORD,,
@@ -1,44 +0,0 @@
1
- # chuk_ai_session_manager/storage/__init__.py
2
- """
3
- Storage module for the chuk session manager.
4
- """
5
- # Import base components first to avoid circular imports
6
- try:
7
- from chuk_ai_session_manager.storage.base import SessionStoreInterface, SessionStoreProvider
8
- except ImportError:
9
- pass
10
-
11
- # Try to import providers if available
12
- try:
13
- from chuk_ai_session_manager.storage.providers.memory import InMemorySessionStore
14
- except ImportError:
15
- pass
16
-
17
- try:
18
- from chuk_ai_session_manager.storage.providers.file import FileSessionStore, create_file_session_store
19
- except ImportError:
20
- pass
21
-
22
- # Try to import Redis - this is optional
23
- try:
24
- from chuk_ai_session_manager.storage.providers.redis import RedisSessionStore, create_redis_session_store
25
- _has_redis = True
26
- except ImportError:
27
- _has_redis = False
28
-
29
- # Define __all__ based on what was successfully imported
30
- __all__ = []
31
-
32
- # Basic components
33
- for name in ['SessionStoreInterface', 'SessionStoreProvider', 'InMemorySessionStore']:
34
- if name in globals():
35
- __all__.append(name)
36
-
37
- # File store
38
- for name in ['FileSessionStore', 'create_file_session_store']:
39
- if name in globals():
40
- __all__.append(name)
41
-
42
- # Redis store (optional)
43
- if _has_redis:
44
- __all__.extend(['RedisSessionStore', 'create_redis_session_store'])
@@ -1,50 +0,0 @@
1
- # chuk_ai_session_manager/storage/base.py
2
- """
3
- Base interfaces and providers for async session storage.
4
- """
5
- from abc import ABC, abstractmethod
6
- from typing import Any, Dict, List, Optional, TypeVar
7
-
8
- T = TypeVar('T')
9
-
10
- class SessionStoreInterface(ABC):
11
- """Interface for pluggable async session stores."""
12
-
13
- @abstractmethod
14
- async def get(self, session_id: str) -> Optional[Any]:
15
- """Retrieve a session by its ID, or None if not found."""
16
- ...
17
-
18
- @abstractmethod
19
- async def save(self, session: Any) -> None:
20
- """Save or update a session object in the store."""
21
- ...
22
-
23
- @abstractmethod
24
- async def delete(self, session_id: str) -> None:
25
- """Delete a session by its ID."""
26
- ...
27
-
28
- @abstractmethod
29
- async def list_sessions(self, prefix: str = "") -> List[str]:
30
- """List all session IDs, optionally filtered by prefix."""
31
- ...
32
-
33
-
34
- class SessionStoreProvider:
35
- """Provider for a globally-shared async session store."""
36
- _store: Optional[SessionStoreInterface] = None
37
-
38
- @classmethod
39
- def get_store(cls) -> SessionStoreInterface:
40
- """Get the currently configured session store."""
41
- if cls._store is None:
42
- # Defer import to avoid circular imports
43
- from chuk_ai_session_manager.storage.providers.memory import InMemorySessionStore
44
- cls._store = InMemorySessionStore()
45
- return cls._store
46
-
47
- @classmethod
48
- def set_store(cls, store: SessionStoreInterface) -> None:
49
- """Set a new session store implementation."""
50
- cls._store = store
@@ -1,348 +0,0 @@
1
- # chuk_ai_session_manager/storage/providers/file.py
2
-
3
- """
4
- Async file-based session storage implementation with improved async semantics.
5
- """
6
- import json
7
- import logging
8
- import asyncio
9
- from datetime import datetime
10
- from pathlib import Path
11
- from typing import Any, Dict, List, Optional, Type, TypeVar, Union, Generic
12
- import os
13
-
14
- # Check for aiofiles availability
15
- try:
16
- import aiofiles
17
- AIOFILES_AVAILABLE = True
18
- except ImportError:
19
- AIOFILES_AVAILABLE = False
20
- logging.warning("aiofiles package not installed; falling back to synchronous I/O in thread pool.")
21
-
22
- # session manager imports
23
- from chuk_ai_session_manager.models.session import Session
24
- from chuk_ai_session_manager.storage.base import SessionStoreInterface
25
- from chuk_ai_session_manager.exceptions import SessionManagerError
26
-
27
- # Type variable for serializable models
28
- T = TypeVar('T', bound='Session')
29
-
30
- # Setup logging
31
- logger = logging.getLogger(__name__)
32
-
33
-
34
- class FileStorageError(SessionManagerError):
35
- """Raised when file storage operations fail."""
36
- pass
37
-
38
-
39
- class SessionSerializer(Generic[T]):
40
- """Handles serialization and deserialization of session objects."""
41
-
42
- @classmethod
43
- def to_dict(cls, obj: T) -> Dict[str, Any]:
44
- """Convert a session object to a dictionary for serialization."""
45
- # Use Pydantic's model_dump method for serialization
46
- return obj.model_dump()
47
-
48
- @classmethod
49
- def from_dict(cls, data: Dict[str, Any], model_class: Type[T]) -> T:
50
- """Convert a dictionary to a session object."""
51
- try:
52
- # Use Pydantic's model validation for deserialization
53
- return model_class.model_validate(data)
54
- except Exception as e:
55
- raise FileStorageError(f"Failed to deserialize {model_class.__name__}: {str(e)}")
56
-
57
-
58
- class FileSessionStore(SessionStoreInterface, Generic[T]):
59
- """
60
- An async file session store that persists sessions to JSON files.
61
-
62
- This implementation stores each session as a separate JSON file in
63
- the specified directory, using aiofiles for non-blocking I/O when available.
64
- It uses file locks to prevent race conditions during reads and writes.
65
- """
66
-
67
- def __init__(self,
68
- directory: Union[str, Path],
69
- session_class: Type[T] = Session,
70
- auto_save: bool = True):
71
- """
72
- Initialize the async file session store.
73
-
74
- Args:
75
- directory: Directory where session files will be stored
76
- session_class: The Session class to use for deserialization
77
- auto_save: Whether to automatically save on each update
78
- """
79
- self.directory = Path(directory)
80
- self.directory.mkdir(parents=True, exist_ok=True)
81
- self.session_class = session_class
82
- self.auto_save = auto_save
83
-
84
- # In-memory cache for better performance
85
- self._cache: Dict[str, T] = {}
86
-
87
- # Locks for file operations (keyed by session ID)
88
- self._locks: Dict[str, asyncio.Lock] = {}
89
-
90
- def _get_path(self, session_id: str) -> Path:
91
- """Get the file path for a session ID."""
92
- return self.directory / f"{session_id}.json"
93
-
94
- def _json_default(self, obj: Any) -> Any:
95
- """Handle non-serializable objects in JSON serialization."""
96
- if isinstance(obj, datetime):
97
- return obj.isoformat()
98
- raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
99
-
100
- async def _get_lock(self, session_id: str) -> asyncio.Lock:
101
- """Get a lock for a specific session ID."""
102
- if session_id not in self._locks:
103
- self._locks[session_id] = asyncio.Lock()
104
- return self._locks[session_id]
105
-
106
- async def get(self, session_id: str) -> Optional[T]:
107
- """Async: Retrieve a session by its ID."""
108
- # Check cache first
109
- if session_id in self._cache:
110
- return self._cache[session_id]
111
-
112
- # If not in cache, try to load from file
113
- file_path = self._get_path(session_id)
114
- if not file_path.exists():
115
- return None
116
-
117
- # Get lock for this session
118
- lock = await self._get_lock(session_id)
119
-
120
- # Use lock for file read to prevent race conditions
121
- async with lock:
122
- try:
123
- if AIOFILES_AVAILABLE:
124
- async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
125
- data_str = await f.read()
126
- data = json.loads(data_str)
127
- else:
128
- # If aiofiles not available, use executor to avoid blocking
129
- loop = asyncio.get_running_loop()
130
- data_str = await loop.run_in_executor(
131
- None,
132
- lambda: open(file_path, 'r', encoding='utf-8').read()
133
- )
134
- data = json.loads(data_str)
135
-
136
- session = SessionSerializer.from_dict(data, self.session_class)
137
- # Update cache
138
- self._cache[session_id] = session
139
- return session
140
- except (FileStorageError, json.JSONDecodeError, IOError) as e:
141
- logger.error(f"Failed to load session {session_id}: {e}")
142
- return None
143
-
144
- async def save(self, session: T) -> None:
145
- """Async: Save a session to the store."""
146
- session_id = session.id
147
- # Update cache
148
- self._cache[session_id] = session
149
-
150
- if self.auto_save:
151
- await self._save_to_file(session)
152
-
153
- async def _save_to_file(self, session: T) -> None:
154
- """Async: Save a session to its JSON file."""
155
- session_id = session.id
156
- file_path = self._get_path(session_id)
157
-
158
- # Get lock for this session
159
- lock = await self._get_lock(session_id)
160
-
161
- # Use lock for file write to prevent race conditions
162
- async with lock:
163
- try:
164
- # Create temp file first to avoid partial writes
165
- temp_path = file_path.with_suffix('.tmp')
166
-
167
- data = SessionSerializer.to_dict(session)
168
- json_str = json.dumps(data, default=self._json_default, indent=2)
169
-
170
- if AIOFILES_AVAILABLE:
171
- async with aiofiles.open(temp_path, 'w', encoding='utf-8') as f:
172
- await f.write(json_str)
173
- else:
174
- # If aiofiles not available, use executor to avoid blocking
175
- loop = asyncio.get_running_loop()
176
- await loop.run_in_executor(
177
- None,
178
- lambda: open(temp_path, 'w', encoding='utf-8').write(json_str)
179
- )
180
-
181
- # Rename temp file to actual file (atomic operation)
182
- os.replace(temp_path, file_path)
183
-
184
- except (FileStorageError, IOError, TypeError) as e:
185
- logger.error(f"Failed to save session {session_id}: {e}")
186
- if temp_path.exists():
187
- temp_path.unlink() # Clean up temp file
188
- raise FileStorageError(f"Failed to save session {session_id}: {str(e)}")
189
-
190
- async def delete(self, session_id: str) -> None:
191
- """Async: Delete a session by its ID."""
192
- # Remove from cache
193
- if session_id in self._cache:
194
- del self._cache[session_id]
195
-
196
- # Get lock for this session
197
- lock = await self._get_lock(session_id)
198
-
199
- # Use lock for deletion to prevent race conditions
200
- async with lock:
201
- # Remove file if it exists
202
- file_path = self._get_path(session_id)
203
- if file_path.exists():
204
- try:
205
- # Run in executor to avoid blocking
206
- loop = asyncio.get_running_loop()
207
- await loop.run_in_executor(None, file_path.unlink)
208
- except IOError as e:
209
- logger.error(f"Failed to delete session file {session_id}: {e}")
210
- raise FileStorageError(f"Failed to delete session {session_id}: {str(e)}")
211
-
212
- # Remove lock for this session
213
- if session_id in self._locks:
214
- del self._locks[session_id]
215
-
216
- async def list_sessions(self, prefix: str = "") -> List[str]:
217
- """Async: List all session IDs, optionally filtered by prefix."""
218
- try:
219
- # Run in executor to avoid blocking
220
- loop = asyncio.get_running_loop()
221
- files = await loop.run_in_executor(
222
- None,
223
- lambda: list(self.directory.glob("*.json"))
224
- )
225
-
226
- # Extract the session IDs (filenames without extension)
227
- session_ids = [f.stem for f in files]
228
-
229
- # Filter by prefix if provided
230
- if prefix:
231
- session_ids = [sid for sid in session_ids if sid.startswith(prefix)]
232
-
233
- return session_ids
234
- except IOError as e:
235
- logger.error(f"Failed to list sessions: {e}")
236
- raise FileStorageError(f"Failed to list sessions: {str(e)}")
237
-
238
- async def flush(self) -> None:
239
- """Async: Force save all cached sessions to disk."""
240
- save_tasks = []
241
- for session in self._cache.values():
242
- # Create tasks but don't await them yet
243
- task = asyncio.create_task(self._save_to_file(session))
244
- save_tasks.append(task)
245
-
246
- # Wait for all save operations to complete
247
- if save_tasks:
248
- # Use gather with return_exceptions to prevent one error from stopping all saves
249
- results = await asyncio.gather(*save_tasks, return_exceptions=True)
250
-
251
- # Log any errors
252
- for result in results:
253
- if isinstance(result, Exception):
254
- logger.error(f"Error during flush: {result}")
255
-
256
- async def clear_cache(self) -> None:
257
- """Async: Clear the in-memory cache."""
258
- self._cache.clear()
259
-
260
- async def vacuum(self) -> int:
261
- """
262
- Async: Remove orphaned temporary files and fix any corrupt files.
263
-
264
- Returns:
265
- Number of fixed or removed files
266
- """
267
- count = 0
268
-
269
- try:
270
- # Find all temp files
271
- loop = asyncio.get_running_loop()
272
- temp_files = await loop.run_in_executor(
273
- None,
274
- lambda: list(self.directory.glob("*.tmp"))
275
- )
276
-
277
- # Delete temp files
278
- for temp_file in temp_files:
279
- try:
280
- await loop.run_in_executor(None, temp_file.unlink)
281
- count += 1
282
- except IOError as e:
283
- logger.error(f"Failed to delete temp file {temp_file}: {e}")
284
-
285
- # Find all json files
286
- json_files = await loop.run_in_executor(
287
- None,
288
- lambda: list(self.directory.glob("*.json"))
289
- )
290
-
291
- # Check each file for corruption
292
- for json_file in json_files:
293
- try:
294
- # Try to read the file
295
- if AIOFILES_AVAILABLE:
296
- async with aiofiles.open(json_file, 'r', encoding='utf-8') as f:
297
- data_str = await f.read()
298
- # Just try to parse it to see if it's valid JSON
299
- json.loads(data_str)
300
- else:
301
- data_str = await loop.run_in_executor(
302
- None,
303
- lambda: open(json_file, 'r', encoding='utf-8').read()
304
- )
305
- json.loads(data_str)
306
- except (json.JSONDecodeError, IOError) as e:
307
- # File is corrupt, rename it
308
- logger.warning(f"Found corrupt file {json_file}: {e}")
309
- corrupt_path = json_file.with_suffix('.corrupt')
310
- await loop.run_in_executor(
311
- None,
312
- lambda: os.rename(json_file, corrupt_path)
313
- )
314
- count += 1
315
-
316
- return count
317
- except Exception as e:
318
- logger.error(f"Error during vacuum: {e}")
319
- raise FileStorageError(f"Failed to vacuum storage: {str(e)}")
320
-
321
-
322
- async def create_file_session_store(
323
- directory: Union[str, Path],
324
- session_class: Type[T] = Session,
325
- auto_save: bool = True
326
- ) -> FileSessionStore[T]:
327
- """
328
- Create an async file-based session store.
329
-
330
- Args:
331
- directory: Directory where session files will be stored
332
- session_class: The Session class to use
333
- auto_save: Whether to automatically save on each update
334
-
335
- Returns:
336
- A configured FileSessionStore
337
- """
338
- store = FileSessionStore(directory, session_class, auto_save)
339
-
340
- # Optional: Run vacuum on startup to clean any leftover temp files
341
- try:
342
- fixed_count = await store.vacuum()
343
- if fixed_count > 0:
344
- logger.info(f"Cleaned up {fixed_count} temporary or corrupt files during store initialization")
345
- except Exception as e:
346
- logger.warning(f"Error during initial vacuum: {e}")
347
-
348
- return store
@@ -1,96 +0,0 @@
1
- # chuk_ai_session_manager/storage/providers/memory.py
2
- """
3
- Async in-memory session storage implementation with improved async semantics.
4
- """
5
- from typing import Any, Dict, List, Optional
6
- import asyncio
7
- from datetime import datetime
8
-
9
- from chuk_ai_session_manager.storage.base import SessionStoreInterface
10
-
11
-
12
- class InMemorySessionStore(SessionStoreInterface):
13
- """A simple in-memory store for Session objects with proper async interface.
14
-
15
- This implementation stores sessions in a dictionary and is not
16
- persistent across application restarts. It uses asyncio locks to
17
- ensure thread safety when multiple coroutines access the store.
18
- """
19
-
20
- def __init__(self) -> None:
21
- """Initialize an empty in-memory store."""
22
- self._data: Dict[str, Any] = {}
23
- self._lock = asyncio.Lock() # For thread safety in async operations
24
-
25
- async def get(self, session_id: str) -> Optional[Any]:
26
- """Async: Retrieve a session by its ID, or None if not found."""
27
- # Read operations don't need locking
28
- return self._data.get(session_id)
29
-
30
- async def save(self, session: Any) -> None:
31
- """Async: Save or update a session object in the store."""
32
- async with self._lock:
33
- self._data[session.id] = session
34
-
35
- # Update metadata timestamp if available
36
- if hasattr(session, 'metadata') and hasattr(session.metadata, 'update_timestamp'):
37
- await session.metadata.update_timestamp()
38
-
39
- async def delete(self, session_id: str) -> None:
40
- """Async: Delete a session by its ID."""
41
- async with self._lock:
42
- if session_id in self._data:
43
- del self._data[session_id]
44
-
45
- async def list_sessions(self, prefix: str = "") -> List[str]:
46
- """Async: List all session IDs, optionally filtered by prefix."""
47
- # Read operations don't need locking
48
- if not prefix:
49
- return list(self._data.keys())
50
- return [sid for sid in self._data.keys() if sid.startswith(prefix)]
51
-
52
- async def clear(self) -> None:
53
- """Async: Clear all sessions from the store."""
54
- async with self._lock:
55
- self._data.clear()
56
-
57
- async def get_by_property(self, key: str, value: Any) -> List[Any]:
58
- """
59
- Async: Find sessions by a specific metadata property value.
60
-
61
- Args:
62
- key: The metadata property key to search for
63
- value: The value to match
64
-
65
- Returns:
66
- A list of matching sessions
67
- """
68
- results = []
69
- for session in self._data.values():
70
- if (hasattr(session, 'metadata') and
71
- hasattr(session.metadata, 'properties') and
72
- session.metadata.properties.get(key) == value):
73
- results.append(session)
74
- return results
75
-
76
- async def get_by_state(self, key: str, value: Any) -> List[Any]:
77
- """
78
- Async: Find sessions by a specific state value.
79
-
80
- Args:
81
- key: The state key to search for
82
- value: The value to match
83
-
84
- Returns:
85
- A list of matching sessions
86
- """
87
- results = []
88
- for session in self._data.values():
89
- if (hasattr(session, 'state') and
90
- session.state.get(key) == value):
91
- results.append(session)
92
- return results
93
-
94
- async def count(self) -> int:
95
- """Async: Count the number of sessions in the store."""
96
- return len(self._data)