feat(copilot): preserve mothership chat when opening workflow#4521
feat(copilot): preserve mothership chat when opening workflow#4521stylessh wants to merge 4 commits intosimstudioai:stagingfrom
Conversation
Clicking "Open Workflow" from a Mothership task now deep-links the originating chat into the workflow page's copilot panel as read-only history, so users don't lose the conversation that produced the workflow.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview The copilot chat list contract/endpoint now includes optional Reviewed by Cursor Bugbot for commit bc431ff. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR deep-links an originating Mothership chat into the workflow page's copilot panel when "Open Workflow" is clicked, preserving context from the chat that generated the workflow. It threads a
Confidence Score: 4/5Safe to merge — the core deep-link flow is correct and no chat data is at risk; two loading-state edge cases in the panel are cosmetic. The contract, API, filter, and prop-threading changes are all straightforward and correct. The two items flagged are both in apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx — auto-select timing and Important Files Changed
Reviews (1): Last reviewed commit: "feat(copilot): preserve mothership chat ..." | Re-trigger Greptile |
| const isCopilotChatReadOnly = useMemo(() => { | ||
| if (!copilotChatId || !activeWorkflowId) return false | ||
| const chat = copilotChatList.find((c) => c.id === copilotChatId) | ||
| if (!chat) return false | ||
| return chat.workflowId !== activeWorkflowId | ||
| }, [copilotChatId, copilotChatList, activeWorkflowId]) |
There was a problem hiding this comment.
Input footer briefly visible before read-only state resolves
isCopilotChatReadOnly returns false whenever copilotChatId is falsy, which is the case during the window between mount and the first auto-select (i.e., while copilotChatList is still loading). When the page opens with ?chatId=, the copilot tab is activated immediately by chatIdParamHandledRef, but copilotChatId isn't set until the list arrives and the auto-select effect fires. During that gap MothershipChat renders with readOnly={false}, briefly showing the input footer before it disappears once the list loads and copilotChatId is set to the Mothership chat. This could be prevented by initialising copilotChatId directly from urlChatIdParam instead of waiting for the list, or by letting isCopilotChatReadOnly return true optimistically when urlChatIdParam is set and copilotChatId is still unresolved.
There was a problem hiding this comment.
Moot now — the read-only behavior was removed in 6be5374 in favor of full continuation (panel swaps useChat to the Mothership branch when the selected chat is type: 'mothership'). There is no readOnly flicker because there is no readOnly path anymore.
| @@ -278,8 +298,12 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel | |||
| if (autoSelectAttemptedForRef.current.has(activeWorkflowId)) return | |||
| if (copilotChatList.length === 0) return | |||
| autoSelectAttemptedForRef.current.add(activeWorkflowId) | |||
| setCopilotChatId(copilotChatList[0].id) | |||
| }, [copilotChatList, copilotChatId, activeWorkflowId, setCopilotChatId]) | |||
| const preferred = | |||
| urlChatIdParam && copilotChatList.find((c) => c.id === urlChatIdParam) | |||
| ? urlChatIdParam | |||
| : copilotChatList[0].id | |||
| setCopilotChatId(preferred) | |||
| }, [copilotChatList, copilotChatId, activeWorkflowId, setCopilotChatId, urlChatIdParam]) | |||
There was a problem hiding this comment.
autoSelectAttemptedForRef prevents re-honoring ?chatId= after in-session workflow navigation
autoSelectAttemptedForRef is keyed by activeWorkflowId and never cleared. If the user opens the workflow with ?chatId=<mothership_id>, navigates to a different workflow (via the sidebar), then navigates back to the same workflow in the same session, the ref still contains the original activeWorkflowId so the urlChatIdParam is silently ignored on the return visit. The most-recently-used chat is auto-selected instead of the linked Mothership chat. This is a subtle divergence from the intended deep-link behaviour, most likely to appear in SPAs where the component stays mounted across workflow switches.
There was a problem hiding this comment.
Addressed in bc431ff. Replaced the once-per-workflow Set guard for URL-driven selection with a consumedUrlChatIdRef keyed by the chatId value itself: any time urlChatIdParam changes to a value that is in the list, we honor it. Returning to the same workflow with a fresh ?chatId= now re-applies. The auto-select-most-recent guard still runs once per workflow when no URL param is present. Same fix applied to the copilot-tab activation effect.
Switch the workflow-panel useChat options to the Mothership branch when the selected chat has type 'mothership'. Sends from the workflow page then go through the broader Mothership agent surface that originally produced the chat, instead of the workflow-scoped copilot. Removes the read-only fallback since both modes are now continuable; resources spawned during continuation still only render in Mothership.
| * that resources spawned during continuation only show up in the | ||
| * Mothership view; this panel shows the conversation only. | ||
| */ | ||
| const isMothershipChat = selectedCopilotChat?.type === 'mothership' |
There was a problem hiding this comment.
Mothership chat read-only mode never applied to UI
High Severity
isMothershipChat is computed but only used to switch copilotChatOptions between routing branches — it is never used to hide the input footer. MothershipChat has no readOnly prop, and none is passed at the call site in panel.tsx. As a result, users viewing a Mothership chat in the workflow copilot panel will see an active input footer and can submit messages, directly contradicting the PR description's stated behavior ("the input footer is hidden") and the test-plan step "Verify the input footer is hidden (read-only)."
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 6be5374. Configure here.
There was a problem hiding this comment.
Stale flag on this thread. The "input footer is hidden / read-only" wording was from an earlier iteration — this commit (and the PR description) deliberately switched to continuation: the panel swaps useChat to the Mothership branch (getMothershipUseChatOptions, no workflowId in the request) so users can keep talking. isMothershipChat is what drives that swap. No readOnly is intended.
Track the consumed URL chatId per value (not once per session) so returning to a workflow with a fresh `?chatId=` re-applies it instead of being shadowed by the once-per-workflow auto-select guard. Same treatment for the copilot-tab activation effect. Make `type` and `resources` on the chat list contract `.nullable()` to tolerate null jsonb reads from older rows even though the columns are declared NOT NULL with defaults — avoids a Zod parse failure silently emptying the chat list on the client.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bc431ff. Configure here.
| const url = chatId | ||
| ? `/workspace/${workspaceId}/w/${workflowId}?chatId=${encodeURIComponent(chatId)}` | ||
| : `/workspace/${workspaceId}/w/${workflowId}` | ||
| router.push(url) |
There was a problem hiding this comment.
Open Workflow navigates same tab instead of new tab
High Severity
handleOpenWorkflow was changed from window.open(url, '_blank') (opens a new tab) to router.push(url) (same-tab navigation). This means clicking "Open Workflow" from a Mothership task now navigates away from the Mothership view, causing the user to lose their in-progress conversation context. The PR test plan explicitly expects "a new tab opens," confirming this is unintended. The original window.open call just needs the ?chatId= query string appended while keeping '_blank'.
Reviewed by Cursor Bugbot for commit bc431ff. Configure here.


Summary
Clicking Open Workflow from a Mothership task now deep-links the
originating chat into the workflow page's copilot panel, so the
conversation that produced the workflow stays visible — and is fully
continuable.
When the selected chat has
type: 'mothership', the workflow panelswaps its
useChatoptions to the Mothership branch (noworkflowIdin the request), so sends route to the broader Mothership agent that
originally produced the chat instead of the workflow-scoped copilot.
Resources created during continuation still only render in Mothership;
the workflow panel shows the conversation only.
Changes
lib/api/contracts/copilot.ts):copilotChatListItemSchemanow exposes optional
type('mothership' | 'copilot') andresourcesso the client can identify mothership chats and chatsthat reference a workflow via
resourceseven whenchat.workflowIdis null./api/copilot/chats): selectstypeandresourcesfromthe existing columns.
hooks/queries/copilot-chats.ts):useCopilotChats(workflowId)now also includes chats whoseresourcescontain a{ type: 'workflow', id }matching theworkflow.
resource-content.tsx): appends?chatId=<currentChat>to the URL.chatIdis threaded throughMothershipView→ResourceActions→EmbeddedWorkflowActions.panel.tsx):?chatId=from the URL, prefers it over the most-recentauto-select on first list arrival, and switches the panel to the
copilot tab on first mount when the param is present.
isMothershipChatfromselectedChat.typeand swaps theuseChatoptions betweengetMothershipUseChatOptionsandgetWorkflowCopilotUseChatOptionsaccordingly.Known limitation
Resources (workflows, files, tables) spawned by the agent during
continuation from the workflow panel are persisted on the chat row but
not rendered in the workflow panel — that side panel only exists in
the Mothership view. Users see the conversation; to inspect or
interact with new resources, they go back to Mothership.
Test plan
the
Open Workflowbutton to appear in the resource panel.?chatId=<id>in the URL and the copilot panel is open with theoriginal conversation visible.
response uses the Mothership agent (broader tools, can still
create new resources) — and that a network request to
/api/mothership/chatgoes out withoutworkflowIdin thebody.
regular workflow-copilot chat — sends include
workflowId.dropdown — sends drop
workflowIdagain.?chatId=param, behavior isunchanged: most recent workflow chat auto-selects.
?chatId=<unknown>: falls through to the most-recentauto-select gracefully.