fix(runtime, channels): unify session backend behind one factory#6384
Open
singlerider wants to merge 2 commits intozeroclaw-labs:masterfrom
Open
fix(runtime, channels): unify session backend behind one factory#6384singlerider wants to merge 2 commits intozeroclaw-labs:masterfrom
singlerider wants to merge 2 commits intozeroclaw-labs:masterfrom
Conversation
The gateway WebSocket handler persists sessions to SqliteSessionBackend (sessions/sessions.db, with gw_-prefixed keys) and the gateway REST API reads from the same place. The session tools (sessions_list, sessions_history, sessions_send) were initialized with the JSONL SessionStore, so they looked at sessions/*.jsonl files the gateway never writes. Result: gateway sessions are invisible to the agent. sessions_list returns "No active sessions found" even when the SQLite store has gw_ entries, and sessions_history returns "No messages found" for any gateway session ID. The agent then hallucinates session IDs because the tool returns empty data. Switch the registration site at crates/zeroclaw-runtime/src/tools/mod.rs to SqliteSessionBackend. Both backends implement the SessionBackend trait with the same new(&Path) signature, so this is a one-line swap plus a comment update. Closes zeroclaw-labs#5769.
The original PR swapped the runtime tools to SqliteSessionBackend without touching the channel orchestrator, which still hardcoded the JSONL SessionStore. That trades one half-blindness for another: sessions written by channels (Telegram, Slack, Discord, ...) become invisible to the agent's sessions_list / sessions_history tools. Introduce zeroclaw_infra::make_session_backend(workspace_dir, &str) that picks JSONL or SQLite based on [channels].session_backend (which the schema already exposes; nothing was reading it). Both call sites (channel orchestrator session_store, runtime tool registration) now go through this factory, so the configured backend is the single source of truth and channel + WS sessions both surface in the same store. The orchestrator's session_store field switches from Option<Arc<SessionStore>> to Option<Arc<dyn SessionBackend>>. The mtime-based hydration sort is replaced with the trait's list_sessions_with_metadata() last_activity field, which both backends already populate, so there is no SessionStore-specific method on the hot path. Closes zeroclaw-labs#5769
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The session tools (
sessions_list,sessions_history,sessions_send,sessions_current) were registered against the JSONLSessionStore, but the gateway WebSocket handler persisted sessions toSqliteSessionBackend. Any session created via/ws/chatwas therefore invisible to the agent's own session tools (sessions_listreturned "No active sessions found" for valid gateway session IDs, and the agent then hallucinated session IDs).Naively swapping the tool registration to SQLite would have traded one half-blindness for another: the channel orchestrator was opening JSONL too, so channel sessions (Telegram, Slack, Discord, ...) would have stopped showing up in the tools.
Introduce
zeroclaw_infra::make_session_backend(workspace_dir, &str)that picks JSONL or SQLite based on the existing[channels].session_backendconfig field (which the schema already exposed; nothing was reading it). Both call sites, the channel orchestrator'ssession_storeand the runtime tool registration, now go through this factory. The configured backend becomes the single source of truth and channel + WS sessions both surface in the same store.The orchestrator's
session_storefield switches fromOption<Arc<SessionStore>>toOption<Arc<dyn SessionBackend>>. The mtime-based hydration sort is replaced with the trait'slist_sessions_with_metadata().last_activityfield, which both backends populate, so noSessionStore-specific method is on the hot path.Closes #5769
Validation Evidence
cargo fmt --all -- --check cargo clippy --workspace --exclude zeroclaw-desktop --all-targets --features ci-all -- -D warnings cargo test --package zeroclaw-channels --lib rollback_orphan_user_turnAll three pass locally.
Security & Privacy Impact
Compatibility
session_backend = "sqlite"). Operators who setsession_backend = "jsonl"continue to read/write JSONL files; the difference is that runtime tools now honour the same setting, so they see those sessions too.[channels].session_backendis now load-bearing for both call sites instead of just the gateway.Rollback
git revert <merge-sha>. The orchestrator and tool registration both revert in lockstep; no migration is required because each backend reads its own on-disk format.