From 3d22fdd251ecd870ceb87644f36d0a2ef72bd543 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= <marco@expensify.com>
Date: Sun, 15 Mar 2026 23:14:42 -0600
Subject: [PATCH 1/2] Show 'Concierge is thinking' indicator in #admins room

The AgentZero status indicator (typing/thinking) was only shown in
Concierge DM chats because the useAgentZeroStatusIndicator hook and
the submit form logic were gated on isConciergeChatReport(), which
returns false for policy #admins rooms. The backend already sends the
indicator NVP for admin rooms, but the App was ignoring it.

Extend the check to also activate the indicator for isAdminRoom()
reports, so users see "Concierge is thinking..." in the #admins room
during onboarding with the suggestedFollowups beta.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 src/hooks/useAgentZeroStatusIndicator.ts                    | 3 ++-
 src/pages/inbox/ReportScreen.tsx                            | 3 ++-
 .../report/ReportActionCompose/ReportActionCompose.tsx      | 6 ++++--
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/hooks/useAgentZeroStatusIndicator.ts b/src/hooks/useAgentZeroStatusIndicator.ts
index fd2e6503593d..c1af11224b11 100644
--- a/src/hooks/useAgentZeroStatusIndicator.ts
+++ b/src/hooks/useAgentZeroStatusIndicator.ts
@@ -15,7 +15,8 @@ type AgentZeroStatusState = {
 };
 
 /**
- * Hook to manage AgentZero status indicator for Concierge chats.
+ * Hook to manage AgentZero status indicator for chats where Concierge responds.
+ * This includes both Concierge DM chats and policy #admins rooms (where Concierge handles onboarding).
  * Subscribes to real-time reasoning updates via Pusher and manages processing state.
  */
 function useAgentZeroStatusIndicator(reportID: string, isConciergeChat: boolean): AgentZeroStatusState {
diff --git a/src/pages/inbox/ReportScreen.tsx b/src/pages/inbox/ReportScreen.tsx
index 41b14a9880ec..c76be0e9d020 100644
--- a/src/pages/inbox/ReportScreen.tsx
+++ b/src/pages/inbox/ReportScreen.tsx
@@ -361,12 +361,13 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr
     const newTransactions = useNewTransactions(reportMetadata?.hasOnceLoadedReportActions, reportTransactions);
 
     const isConciergeChat = isConciergeChatReport(report);
+    const shouldShowConciergeIndicator = isConciergeChat || isAdminRoom(report);
     const {
         isProcessing: isConciergeProcessing,
         reasoningHistory: conciergeReasoningHistory,
         statusLabel: conciergeStatusLabel,
         kickoffWaitingIndicator,
-    } = useAgentZeroStatusIndicator(String(report?.reportID ?? CONST.DEFAULT_NUMBER_ID), isConciergeChat);
+    } = useAgentZeroStatusIndicator(String(report?.reportID ?? CONST.DEFAULT_NUMBER_ID), shouldShowConciergeIndicator);
 
     const {closeSidePanel} = useSidePanelActions();
 
diff --git a/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx
index 29118046e8dd..c6f626f4852a 100644
--- a/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx
+++ b/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx
@@ -47,6 +47,7 @@ import {
     chatIncludesConcierge,
     getParentReport,
     getReportRecipientAccountIDs,
+    isAdminRoom,
     isChatRoom,
     isConciergeChatReport,
     isGroupChat,
@@ -222,6 +223,7 @@ function ReportActionCompose({
     const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]);
     const isReportArchived = useReportIsArchived(report?.reportID);
     const isConciergeChat = useMemo(() => isConciergeChatReport(report), [report]);
+    const shouldShowConciergeIndicator = useMemo(() => isConciergeChat || isAdminRoom(report), [isConciergeChat, report]);
 
     const isTransactionThreadView = useMemo(() => isReportTransactionThread(report), [report]);
     const isExpensesReport = useMemo(() => reportTransactions && reportTransactions.length > 1, [reportTransactions]);
@@ -336,7 +338,7 @@ function ReportActionCompose({
         (newComment: string) => {
             const newCommentTrimmed = newComment.trim();
 
-            if (isConciergeChat && kickoffWaitingIndicator) {
+            if (shouldShowConciergeIndicator && kickoffWaitingIndicator) {
                 kickoffWaitingIndicator();
             }
 
@@ -373,7 +375,7 @@ function ReportActionCompose({
             }
         },
         [
-            isConciergeChat,
+            shouldShowConciergeIndicator,
             kickoffWaitingIndicator,
             transactionThreadReport,
             report,

From 1d5e72ed1ada13394c54fea6792cf688b39befb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= <marco@expensify.com>
Date: Tue, 17 Mar 2026 15:28:53 -0600
Subject: [PATCH 2/2] Rename isConciergeChat to isAgentZeroChat and remove
 unnecessary useMemo

Address review feedback:
- Rename isConciergeChat parameter to isAgentZeroChat in useAgentZeroStatusIndicator
  hook since it now supports both Concierge DMs and #admins rooms
- Remove useMemo wrapper for shouldShowConciergeIndicator in ReportActionCompose
  since it's a simple boolean expression that doesn't need memoization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
 src/hooks/useAgentZeroStatusIndicator.ts        | 17 +++++++++--------
 .../ReportActionCompose/ReportActionCompose.tsx |  2 +-
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/hooks/useAgentZeroStatusIndicator.ts b/src/hooks/useAgentZeroStatusIndicator.ts
index c1af11224b11..a99893e64c59 100644
--- a/src/hooks/useAgentZeroStatusIndicator.ts
+++ b/src/hooks/useAgentZeroStatusIndicator.ts
@@ -15,11 +15,12 @@ type AgentZeroStatusState = {
 };
 
 /**
- * Hook to manage AgentZero status indicator for chats where Concierge responds.
+ * Hook to manage AgentZero status indicator for chats where AgentZero responds.
  * This includes both Concierge DM chats and policy #admins rooms (where Concierge handles onboarding).
- * Subscribes to real-time reasoning updates via Pusher and manages processing state.
+ * @param reportID - The report ID to monitor
+ * @param isAgentZeroChat - Whether the chat is an AgentZero-enabled chat (Concierge DM or #admins room)
  */
-function useAgentZeroStatusIndicator(reportID: string, isConciergeChat: boolean): AgentZeroStatusState {
+function useAgentZeroStatusIndicator(reportID: string, isAgentZeroChat: boolean): AgentZeroStatusState {
     const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`);
     const serverLabel = reportNameValuePairs?.agentZeroProcessingRequestIndicator?.trim() ?? '';
 
@@ -53,7 +54,7 @@ function useAgentZeroStatusIndicator(reportID: string, isConciergeChat: boolean)
     }, [reportID]);
 
     useEffect(() => {
-        if (!isConciergeChat) {
+        if (!isAgentZeroChat) {
             return;
         }
 
@@ -64,7 +65,7 @@ function useAgentZeroStatusIndicator(reportID: string, isConciergeChat: boolean)
         return () => {
             unsubscribeFromReportReasoningChannel(reportID);
         };
-    }, [isConciergeChat, reportID]);
+    }, [isAgentZeroChat, reportID]);
 
     useEffect(() => {
         const hadServerLabel = !!prevServerLabelRef.current;
@@ -140,13 +141,13 @@ function useAgentZeroStatusIndicator(reportID: string, isConciergeChat: boolean)
     }, [isOffline]);
 
     const kickoffWaitingIndicator = useCallback(() => {
-        if (!isConciergeChat) {
+        if (!isAgentZeroChat) {
             return;
         }
         setOptimisticStartTime(Date.now());
-    }, [isConciergeChat]);
+    }, [isAgentZeroChat]);
 
-    const isProcessing = isConciergeChat && !isOffline && (!!serverLabel || !!optimisticStartTime);
+    const isProcessing = isAgentZeroChat && !isOffline && (!!serverLabel || !!optimisticStartTime);
 
     return useMemo(
         () => ({
diff --git a/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx
index c6f626f4852a..dbe93d972706 100644
--- a/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx
+++ b/src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx
@@ -223,7 +223,7 @@ function ReportActionCompose({
     const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]);
     const isReportArchived = useReportIsArchived(report?.reportID);
     const isConciergeChat = useMemo(() => isConciergeChatReport(report), [report]);
-    const shouldShowConciergeIndicator = useMemo(() => isConciergeChat || isAdminRoom(report), [isConciergeChat, report]);
+    const shouldShowConciergeIndicator = isConciergeChat || isAdminRoom(report);
 
     const isTransactionThreadView = useMemo(() => isReportTransactionThread(report), [report]);
     const isExpensesReport = useMemo(() => reportTransactions && reportTransactions.length > 1, [reportTransactions]);
