Skip to content

fix(mothership): persist @-mentioned resources across send#4587

Merged
waleedlatif1 merged 3 commits into
stagingfrom
waleedlatif1/mship-at-resource-tab
May 14, 2026
Merged

fix(mothership): persist @-mentioned resources across send#4587
waleedlatif1 merged 3 commits into
stagingfrom
waleedlatif1/mship-at-resource-tab

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • @-mentioned resources opened a tab on the right but disappeared on send — local state was wiped by hydration because pre-chat additions never reached the server
  • Switched to local-first + merge-on-hydrate: resources added before chat creation queue into a pending set, flush on first chat-id assignment, retry on next hydration
  • Hydration now merges server ∪ local instead of replacing — optimistic items survive any refetch
  • Reorder now actually persists (PATCH)
  • Migrated 6 raw fetches in this file to requestJson(contract, ...) for type-safe request shapes; remaining raw fetches kept for SSE streaming + traceparent header propagation

Type of Change

  • Bug fix

Testing

Tested manually. bun run check:api-validation passes; tsc --noEmit clean.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel Bot commented May 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 14, 2026 1:28am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 14, 2026

PR Summary

Medium Risk
Adjusts client-side resource persistence and hydration semantics in useChat, which could affect resource ordering and add/remove consistency across refreshes and in-flight requests. Failures are handled with retries, but edge cases in queued/in-flight state tracking could still cause dropped or duplicated resource operations.

Overview
Fixes a bug where resources (e.g., @-mentioned items) added before a chat had an ID could disappear after send by queueing local resource adds, flushing them once a chatId is known, and retrying failed persists on subsequent hydrations.

Changes hydration to merge server resources with any local-only resources (instead of replacing), and adds logic to persist resource reorders (and defer reorder persistence until pending/in-flight adds settle). Also migrates several fire-and-forget fetch calls for resource add/remove/reorder and workflow execution cancel to requestJson + typed contracts for consistent request shapes.

Reviewed by Cursor Bugbot for commit f48fa3a. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 14, 2026

Greptile Summary

This PR fixes @-mentioned resources disappearing after send by introducing a local-first, merge-on-hydrate approach. Resources added before a chat ID exists are queued in pendingPersistResourceKeysRef, flushed the moment a chat ID is assigned, and hydration now merges server ∪ local instead of replacing local state.

  • Local-first persistence: addResource queues to a pending set when no chat ID exists; flushPendingResources drains the set on first chat-ID assignment, with retry-on-hydration for failures.
  • Race condition handling: inFlightResourceAddsRef tracks in-flight ADD requests so removeResource chains a DELETE after the ADD settles, preventing orphaned server rows.
  • Reorder persistence: reorderResources now PATCHes the server with reorderNeededAfterFlushRef deferring the PATCH until in-flight ADDs complete; 6 raw fetch calls migrated to type-safe requestJson.

Confidence Score: 5/5

Safe to merge; the core persistence, race-condition, and reorder bugs are all correctly addressed.

All three key scenarios — pre-chat resource queueing, ADD/DELETE ordering via in-flight tracking, and deferred reorder PATCHing — are handled correctly. The one ordering edge case only affects sort order during a narrow timing window and self-corrects on next hydration.

No files require special attention; the change is self-contained in use-chat.ts.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts Adds pending-queue + in-flight tracking for resource persistence, merge-on-hydrate logic, reorder persistence via PATCH, and migrates 6 raw fetches to requestJson. Previous race conditions addressed; one narrow ordering edge case noted.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant H as useChat (hook)
    participant S as Server

    Note over U,H: Before first send (no chatId)
    U->>H: addResource(A)
    H->>H: pendingPersistResourceKeysRef.add(type:A)

    U->>H: reorderResources([A, B])
    H->>H: "reorderNeededAfterFlushRef = true"

    U->>H: sendMessage()
    H->>S: POST /chat
    S-->>H: chatId assigned
    H->>H: "adoptResolvedChatId -> flushPendingResources(chatId)"

    loop each pending resource
        H->>S: POST addResource(chatId, A)
        S-->>H: 200 OK
    end

    H->>H: "reorderNeededAfterFlushRef=true -> fire PATCH"
    H->>S: PATCH reorderResources(chatId, [A,B])

    Note over U,H: Remove resource with in-flight ADD
    U->>H: addResource(C) in-flight
    U->>H: removeResource(C)
    H->>H: inFlightAdd.finally(fireDelete)
    S-->>H: ADD resolves
    H->>S: DELETE removeResource(chatId, C)

    Note over U,H: Hydration merge
    S-->>H: "chatHistory.resources=[A,B]"
    H->>H: "localOnly = resourcesRef minus serverKeys"
    H->>H: setResources([...server,...localOnly])
Loading

Reviews (3): Last reviewed commit: "fix(mship-resources): defer reorder when..." | Re-trigger Greptile

Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
…ng flush

- Track in-flight ADD promises so DELETE chains off finally(), preventing orphaned server rows when a user removes a resource before its POST resolves
- Defer reorder PATCH until pending flush completes; emit with full local order
- Clear new refs in reset paths
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
…ng chat

reorderResources previously only checked pendingPersistResourceKeysRef. When a
chatId exists, addResource fires the POST immediately and only tracks the
promise in inFlightResourceAddsRef — so a reorder before those ADDs settle
shipped a PATCH the server rejected, and the silent catch lost the reorder.

Now treat in-flight ADDs like pending ones: defer the PATCH and replay it
after Promise.allSettled on the in-flight map.
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f48fa3a. Configure here.

@waleedlatif1 waleedlatif1 merged commit 1c111ff into staging May 14, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/mship-at-resource-tab branch May 14, 2026 01:47
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