feat: add cursor-based pagination for chat listing#295
feat: add cursor-based pagination for chat listing#295codeofpi wants to merge 1 commit intoHanaokaYuzu:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds cursor-based pagination to the chat listing API so clients can retrieve older conversations beyond the init-time cache, and updates the CLI to expose paging/all-chats retrieval.
Changes:
- Introduce
ChatListPagemodel to return chat items plus a next-page cursor. - Add new paginated chat listing APIs (
list_chats_page,list_all_chats) and internal parsing/helpers inChatMixin. - Update
cli.py listcommand to use the new pagination APIs and add--cursor/--allflags.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/gemini_webapi/types/chatlistpage.py |
Adds a typed container for a chat listing page (items + cursor). |
src/gemini_webapi/types/__init__.py |
Exports ChatListPage from the types package. |
src/gemini_webapi/components/chat_mixin.py |
Implements parsing + paginated listing methods and refactors init-time recent chat fetch. |
cli.py |
Switches list to paginated APIs and adds CLI flags for cursor/all. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ------- | ||
| :class:`ChatListPage` | ||
| A page containing chat items and a next-page cursor. | ||
| If ``cursor`` is empty, there are no more pages. |
There was a problem hiding this comment.
The docstring says "If cursor is empty, there are no more pages", but cursor being empty means "start from the beginning". It should instead describe that when the returned ChatListPage.cursor is empty, there are no more pages.
| If ``cursor`` is empty, there are no more pages. | |
| If the returned :attr:`ChatListPage.cursor` is empty, there | |
| are no more pages. |
| if fetch_all: | ||
| items = await client.list_all_chats(limit=120) | ||
| next_cursor = "" | ||
| else: |
There was a problem hiding this comment.
--all is documented/advertised as fetching all chats, but this code hard-caps the result to 120 via list_all_chats(limit=120). Either remove the cap (paginate until page.cursor is empty), or expose a --limit option and update the help text to match the behavior.
| p_list.add_argument( | ||
| "--all", | ||
| action="store_true", | ||
| help="Fetch all chats by paginating through every page", |
There was a problem hiding this comment.
The --all flag help text says it fetches "all chats" by paginating through every page, but cmd_list currently only fetches up to 120. Update the help text (or add a --limit argument) so CLI behavior and documentation are consistent.
| help="Fetch all chats by paginating through every page", | |
| help="Fetch chats across pages, up to 120 total", |
| async def list_chats_page( | ||
| self, | ||
| cursor: str = "", | ||
| page_size: int = 20, | ||
| ) -> ChatListPage: |
There was a problem hiding this comment.
New public pagination APIs (list_chats_page / list_all_chats) are introduced here, but there are no corresponding tests validating cursor handling, variant fallback behavior, and termination when the cursor is empty. Adding coverage would prevent regressions in pagination semantics.
Summary
Adds cursor-based pagination support to the chat listing functionality, achieving
feature parity with this Go reference implementation at https://github.com/Leechael/gemini-web-cli.
The existing
list_chats()method remains unchanged for backward compatibility.Motivation
The
MaZiqc(LIST_CHATS) RPC response contains a pagination cursor at index[1]of the response body that was previously ignored. Without pagination, users could only
retrieve the ~13 most recent chats cached at init time. Accounts with many conversations
had no way to access older chats.
Changes
New file:
src/gemini_webapi/types/chatlistpage.pyChatListPagePydantic model withitems: list[ChatInfo]andcursor: strfields.Updated:
src/gemini_webapi/types/__init__.pyChatListPage.Updated:
src/gemini_webapi/components/chat_mixin.py_parse_chat_list_response()— new static helper that extracts both chat itemsand the next-page cursor from a
LIST_CHATSRPC response._try_list_chats()— new helper that wraps a single RPC attempt with errorhandling, eliminating duplicated
_batch_execute/ parse / try-except logic._fetch_recent_chats()— refactored to use the new helpers; now tries a thirdpayload variant
[0, None, 2]for Go compatibility and iterates all variantsto collect both pinned and unpinned chats.
list_chats_page(cursor, page_size)— new public async method that fetches asingle page of chats. When
cursoris provided, sends[page_size, cursor, [0, None, 1]];otherwise tries multiple payload variants. Returns
ChatListPage.list_all_chats(limit)— new public async method that auto-paginates throughall pages up to
limitchats.list_chats()— unchanged, still returns the init-time cache.Updated:
cli.pycmd_listrewritten to uselist_chats_page/list_all_chats.listsubparser gains--cursorand--allflags.New public API
CLI usage
Backward compatibility
list_chats()is unchanged — still synchronous, still returns the cached list from init._fetch_recent_chats()signature is unchanged; internal behavior is improved(tries 3 payload variants instead of 2, uses shared helpers).