Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,6 @@ export function useChat(
chatIdRef.current = undefined
setResolvedChatId(undefined)
appliedChatIdRef.current = undefined
abortControllerRef.current?.abort()
abortControllerRef.current = null
sendingRef.current = false
setMessages([])
Expand All @@ -445,7 +444,26 @@ export function useChat(

appliedChatIdRef.current = chatHistory.id
const mappedMessages = chatHistory.messages.map(mapStoredMessage)
setMessages(mappedMessages)
const shouldPreserveActiveStreamingMessage =
sendingRef.current && Boolean(activeStreamId) && activeStreamId === streamIdRef.current

if (shouldPreserveActiveStreamingMessage) {
setMessages((prev) => {
const localStreamingAssistant = prev[prev.length - 1]
if (localStreamingAssistant?.role !== 'assistant') {
return mappedMessages
}

const nextMessages =
mappedMessages[mappedMessages.length - 1]?.role === 'assistant'
? mappedMessages.slice(0, -1)
: mappedMessages

return [...nextMessages, localStreamingAssistant]
})
} else {
setMessages(mappedMessages)
}

if (chatHistory.resources.some((r) => r.id === 'streaming-file')) {
fetch('/api/copilot/chat/resources', {
Expand Down Expand Up @@ -1467,7 +1485,6 @@ export function useChat(
return () => {
streamReaderRef.current?.cancel().catch(() => {})
streamReaderRef.current = null
abortControllerRef.current?.abort()
abortControllerRef.current = null
streamGenRef.current++
sendingRef.current = false
Expand Down
1 change: 0 additions & 1 deletion apps/sim/lib/copilot/chat-streaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ export function createSSEStream(params: StreamingOrchestrationParams): ReadableS
},
cancel() {
clientDisconnected = true
abortController.abort()
if (eventWriter) {
eventWriter.flush().catch(() => {})
}
Expand Down
19 changes: 14 additions & 5 deletions apps/sim/lib/workflows/diff/diff-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,12 +505,21 @@ export class WorkflowDiffEngine {
try {
const baselineBlockIds = new Set(Object.keys(mergedBaseline.blocks))

// Identify blocks that need positioning: genuinely new blocks AND
// blocks inserted into subflows (position reset to 0,0). Extracted
// blocks are excluded — the server computes valid absolute positions
// from the container offset, so they don't need repositioning.
// Identify blocks that need positioning: genuinely new blocks that
// don't have valid positions yet. Blocks already positioned by a
// previous server-side layout (non-origin position) are skipped to
// avoid redundant client-side re-layout that can shift blocks when
// block metrics change between edits (e.g. condition handle offsets).
const blocksNeedingLayout = Object.keys(finalBlocks).filter((id) => {
if (!baselineBlockIds.has(id)) return true
if (!baselineBlockIds.has(id)) {
const pos = finalBlocks[id]?.position
const hasValidPosition =
pos &&
Number.isFinite(pos.x) &&
Number.isFinite(pos.y) &&
!(pos.x === 0 && pos.y === 0)
return !hasValidPosition
}
const baselineParent = mergedBaseline.blocks[id]?.data?.parentId ?? null
const proposedParent = finalBlocks[id]?.data?.parentId ?? null
if (baselineParent === proposedParent) return false
Expand Down
Loading