Skip to content

refactor(memory): Refactor memories to use ID-based persistence and new memories UI#8294

Merged
Subash-Mohan merged 16 commits intomainfrom
new-memory-component
Feb 11, 2026
Merged

refactor(memory): Refactor memories to use ID-based persistence and new memories UI#8294
Subash-Mohan merged 16 commits intomainfrom
new-memory-component

Conversation

@Subash-Mohan
Copy link
Copy Markdown
Contributor

@Subash-Mohan Subash-Mohan commented Feb 10, 2026

Description

  • Refactors memory storage from delete-all-and-recreate to ID-based upsert, preserving stable database IDs across edits
  • Replaces the inline memories editor in SettingsPage with a dedicated Memories component that displays memories as
    FileTile previews and opens a full MemoriesModal for viewing, searching, adding, and editing
  • Extracts memory management logic into a reusable useMemoryManager hook
  • Introduces new reusable UI components: FileTile, ButtonTile, SvgTextLines icon, and skeleton variant for
    LineItem
  • Adds small variant to IconButton and resizable prop to InputTextArea
Screen.Recording.2026-02-10.at.5.47.17.PM.mov
Screen.Recording.2026-02-10.at.6.02.04.PM.mov

How Has This Been Tested?

Tested by adding, updating and deleting memories.

Additional Options

  • [Required] I have considered whether this PR needs to be cherry-picked to the latest beta branch.
  • [Optional] Override Linear Check

Summary by cubic

Refactored memory persistence to ID-based upsert and introduced a new Memories UI with a modal, improving auto-save behavior and preventing duplicate saves. Enforces a 10-memory limit with server-side validation and UI guards; orders by newest and resets focus/highlight on open for a smoother add/edit/search experience.

  • New Features

    • Dedicated Memories component in Settings with FileTile previews; opens a MemoriesModal to view/search/add/edit/delete. Includes focus/highlight with scroll-into-view, character and line counts, Add disabled at 10, auto-save on blur or before adding a new item, reuses empty rows, and success/error notifications.
    • New building blocks: useMemoryManager hook, FileTile (spacing/alignment, maximize button), ButtonTile, SvgTextLines, LineItem skeleton variant, IconButton small variant, and InputTextArea resizable prop.
  • Migration

    • API change: UserPersonalization.memories is now MemoryItem[] ({ id: number|null, content: string }). Clients must send IDs for existing items and null for new.
    • Backend uses ID-based upsert, deletes missing IDs, orders memories by newest, and enforces a max of 10 memories. No DB migration required.

Written for commit fe948c9. Summary will update on new commits.

@Subash-Mohan Subash-Mohan requested a review from a team as a code owner February 10, 2026 12:32
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 10, 2026

Greptile Overview

Greptile Summary

This PR refactors user memories from a delete-and-recreate flow to an ID-based upsert model, updating the backend personalization schemas/APIs and the frontend types accordingly. On the web side, the inline settings memories editor is replaced with a new Memories tile preview and a dedicated MemoriesModal, with shared CRUD/search logic extracted into useMemoryManager. It also introduces new reusable UI building blocks (FileTile/ButtonTile, skeleton variant for LineItem, TextLines icon) and minor component API extensions (IconButton small, InputTextArea resizable).

The main correctness issue found is in the new modal list rendering: the mapped fragments are missing keys, which will produce React warnings and can lead to incorrect UI/state association when adding/removing memories.

Confidence Score: 4/5

  • Mostly safe to merge once the React list key issue is fixed.
  • Changes are largely mechanical schema/type refactors plus new UI components. The one verified functional issue is missing keys on fragments in the modal memory list, which will surface as React warnings and can cause incorrect item association during edits/removals.
  • web/src/refresh-components/modals/MemoriesModal.tsx

Important Files Changed

Filename Overview
backend/onyx/db/models.py Adds ordering to User.memories relationship (desc by Memory.id).
backend/onyx/db/user_preferences.py Refactors memory persistence to ID-based upsert/delete using new MemoryItem model.
backend/onyx/server/manage/models.py Introduces MemoryItem schema and switches personalization memories to typed items with ids.
backend/onyx/server/manage/users.py Updates personalization update flow to use MemoryItem objects for existing/new memories.
web/lib/opal/src/icons/index.ts Exports new SvgTextLines icon from opal icon barrel.
web/lib/opal/src/icons/text-lines.tsx Adds SvgTextLines icon component.
web/src/app/css/line-item.css Adds skeleton variant styles for LineItem button/text/icon.
web/src/components/settings/Memories.tsx Adds Memories component showing tiles and opening MemoriesModal with target memory highlighting.
web/src/hooks/useMemoryManager.ts Adds useMemoryManager hook for local memory CRUD/search and persistence via onBlur/onRemove.
web/src/hooks/useUserPersonalization.ts Updates personalization hook to treat memories as MemoryItem objects instead of strings.
web/src/lib/types.ts Adds MemoryItem type and updates UserPersonalization.memories to use it.
web/src/refresh-components/buttons/IconButton.tsx Adds 'small' variant to IconButton with adjusted paddings and icon sizing.
web/src/refresh-components/buttons/LineItem.tsx Adds skeleton variant and makes children optional with adjusted layout logic.
web/src/refresh-components/inputs/InputTextArea.tsx Adds resizable prop to control textarea resize behavior (disabled when autoResize or resizable=false).
web/src/refresh-components/modals/MemoriesModal.tsx Adds MemoriesModal with search/add/edit/delete, focus/highlight behavior; has missing key on list fragments causing React warnings/state issues.
web/src/refresh-components/tiles/ButtonTile.tsx Adds ButtonTile reusable interactive tile component.
web/src/refresh-components/tiles/FileTile.tsx Adds FileTile component for memory previews with optional remove/open actions.
web/src/refresh-pages/SettingsPage.tsx Replaces inline memories editor with new Memories component and updates save handler types.

Sequence Diagram

sequenceDiagram
  autonumber
  participant UI as SettingsPage/Memories UI
  participant Modal as MemoriesModal
  participant Hook as useMemoryManager
  participant Pers as useUserPersonalization
  participant API as manage/users API
  participant DB as update_user_personalization (DB)

  UI->>Modal: open (View/Add or skeleton LineItem)
  UI->>Modal: pass memories + onSaveMemories
  Modal->>Hook: init localMemories from props

  Modal->>Hook: handleAddMemory()
  Hook-->>Modal: returns new local id
  Modal->>Modal: setFocusMemoryId(newId)

  Modal->>Hook: handleUpdateMemory(index, value)
  Modal->>Hook: handleBlurMemory(index)
  Hook->>Pers: onSaveMemories(newMemories)
  Pers->>API: PATCH /manage/user/personalization (memories: [{id, content}])
  API->>DB: update_user_personalization(user_id, memories)
  DB->>DB: delete missing ids
  DB->>DB: update matching ids
  DB->>DB: insert items with id=None
  DB-->>API: commit
  API-->>Pers: success
  Pers-->>Hook: success boolean
  Hook-->>Modal: notify popup

  Modal->>Hook: handleRemoveMemory(index)
  Hook->>Pers: onSaveMemories(without removed)
  Pers->>API: PATCH personalization
  API->>DB: upsert/delete
  DB-->>API: commit
  API-->>Pers: success
  Pers-->>Hook: success boolean
Loading

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +203 to +207
{filteredMemories.map(({ memory, originalIndex }) => (
<>
<MemoryItem
key={memory.id}
memory={memory}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing keys on fragments

filteredMemories.map(...) returns a fragment (<>...</>) but the key is on MemoryItem instead of the fragment. React will warn and can mis-associate state when inserting/removing memories. Put the key on the fragment (or wrap in a keyed element) so the list item identity is stable.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

5 issues found across 18 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="web/src/app/css/line-item.css">

<violation number="1" location="web/src/app/css/line-item.css:123">
P2: Add a `[data-transient="true"]` rule so programmatic hover matches the hover background for the skeleton variant.

(Based on your team's feedback about treating [data-transient="true"] as hover.) [FEEDBACK_USED]</violation>

<violation number="2" location="web/src/app/css/line-item.css:131">
P2: Add a `[data-transient="true"]` rule so programmatic hover matches the hover background for the emphasized skeleton variant.

(Based on your team's feedback about treating [data-transient="true"] as hover.) [FEEDBACK_USED]</violation>
</file>

<file name="web/src/components/settings/Memories.tsx">

<violation number="1" location="web/src/components/settings/Memories.tsx:28">
P2: Clear targetMemoryId when opening the modal without a specific memory target; otherwise the modal can keep highlighting the previously selected memory when users click “View/Add” or the empty-state action.</violation>
</file>

<file name="web/src/hooks/useMemoryManager.ts">

<violation number="1" location="web/src/hooks/useMemoryManager.ts:32">
P2: Memories with `id: null` are treated as existing (`isNew: false`), so saves will send the negative placeholder ID instead of null. Mark null IDs as new so persistence keeps `id: null`.</violation>
</file>

<file name="web/src/refresh-components/modals/MemoriesModal.tsx">

<violation number="1" location="web/src/refresh-components/modals/MemoriesModal.tsx:204">
P3: Add a key to the fragment returned by the map; the key on MemoryItem doesn’t cover the fragment wrapper, so React will warn and may mis-handle list reconciliation when the Separator is present.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

}

.line-item-button-skeleton-emphasized {
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-02;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 10, 2026

Choose a reason for hiding this comment

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

P2: Add a [data-transient="true"] rule so programmatic hover matches the hover background for the emphasized skeleton variant.

(Based on your team's feedback about treating [data-transient="true"] as hover.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/src/app/css/line-item.css, line 131:

<comment>Add a `[data-transient="true"]` rule so programmatic hover matches the hover background for the emphasized skeleton variant.

(Based on your team's feedback about treating [data-transient="true"] as hover.) </comment>

<file context>
@@ -118,6 +118,32 @@
+}
+
+.line-item-button-skeleton-emphasized {
+  @apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-02;
+
+  [data-keyboard-nav="true"] &:hover {
</file context>
Suggested change
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-02;
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-02;
&[data-transient="true"] {
@apply bg-background-tint-02;
}
Fix with Cubic


/* Skeleton Variant - dashed border placeholder style */
.line-item-button-skeleton {
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-01;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 10, 2026

Choose a reason for hiding this comment

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

P2: Add a [data-transient="true"] rule so programmatic hover matches the hover background for the skeleton variant.

(Based on your team's feedback about treating [data-transient="true"] as hover.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/src/app/css/line-item.css, line 123:

<comment>Add a `[data-transient="true"]` rule so programmatic hover matches the hover background for the skeleton variant.

(Based on your team's feedback about treating [data-transient="true"] as hover.) </comment>

<file context>
@@ -118,6 +118,32 @@
 
+/* Skeleton Variant - dashed border placeholder style */
+.line-item-button-skeleton {
+  @apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-01;
+
+  [data-keyboard-nav="true"] &:hover {
</file context>
Suggested change
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-01;
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-01;
&[data-transient="true"] {
@apply bg-background-tint-01;
}
Fix with Cubic

@Subash-Mohan Subash-Mohan added this pull request to the merge queue Feb 11, 2026
Merged via the queue into main with commit 9e581f4 Feb 11, 2026
81 checks passed
@Subash-Mohan Subash-Mohan deleted the new-memory-component branch February 11, 2026 06: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.

2 participants