-
Notifications
You must be signed in to change notification settings - Fork 28
Chat sidebar: lazy Archived + System groups, unbounded conversation feed #269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
72c7263
Chat sidebar: configurable page size, lazy Archived + System groups
arsenmuk 5c3d406
Chat sidebar: unarchive endpoint returns 404 (not 500) for a missing …
arsenmuk 5030414
Chat sidebar: unarchiving a session bumps updated_at so it resurfaces…
arsenmuk cc140f1
Chat sidebar: star-restore an archived session through the shared una…
arsenmuk ee8bf8d
Chat sidebar: Archived group holds conversations only (exclude system…
arsenmuk c8922dc
Chat sidebar: loadSessions re-pages to preserve the feed depth on ref…
arsenmuk f577316
Chat sidebar: resolve the active session across the feed and lazy arc…
arsenmuk 8e7792c
Chat sidebar: document the paginated feed, lazy Archived/System endpo…
arsenmuk ad101e6
Chat sidebar: condense all PR-added comments and docstrings to one line
arsenmuk 462a63f
Merge remote-tracking branch 'origin/main' into arsenmuk/archived-ses…
arsenmuk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -134,17 +134,44 @@ async def _attach_review_loops(deps, sessions: list[dict]) -> None: | |
| s["review_loop"] = _loop_summary(lp) | ||
|
|
||
|
|
||
| @router.get("/api/sessions") | ||
| async def list_sessions(user: dict = Depends(require_auth)): | ||
| deps = get_deps() | ||
| sessions = await deps.engine.sessions.list_sessions() | ||
| def _page_size() -> int | None: | ||
| """Sidebar page size from config; ``None`` when configured unlimited.""" | ||
| size = get_config().sessions.sidebar_page_size | ||
| return size if size and size > 0 else None | ||
|
|
||
|
|
||
| async def _decorate(deps, sessions: list[dict]) -> list[dict]: | ||
| """Attach the live per-row bits every sidebar list needs.""" | ||
| running_ids = deps.engine.sessions.get_running_ids() | ||
| awaiting_ids = get_awaiting_ids() | ||
| for s in sessions: | ||
| s["is_running"] = s["id"] in running_ids | ||
| s["awaiting_input"] = s["id"] in awaiting_ids | ||
| await _attach_review_loops(deps, sessions) | ||
| return {"sessions": sessions} | ||
| return sessions | ||
|
|
||
|
|
||
| def _page_meta(page: list[dict], offset: int, total: int, limit: int | None) -> dict: | ||
| """``has_more``/``next_offset`` for the client's '...' control.""" | ||
| seen = offset + len(page) | ||
| return {"has_more": limit is not None and seen < total, "next_offset": seen} | ||
|
|
||
|
|
||
| @router.get("/api/sessions") | ||
| async def list_sessions(offset: int = 0, user: dict = Depends(require_auth)): | ||
| """Sidebar feed: one page of conversations, plus every starred session (starred ride along in full on offset=0).""" | ||
| deps = get_deps() | ||
| limit = _page_size() | ||
| page = await deps.engine.sessions.list_conversation_sessions(limit=limit, offset=offset) | ||
| total = await deps.engine.sessions.count_conversation_sessions() | ||
| sessions = page if offset else await deps.engine.sessions.list_starred_sessions() + page | ||
| await _decorate(deps, sessions) | ||
| return { | ||
| "sessions": sessions, | ||
| "archived_count": await deps.engine.sessions.count_archived_sessions(), | ||
| "system_count": await deps.engine.sessions.count_system_sessions(), | ||
| **_page_meta(page, offset, total, limit), | ||
| } | ||
|
|
||
|
|
||
| @router.get("/api/sessions/search") | ||
|
|
@@ -163,6 +190,28 @@ async def search_sessions(q: str, user: dict = Depends(require_auth)): | |
| return {"sessions": sessions} | ||
|
|
||
|
|
||
| @router.get("/api/sessions/archived") | ||
| async def list_archived_sessions(offset: int = 0, user: dict = Depends(require_auth)): | ||
| """One page of archived sessions — fetched only when the group is expanded.""" | ||
| deps = get_deps() | ||
| limit = _page_size() | ||
| page = await deps.engine.sessions.list_archived_sessions(limit=limit, offset=offset) | ||
| total = await deps.engine.sessions.count_archived_sessions() | ||
| await _decorate(deps, page) | ||
| return {"sessions": page, **_page_meta(page, offset, total, limit)} | ||
|
|
||
|
|
||
| @router.get("/api/sessions/system") | ||
| async def list_system_sessions(offset: int = 0, user: dict = Depends(require_auth)): | ||
| """One page of system (cron/hook) sessions — fetched only when expanded.""" | ||
| deps = get_deps() | ||
| limit = _page_size() | ||
| page = await deps.engine.sessions.list_system_sessions(limit=limit, offset=offset) | ||
| total = await deps.engine.sessions.count_system_sessions() | ||
| await _decorate(deps, page) | ||
| return {"sessions": page, **_page_meta(page, offset, total, limit)} | ||
|
|
||
|
|
||
| @router.post("/api/sessions") | ||
| async def create_session(req: SessionCreateRequest, user: dict = Depends(require_auth)): | ||
| deps = get_deps() | ||
|
|
@@ -338,6 +387,13 @@ async def update_session(session_id: str, req: dict, user: dict = Depends(requir | |
| if not fields: | ||
| raise HTTPException(status_code=400, detail="No valid fields to update") | ||
| old_starred = int(session.get("starred") or 0) | ||
| # Starring an archived session restores it via the shared unarchive path (logs "unarchived", bumps updated_at) before the star write, so the star->project hook fires on a live session. | ||
| if fields.get("starred") == 1 and session.get("status") == "archived": | ||
| if deps.engine: | ||
| await deps.engine.sessions.unarchive_session(session_id) | ||
| else: | ||
| fields["status"] = "idle" | ||
| fields["archived_at"] = None | ||
| await deps.db.update_session_fields(session_id, fields) | ||
| updated = await deps.db.get_session(session_id) | ||
| # Star = opt-in project registration (sessions.star_project_hook, default | ||
|
|
@@ -466,6 +522,17 @@ async def archive_session(session_id: str, user: dict = Depends(require_auth)): | |
| return {"archived": True} | ||
|
|
||
|
|
||
| @router.post("/api/sessions/{session_id}/unarchive") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will return 500 when the session is not found, let's catch the ValueError and return 404.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, done - 5c3d406 |
||
| async def unarchive_session(session_id: str, user: dict = Depends(require_auth)): | ||
| """Restore an archived session (Archived group → Unarchive / Star).""" | ||
| deps = get_deps() | ||
| try: | ||
| await deps.engine.sessions.unarchive_session(session_id) | ||
| return {"unarchived": True} | ||
| except ValueError as e: | ||
| raise HTTPException(status_code=404, detail=str(e)) | ||
|
|
||
|
|
||
| @router.get("/api/sessions/{session_id}/events") | ||
| async def get_session_events( | ||
| session_id: str, limit: int = 50, user: dict = Depends(require_auth), | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should also update
updated_athere, so that unarchiving a session pushes it to the top?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch, thank you - 5030414