aimu.sessions¶
Multi-user session storage: per-conversation state keyed by channel:sender, so one process serves many users/chats. See how-to: use sessions.
Sync, matching the MemoryStore / ConversationManager family; the async assistant loop calls it directly.
aimu.sessions.Session
dataclass
¶
Session(key: str, messages: list[dict] = list(), memory_namespace: Optional[str] = None, metadata: dict[str, Any] = dict())
One conversation's persisted state.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
The session key (see :func: |
messages |
list[dict]
|
Conversation history as |
memory_namespace |
Optional[str]
|
Optional scope a caller can pass to a |
metadata |
dict[str, Any]
|
Free-form, opaque to the library (display name, locale, ...). |
aimu.sessions.SessionSummary
dataclass
¶
SessionSummary(key: str, message_count: int, memory_namespace: Optional[str], metadata: dict[str, Any])
One stored session, without its messages.
Everything a :class:Session carries except messages, plus how many of them there are. That
definition is the point: a caller listing conversations wants titles and timestamps, and reading
every transcript to get them is the cost this type exists to avoid.
message_count is the one field that is not a projection, since it is computed over the very
thing being excluded. It is here because "how many messages" is the most universal summary fact
about a conversation, and recovering it otherwise means the full read again.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
The session key (see :func: |
message_count |
int
|
How many messages the stored session holds. |
memory_namespace |
Optional[str]
|
The stored session's |
metadata |
dict[str, Any]
|
A detached copy of the stored session's metadata. Mutating it does nothing until
the corresponding :class: |
aimu.sessions.SessionStore ¶
Bases: ABC
A store of :class:Session state keyed by session_key(channel, sender).
get returns a detached snapshot (mutating it does nothing until save); save persists.
get
abstractmethod
¶
Return the session for key, or a fresh empty :class:Session if none is stored.
save
abstractmethod
¶
Persist session (create or replace by session.key).
delete
abstractmethod
¶
Delete the session for key. A no-op if no such session exists.
list_summaries ¶
Every stored session without its messages, in unspecified order.
Concrete rather than abstract, so an existing implementation keeps working: this default is
correct everywhere and slow anywhere a full read is expensive, and a store that can do better
overrides it. The same reasoning as :meth:close's default no-op.
Deep-copies each session's metadata before handing it back, rather than trusting whatever
detachment get() already did. SessionSummary.metadata promises a caller can mutate it
freely, and this default has no way to know how deep an arbitrary subclass's get() copies:
this library's own InMemorySessionStore.get copies only one level, which is enough for a
Session a caller is expected to fetch, change, and save again, but not enough for a
summary nobody saves. Overriding list_summaries (as TinyDBSessionStore does) can skip
this copy when the override's own read path already returns freshly-built data.
No ordering parameter and no paging, because both need a sort key and every candidate lives
in metadata, which this library treats as opaque. A caller sorts the result by whichever
of its own keys it means.
aimu.sessions.InMemorySessionStore ¶
Bases: SessionStore
A non-durable :class:SessionStore backed by a dict. Sessions are lost on process exit.
get and save copy, so the stored state is detached from the returned/passed object
(same contract as the persisted stores).
list_summaries ¶
Summaries with deeply-copied metadata.
Deeper than :meth:get's one-level copy, deliberately. get hands back a whole
Session a caller is expected to save again, so a shared nested value is visible there;
a summary is a read-only snapshot nobody saves, and a caller mutating one must not be able
to reach stored state at all.
aimu.sessions.TinyDBSessionStore ¶
Bases: SessionStore
A durable :class:SessionStore persisting one document per session to a TinyDB file.
list_summaries ¶
Summaries from one table read, projecting the messages out.
The reason this override exists: the inherited default is one whole-file parse per stored session, and TinyDB's JSON storage re-reads and re-parses the entire file on every operation. Rows come back freshly parsed, so no copy is needed for detachment.
aimu.sessions.SessionLocks ¶
Lazily-created per-key asyncio.Lock.
Serializes a single session's turns (shared message state, ordering) while letting different sessions run concurrently::
locks = SessionLocks()
async with locks(key):
... # this session's turn
Created locks are retained, so the same key always returns the same lock. Bound to the running
event loop via asyncio.Lock; use one SessionLocks per assistant process.
aimu.sessions.session_key ¶
Canonical session key from a message's channel + sender.
Single-user transports (no channel/sender) collapse to "default:default", so single-user
usage needs no ceremony.