Skip to content

Move thread list + messages off Redux cache to direct RPC reads #1197

Closed

Description

@senamakel

Status: Draft / scoping. Filed as a follow-up to #1196 to capture the structural shape of the fix; not scheduled.

Summary

Stop maintaining threadSlice.threads and threadSlice.messagesByThreadId as a parallel client-side cache. Replace consumers with direct RPC reads against openhuman.threads_list / openhuman.thread_messages (the Rust core already persists these as JSONL upsert logs in src/openhuman/memory/conversations/store.rs), wrapped in a stale-while-revalidate layer (react-query or equivalent). Keep selectedThreadId as a small persisted UI atom.

Problem / Context

The Rust core is already the source of truth — threads live in a JSONL upsert log under the workspace dir, and threads_list is exposed over JSON-RPC. The React app shadows that as a Redux slice (threads, messagesByThreadId, messages) for sync render-time access and optimistic updates. Maintaining two stores creates a steady stream of cache-coherence bugs:

Going cache-less makes this entire class of bug structurally impossible. The cost is a non-trivial refactor — see Scope.

Scope

In scope

  • Introduce a query layer over coreRpcClient for thread reads (useThreads(), useThreadMessages(id)). Stale-while-revalidate semantics, error/loading states surfaced to consumers, automatic refetch on identity change.
  • Migrate ~30 useAppSelector(s => s.thread.*) call sites in app/src/pages/Conversations.tsx, app/src/components/**, app/src/providers/ChatRuntimeProvider.tsx, etc.
  • Migrate the streaming append path in ChatRuntimeProvider — today it dispatches addInferenceResponse / addMessageLocal thunks that mutate messagesByThreadId. Needs to push into the query cache instead (or hold the in-flight turn in component-local state and let the post-turn refetch reconcile).
  • Migrate optimistic UI for rename / delete / new-thread to query-cache mutations.
  • Reduce threadSlice to just { selectedThreadId, activeThreadId }. Drop threads, messagesByThreadId, messages, welcomeThreadId (already a no-op per feat(onboarding): replace welcome-agent bot with react-joyride walkthrough #1180), and the loadThreads / loadThreadMessages thunks.
  • Remove resetThreadCachesPreservingSelection (added in fix(threads): preserve selectedThreadId on cold-boot identity hydration #1196 as a workaround) and the boot-time scrub branch in CoreStateProvider.tsx:259 — no in-memory cache means nothing to scrub.

Out of scope

  • Any change to the Rust storage layer or RPC surface. The JSONL upsert log is fine as-is.
  • Realtime push from core → app for thread list changes (currently a poll/refetch model). Could be revisited separately if latency becomes a UX concern.
  • Replacing Redux as a whole — non-thread slices stay.

Tradeoffs

  • Adds a query-layer dependency (likely react-query) — already a common pattern, but a new top-level concept in this app.
  • Streaming UX is the trickiest piece: tokens arrive ~10–50/s and currently mutate the slice cheaply. Need to either (a) buffer in component state during the turn and refetch on chat_done, or (b) write directly into the query cache with manual invalidation. (a) is simpler but flickers if the refetch is slow; (b) preserves current behavior.

Acceptance criteria

Related

Activity

  1. added
    refactorStructural code change without a primary behavior change.
    taskWork item that is not primarily a bug or a feature.
    react-uiReact app work in app/src: pages, components, providers, store, and UX.
    mcp-rpcMCP transport, tool registry, JSON-RPC, and core relay surfaces.
    on May 4, 2026
  2. added theissue type on May 9, 2026
  3. self-assigned this
    on May 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

mcp-rpcMCP transport, tool registry, JSON-RPC, and core relay surfaces.react-uiReact app work in app/src: pages, components, providers, store, and UX.refactorStructural code change without a primary behavior change.taskWork item that is not primarily a bug or a feature.

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions