Skip to content

feat: show custom profiles in chat header profile selector#4382

Open
salarkhannn wants to merge 5 commits into
tinyhumansai:mainfrom
salarkhannn:feat/profile-custom-profiles-in-header
Open

feat: show custom profiles in chat header profile selector#4382
salarkhannn wants to merge 5 commits into
tinyhumansai:mainfrom
salarkhannn:feat/profile-custom-profiles-in-header

Conversation

@salarkhannn

@salarkhannn salarkhannn commented Jul 1, 2026

Copy link
Copy Markdown

Summary

The chat header profile selector now surfaces custom (non-built-in) agent
profiles, so users can switch to any profile available on their account — not
just the built-in Default and Reasoning options.

Custom profiles are those with builtIn: false. They are listed after the two
built-in options, sorted by sortOrder (fallback 0) and then by localized
name. The active profile is highlighted (aria-checked), and selecting one
fires onSelect(profile.id).

Part of #3486 — this PR covers chat-header visibility of custom profiles.
Full profile isolation / scoped state remains tracked in #3486.

Changes

  • Extracted the profile-selector UI out of Conversations into a dedicated
    AgentProfileSelector component
    (app/src/features/conversations/components/AgentProfileSelector.tsx).
  • Added a shared sortAgentProfiles(profiles, locale) helper that filters to
    non-built-in profiles and sorts by sortOrder then name.localeCompare(..., locale);
    re-exported from Conversations so existing tests still resolve it.
  • Replaced the flaky full-page render assertion with an isolated unit test
    (AgentProfileSelector.test.tsx) covering: custom profiles render with
    profile.name, the active profile is marked aria-checked, and selecting it
    invokes the handler.

Test plan

  • yarn test / vitest run — new AgentProfileSelector.test.tsx passes
    (i18n mocked).
  • yarn format:check and yarn typecheck pass (Frontend Checks / compile lanes).
  • Manual: open a conversation → open the profile selector in the chat header →
    confirm custom profiles appear, the active one is highlighted, and selecting
    it updates the active profile.

Linked issue

Part of #3486

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The chat header now renders agent profile buttons from a locale-aware sorted helper that excludes builtIn profiles, and the helper is covered by unit tests for filtering and ordering.

Changes

Agent Profile Selector UI

Layer / File(s) Summary
Sorting helper and dynamic selector
app/src/pages/Conversations.tsx
Adds sortAgentProfiles for filtering and ordering agent profiles, then uses it to render selectable chat header buttons for each non-builtIn profile with active-state and analytics wiring.
Sorting helper tests
app/src/pages/__tests__/Conversations.test.tsx
Adds unit coverage for sortAgentProfiles, including builtIn filtering, sort order and name ordering, default handling, and empty-input cases.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit hopped through profiles new,
Sorted neatly, one to view.
Built-in ones hopped out of sight,
Named ones lined up just right.
Click, switch, hop—what a cheerful crew! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR only updates the chat header selector and tests; it does not implement the profile isolation, scoped state, or broader switching requirements in #3486. Expand the implementation to cover profile-specific persona/context, scoped memory/connectors/skills/MCP, safe switching, and profile CRUD behaviors.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding custom profiles to the chat header selector.
Out of Scope Changes check ✅ Passed The code changes stay focused on surfacing and sorting custom profiles in the chat header, plus matching unit tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
app/src/pages/Conversations.tsx (1)

2955-2960: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Sort doesn't actually use the app's locale.

a.name.localeCompare(b.name) uses the runtime's default locale, not the app's selected uiLocale (already available at Line 333 and used elsewhere in this component for chatSend). For non-English users this can order custom profiles inconsistently with the rest of the localized UI.

🔧 Proposed fix
                 {agentProfiles
                   .filter(p => !p.builtIn)
                   .sort(
                     (a, b) =>
-                      (a.sortOrder ?? 0) - (b.sortOrder ?? 0) || a.name.localeCompare(b.name)
+                      (a.sortOrder ?? 0) - (b.sortOrder ?? 0) ||
+                      a.name.localeCompare(b.name, uiLocale)
                   )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/pages/Conversations.tsx` around lines 2955 - 2960, The custom agent
profile sort in Conversations.tsx is using the runtime default locale via a
plain localeCompare call instead of the app’s selected uiLocale. Update the
comparator in the agentProfiles sort to pass the existing uiLocale value (the
same one already used in chatSend and available in this component) into the name
comparison so ordering matches the localized UI for non-English users.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/src/pages/Conversations.tsx`:
- Around line 2955-2960: The custom agent profile sort in Conversations.tsx is
using the runtime default locale via a plain localeCompare call instead of the
app’s selected uiLocale. Update the comparator in the agentProfiles sort to pass
the existing uiLocale value (the same one already used in chatSend and available
in this component) into the name comparison so ordering matches the localized UI
for non-English users.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 88b80c28-27a1-4018-ac17-c8bdde5b9ccc

📥 Commits

Reviewing files that changed from the base of the PR and between 811669b and d3e69ac.

📒 Files selected for processing (1)
  • app/src/pages/Conversations.tsx

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 1, 2026

Copilot AI left a comment

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.

Pull request overview

This PR extends the chat header’s agent-profile selector so that user-created (non-built-in) profiles from Settings → Profiles are visible and selectable directly from the main chat surface, alongside the existing Quick/Reasoning options.

Changes:

  • Render additional radio-style buttons for each non-built-in agent profile in the chat header.
  • Sort custom profiles by sortOrder, then by name.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/src/pages/Conversations.tsx Outdated
Comment on lines +2957 to +2960
.sort(
(a, b) =>
(a.sortOrder ?? 0) - (b.sortOrder ?? 0) || a.name.localeCompare(b.name)
)
Comment thread app/src/pages/Conversations.tsx Outdated
Comment on lines +2955 to +2969
{agentProfiles
.filter(p => !p.builtIn)
.sort(
(a, b) =>
(a.sortOrder ?? 0) - (b.sortOrder ?? 0) || a.name.localeCompare(b.name)
)
.map(profile => (
<button
key={profile.id}
type="button"
role="radio"
aria-checked={selectedAgentProfileId === profile.id}
data-analytics-id={`chat-header-mode-${profile.id}`}
onClick={() => void handleSelectAgentProfile(profile.id)}
className={`rounded-full px-2.5 py-0.5 text-xs font-medium transition-all ${
@salarkhannn
salarkhannn force-pushed the feat/profile-custom-profiles-in-header branch from d3e69ac to 22a7d71 Compare July 1, 2026 12:52

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
app/src/pages/Conversations.tsx (1)

221-228: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider memoizing the sort result.

sortAgentProfiles is called inline during render (line 2964) rather than being memoized, so it re-filters/re-sorts on every render. Logic itself is correct.

♻️ Optional refactor
-{sortAgentProfiles(agentProfiles, uiLocale).map(profile => (
+{sortedAgentProfiles.map(profile => (

with const sortedAgentProfiles = useMemo(() => sortAgentProfiles(agentProfiles, uiLocale), [agentProfiles, uiLocale]); declared near other memoized values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/pages/Conversations.tsx` around lines 221 - 228, Memoize the agent
profile sorting result in Conversations to avoid re-filtering/re-sorting on
every render. Update the `Conversations` component by introducing a
`useMemo`-based `sortedAgentProfiles` near the other memoized values, using
`sortAgentProfiles(agentProfiles, uiLocale)` with `agentProfiles` and `uiLocale`
as dependencies, and then replace the inline call site with the memoized value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/src/pages/Conversations.tsx`:
- Around line 221-228: Memoize the agent profile sorting result in Conversations
to avoid re-filtering/re-sorting on every render. Update the `Conversations`
component by introducing a `useMemo`-based `sortedAgentProfiles` near the other
memoized values, using `sortAgentProfiles(agentProfiles, uiLocale)` with
`agentProfiles` and `uiLocale` as dependencies, and then replace the inline call
site with the memoized value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 12e09cb6-c347-4b95-90e0-bfb1eae577a7

📥 Commits

Reviewing files that changed from the base of the PR and between d3e69ac and 22a7d71.

📒 Files selected for processing (2)
  • app/src/pages/Conversations.tsx
  • app/src/pages/__tests__/Conversations.test.tsx

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 1, 2026
Resolve rename conflict: app/src/pages/Conversations.tsx was moved to
app/src/features/conversations/Conversations.tsx on main. Port the PR's
AgentProfile import and sortAgentProfiles test import to the new location
and corrected relative-path depth (../ -> ../../).
@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Maintainer review changes: merged current upstream/main into the PR branch and resolved the resulting conflicts. Upstream moved app/src/pages/Conversations.tsxapp/src/features/conversations/Conversations.tsx, which collided with this PR's edits to the old path.

  • app/src/features/conversations/Conversations.tsx — resolved the import-block conflict: kept main's new relative-path depth (../../) and re-added this PR's import type { AgentProfile } from '../../types/agentProfile' at the corrected path. The PR's other two hunks (the sortAgentProfiles helper and the per-profile header buttons) applied cleanly to the moved file; all referenced symbols (agentProfiles, selectedAgentProfileId, uiLocale, handleSelectAgentProfile) exist there.
  • app/src/pages/tests/Conversations.test.tsx — resolved the test import conflict: import from the new module path ../../features/conversations/Conversations while preserving this PR's added sortAgentProfiles import and its test block.

No functional changes to the feature itself; this only re-homes the PR onto the relocated file. Letting CI verify.

@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Re: CodeRabbit nitpicks (both non-blocking COMMENTED, not a CHANGES_REQUESTED block):

  1. "Sort doesn't use the app's locale" — already resolved in the current revision: sortAgentProfiles(profiles, locale) passes uiLocale through and calls a.name.localeCompare(b.name, locale). The comment referenced an earlier draft. No change needed.

  2. "Memoize the sort result" — declining as an optional micro-optimization (CodeRabbit itself rated it Trivial / Low value). The custom-profile list is a handful of entries, so the inline filter+sort per render is negligible, and adding a useMemo in this very large component isn't worth the churn for this PR. Can be revisited if the profile count ever grows materially.

salarkhannn and others added 3 commits July 15, 2026 12:26
Extract the chat-header profile selector into AgentProfileSelector so the
new button JSX can be unit-tested without mounting the full Conversations
page (avoids Redux/API/browser-API flakiness). sortAgentProfiles moves with
it and is re-exported to keep existing imports resolving. Covers the
previously-uncovered custom-profile render path to satisfy the 80% diff
coverage gate.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be8c94d133

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

type="button"
role="radio"
aria-checked={selectedProfileId === profile.id}
data-analytics-id={`chat-header-mode-${profile.id}`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use a stable analytics id for custom profiles

When a user clicks a custom profile, the app-wide interaction tracker reads data-analytics-id as the control_id for ui_click events, so interpolating profile.id sends a user-created entity identifier (the profile editor lets users type this id) into analytics. This leaks potentially sensitive/custom account data and creates unbounded event cardinality; use a fixed id such as chat-header-mode-custom and keep the actual profile id out of analytics attributes.

Useful? React with 👍 / 👎.

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.

4 participants