Skip to content

feat: add cursor-based pagination for chat listing#295

Open
codeofpi wants to merge 1 commit intoHanaokaYuzu:masterfrom
codeofpi:master
Open

feat: add cursor-based pagination for chat listing#295
codeofpi wants to merge 1 commit intoHanaokaYuzu:masterfrom
codeofpi:master

Conversation

@codeofpi
Copy link
Copy Markdown

@codeofpi codeofpi commented Apr 8, 2026

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.py

  • ChatListPage Pydantic model with items: list[ChatInfo] and cursor: str fields.

Updated: src/gemini_webapi/types/__init__.py

  • Export ChatListPage.

Updated: src/gemini_webapi/components/chat_mixin.py

  • _parse_chat_list_response() — new static helper that extracts both chat items
    and the next-page cursor from a LIST_CHATS RPC response.
  • _try_list_chats() — new helper that wraps a single RPC attempt with error
    handling, eliminating duplicated _batch_execute / parse / try-except logic.
  • _fetch_recent_chats() — refactored to use the new helpers; now tries a third
    payload variant [0, None, 2] for Go compatibility and iterates all variants
    to collect both pinned and unpinned chats.
  • list_chats_page(cursor, page_size)new public async method that fetches a
    single page of chats. When cursor is 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 through
    all pages up to limit chats.
  • list_chats() — unchanged, still returns the init-time cache.

Updated: cli.py

  • cmd_list rewritten to use list_chats_page / list_all_chats.
  • list subparser gains --cursor and --all flags.

New public API

# Single page  [header-3](#header-3)
page = await client.list_chats_page(cursor="", page_size=20)  
print(page.items, page.cursor)  
  
# Next page  [header-4](#header-4)
page = await client.list_chats_page(cursor=page.cursor)  
  
# Auto-paginate up to N chats  [header-5](#header-5)
all_chats = await client.list_all_chats(limit=100)

CLI usage

# First page (20 chats)  [header-6](#header-6)
python cli.py list  
  
# Next page with cursor  [header-7](#header-7)
python cli.py list --cursor "abc123..."  
  
# All chats  [header-8](#header-8)
python cli.py list --all

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).

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ChatListPage model 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 in ChatMixin.
  • Update cli.py list command to use the new pagination APIs and add --cursor / --all flags.

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.
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
If ``cursor`` is empty, there are no more pages.
If the returned :attr:`ChatListPage.cursor` is empty, there
are no more pages.

Copilot uses AI. Check for mistakes.
Comment thread cli.py
Comment on lines +386 to +389
if fetch_all:
items = await client.list_all_chats(limit=120)
next_cursor = ""
else:
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--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.

Copilot uses AI. Check for mistakes.
Comment thread cli.py
p_list.add_argument(
"--all",
action="store_true",
help="Fetch all chats by paginating through every page",
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
help="Fetch all chats by paginating through every page",
help="Fetch chats across pages, up to 120 total",

Copilot uses AI. Check for mistakes.
Comment on lines +189 to +193
async def list_chats_page(
self,
cursor: str = "",
page_size: int = 20,
) -> ChatListPage:
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
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.

2 participants