Skip to content

Commit f2fcfe7

Browse files
committed
Bad hook
1 parent b49d67e commit f2fcfe7

File tree

28 files changed

+801
-177
lines changed

28 files changed

+801
-177
lines changed

apps/sim/app/api/copilot/chat/abort/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ export async function POST(request: Request) {
4949
headers['x-api-key'] = env.COPILOT_API_KEY
5050
}
5151
const controller = new AbortController()
52-
const timeout = setTimeout(() => controller.abort(), GO_EXPLICIT_ABORT_TIMEOUT_MS)
52+
const timeout = setTimeout(
53+
() => controller.abort('timeout:go_explicit_abort_fetch'),
54+
GO_EXPLICIT_ABORT_TIMEOUT_MS
55+
)
5356
const response = await fetch(`${SIM_AGENT_API_URL}/api/streams/explicit-abort`, {
5457
method: 'POST',
5558
headers,

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,7 @@ function TextEditor({
388388
)
389389

390390
const isStreaming = streamingContent !== undefined
391-
const shouldAnimateStreaming = isStreaming && streamingMode === 'append'
392-
const revealedContent = useStreamingText(content, shouldAnimateStreaming)
391+
const revealedContent = useStreamingText(content, false)
393392

394393
const textareaStuckRef = useRef(true)
395394

apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { forwardRef, memo, useCallback, useState } from 'react'
3+
import { forwardRef, memo, useCallback, useEffect, useState } from 'react'
44
import { cn } from '@/lib/core/utils/cn'
55
import { getFileExtension } from '@/lib/uploads/utils/file-utils'
66
import type { PreviewMode } from '@/app/workspace/[workspaceId]/files/components/file-viewer'
@@ -101,11 +101,12 @@ export const MothershipView = memo(
101101
const [prevActiveId, setPrevActiveId] = useState<string | null | undefined>(active?.id)
102102
const handleCyclePreview = useCallback(() => setPreviewMode((m) => PREVIEW_CYCLE[m]), [])
103103

104-
// Reset preview mode to default when the active resource changes (guarded render-phase update)
105-
if (active?.id !== prevActiveId) {
106-
setPrevActiveId(active?.id)
107-
setPreviewMode('preview')
108-
}
104+
useEffect(() => {
105+
if (active?.id !== prevActiveId) {
106+
setPrevActiveId(active?.id)
107+
setPreviewMode('preview')
108+
}
109+
}, [active?.id, prevActiveId])
109110

110111
const isActivePreviewable =
111112
canEdit &&

apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -755,9 +755,15 @@ export function useChat(
755755
const lines = buffer.split('\n')
756756
buffer = lines.pop() || ''
757757
pendingLines.push(...lines)
758+
if (pendingLines.length === 0) {
759+
continue
760+
}
758761
}
759762

760-
const line = pendingLines.shift()!
763+
const line = pendingLines.shift()
764+
if (line === undefined) {
765+
continue
766+
}
761767
if (isStale()) {
762768
pendingLines.length = 0
763769
continue
@@ -893,9 +899,18 @@ export function useChat(
893899
const nextSession: StreamingFilePreview = {
894900
...prevSession,
895901
toolCallId: id,
902+
...(typeof payload.operation === 'string'
903+
? { operation: payload.operation }
904+
: {}),
905+
...(typeof payload.fileId === 'string'
906+
? { fileId: payload.fileId, targetKind: 'file_id' as const }
907+
: {}),
896908
}
897909
sessions.set(id, nextSession)
898910
activeFilePreviewToolCallIdRef.current = id
911+
if (nextSession.fileId) {
912+
setActiveResourceId(nextSession.fileId)
913+
}
899914
setStreamingFile(nextSession)
900915
break
901916
}
@@ -958,9 +973,18 @@ export function useChat(
958973

959974
if (previewPhase === 'file_preview_content') {
960975
const content = typeof payload.content === 'string' ? payload.content : ''
961-
const isAppendOp = prevSession.operation === 'append'
962-
const prevContent = streamingFileRef.current?.content ?? ''
963-
const nextContent = isAppendOp ? prevContent + content : content
976+
const contentMode =
977+
typeof payload.contentMode === 'string' ? payload.contentMode : undefined
978+
let nextContent: string
979+
if (contentMode === 'snapshot') {
980+
nextContent = content
981+
} else if (contentMode === 'delta') {
982+
nextContent = (prevSession.content ?? '') + content
983+
} else {
984+
const isAppendOp = prevSession.operation === 'append'
985+
const prevContent = streamingFileRef.current?.content ?? ''
986+
nextContent = isAppendOp ? prevContent + content : content
987+
}
964988
const nextSession: StreamingFilePreview = {
965989
...prevSession,
966990
content: nextContent,
@@ -971,6 +995,34 @@ export function useChat(
971995
setStreamingFile(nextSession)
972996
break
973997
}
998+
999+
if (previewPhase === 'file_preview_complete') {
1000+
const fileId =
1001+
typeof payload.fileId === 'string' ? payload.fileId : prevSession.fileId
1002+
const resultData = asPayloadRecord(payload.data)
1003+
sessions.delete(id)
1004+
activeFilePreviewToolCallIdRef.current = null
1005+
1006+
if (fileId && resultData?.id) {
1007+
const fileName = (resultData.name as string) ?? prevSession.fileName ?? 'File'
1008+
const fileResource = { type: 'file' as const, id: fileId, title: fileName }
1009+
setResources((rs) => {
1010+
const without = rs.filter((r) => r.id !== 'streaming-file')
1011+
if (without.some((r) => r.type === 'file' && r.id === fileResource.id)) {
1012+
return without
1013+
}
1014+
return [...without, fileResource]
1015+
})
1016+
setActiveResourceId(fileId)
1017+
invalidateResourceQueries(queryClient, workspaceId, 'file', fileId)
1018+
}
1019+
1020+
if (!activeSubagent || activeSubagent !== FileTool.id) {
1021+
setStreamingFile(null)
1022+
streamingFileRef.current = null
1023+
}
1024+
break
1025+
}
9741026
}
9751027

9761028
if (phase === MothershipStreamV1ToolPhase.args_delta) {
@@ -1327,7 +1379,7 @@ export function useChat(
13271379
if (!isSameActiveSubagent) {
13281380
blocks.push({ type: 'subagent', content: name })
13291381
}
1330-
if (name === FileTool.id) {
1382+
if (name === FileTool.id && !isSameActiveSubagent) {
13311383
const emptyFile: StreamingFilePreview = {
13321384
toolCallId: parentToolCallId || 'file-preview',
13331385
fileName: '',
@@ -1937,7 +1989,7 @@ export function useChat(
19371989
streamGenRef.current++
19381990
streamReaderRef.current?.cancel().catch(() => {})
19391991
streamReaderRef.current = null
1940-
abortControllerRef.current?.abort()
1992+
abortControllerRef.current?.abort('user_stop:client_stopGeneration')
19411993
abortControllerRef.current = null
19421994
sendingRef.current = false
19431995
setIsSending(false)

apps/sim/hooks/use-streaming-reveal.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,15 @@ interface StreamingRevealResult {
5353
* by DOM restructuring. It only resets when content clears (new message).
5454
*/
5555
export function useStreamingReveal(content: string, isStreaming: boolean): StreamingRevealResult {
56-
const [committedEnd, setCommittedEnd] = useState(0)
57-
const [generation, setGeneration] = useState(0)
56+
const [revealState, setRevealState] = useState({ committedEnd: 0, generation: 0 })
5857
const prevSplitRef = useRef(0)
5958

6059
useEffect(() => {
6160
if (content.length === 0) {
6261
prevSplitRef.current = 0
63-
setCommittedEnd(0)
62+
setRevealState((prev) =>
63+
prev.committedEnd === 0 && prev.generation === 0 ? prev : { committedEnd: 0, generation: 0 }
64+
)
6465
return
6566
}
6667

@@ -69,11 +70,16 @@ export function useStreamingReveal(content: string, isStreaming: boolean): Strea
6970
const splitPoint = findSafeSplitPoint(content)
7071
if (splitPoint > prevSplitRef.current) {
7172
prevSplitRef.current = splitPoint
72-
setCommittedEnd(splitPoint)
73-
setGeneration((g) => g + 1)
73+
setRevealState((prev) =>
74+
prev.committedEnd === splitPoint
75+
? prev
76+
: { committedEnd: splitPoint, generation: prev.generation + 1 }
77+
)
7478
}
7579
}, [content, isStreaming])
7680

81+
const { committedEnd, generation } = revealState
82+
7783
if (!isStreaming) {
7884
const preservedSplit = prevSplitRef.current
7985

apps/sim/lib/copilot/chat/persisted-message.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ interface RawBlock {
221221
type: string
222222
lane?: string
223223
content?: string
224+
/** Go persists text blocks with key "text" instead of "content" */
225+
text?: string
224226
channel?: string
225227
phase?: string
226228
kind?: string
@@ -275,7 +277,8 @@ function normalizeCanonicalBlock(block: RawBlock): PersistedContentBlock {
275277
if (block.lane === 'main' || block.lane === 'subagent') {
276278
result.lane = block.lane
277279
}
278-
if (block.content !== undefined) result.content = block.content
280+
const blockContent = block.content ?? block.text
281+
if (blockContent !== undefined) result.content = blockContent
279282
if (block.channel) result.channel = block.channel as MothershipStreamV1TextChannel
280283
if (block.phase) result.phase = block.phase as MothershipStreamV1ToolPhase
281284
if (block.kind) result.kind = block.kind as MothershipStreamV1SpanPayloadKind
@@ -364,7 +367,7 @@ function normalizeLegacyBlock(block: RawBlock): PersistedContentBlock {
364367
return {
365368
type: MothershipStreamV1EventType.text,
366369
channel: MothershipStreamV1TextChannel.assistant,
367-
content: block.content,
370+
content: block.content ?? block.text,
368371
}
369372
}
370373

0 commit comments

Comments
 (0)