session/¶
Session lifecycle and persistence with provider isolation and topic/channel-aware keys.
Files¶
session/key.py:SessionKey(transport, chat_id, topic_id)session/manager.py:ProviderSessionData,SessionData,SessionManagersession/named.py:NamedSession,NamedSessionRegistry
Session identity (SessionKey)¶
SessionKey is transport-aware:
- Telegram default chats ->
SessionKey("tg", chat_id, None) - Telegram forum topics ->
SessionKey("tg", chat_id, message_thread_id) - Matrix rooms ->
SessionKey("mx", mapped_room_int, None) - API channel scope ->
SessionKey("api", chat_id, channel_id)
Persistence key (storage_key) format:
- legacy accepted on parse:
"<chat_id>"or"<chat_id>:<topic_id>" - current:
"<transport>:<chat_id>"or"<transport>:<chat_id>:<topic_id>"
Parsing is backward-compatible (SessionKey.parse).
SessionData model¶
Fields:
chat_idtopic_id(optional)topic_name(optional cached display name)provider,model(active target for this session key)created_at,last_activeprovider_sessions: dict[str, ProviderSessionData]
Provider bucket (ProviderSessionData):
session_idmessage_counttotal_cost_usdtotal_tokens
Compatibility behavior:
- legacy flat metrics/session fields are migrated into provider buckets
- legacy storage keys are still accepted
SessionManager API¶
resolve_session(key, provider=None, model=None, preserve_existing_target=False)get_active(key)list_active_for_chat(chat_id)list_all()reset_session(key, provider=None, model=None)reset_provider_session(key, provider, model)update_session(session, cost_usd=0.0, tokens=0)sync_session_target(session, provider=None, model=None)set_topic_name_resolver(resolver)
Freshness and rollover¶
Session freshness checks include:
max_session_messages- idle timeout (
idle_timeout_minutes,0disables) - daily reset boundary (
daily_reset_enabled,daily_reset_hour,user_timezone) - timestamp validity
Stale sessions are replaced on next resolve_session(...) call.
Provider/model switching behavior¶
Switching model/provider for a key:
- updates active target for that key
- keeps other provider buckets intact
is_new=Trueonly if target provider bucket lackssession_id
This enables seamless return to previously used provider buckets.
Topic name integration¶
SessionManager can resolve and backfill topic names through a callback:
set_topic_name_resolver((chat_id, topic_id) -> str)- used by bot startup with
TopicNameCache - persisted
topic_nameimproves/statusand/sessionsreadability
Named sessions (NamedSessionRegistry)¶
Purpose:
- background
/sessionregistry - deterministic inter-agent sessions (
ia-<sender>)
Model fields:
name,chat_id,provider,modelsession_id,prompt_preview,status,created_at,message_count,last_prompt
Status values:
runningidleended
Behavior:
- user-created cap:
MAX_SESSIONS_PER_CHAT = 10 - persisted
runningentries are downgraded toidleon load - recovered-running sessions are tracked for startup recovery
Persistence¶
- sessions:
~/.sygen/sessions.json - named sessions:
~/.sygen/named_sessions.json
Storage is JSON + atomic write helpers (atomic_json_save). I/O runs in worker threads (asyncio.to_thread).