Skip to content

Commit bc431ff

Browse files
committed
fix(copilot): re-honor ?chatId= on revisits, tolerate null jsonb
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.
1 parent e8a692e commit bc431ff

2 files changed

Lines changed: 24 additions & 11 deletions

File tree

  • apps/sim
    • app/workspace/[workspaceId]/w/[workflowId]/components/panel
    • lib/api/contracts

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,11 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel
285285
// chat was deleted in another tab). When a `?chatId=` param is present in
286286
// the URL (e.g. after clicking "Open Workflow" from a Mothership task),
287287
// prefer that chat over the most recent so the original conversation is
288-
// shown right away.
288+
// shown right away. The URL param is honored once per distinct value so
289+
// returning to a workflow with a fresh `?chatId=` re-applies it instead of
290+
// being shadowed by the once-per-workflow auto-select guard.
289291
const autoSelectAttemptedForRef = useRef<Set<string>>(new Set())
292+
const consumedUrlChatIdRef = useRef<string | null>(null)
290293
useEffect(() => {
291294
if (!activeWorkflowId) return
292295

@@ -295,15 +298,22 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel
295298
return
296299
}
297300

301+
if (
302+
urlChatIdParam &&
303+
consumedUrlChatIdRef.current !== urlChatIdParam &&
304+
copilotChatList.find((c) => c.id === urlChatIdParam)
305+
) {
306+
consumedUrlChatIdRef.current = urlChatIdParam
307+
autoSelectAttemptedForRef.current.add(activeWorkflowId)
308+
setCopilotChatId(urlChatIdParam)
309+
return
310+
}
311+
298312
if (copilotChatId) return
299313
if (autoSelectAttemptedForRef.current.has(activeWorkflowId)) return
300314
if (copilotChatList.length === 0) return
301315
autoSelectAttemptedForRef.current.add(activeWorkflowId)
302-
const preferred =
303-
urlChatIdParam && copilotChatList.find((c) => c.id === urlChatIdParam)
304-
? urlChatIdParam
305-
: copilotChatList[0].id
306-
setCopilotChatId(preferred)
316+
setCopilotChatId(copilotChatList[0].id)
307317
}, [copilotChatList, copilotChatId, activeWorkflowId, setCopilotChatId, urlChatIdParam])
308318

309319
useEffect(() => {
@@ -490,11 +500,14 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel
490500
/**
491501
* If the workflow page was opened with `?chatId=`, surface the copilot
492502
* tab so the linked conversation is visible without an extra click.
503+
* Re-applies whenever the param changes so returning to a workflow with
504+
* a fresh `?chatId=` switches the tab again.
493505
*/
494-
const chatIdParamHandledRef = useRef(false)
506+
const handledTabSwitchForChatIdRef = useRef<string | null>(null)
495507
useEffect(() => {
496-
if (chatIdParamHandledRef.current || !urlChatIdParam) return
497-
chatIdParamHandledRef.current = true
508+
if (!urlChatIdParam) return
509+
if (handledTabSwitchForChatIdRef.current === urlChatIdParam) return
510+
handledTabSwitchForChatIdRef.current = urlChatIdParam
498511
setActiveTab('copilot')
499512
}, [urlChatIdParam, setActiveTab])
500513

apps/sim/lib/api/contracts/copilot.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,8 @@ export const copilotChatListItemSchema = z.object({
307307
workspaceId: z.string().nullable().optional(),
308308
activeStreamId: z.string().nullable(),
309309
updatedAt: z.string().nullable(),
310-
type: z.enum(['mothership', 'copilot']).optional(),
311-
resources: z.array(copilotChatResourceSchema).optional(),
310+
type: z.enum(['mothership', 'copilot']).nullable().optional(),
311+
resources: z.array(copilotChatResourceSchema).nullable().optional(),
312312
})
313313
export type CopilotChatListItem = z.output<typeof copilotChatListItemSchema>
314314

0 commit comments

Comments
 (0)