[NoQA] Display human agent identity on Concierge messages#87508
[NoQA] Display human agent identity on Concierge messages#87508
Conversation
When a Concierge message contains humanAgentAccountID in its message JSON, show a subscript avatar (Concierge main + agent secondary) and display "assisted by [Agent Name]" text below the message header. This lets customers know when a human agent is helping them through Concierge. Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
Use destructuring instead of bracket notation for array access to satisfy the prefer-at ESLint rule, and run Prettier to fix formatting. Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
|
Fixed the failing checks:
|
…tils Add assistedBy translation string to all 8 remaining language files (de, fr, it, ja, nl, pl, pt-BR, zh-hans) and add humanAgentAccountID field to both pendingFields and linkedTrackedExpenseReportAction objects in DebugUtils.ts. Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
|
Fixed the typecheck failures:
|
Add humanAgentAccountID case to the validateReportActionDraftProperty switch statement to satisfy the switch-exhaustiveness-check ESLint rule. Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
|
Fixed another ESLint failure: added |
…bility Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
|
Fixed the typecheck failure by merging main into the branch. The |
|
MelvinBot has made 5 consecutive commits trying to fix CI failures. Automatic CI fix dispatches are now paused for this PR. Next steps: A human should review the recent commits and resolve the conflicting CI errors manually. |
Consecutive Concierge messages were grouped under a single avatar even when the human agent presence changed (e.g. agent replies as themselves then switches back to Concierge). Add a humanAgentAccountID comparison in canActionsBeGrouped so each persona transition gets its own avatar. Made-with: Cursor
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
…nd whisperedTo to tests Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
|
Fixed the typecheck failure:
Note: there are also pre-existing typecheck errors in |
|
Fixed the failing checklist check: the PR body was missing the standard All other checks are passing or still running. |
The agent avatar name was falling back to humanAgentDetails.login (email) when displayName was empty. Use only displayName to prevent leaking the agent's email address in tooltips. Made-with: Cursor
…countIDFromReportAction Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
|
Fixed the failing ESLint check: replaced |
…name When a Concierge agent has no display name set, the "assisted by" text and avatar tooltip now show "a human support agent" instead of an empty string. Made-with: Cursor
🦜 Polyglot Parrot! 🦜Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues: The diff is too large to include in this comment (62KB), so I've created a gist for you: 📋 View the translation diff here 📋 Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
…t compliance Co-authored-by: Neil Marcellini <neil-marcellini@users.noreply.github.com>
|
Fixed the failing ESLint check: replaced
|
|
The failing Changed files ESLint check is unrelated to this PR's code changes. It failed with a transient TLS error ( |
|
The The CI runner hit a TLS network error ( Fix: Re-run the failed workflow. This should resolve on retry. |
|
The The GitHub API call to compute the diff returned corrupted data due to the TLS error, causing jq to fail before ESLint even ran. All other checks (full ESLint, typecheck, tests, builds) passed. Fix: Re-run the failed workflow — no code changes needed. |
|
The The check failed with To resolve: Re-run the failed |
When viewing a thread on a Concierge message sent by a human agent, the header subtitle now shows "from Concierge - assisted by [Name]" instead of just "from Concierge". Applied in both HeaderView and AvatarWithDisplayName to cover all thread header contexts. Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 38a9e41a8e
ℹ️ 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".
Three call sites were repeating the same personalDetails?.[humanAgentAccountID]?.displayName lookup after calling getHumanAgentAccountIDFromReportAction. Add a small helper in ReportActionsUtils so the resolution logic lives in one place and all consumers stay in sync if it changes. Made-with: Cursor
|
The only failing checks are:
All code checks pass: ESLint, Prettier, typecheck, all 8 test jobs, builds, storybook, and spellcheck. |
|
The Please re-run the failed job. All other checks (ESLint, typecheck, tests, builds, etc.) are passing. |
ParentNavigationSubtitle previously hid the "- assisted by [...]" suffix whenever humanAgentName was falsy, which also dropped it when the account exists but personal details have not yet hydrated (or have no displayName). Match the inline message behavior by gating on humanAgentAccountID and falling back to the generic "a human support agent" label when the name is missing. Made-with: Cursor
trjExpensify
left a comment
There was a problem hiding this comment.
Product change coming from @zanyrenney's WN post.
I can see from here the dual avatar and "assisted by FirstName" text is the intended design.
|
@MelvinBot CAn you please review this PR? |
|
@codex review |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / Safari |
PR ReviewOverall this is a clean, well-structured implementation. All CI checks pass (only the PR Author Checklist is failing, which is expected). Here's my assessment: Architecture — The approach is sound: a single utility function ( What looks good:
One minor observation (not a blocker): There's a brief visual inconsistency during the moment before No blocking issues found. 👍 |
mountiny
left a comment
There was a problem hiding this comment.
Overall looks good, can you add unit test for the new utils method please even if its quite simple? Also I marked it as NoQa as we cannot test it until the web PR is deployed
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dab0c73445
ℹ️ 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".
|
|
||
| function getHumanAgentDisplayName(reportAction: OnyxInputOrEntry<ReportAction>, personalDetails: OnyxEntry<PersonalDetailsList>): string | undefined { | ||
| const humanAgentAccountID = getHumanAgentAccountIDFromReportAction(reportAction); | ||
| return humanAgentAccountID ? personalDetails?.[humanAgentAccountID]?.displayName : undefined; |
There was a problem hiding this comment.
Normalize empty agent names before using assisted-by fallbacks
getHumanAgentDisplayName() returns the raw displayName, so an empty string is treated as a valid name instead of “missing.” Because downstream call sites use nullish fallback (??), a blank profile name yields UI like assisted by (no name) and can suppress the subscript avatar label path that expects a non-empty secondary name. This is user-visible whenever a Concierge agent account has an empty displayName; returning undefined for empty/whitespace names would preserve the intended generic fallback.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
(Neil's AI agent) Good catch, agreed. Nullish fallback (??) won't substitute humanSupportAgent for an empty string, and the subscript label downstream would have rendered as assisted by with no name. Changed getHumanAgentDisplayName to treat empty / whitespace-only displayName as missing (returns undefined), so the generic fallback kicks in on every call site. Added two unit tests (empty string, whitespace-only) in ReportActionsUtilsTest.ts. Pushed in 5a86317.
- Add unit tests covering getHumanAgentAccountIDFromReportAction and getHumanAgentDisplayName (PR review from @mountiny). - Treat empty / whitespace-only agent displayName as missing in getHumanAgentDisplayName so downstream `?? humanSupportAgent` fallbacks kick in and the subscript label is never rendered as "assisted by " with no name (codex P2 feedback). Made-with: Cursor
5a86317
|
🚧 @mountiny has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
The backend sets `displayName` to "First Last" via `Account::getDisplayNameUsingFirstAndLastName`, but the product design (per review on PR Expensify#87508) is to show "assisted by FirstName" and label the subscript avatar with only the agent's first name. Switch to the dedicated `firstName` field (which Auth already sends via `formatNewDotPersonalDetails`) and fall back to the generic human support agent label when firstName is missing/blank. Made-with: Cursor
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.3.61-0 🚀
Bundle Size Analysis (Sentry): |
|
🤖 Help site changes are required. PR #87508 introduces user-visible "assisted by [Agent Name]" labels and subscript avatars on Concierge messages when a human agent is assisting. The help site article Draft PR created: #88404 Changes made:
|
|
Did Internal QA for this pass? |
Explanation of Change
When a Concierge message contains
humanAgentAccountIDin its message JSON (set by an agent using "Reply as yourself" in the Concierge app), the App now shows:How it works:
getHumanAgentAccountIDFromReportAction()checks if the actor is Concierge AND the originalMessage containshumanAgentAccountIDuseReportActionAvatarsbuilds a subscript avatar pair (Concierge + agent) when presentReportActionItemSinglerenders "assisted by [Name]" below the sender linecanActionsBeGroupedbreaks grouping whenhumanAgentAccountIDchanges between messagesFixed Issues
$ https://github.com/Expensify/Expensify/issues/622128
Tests
Set up
Main flow
2026-04-13_13-57-24.mp4
Concierge chat thread
Offline tests
N/A — these are display-only changes for server-generated report actions. The
humanAgentAccountIDand personal details are loaded from the server; offline behavior is unchanged.QA Steps
Internal QA, run the test steps above on staging, following this SO too How can I test sending myself or a specific account a Concierge message?
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Changes are platform independent. Please see the evidence above in the tests section.
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Related PRs
humanAgentAccountIDin message JSON + OpenReport personal details)