Skip to content

feat(memory): add user preferences and structured user context in system prompt#8264

Merged
Subash-Mohan merged 9 commits intomainfrom
add-user-preference
Feb 10, 2026
Merged

feat(memory): add user preferences and structured user context in system prompt#8264
Subash-Mohan merged 9 commits intomainfrom
add-user-preference

Conversation

@Subash-Mohan
Copy link
Copy Markdown
Contributor

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

Description

  • Add a "Personal Preferences" free-text field (up to 500 chars) to user settings, stored as a new user_preferences column
    on the User model
  • Introduce UserMemoryContext to consolidate user info (name, email, role), preferences, and memories into a single
    structured object
  • Replace the flat bullet-list user info format in the system prompt with properly sectioned headers (## Basic Information, ## User Preferences, ## User Memories) using templates from user_info.py
  • Reorganize the Settings page: add a preferences textarea with character count and save feedback, move Memory and Prompt Shortcuts sections
Screenshot 2026-02-09 at 2 16 05 PM

How Has This Been Tested?

I tested it by adding preferences and sending a message to confirm whether it is acting as preferred.

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

Adds a Personal Preferences field and a structured UserMemoryContext to render a clearer “User Information” section in system prompts, improving personalization and search query expansion. Updates Settings with a preferences textarea, 500-character counter, and save success/error toasts, and reorganizes Memory and Prompt Shortcuts.

  • New Features

    • Added user_preferences column to User.
    • Introduced frozen UserMemoryContext (user_info, preferences, memories as tuple) with .as_formatted_list()/.as_formatted_prompt().
    • Replaced memories args with user_memory_context across chat loop, tool runner, and search tool; search uses formatted list for expansion.
    • System prompt now uses USER_INFORMATION_HEADER and templates to render Basic Information, User Preferences, and User Memories.
    • Settings: new Personal Preferences textarea with counter and toasts; Memory and Prompt Shortcuts reorganized; API/types/hooks updated (incl. updateUserPreferences).
  • Migration

    • Run Alembic migration 175ea04c7087 to add the user_preferences column (down_revision corrected).

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

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

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR adds a new free-text user_preferences field (DB column + API + UI) and replaces the legacy flat “memories” list in prompts with a structured UserMemoryContext that can render sectioned user context (## Basic Information, ## User Preferences, ## User Memories) into the system prompt. It also plumbs that structured context through the chat loop/tool runner and adapts the SearchTool to still receive a legacy list of memory strings for query expansion.

Two merge-blockers were found: UserMemoryContext.memories uses a mutable default list (risking cross-instance/request leakage) and the system prompt builder can emit a # User Information header even when the rendered user context is empty, leaving a dangling section header.

Confidence Score: 3/5

  • This PR is close to mergeable but needs a couple correctness fixes in the new user context plumbing.
  • Main changes are straightforward plumbing plus UI additions, but there are two concrete correctness issues: a mutable default list in a Pydantic model that can leak state across instances, and system prompt assembly that can emit an empty user-info section header when the rendered context is empty. Fixing these should make the changes low-risk.
  • backend/onyx/db/memory.py, backend/onyx/chat/prompt_utils.py

Important Files Changed

Filename Overview
backend/onyx/chat/prompt_utils.py Switches system prompt user section to structured UserMemoryContext; header gating likely produces empty # User Information header when context renders empty.
backend/onyx/db/memory.py Introduces UserMemoryContext formatting; uses mutable default list for memories which can leak across instances.
backend/onyx/server/manage/users.py Wires user_preferences through personalization update endpoint.
backend/onyx/tools/tool_implementations/search/search_tool.py Adapts search tool override to format memories from UserMemoryContext for query expansion.
web/src/refresh-pages/SettingsPage.tsx Adds Personal Preferences textarea with character count and save feedback popup; reorganizes Memory and Prompt Shortcuts sections.

Sequence Diagram

sequenceDiagram
  participant UI as SettingsPage (Web)
  participant Hook as useUserPersonalization
  participant API as PATCH /user/personalization
  participant DB as update_user_personalization
  participant Msg as process_message
  participant Mem as get_memories(UserMemoryContext)
  participant Prompt as build_system_prompt
  participant ToolRun as run_tool_calls
  participant Search as SearchTool

  UI->>Hook: updateUserPreferences(value)
  UI->>Hook: handleSavePersonalization()
  Hook->>API: persistPersonalization({ user_preferences, ... })
  API->>DB: update_user_personalization(..., user_preferences)
  DB-->>API: commit
  API-->>Hook: 200 OK

  Msg->>Mem: get_memories(user)
  Mem-->>Msg: UserMemoryContext
  Msg->>Prompt: build_system_prompt(..., user_memory_context)
  Prompt-->>Msg: system prompt w/ structured user sections

  Msg->>ToolRun: run_tool_calls(..., user_memory_context)
  ToolRun->>Search: override_kwargs.user_memory_context
  Search->>Search: as_formatted_list() used for query expansion
  Search-->>ToolRun: SearchDocsResponse/citations
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.

5 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 9, 2026

Additional Comments (2)

backend/onyx/chat/prompt_utils.py
Dangling user info header
build_system_prompt adds USER_INFORMATION_HEADER when user_memory_context is non-None, but call sites now pass a UserMemoryContext object even when it renders to an empty string. This can produce a # User Information header with no content (when no company context and user has no name/email/preferences/memories). Consider gating the header on the rendered content (or checking that the context actually has something to include).


backend/onyx/chat/prompt_utils.py
Dangling user header
build_system_prompt now gates on if company_context or user_memory_context: and then unconditionally appends USER_INFORMATION_HEADER. Since callers pass a UserMemoryContext object even when it contains no name/email/preferences/memories (and as_formatted_prompt() returns ""), this can emit a # User Information header with no content. Consider gating on the rendered string (or on as_formatted_prompt() being non-empty) before adding the header.

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.

3 issues found across 17 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="backend/onyx/chat/prompt_utils.py">

<violation number="1" location="backend/onyx/chat/prompt_utils.py:161">
P3: Avoid adding USER_INFORMATION_HEADER when the formatted user context is empty; otherwise the system prompt includes a blank section.</violation>
</file>

<file name="backend/onyx/server/manage/models.py">

<violation number="1" location="backend/onyx/server/manage/models.py:218">
P2: Enforce the 500-character limit for user preferences in the update request so the API matches the stated feature constraints and prevents oversized inputs.</violation>
</file>

<file name="backend/onyx/db/memory.py">

<violation number="1" location="backend/onyx/db/memory.py:47">
P2: `User role` is omitted from the system prompt when a user has only a role set (no name/email) because `has_basic_info` ignores `self.user_info.role`. Include role in the check so role-only users still get their role in the Basic Information section.</violation>
</file>

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

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.

1 issue found across 2 files (changes from recent commits).

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/refresh-components/inputs/InputTextArea.tsx">

<violation number="1" location="web/src/refresh-components/inputs/InputTextArea.tsx:103">
P2: Auto-resize only re-runs when `props.value` changes, so uncontrolled textareas won’t resize as the user types. Consider wiring `adjustHeight` to an input/change handler to update height on user input.</violation>
</file>

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

textarea.style.overflowY = contentHeight > maxHeight ? "auto" : "hidden";
}, [autoResize, rows, maxRows]);

React.useEffect(() => {
Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

P2: Auto-resize only re-runs when props.value changes, so uncontrolled textareas won’t resize as the user types. Consider wiring adjustHeight to an input/change handler to update height on user input.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/src/refresh-components/inputs/InputTextArea.tsx, line 103:

<comment>Auto-resize only re-runs when `props.value` changes, so uncontrolled textareas won’t resize as the user types. Consider wiring `adjustHeight` to an input/change handler to update height on user input.</comment>

<file context>
@@ -50,13 +50,62 @@ import {
+      textarea.style.overflowY = contentHeight > maxHeight ? "auto" : "hidden";
+    }, [autoResize, rows, maxRows]);
+
+    React.useEffect(() => {
+      adjustHeight();
+    }, [adjustHeight, props.value]);
</file context>
Fix with Cubic

@Subash-Mohan Subash-Mohan added this pull request to the merge queue Feb 10, 2026
Merged via the queue into main with commit 2d2d998 Feb 10, 2026
84 checks passed
@Subash-Mohan Subash-Mohan deleted the add-user-preference branch February 10, 2026 04:27
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