Skip to content

Chat sidebar: lazy Archived + System groups, unbounded conversation feed - #269

Open
arsenmuk wants to merge 1 commit into
mainfrom
arsenmuk/archived-sessions-group
Open

Chat sidebar: lazy Archived + System groups, unbounded conversation feed#269
arsenmuk wants to merge 1 commit into
mainfrom
arsenmuk/archived-sessions-group

Conversation

@arsenmuk

@arsenmuk arsenmuk commented Aug 4, 2026

Copy link
Copy Markdown
Member

Problem

The sidebar silently dropped active chats: GET /api/sessions capped non-starred sessions at 50, and cron sessions (bumped every heartbeat tick) crowded conversations out of those slots. Archived sessions had no UI at all — and no unarchive path existed anywhere in the backend.

Changes

Backend

  • GET /api/sessions now serves list_active_sessions(): all non-archived conversation sessions, unbounded; cron/hook sources excluded from the feed. archived_count + system_count ride on the payload (two COUNT(*)s), so collapsed groups show a badge without fetching rows.
  • New GET /api/sessions/archived and GET /api/sessions/system — fetched lazily, only when the corresponding sidebar group is expanded.
  • New POST /api/sessions/{id}/unarchive (restores to idle, clears archived_at, logs an unarchived event) — inverse of archive.
  • PATCH /api/sessions/{id} with starred: true on an archived session unarchives + stars in one write, so the star→project hook fires on a live session.
  • Telegram's session picker keeps the old bounded list_sessions — untouched.

Frontend

  • New Archived and System groups at the bottom of the sidebar: collapsed by default (not persisted), lazy-fetch on first expand with spinner/empty states, hidden entirely when their count is 0.
  • Archived rows use the standard session item with a Star / Rename / Unarchive / Delete menu.
  • Date buckets simplified to Last hour / Last 3 hours / Today / This week / Other; the first two are elapsed-time (correct across midnight); empty buckets never render.

Testing

  • pytest tests/test_sessions.py — 70/70 (10 new: unarchive lifecycle/events/missing, archived list/count, star-unarchive write, active-feed exclusions, unbounded feed regression, system list/count).
  • npm run build (tsc + vite) green.
  • Validated live: no /archived / /system request until expand; unarchive returns a session to its date group; starring an archived session lands it in Starred.

🤖 Generated with Claude Code

The sidebar feed used one LIMIT 50 window over every session row, cron
included, so ~96 cron runs a day pushed conversations out of the pane
within hours. Rework it into three server-scoped lists with one shared
page-size knob:

- sessions.sidebar_page_size (default 50, 0 = unlimited) caps the feed
  and sizes one Archived/System page.
- The window applies only to non-archived, non-system rows, so cron
  traffic can never displace conversations.
- Starred sessions are off-budget: always returned in full, whatever
  the page size, and pinned even when their source is cron/hook.
- Archived and System load lazily (nothing fetched until expanded) and
  page via ?offset=, with has_more/next_offset driving a '...' row.
  Collapsing a group drops its rows, so reopening repeats the same
  cold request. The feed gets the same '...' rather than truncating
  silently.
- Sources split by exclusion (system = cron/hook): the client no longer
  whitelists, so workflow/external sessions stop rendering nowhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@arsenmuk
arsenmuk force-pushed the arsenmuk/archived-sessions-group branch from 8e8d187 to 72c7263 Compare August 11, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant