Coverage for session_buddy / backends / base.py: 85.37%
41 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-04 00:43 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-04 00:43 -0800
1"""Base classes for serverless session storage backends.
3This module provides the abstract base class and data models for session storage
4backends including Redis, S3, local file storage, and ACB cache.
5"""
7from __future__ import annotations
9import gzip
10import logging
11from abc import ABC, abstractmethod
12from datetime import datetime
13from typing import Any
15from pydantic import BaseModel, Field, field_validator
18class SessionState(BaseModel):
19 """Represents complete session state for serialization."""
21 session_id: str = Field(
22 min_length=1,
23 description="Unique identifier for the session",
24 )
25 user_id: str = Field(min_length=1, description="Identifier for the user")
26 project_id: str = Field(min_length=1, description="Identifier for the project")
27 created_at: str = Field(description="ISO timestamp when session was created")
28 last_activity: str = Field(description="ISO timestamp of last activity")
29 permissions: list[str] = Field(
30 default_factory=list,
31 description="List of permissions granted to the session",
32 )
33 conversation_history: list[dict[str, Any]] = Field(
34 default_factory=list,
35 description="History of conversation entries",
36 )
37 reflection_data: dict[str, Any] = Field(
38 default_factory=dict,
39 description="Stored reflection and memory data",
40 )
41 app_monitoring_state: dict[str, Any] = Field(
42 default_factory=dict,
43 description="Application monitoring state",
44 )
45 llm_provider_configs: dict[str, Any] = Field(
46 default_factory=dict,
47 description="LLM provider configurations",
48 )
49 metadata: dict[str, Any] = Field(
50 default_factory=dict,
51 description="Additional session metadata",
52 )
54 @field_validator("created_at", "last_activity")
55 @classmethod
56 def validate_iso_timestamp(cls, v: str) -> str:
57 """Validate that timestamps are in ISO format."""
58 try:
59 datetime.fromisoformat(v)
60 return v
61 except ValueError as e:
62 msg = f"Invalid ISO timestamp format: {v}"
63 raise ValueError(msg) from e
65 def to_dict(self) -> dict[str, Any]:
66 """Convert to dictionary for serialization."""
67 return self.model_dump()
69 @classmethod
70 def from_dict(cls, data: dict[str, Any]) -> SessionState:
71 """Create from dictionary."""
72 return cls.model_validate(data)
74 def get_compressed_size(self) -> int:
75 """Get compressed size of session state."""
76 serialized = self.model_dump_json()
77 compressed = gzip.compress(serialized.encode("utf-8"))
78 return len(compressed)
81class SessionStorage(ABC):
82 """Abstract base class for session storage backends."""
84 def __init__(self, config: dict[str, Any]) -> None:
85 self.config = config
86 self.logger = logging.getLogger(f"serverless.{self.__class__.__name__.lower()}")
88 @abstractmethod
89 async def store_session(
90 self,
91 session_state: SessionState,
92 ttl_seconds: int | None = None,
93 ) -> bool:
94 """Store session state with optional TTL."""
96 @abstractmethod
97 async def retrieve_session(self, session_id: str) -> SessionState | None:
98 """Retrieve session state by ID."""
100 @abstractmethod
101 async def delete_session(self, session_id: str) -> bool:
102 """Delete session state."""
104 @abstractmethod
105 async def list_sessions(
106 self,
107 user_id: str | None = None,
108 project_id: str | None = None,
109 ) -> list[str]:
110 """List session IDs matching criteria."""
112 @abstractmethod
113 async def cleanup_expired_sessions(self) -> int:
114 """Clean up expired sessions, return count removed."""
116 @abstractmethod
117 async def is_available(self) -> bool:
118 """Check if storage backend is available."""