session¶
Session persistence — markdown file legacy + Supabase PostgreSQL manager.
SQLSessionManager
¶
Supabase PostgreSQL session persistence with per-user isolation.
All queries are parameterized and run via asyncio.to_thread() through the supabase-py client.
__init__(_unused='')
¶
Create the manager (stateless — keeps the legacy signature).
add_turn(session_id, turn_data, dek=None)
async
¶
Persist one turn as two message rows (user + assistant).
Assigns the next turn_number, encrypts content fields when a DEK is available, and bumps the session's updated_at.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
Target session id. |
required |
turn_data
|
dict
|
Dict with prompt, response, tools_called, cited_sources, chunks, timestamp. |
required |
dek
|
bytes | None
|
Optional data key for runtime encryption. |
None
|
delete_session(session_id, user_id)
async
¶
Delete a user-owned session and all its messages.
Returns False when the session does not exist or belongs to another user (nothing deleted).
get_session(session_id, user_id, dek=None)
async
¶
Load one session with merged turns, decrypted via the DEK.
Rows written before runtime encryption are lazily re-keyed when a DEK is available. Returns None when the session does not belong to the user.
get_session_preview(session_id, user_id, dek=None)
async
¶
Return a sidebar preview — first 3 turns, truncated.
list_sessions(user_id, role='user', dek=None)
async
¶
List a user's sessions with decrypted titles and turn counts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
Owner UUID. |
required |
role
|
str
|
Ignored (kept for CLI compatibility). |
'user'
|
dek
|
bytes | None
|
Optional data key — encrypted titles decrypt only when it is provided; otherwise they surface as empty. |
None
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
List of session dicts (id, title, created, updated, axes, |
list[dict]
|
turns), newest first. |
owns_session(session_id, user_id)
async
¶
Return True if the session exists and belongs to the user.
purge_legacy()
async
¶
Delete plaintext (pre-encryption) rows and blank legacy titles.
One-click admin cleanup for data that predates runtime encryption. Encrypted rows are never touched. Returns counts of deleted message rows and cleared titles.
rekey_user(user_id, dek)
async
¶
Bulk-encrypt every plaintext field belonging to a user.
Runs after a client first presents its DEK post-rollout (the login-triggered lazy re-key). Encrypts session titles and message fields in place; encrypted rows are skipped. Returns the number of rows rewritten. Best-effort — a failure on one row must not abort the sweep.
start_new_session(user_id, session_id, title, axes='{}', dek=None)
async
¶
Create a session row; the title is encrypted when a DEK is set.
SessionManager
¶
Legacy markdown-file session persistence.
Maintained for migration and backward compatibility with CLI. For web API, use SQLSessionManager instead.
__init__(sessions_dir, axes=None)
¶
Create the manager, ensuring the sessions directory exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sessions_dir
|
Path | str
|
Directory holding one .md file per session. |
required |
axes
|
dict | None
|
Initial axis values (defaults to a balanced config). |
None
|
add_turn(turn)
¶
Append one conversation turn to the session file.
The turn dict carries prompt, response, chunks (RAG context), tools_called, cited_sources, and timestamp. Appends a '## Turn N' section and refreshes the file's Last Updated.
get_title()
¶
Return the first turn's prompt truncated to 60 chars.
list_sessions()
¶
List up to 50 session metadata dicts, newest first.
load_session(session_id_or_prefix)
¶
Load a session by exact id or id prefix into current state.
Returns the metadata dict, or None when no session matches.
set_axes(axes)
¶
Merge new axis values over the current configuration.
start_new(first_prompt)
¶
Create a fresh session file with a header derived from the prompt.
The session id is YYYYMMDD_HHMMSS_slug where the slug comes
from the first 50 chars of the prompt. In-memory turns reset.
turns_to_history(messages)
¶
Convert merged session turns into LLM history messages.
Each turn has a prompt and response; empty parts are skipped
so a half-saved turn (e.g. interrupted reply) never produces an
empty message in the model's context.