Skip to content

Memory Feed Session Grouping

Status: Complete Date: 2026-04-28

Problem

The memory feed was returning one item per segment, not per recording session. When a user captured audio and video in a single session, they would see two separate feed items instead of one unified memory.

Solution

Modified the /memories/feed Lambda endpoint to:

  1. Group segments by source_session_id — All segments with the same session ID are merged into a single feed item
  2. Aggregate at session level — Each feed item represents one complete session with aggregated properties:
  3. id: The session ID (or segment ID if ungrouped)
  4. time: Session start time (earliest segment start_time)
  5. type: Richest type across all segments (visual > audio > text)
  6. thumbnail: First visual segment's thumbnail, if any
  7. processing_status: Overall status (pending if any segment pending, failed if any failed, complete otherwise)
  8. Paginate at session level — The cursor and limit now apply to sessions, not segments

Implementation Details

Backend Changes

File: main/server/api/memories/feed/app.py

  • Added _derive_richest_type(segments) to select the best type across multiple segments
  • Added _get_richest_frame_key(segments) to find the first visual segment's frame key
  • Added _get_overall_processing_status(segments) to compute aggregate status
  • Added _group_segments_by_session(segments) to organize segments by session ID
  • Modified implementation() to:
  • Query all user segments (removed offset/limit from query)
  • Group segments into sessions
  • Sort sessions by latest segment start_time (newest first)
  • Apply pagination at the session level
  • Build one feed item per session with aggregated properties

Testing

New tests: main/server/tests/integration/test_memories_feed_session_grouping.py

Added comprehensive tests validating: - Single segments become single feed items - Multiple segments with same session ID are grouped - Session type reflects richest segment type - Session thumbnail comes from visual segments - Session processing_status is pending if any segment is pending - Pagination is applied at session level - Session start_time is the earliest segment - Sessions are ordered newest-first

Existing tests: main/server/tests/integration/test_memories_feed_pagination.py

All 14 existing tests pass unchanged because: - Test fixture seeds segments without explicit source_session_id - Each segment is treated as its own session (keyed by segment ID) - Old test expectations (e.g., seg-a-0, seg-a-1) still work because segment IDs become session IDs

Documentation

File: docs/docs/memories-feed.md

Updated to reflect: - Feed now returns sessions, not segments - Grouping logic and session-level aggregation - Type, thumbnail, and status derivation rules - Session-level pagination - Key changes section explaining the shift from segment-level to session-level

Backwards Compatibility

The feed response structure ({ memories: [...], next_cursor }) and memory item schema (id, time, type, thumbnail, processing_status) remain unchanged. The semantic meaning of id shifts from segment ID to session ID, which is transparent to the frontend.

Frontend impact: None required. The MemoryFeed.tsx component treats id as an opaque identifier and works identically with session IDs or segment IDs.

Testing Results

  • All 14 existing pagination tests pass
  • All 8 new session grouping tests pass
  • Total: 22 tests, 100% pass rate

Future Work

Possible enhancements: 1. Add a segment_count field to each feed item to indicate how many segments comprise the session 2. Add segment-level access via a new /memories/{id}/segments endpoint to inspect individual segments within a session 3. Consider storing the session-level aggregation in the database (denormalization) if query performance becomes an issue