Skip to content

fix(agents): use correct SWRInfinite cache key and add optimistic update for session editing#13475

Merged
kangfenmao merged 3 commits intomainfrom
fix/session-optimistic-update
Mar 15, 2026
Merged

fix(agents): use correct SWRInfinite cache key and add optimistic update for session editing#13475
kangfenmao merged 3 commits intomainfrom
fix/session-optimistic-update

Conversation

@EurFelux
Copy link
Copy Markdown
Collaborator

@EurFelux EurFelux commented Mar 14, 2026

What this PR does

Before this PR:

Editing a session (e.g., renaming) in the Agent sidebar does not immediately reflect in the UI. The global mutate(listKey, ...) in useUpdateSession fails to match useSWRInfinite's internal cache key format, so the list cache is never actually updated. The change only appears after SWR's automatic revalidation (~2-3 seconds).

After this PR:

  • Session edits are optimistically applied to both the SWRInfinite list cache and the item cache immediately. The UI updates instantly, with rollback on API failure.
  • Session name uses Tailwind truncate utility instead of a styled-component with -webkit-line-clamp. Also cleaned up Tailwind v4 syntax in shared.tsx (text-[var(--color-text)]text-(--color-text), p-[16px]p-4).
  • DEFAULT_SESSION_PAGE_SIZE moved to api/agent.ts as a shared API-level constant.

Fixes #13474

Why we need it and why it was done in this way

The following tradeoffs were made:

  • Used unstable_serialize from swr/infinite to generate the correct SWRInfinite cache key. This is the official SWR approach for mutating useSWRInfinite data from outside the hook.
  • DEFAULT_SESSION_PAGE_SIZE lives in api/agent.ts because page size is an API-level concern shared by both useSessions and useUpdateSession.

The following alternatives were considered:

  • Moving update logic into useSessions hook — rejected because useUpdateSession is used independently in multiple places (e.g., SessionSettingsPopup).
  • Using a filter-based global mutate (mutate(key => key.includes(...))) — rejected as it relies on SWR internals and is fragile.
  • Exporting the constant from useSessions.ts — rejected to avoid a hook module exporting non-hook values.

Breaking changes

None.

Special notes for your reviewer

  • The mutateInfiniteList helper is extracted as a module-level function to avoid recreation on each render.
  • Tailwind v4 syntax cleanup in shared.tsx is a drive-by fix.

Checklist

Release note

NONE

EurFelux and others added 3 commits March 15, 2026 01:20
…ate for session editing

The global mutate(listKey) in useUpdateSession did not match useSWRInfinite's
internal cache key format, causing stale UI after session edits. Use
unstable_serialize from swr/infinite to generate the correct cache key, and
implement optimistic updates for immediate UI feedback with rollback on failure.

Fixes #13474

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: icarus <[email protected]>
Replace SessionName styled-component with Tailwind `truncate` utility.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: icarus <[email protected]>
Move the session page size constant from useSessions.ts to
AgentApiClient module as it is an API-level concern shared by
both useSessions and useUpdateSession.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: icarus <[email protected]>
@EurFelux EurFelux requested review from DeJeune and kangfenmao March 15, 2026 03:11
Copy link
Copy Markdown
Collaborator

@kangfenmao kangfenmao left a comment

Choose a reason for hiding this comment

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

Note

This issue/comment/review was translated by Claude.

LGTM! High-quality bug fix:

  • Correctly use unstable_serialize to resolve SWRInfinite cache key matching issue
  • Optimistic update + failure rollback mechanism is complete
  • Includes Tailwind code cleanup
  • No breaking changes

Thank you for your contribution!


Original Content

LGTM! 高质量的 bug 修复:

  • 正确使用 unstable_serialize 解决 SWRInfinite 缓存键匹配问题
  • 乐观更新 + 失败回滚机制完善
  • 附带 Tailwind 代码清理
  • 无破坏性变更

感谢贡献!

const sessionId = form.id
const itemKey = paths.withId(sessionId)
const infKey = unstable_serialize(() => [listKey, 0, DEFAULT_SESSION_PAGE_SIZE])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Concern: unstable_serialize(() => [listKey, 0, DEFAULT_SESSION_PAGE_SIZE]) hardcodes the default page size. If a caller of useSessions passes a custom pageSize, the serialized key here won't match the SWRInfinite cache key, causing the optimistic update to silently miss that cache entry.

Consider either:

  1. Accept pageSize as a parameter in useUpdateSession, or
  2. Extract the getKey function from useSessions as a shared utility so both hooks use the same key generation logic.

This would make the coupling between the two hooks explicit and prevent silent cache misses.

Comment on lines 10 to +14
import { useAgentClient } from './useAgentClient'

type InfiniteData = ListAgentSessionsResponse[]

const mutateInfiniteList = (
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: mutateInfiniteList is a clean extraction. Consider adding a brief JSDoc noting that the infKey must be generated via unstable_serialize from swr/infinite — this would help future contributors understand the coupling.

@kangfenmao kangfenmao merged commit 8b98b8f into main Mar 15, 2026
17 checks passed
@kangfenmao kangfenmao deleted the fix/session-optimistic-update branch March 15, 2026 03:32
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.

[Bug]: Session edit does not optimistically update SWR cache due to SWRInfinite key mismatch

3 participants