feat(agent-memory): add long-term memory explorer tab - #6429
feat(agent-memory): add long-term memory explorer tab#6429booleanhunter wants to merge 1 commit into
Conversation
Code Coverage - Frontend unit tests
Test suite run success8154 tests passing in 888 suites. Report generated by 🧪jest coverage report action from 6c70467 |
c9b5da6 to
118ce70
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 118ce709cf
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (isLtmTab) { | ||
| dispatch(fetchLongTermMemoryAction(endpointId)) |
There was a problem hiding this comment.
Fetch explorer data during initial tab load
When the workspace is opened or reloaded directly on the Long-term memory URL, didMountRef makes this effect skip its first run, while bootstrap() only calls refreshAll(), which fetches long-term memory with scopeToSession=true. The explorer therefore initially shows records from the auto-selected Overview session rather than the explorer result set, and remains incomplete until the user manually refreshes or changes a filter; make the bootstrap request depend on the active tab or allow the initial explorer fetch.
Useful? React with 👍 / 👎.
| if (!searchDidMountRef.current) { | ||
| searchDidMountRef.current = true | ||
| return |
There was a problem hiding this comment.
Do not discard the first debounced search
If the user types or pastes within the first 300 ms after this component mounts, the dependency change cancels the initial timer, so the callback for the user's query is the first callback to run; this branch then treats it as the mount callback and returns without issuing a search. The entered query remains displayed while the results are not refreshed until the search changes again, so initialize the mount flag independently of the debounced callback.
Useful? React with 👍 / 👎.
| if (!isConnected) return | ||
| dispatch(fetchLongTermMemoryAction(endpointId)) |
There was a problem hiding this comment.
Cancel explorer searches when leaving the tab
When a user changes the search and switches to Overview before the 300 ms debounce expires, this callback remains scheduled because activeTab is neither a dependency nor a guard. It starts an unscoped explorer request after the tab-switch effect starts the session-scoped Overview request; the thunk's monotonic request sequence makes this later request authoritative, so the Overview pane is populated with explorer results. Cancel or suppress the callback whenever the Long-term memory tab is no longer active.
Useful? React with 👍 / 👎.
|
For feature request GH-6226 |
118ce70 to
36f241a
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36f241ac6a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| /> | ||
| <FilterDropdown | ||
| label="sessions" | ||
| options={sessions} |
There was a problem hiding this comment.
Populate the explorer with sessions from every owner
When an endpoint has multiple owners, this list contains only the sessions fetched for the auto-selected Overview owner: discoverFiltersAction calls the sessions endpoint with filters.userId, while selecting an owner here only updates longTermMemory.userIds. As a result, the independent explorer cannot select sessions belonging to any other owner, even after that owner is selected in this toolbar; load independent/all session options for the explorer instead of reusing the Overview-scoped list.
Useful? React with 👍 / 👎.
| try { | ||
| const body: Record<string, unknown> = { | ||
| text: longTermMemory.search, | ||
| similarityThreshold: longTermMemory.similarityThreshold ?? undefined, |
There was a problem hiding this comment.
Keep the explorer threshold out of Overview requests
After setting a minimum similarity in the Long-term memory tab and returning to Overview, fetchOverviewLongTermMemoryAction calls this same helper with useSharedScope=true, but the new threshold is still serialized unconditionally. The supposedly owner/session-scoped Overview query is therefore narrowed by a hidden explorer setting and can omit records until the user returns to the explorer and clears it; only include this parameter for explorer requests.
Useful? React with 👍 / 👎.
| } | ||
| const value = Math.min(1, Math.max(0, Number(raw))) | ||
| dispatch(setSimilarityThreshold(Number.isNaN(value) ? null : value)) | ||
| } |
There was a problem hiding this comment.
Threshold input swallows decimals
Medium Severity
handleThresholdChange immediately stores Number(raw) while the controlled input binds value={similarityThreshold ?? ''}. Intermediate values like a trailing decimal become "" or lose the ., so typing a value such as 0.5 is unreliable for the min-similarity control.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 36f241a. Configure here.
36f241a to
d4289ef
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d4289efa38
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (!didMountRef.current || !isConnected) return | ||
| dispatch(fetchLongTermMemoryAction(endpointId)) |
There was a problem hiding this comment.
Gate explorer filter refetches to the explorer tab
On a normal initial Overview load, discoverFiltersAction eventually dispatches loadSessionsSuccess, which replaces longTermMemory.sessionIds with a new array; because didMountRef is already true and this effect is not gated by isLtmTab, it starts an unscoped explorer request after the bootstrap/session-scoped requests. The monotonic long-term request sequence makes that request authoritative, so Overview can display records from every owner/session instead of its selected scope.
Useful? React with 👍 / 👎.
| const handleDelete = (memory: LongTermMemoryRecord) => { | ||
| dispatch( | ||
| deleteLongTermMemoryAction(endpointId, memory.id, () => | ||
| setDeletingId(''), | ||
| ), |
There was a problem hiding this comment.
Keep post-delete refetches on the active tab
If a user confirms a deletion and switches to Overview before the DELETE resolves, this action's success path unconditionally starts fetchLongTermMemoryAction, an unscoped explorer request. Because it starts after the tab-switch Overview request, it wins the shared request sequence and replaces the Overview pane with explorer results; the completion refetch needs to respect the current tab or use separate result state.
Useful? React with 👍 / 👎.
| }, | ||
| { | ||
| value: AgentMemoryWorkspaceTab.LongTermMemory, | ||
| label: 'Long-term memory', |
There was a problem hiding this comment.
Translate the new explorer copy
When the UI is displayed in a non-English locale, this new tab label—and the newly added toolbar, card, tooltip, empty-state, and deletion copy—bypasses i18next and remains English. Add agent-memory keys to both locale files and render this copy through useTranslation, as required by the repository's i18n guidance.
AGENTS.md reference: AGENTS.md:L127-L127
Useful? React with 👍 / 👎.
| } | ||
| const value = Math.min(1, Math.max(0, Number(raw))) | ||
| dispatch(setSimilarityThreshold(Number.isNaN(value) ? null : value)) | ||
| } |
There was a problem hiding this comment.
Threshold applied without search text
Medium Severity
similarityThreshold is sent on every long-term search whenever it is set, including when search is empty. With no other filters the API falls back to match-all text, so a min-similarity value used while browsing can heavily filter or empty the records list even though no semantic query was entered.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d4289ef. Configure here.
d4289ef to
0c454b2
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0c454b2522
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| ...data | ||
| .map((m) => m.sessionId) | ||
| .filter((id): id is string => Boolean(id)), | ||
| ...sessionIds, |
There was a problem hiding this comment.
Preserve unselected sessions after applying a filter
When a user selects one session, the refetch returns records only for that selected session, so rebuilding sessionOptions from data plus sessionIds removes every unselected session from the dropdown. This makes the checkbox-based multi-select unable to add a second session, even though the request supports multiple session IDs; preserve the initially discovered result options or load them independently of the filtered result set.
Useful? React with 👍 / 👎.
Add the Long-term memory tab to the Agent Memory workspace: a searchable records explorer. Memory records pane: - Semantic + keyword search with a minimum-similarity control - Filter by owner, namespace, session, memory type, and topic, with active filters shown as removable pills - Record cards: type badge, created/updated time, id, text, topic chips, and source session - Copy a record's id or session id - Click a topic or session on a card to filter by it
0c454b2 to
6c70467
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c7046793f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| export const ThresholdControl = styled.div` | ||
| display: inline-flex; | ||
| align-items: center; | ||
| gap: 6px; | ||
| flex-shrink: 0; |
There was a problem hiding this comment.
Replace the flex div with a layout component
The new threshold control implements a flex container with styled.div and hardcodes its alignment and gap, bypassing the shared layout system. Use Row or FlexGroup and pass align and gap at the JSX call site so this control follows the repository's layout and spacing conventions.
AGENTS.md reference: AGENTS.md:L154-L155
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6c70467. Configure here.
| </S.CardFooter> | ||
| )} | ||
| </S.Card> | ||
| ) |
There was a problem hiding this comment.
Record delete action missing
Medium Severity
MemoryCard never wires delete even though the PR describes deleting a record, deleteLongTermMemoryAction is exported, and CardDeleteWrapper is styled and re-exported for a hover delete control. Users on the Long-term memory tab cannot remove records from the UI.
Reviewed by Cursor Bugbot for commit 6c70467. Configure here.


Add the Long-term memory tab to the Agent Memory workspace: a searchable records explorer.
Memory records pane: