Skip to content

[Hold] add create agent to top of approver#92106

Open
NicolasBonet wants to merge 7 commits into
mainfrom
feat/91245-add-create-agent-to-top-of-approver
Open

[Hold] add create agent to top of approver#92106
NicolasBonet wants to merge 7 commits into
mainfrom
feat/91245-add-create-agent-to-top-of-approver

Conversation

@NicolasBonet
Copy link
Copy Markdown
Contributor

@NicolasBonet NicolasBonet commented May 29, 2026

Explanation of Change

Adds the option to add agents in the approver list, so they are automatically added as approvers on creation

Hold

For: #91441

Fixed Issues

$ #91245
PROPOSAL: #91245

Tests

  1. Enable the customAgent beta on a test workspace.
  2. Go to Workspace > Workflows, open a workflow for editing, and tap the approver field to reach the Set Approver page.
  3. Verify a "Create an agent" row appears at the top of the approver list.
  4. Tap "Create an agent" — verify the create-agent modal launches with the workspace context.
  5. Complete the create-agent flow — verify you return to the Set Approver page with the new agent's row visible and already selected.
  6. Confirm the workflow and verify the agent is saved as the approver.
  7. Repeat all steps on a workspace where the customAgent beta is not enabled — verify the "Create an agent" row never appears.
  • Verify that no errors appear in the JS console

Offline tests

Repeat the process but set offline mode before creating the agent, you should see the agent opaque until you resume connection.

QA Steps

Same as tests

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-05-29.at.2.43.21.PM.mov

@OSBotify
Copy link
Copy Markdown
Contributor

🦜 Polyglot Parrot! 🦜

Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues:

View the translation diff
diff --git a/src/languages/de.ts b/src/languages/de.ts
index 73d20ca03d4..11c1fd71cfb 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -497,6 +497,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: 'Vorheriges Jahr',
         nextYear: 'Nächstes Jahr',
         avatar: 'Avatar',
+        agent: 'Agent',
     },
     socials: {
         podcast: 'Folgen Sie uns auf Podcast',
@@ -2674,6 +2675,8 @@ ${amount} für ${merchant} – ${date}`,
         genericErrorMessage: 'Die genehmigende Person konnte nicht geändert werden. Bitte versuche es erneut oder kontaktiere den Support.',
         title: 'Genehmigenden festlegen',
         description: 'Diese Person wird die Ausgaben genehmigen.',
+        createNewAgent: 'Neue Agent:in erstellen',
+        createNewAgentDescription: 'Automatisieren Sie Ihre Genehmigungen mit Prompt',
     },
     workflowsApprovalLimitPage: {
         title: 'Genehmiger',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index d27d58ac260..26e589906e1 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -449,6 +449,7 @@ const translations: TranslationDeepObject<typeof en> = {
         expensifyLogo: 'Logo de Expensify',
         approver: 'Aprobador',
         enterDigitLabel: ({digitIndex, totalDigits}: {digitIndex: number; totalDigits: number}) => `introducir dígito ${digitIndex} de ${totalDigits}`,
+        agent: 'Agente',
     },
     socials: {
         podcast: 'Síguenos en Podcast',
@@ -2550,7 +2551,7 @@ ${amount} para ${merchant} - ${date}`,
         title: 'Establecer aprobador',
         description: 'Esta persona aprobará los gastos.',
         createNewAgent: 'Crear nuevo agente',
-        createNewAgentDescription: 'Automatiza tus aprobaciones con un prompt',
+        createNewAgentDescription: 'Automatiza tus aprobaciones con rapidez',
     },
     workflowsApprovalLimitPage: {
         title: 'Aprobador',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index ead01bebcc4..01fe8f7ed31 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -497,6 +497,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: 'Année précédente',
         nextYear: 'L’an prochain',
         avatar: 'Avatar',
+        agent: 'Agent',
     },
     socials: {
         podcast: 'Suivez-nous sur Podcast',
@@ -2681,6 +2682,8 @@ ${amount} pour ${merchant} - ${date}`,
         genericErrorMessage: 'L’approbateur n’a pas pu être modifié. Veuillez réessayer ou contacter l’assistance.',
         title: 'Définir l’approbateur',
         description: 'Cette personne approuvera les dépenses.',
+        createNewAgent: 'Créer un nouvel agent',
+        createNewAgentDescription: 'Automatisez vos approbations avec l’IA',
     },
     workflowsApprovalLimitPage: {
         title: 'Approbateur',
@@ -2978,7 +2981,7 @@ ${amount} pour ${merchant} - ${date}`,
         phoneOrEmail: 'Téléphone ou e-mail',
         error: {
             agentSignInBlocked:
-                'Les comptes d\u2019agent ne permettent pas de se connecter directement. Pour utiliser un agent, connectez-vous avec votre propre compte et accédez-y via Copilot.',
+                'Les comptes d’agent ne permettent pas de se connecter directement. Pour utiliser un agent, connectez-vous avec votre propre compte et accédez-y via Copilot.',
             invalidFormatEmailLogin: 'L’adresse e-mail saisie est invalide. Veuillez corriger le format et réessayer.',
         },
         cannotGetAccountDetails: 'Impossible de récupérer les détails du compte. Veuillez essayer de vous reconnecter.',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index e358d2cf3e8..1b2effccc77 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -497,6 +497,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: 'Anno precedente',
         nextYear: "L'anno prossimo",
         avatar: 'Avatar',
+        agent: 'Agente',
     },
     socials: {
         podcast: 'Seguici su Podcast',
@@ -2669,6 +2670,8 @@ ${amount} per ${merchant} - ${date}`,
         genericErrorMessage: "Non è stato possibile modificare l'approvatore. Riprova o contatta l'assistenza.",
         title: 'Imposta approvatore',
         description: 'Questa persona approverà le spese.',
+        createNewAgent: 'Crea nuovo agente',
+        createNewAgentDescription: 'Automatizza le tue approvazioni con prompt',
     },
     workflowsApprovalLimitPage: {
         title: 'Approvante',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 340cdace1a8..95be8740f19 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -496,6 +496,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: '前年',
         nextYear: '来年',
         avatar: 'アバター',
+        agent: 'エージェント',
     },
     socials: {
         podcast: 'ポッドキャストでフォロー',
@@ -2560,7 +2561,7 @@ ${date} の ${merchant} への ${amount}`,
         accessibilityLabel: ({members, approvers}: {members: string; approvers: string}) => `${members} の経費で、承認者は ${approvers} です`,
         addApprovalButton: '承認ワークフローを追加',
         editWorkflowAction: '編集',
-        addAgentAction: 'エージェントを追加',
+        addAgentAction: '担当者を追加',
         findWorkflow: 'ワークフローを検索',
         addApprovalTip: 'より詳細なワークフローが存在する場合を除き、このデフォルトのワークフローがすべてのメンバーに適用されます。',
         approver: '承認者',
@@ -2647,6 +2648,8 @@ ${date} の ${merchant} への ${amount}`,
         genericErrorMessage: '承認者を変更できませんでした。もう一度お試しいただくか、サポートにお問い合わせください。',
         title: '承認者を設定',
         description: 'この人が経費を承認します。',
+        createNewAgent: '新しいエージェントを作成',
+        createNewAgentDescription: '迅速な承認でワークフローを自動化しましょう',
     },
     workflowsApprovalLimitPage: {
         title: '承認者',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 5c4c429c12c..d5890f3a715 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -496,6 +496,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: 'Vorig jaar',
         nextYear: 'Volgend jaar',
         avatar: 'Avatar',
+        agent: 'Agent',
     },
     socials: {
         podcast: 'Volg ons op Podcast',
@@ -2666,6 +2667,8 @@ ${amount} voor ${merchant} - ${date}`,
         genericErrorMessage: 'De fiatteur kon niet worden gewijzigd. Probeer het opnieuw of neem contact op met support.',
         title: 'Stel fiatteur in',
         description: 'Deze persoon keurt de declaraties goed.',
+        createNewAgent: 'Nieuwe agent toevoegen',
+        createNewAgentDescription: 'Automatiseer je goedkeuringen met prompt',
     },
     workflowsApprovalLimitPage: {
         title: 'Fiatteur',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 66a543121ff..ec80df214a8 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -496,6 +496,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: 'Poprzedni rok',
         nextYear: 'W przyszłym roku',
         avatar: 'Avatar',
+        agent: 'Agent',
     },
     socials: {
         podcast: 'Śledź nas na Podcast',
@@ -2662,6 +2663,8 @@ ${amount} dla ${merchant} - ${date}`,
         genericErrorMessage: 'Nie udało się zmienić osoby zatwierdzającej. Spróbuj ponownie lub skontaktuj się z pomocą techniczną.',
         title: 'Ustaw zatwierdzającego',
         description: 'Ta osoba będzie zatwierdzać wydatki.',
+        createNewAgent: 'Utwórz nowego agenta',
+        createNewAgentDescription: 'Automatyzuj swoje akceptacje za pomocą promptów',
     },
     workflowsApprovalLimitPage: {
         title: 'Osoba zatwierdzająca',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 5155a743303..eb4fce64943 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -495,6 +495,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: 'Ano anterior',
         nextYear: 'Ano que vem',
         avatar: 'Avatar',
+        agent: 'Agente',
     },
     socials: {
         podcast: 'Siga-nos no Podcast',
@@ -2660,6 +2661,8 @@ ${amount} para ${merchant} - ${date}`,
         genericErrorMessage: 'O aprovador não pôde ser alterado. Tente novamente ou entre em contato com o suporte.',
         title: 'Definir aprovador',
         description: 'Essa pessoa vai aprovar as despesas.',
+        createNewAgent: 'Criar novo agente',
+        createNewAgentDescription: 'Automatize suas aprovações com agilidade',
     },
     workflowsApprovalLimitPage: {
         title: 'Aprovador',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index e77148a1541..acde0379803 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -492,6 +492,7 @@ const translations: TranslationDeepObject<typeof en> = {
         previousYear: '上一年',
         nextYear: '明年',
         avatar: '头像',
+        agent: '代理人',
     },
     socials: {
         podcast: '在播客上关注我们',
@@ -2594,6 +2595,8 @@ ${amount},商户:${merchant} - 日期:${date}`,
         genericErrorMessage: '无法更改审批人。请重试或联系支持。',
         title: '设置审批人',
         description: '此人将审核并批准这些报销。',
+        createNewAgent: '创建新代理',
+        createNewAgentDescription: '使用 Prompt 自动化您的审批',
     },
     workflowsApprovalLimitPage: {
         title: '审批人',

Note

You can apply these changes to your branch by copying the patch to your clipboard, then running pbpaste | git apply 😉

View workflow run

@NicolasBonet NicolasBonet changed the base branch from main to feat/91244-add-agent-to-workflow-approval May 29, 2026 18:01
@NicolasBonet NicolasBonet changed the title add create agent to top of approver [Hold] add create agent to top of approver May 29, 2026
NicolasBonet and others added 4 commits May 29, 2026 14:37
- Added a new `headerContent` prop to the ApproverSelectionList component for customizable header content.
- Introduced translations for creating new agents in English and Spanish.
- Updated AddAgentPage to handle optimistic agent creation and reconciliation within approval workflows.
- Enhanced WorkspaceWorkflowsApprovalsApproverPage to conditionally display a menu item for creating new agents, improving user experience in agent management.
- Introduced a new translation for 'Agent' in the English language file.
- Updated MemberRightIcon component to include an `isAgent` prop for displaying agent badges.
- Enhanced WorkspaceWorkflowsApprovalsApproverPage to conditionally render agent-related information and manage optimistic agent states.
- Added styles for agent approver avatars to improve UI consistency.
- Added `onDismissError` prop to ApproverSelectionList for improved error management.
- Implemented `clearOptimisticAgentFromApprovalWorkflow` function to handle optimistic agent state during approval processes.
- Updated AddAgentPage to navigate correctly based on approval workflow actions.
- Enhanced WorkspaceWorkflowsApprovalsApproverPage to manage optimistic approver display and dismissal, improving user experience in agent management.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@NicolasBonet NicolasBonet force-pushed the feat/91245-add-create-agent-to-top-of-approver branch from 02b5707 to bdaaf14 Compare May 29, 2026 19:38
@NicolasBonet NicolasBonet requested a review from ShridharGoel May 29, 2026 19:39
@NicolasBonet NicolasBonet marked this pull request as ready for review May 29, 2026 19:39
@NicolasBonet NicolasBonet requested review from a team as code owners May 29, 2026 19:39
@melvin-bot
Copy link
Copy Markdown

melvin-bot Bot commented May 29, 2026

@parasharrajat @yuwenmemon One of you needs to copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@melvin-bot melvin-bot Bot removed request for a team May 29, 2026 19:39
@github-actions
Copy link
Copy Markdown
Contributor

🚧 @NicolasBonet has triggered a test Expensify/App build. You can view the workflow run here.

Copy link
Copy Markdown

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

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: bdaaf14aed

ℹ️ 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".

Comment thread src/pages/settings/Agents/AddAgentPage.tsx
@ShridharGoel
Copy link
Copy Markdown
Contributor

Tap "Create an agent" — verify the create-agent modal launches with the workspace context.

Does workspace context mean the agent will be connected to the workspace? Aren't agents tied to the whole profile and not a workspace?

@NicolasBonet
Copy link
Copy Markdown
Contributor Author

Tap "Create an agent" — verify the create-agent modal launches with the workspace context.

Does workspace context mean the agent will be connected to the workspace? Aren't agents tied to the whole profile and not a workspace?

They need to be added as members of the workspace as well, not only to the profile.

- Changed the `makeRoute` function to accept an optional `name` parameter for better flexibility in route creation.
- Updated the test case for `AddAgentPage` to use the new route handling, ensuring accurate navigation based on the approval workflow.
…r retrieval in WorkspaceWorkflowsApprovalsApproverPage

- Refactored route determination logic in AddAgentPage for better readability and maintainability.
- Updated the method of accessing approvers in WorkspaceWorkflowsApprovalsApproverPage to use the `at` method for improved clarity and performance.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2026

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.

Files with missing lines Coverage Δ
src/components/ApproverSelectionList.tsx 92.68% <100.00%> (+0.18%) ⬆️
src/styles/index.ts 59.06% <ø> (ø)
src/pages/workspace/MemberRightIcon.tsx 94.44% <66.66%> (-5.56%) ⬇️
src/pages/settings/Agents/AddAgentPage.tsx 79.72% <66.66%> (-4.15%) ⬇️
src/libs/actions/Agent.ts 68.05% <0.00%> (-6.19%) ⬇️
...rovals/WorkspaceWorkflowsApprovalsApproverPage.tsx 0.00% <0.00%> (ø)
... and 76 files with indirect coverage changes

Copy link
Copy Markdown
Contributor

@joekaufmanexpensify joekaufmanexpensify left a comment

Choose a reason for hiding this comment

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

Core design doc issue

Comment thread src/styles/index.ts
@NicolasBonet NicolasBonet removed the request for review from parasharrajat May 29, 2026 22:29
Base automatically changed from feat/91244-add-agent-to-workflow-approval to main May 30, 2026 00:01
@yuwenmemon yuwenmemon dismissed joekaufmanexpensify’s stale review May 30, 2026 00:01

The base branch was changed.

@ShridharGoel
Copy link
Copy Markdown
Contributor

Bug:

  1. Complete the create-agent flow to add the first approver.
  2. Then, click on "Add agent".
  3. Go to the first approver.
  4. Click on "Create new agent".
  5. Save.
  6. Notice that the edit approver screen shows with just the already added approver.
Screen.Recording.2026-05-30.at.8.13.02.PM.mov

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