Sync Reducer & State Management
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
Sync Reducer & State Management is a core subsystem of the Happy React Native application responsible for processing real-time updates and maintaining a consistent local state of sessions, messages, and artifacts. The system uses a centralized Sync engine that coordinates between WebSocket events, REST API polling, and a specialized reducer to transform raw network data into UI-ready state. It employs advanced optimizations like Delta Sync, ETag-based conditional fetching, and debounced persistence to ensure high performance and reliability across mobile and web platforms.
The state management logic is built around an immutable contract using Immer, ensuring that state transitions are predictable and efficient. This architecture handles complex scenarios such as end-to-end encrypted message decryption, tool execution lifecycles, and sidechain (sub-agent) branching.
Architecture & Data Flow
The state management architecture follows a unidirectional flow where external updates (WebSocket or API) are ingested by the Sync class, processed through specialized accumulators or logic blocks, and finally applied to the global store via the reducer.
The diagram shows how various data sources flow through the Sync engine into the Global Storage and out to the UI and persistence layers.
Sources: apps/web/react/sources/sync/sync.ts:1085-1100, apps/web/react/sources/sync/reducer/reducer.ts:1-20
Core Components
| Component | Responsibility |
|---|---|
| Sync Engine | Orchestrates all synchronization activities, manages encryption keys, and handles connectivity logic. |
| Message Reducer | A pure function (using Immer) that handles message deduplication, tool state transitions, and sidechain processing. |
| Activity Accumulator | Batches and debounces high-frequency ephemeral updates (like typing indicators) to prevent UI thrashing. |
| Persistence Layer | Manages long-term storage of sync cursors, ETags, and cached messages for offline access. |
Sources: apps/web/react/sources/sync/sync.ts:167-210, apps/web/react/sources/sync/reducer/activityUpdateAccumulator.ts:5-15, apps/web/react/sources/sync/persistence.ts
Sync Engine Logic
The Sync class serves as the primary controller for state synchronization. It implements several strategies to optimize network usage and data consistency.
Delta Sync and Sequence Tracking
To avoid full data re-fetches on WebSocket reconnection, the engine implements Delta Sync. It tracks the lastKnownSeq (sequence number) for different entity types (sessions, machines, artifacts). Upon reconnection, it requests only the updates that occurred since the last recorded sequence.
Conditional Fetching (ETags)
For frequently polled data like user profiles, the system uses ETags. The server returns a 304 Not Modified status if the data hasn't changed, saving bandwidth.
Sources: apps/web/react/sources/sync/sync.ts:983-1005
The Message Reducer
The reducer is responsible for the complex task of transforming NormalizedMessage objects into ReducerMessage formats suitable for rendering. It operates in distinct phases to handle permissions, tool calls, and sidechains.
Tool Lifecycle Management
One of the most critical roles of the reducer is managing the state of tool executions. A tool call typically progresses through three states:
- Running: The tool has been called but no result is received.
- Completed: A successful tool result has been processed.
- Error: The tool execution failed or was denied by the user.
Reducer Phases
- Phase 0: Permissions: Processes
AgentStateto match pending or completed permission requests with their corresponding tool IDs. - Phase 1: Deduplication: Uses
localIdand message IDs to filter out messages already present in the local state. - Phase 2: Tool Calls: Registers new tool executions and maps them to their parent messages.
- Phase 3: Tool Results: Updates the status and output of existing tool calls.
- Phase 4: Sidechains: Manages "sub-agent" branches where tools may spawn their own message sequences.
Sources: apps/web/react/sources/sync/reducer/reducer.ts:375-390, apps/web/react/sources/sync/reducer/reducer.ts:600-615, apps/web/react/sources/sync/reducer/reducer.ts:880-900
Ephemeral State Accumulation
High-frequency updates, such as "thinking" indicators or "active" status changes, are not processed through the standard reducer to avoid performance degradation. Instead, the ActivityUpdateAccumulator batches these updates.
The accumulator uses a Map to keep only the latest update per session ID, flushing them periodically to the global storage.
Sources: apps/web/react/sources/sync/reducer/activityUpdateAccumulator.ts:10-40, apps/web/react/sources/sync/sync.ts:1416-1435
Persistence & Cache Management
The persistence.ts module ensures that critical sync state survives application restarts.
| Data Type | Persistence Strategy |
|---|---|
| Sync Cursors | Saved with a 5-second debounce to avoid excessive disk I/O. |
| Cached Messages | Stored per-session, limited to MAX_CACHED_MESSAGES_PER_SESSION (default 50). |
| Stale Cache | Automatically cleaned up if not accessed for 30 days. |
Sources: apps/web/react/sources/sync/sync.ts:1200-1215, apps/web/react/sources/sync/persistence.ts
Conclusion
The Sync Reducer & State Management system provides a robust framework for real-time collaboration. By separating persistent state (messages, sessions) from ephemeral state (activity) and utilizing efficient sync protocols like Delta Sync and ETags, the system maintains a high-performance experience even under constrained network conditions. The use of an immutable reducer pattern ensures that complex UI states, such as nested tool calls and agent sidechains, remain consistent and bug-free.