Skip to content

[IJAI-1134] feat(agent,protocol): support suspend-based paginated session/list - #123

Open
forketyfork wants to merge 1 commit into
agentclientprotocol:masterfrom
forketyfork:feat/suspend-paginated-session-list
Open

[IJAI-1134] feat(agent,protocol): support suspend-based paginated session/list#123
forketyfork wants to merge 1 commit into
agentclientprotocol:masterfrom
forketyfork:feat/suspend-paginated-session-list

Conversation

@forketyfork

@forketyfork forketyfork commented Aug 18, 2026

Copy link
Copy Markdown

Issue

https://youtrack.jetbrains.com/issue/IJAI-1134

session/list (and any other AcpPaginatedRequest/AcpPaginatedResponse method) is served through setPaginatedRequestHandler, backed by SequenceToPaginatedResponseAdapter. That adapter needs a non-suspending Sequence, so an agent whose session source is a database can only satisfy the contract by materializing the entire result set inside the one suspend call it's given, before pagination even starts. The adapter also keeps the resulting iterator in server-process memory behind a cursor that is single-use and evicted after a minute of inactivity — a real cost for a client that scrolls slowly or reconnects, since its cursor is simply gone.

In our cloud-based implementation, we need a session/list that walks a keyset straight from the DB, one page per request, with a cursor that stays valid indefinitely and survives a reconnect.

Solution

  • setSuspendPaginatedRequestHandler (Protocol.extensions.kt): a sibling of setPaginatedRequestHandler that takes pageFactory: suspend (request) -> Pair<List<TItem>, String?> instead of a Sequence. No iterator or cursor state is kept by the SDK — the cursor is opaque and entirely owned by whatever pageFactory encodes into it, so it can be as durable as a database keyset, and a client that pauses or reconnects loses nothing.
  • AgentSupport.listSessionsPage (AgentSupport.kt): a new optional hook alongside listSessions, defaulting to null ("not overridden"). Agent now tries this first for session/list; when it returns non-null, the response is served directly from it via the new suspend-based path. When it returns null (the default), session/list falls back to listSessions()/Sequence exactly as before — existing agents that only override listSessions() see no behavior change.

Context

  • Happy to adjust the API or shape of listSessionsPage (e.g. request-object vs. individual params, Pair vs. a small Page type) based on review.
  • No existing test exercised session/list end-to-end through Agent before this PR (only SequenceToPaginatedResponseAdapter was unit-tested directly); AgentSessionListTest adds that coverage for both the new and the fallback path.

Issue: session/list is served through setPaginatedRequestHandler, whose
SequenceToPaginatedResponseAdapter needs a non-suspending Sequence. An
agent whose session source is a database can only satisfy that by
materializing the entire list on the first request, and the adapter's
cursors live in server memory, are single-use, and are evicted after a
minute of inactivity — costly for a slow-scrolling or reconnecting client.

Solution: add setSuspendPaginatedRequestHandler, a sibling of
setPaginatedRequestHandler that takes a suspend (request) -> Pair<List,
cursor> page fetcher instead of a Sequence, with no iterator or cursor
state kept by the SDK — the cursor is opaque and entirely owned by
whatever the caller encodes into it, so it can be as durable as a
database keyset. Wire this into session/list itself via a new
AgentSupport.listSessionsPage hook: when an agent overrides it, Agent
serves session/list from it directly; otherwise it falls back to the
existing listSessions()/Sequence path unchanged, so existing agents keep
working exactly as before.
@forketyfork forketyfork changed the title feat(agent,protocol): support suspend-based paginated session/list [IJAI-1134] feat(agent,protocol): support suspend-based paginated session/list Aug 18, 2026
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