Skip to content

Open the agent DM via an optimistic reportID instead of guessing its identity#95631

Draft
mjasikowski wants to merge 5 commits into
mainfrom
agent-dm-optimistic-reportid
Draft

Open the agent DM via an optimistic reportID instead of guessing its identity#95631
mjasikowski wants to merge 5 commits into
mainfrom
agent-dm-optimistic-reportid

Conversation

@mjasikowski

Copy link
Copy Markdown
Contributor

Explanation of Change

Replaces the "poll and diff the agent-prompt collection" approach for opening the DM with a newly created agent with proper optimistic-report reconciliation, following up on review feedback on #95482.

createAgent now generates the owner<->agent DM's reportID client-side - the same way any other new chat's reportID is generated - and writes the DM report to Onyx optimistically (via buildOptimisticChatReport), alongside the existing optimistic agent personal detail / prompt writes. That reportID is sent to CREATE_AGENT, and the backend (Expensify/Auth#22772, Expensify/Web-Expensify#54367) creates the DM under that exact ID.

AddAgentPage navigates to the returned optimisticReportID immediately after submitting, online or offline, with no waiting, no submit spinner, and no polling hook. This removes the whole class of bugs surfaced during review of #95482 (cold-hydration baseline, concurrent-agent-creation mismatch, batched-response-before-baseline race) - none of them apply once identity is carried via a client-generated reportID instead of reconstructed via collection diffing.

Depends on (must merge/deploy first, though this PR is safe to review in parallel):

Fixed Issues

$
PROPOSAL:

Tests

  1. Create a new agent (Settings > Agents > Create Agent)
  2. Verify you're taken directly to a DM with the new agent, immediately after tapping "Create"
  3. Verify the DM shows the agent's welcome message once it arrives
  4. Repeat with an avatar image and with a policy selected
  • Verify that no errors appear in the JS console

Offline tests

  1. Turn off your network connection
  2. Create a new agent
  3. Verify you're taken directly to the (offline) DM immediately, exactly as when online
  4. Reconnect and verify the DM reconciles normally (welcome message appears, no duplicate/broken reports)

QA Steps

Same as Tests. Requires the two backend PRs above to be deployed to staging/production first.

  • 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 added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.

Note: this is a draft. Manual/device QA is pending until the dependent Auth and Web-Expensify PRs are deployed, since CREATE_AGENT needs to understand the reportID param for the DM to actually reconcile end-to-end.

Screenshots/Videos

Pending backend PRs.

…identity

Generate the owner<->agent DM's reportID client-side, the same way any
other new chat's reportID is generated, and write the DM to Onyx
optimistically alongside the agent itself. CreateAgent (see
Expensify/Auth#22772 and Expensify/Web-Expensify#54367) creates the DM
under that exact reportID, so the client can navigate to it immediately
after submitting, online or offline, without waiting for the response
or reconstructing the agent's identity from Onyx collection diffs.

This replaces the previous approach of polling the agent-prompt
collection to detect the newly created agent, which produced multiple
race-condition bugs across review rounds.
dismissModal() and the delayed navigate() were scheduled independently via
setTimeout + isNavigationReady(), which only checks the nav ref exists and
doesn't wait for the dismiss transition to settle. Under load (e.g. creating
several agents in quick succession) the dismissal's own delayed navigation
could land after our navigate() and send the user back to the previous
screen instead of the report they just opened.

Sequence the navigate through dismissModal's afterTransition callback
instead, matching the existing dismissModalWithReport pattern.
getDisplayNameForParticipant short-circuited to the formatted login for
any optimistic personal detail, on the assumption that a login is the only
thing known about it (true for invite-by-email flows). Agent creation is
different: the display name the user chose is already known, but login is
intentionally omitted (it's server-assigned), so the DM title resolved to
an empty string.

Since CREATE_AGENT's response usually lands within a second online, this
was an imperceptible flicker there, but offline the write stays queued
indefinitely and the blank title persists.

Only take the login-based shortcut when no display name is already known,
which existing optimistic-personal-detail callers already set to the same
value as the login anyway, so their behavior is unchanged.
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
src/libs/ReportUtils.ts 86.92% <100.00%> (+0.01%) ⬆️
src/libs/actions/Agent.ts 81.15% <100.00%> (+0.85%) ⬆️
src/pages/settings/Agents/AddAgentPage.tsx 86.44% <100.00%> (ø)
... and 137 files with indirect coverage changes

Matches the Auth/Web-Expensify rename: CreateAgent's primary subject is the
agent account, not a report, so the owner<->agent DM's client-supplied ID
follows the optimisticReportID naming SharePolicy and
MoveIOUReportToExistingPolicy already use for the same kind of auxiliary,
side-effect report ID.
dismissModalWithReport is the established pattern for "dismiss the modal and
open a report" (used by WorkspaceNewRoomPage, NewChatPage, Split, TeachersUnite,
etc.) and already sequences the navigate through dismissModal's afterTransition
correctly, so it isn't affected by the race that motivated exporting and
patching navigateToReport. That patch is no longer needed, so revert
navigateToReport back to its prior implementation and drop its export.
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.

1 participant