diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx index 98c4f312ede53..91f8abcdc45bf 100644 --- a/apps/desktop/src/app/chat/sidebar/index.tsx +++ b/apps/desktop/src/app/chat/sidebar/index.tsx @@ -1288,7 +1288,7 @@ export function ChatSidebar({ {!trimmedQuery && ( } label={s.pinned} diff --git a/apps/desktop/src/app/chat/sidebar/sessions-section.tsx b/apps/desktop/src/app/chat/sidebar/sessions-section.tsx index 37d6be115559f..12ba16134f6d5 100644 --- a/apps/desktop/src/app/chat/sidebar/sessions-section.tsx +++ b/apps/desktop/src/app/chat/sidebar/sessions-section.tsx @@ -313,7 +313,11 @@ export function SidebarSessionsSection({ // wasn't looking at — the drag that landed a row in the wrong slot. const sortableRowIds = useMemo(() => reorderableRowIds(flatRows), [flatRows]) + // Pinned never virtualizes. Virtualization needs a bounded viewport to + // measure against, and Pinned deliberately has none — however many chats you + // pin, all of them render and the sidebar's own scroll carries the length. const flatVirtualized = + !pinned && !showEmptyState && !groups?.length && !projectOverview?.length && diff --git a/gateway/platforms/api_server.py b/gateway/platforms/api_server.py index 0f0dff5fbbc77..24cc8f1bca55d 100644 --- a/gateway/platforms/api_server.py +++ b/gateway/platforms/api_server.py @@ -3279,13 +3279,19 @@ class APIServerAdapter(BasePlatformAdapter): offset=offset, include_children=include_children, order_by_last_active=True, + # A pin means "always reachable", so a pinned conversation that has + # aged past the recency window is back-filled rather than dropped. + include_pinned=True, ) + # Back-filled pins arrive PAST the limit, so counting them would report + # another page that doesn't exist. Only the recency window decides. + windowed = sum(1 for s in sessions if not s.get("pinned")) return web.json_response({ "object": "list", "data": [self._session_response(s) for s in sessions], "limit": limit, "offset": offset, - "has_more": len(sessions) == limit, + "has_more": windowed >= limit, }) async def _handle_create_session(self, request: "web.Request") -> "web.Response":