Skip to content

Commit 578fc50

Browse files
authored
fix(mothership): stop persisting log resources from get_workflow_logs and self-heal stale log panel entries (#4424)
* fix(mothership): stop persisting log resources from get_workflow_logs and self-heal stale log panel entries * fix(mothership): skip retries on 404 in useLogDetail for instant self-heal * fix(mothership): simplify onNotFoundRef sync to inline assignment
1 parent 3af6c25 commit 578fc50

5 files changed

Lines changed: 39 additions & 19 deletions

File tree

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

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

3-
import { lazy, memo, Suspense, useEffect, useMemo } from 'react'
3+
import { lazy, memo, Suspense, useEffect, useMemo, useRef } from 'react'
44
import { createLogger } from '@sim/logger'
55
import { Square } from 'lucide-react'
66
import { useRouter } from 'next/navigation'
@@ -13,6 +13,7 @@ import {
1313
SquareArrowUpRight,
1414
WorkflowX,
1515
} from '@/components/emcn/icons'
16+
import { isApiClientError } from '@/lib/api/client/errors'
1617
import type { FilePreviewSession } from '@/lib/copilot/request/session'
1718
import {
1819
cancelRunToolExecution,
@@ -70,6 +71,7 @@ interface ResourceContentProps {
7071
previewSession?: FilePreviewSession | null
7172
genericResourceData?: GenericResourceData
7273
previewContextKey?: string
74+
onNotFound?: (resourceId: string) => void
7375
}
7476

7577
/**
@@ -86,6 +88,7 @@ export const ResourceContent = memo(function ResourceContent({
8688
previewSession,
8789
genericResourceData,
8890
previewContextKey,
91+
onNotFound,
8992
}: ResourceContentProps) {
9093
const streamFileName = previewSession?.fileName || 'file.md'
9194
const syntheticFile = useMemo(() => {
@@ -179,7 +182,13 @@ export const ResourceContent = memo(function ResourceContent({
179182
return <EmbeddedFolder key={resource.id} workspaceId={workspaceId} folderId={resource.id} />
180183

181184
case 'log':
182-
return <EmbeddedLog key={resource.id} logId={resource.id} />
185+
return (
186+
<EmbeddedLog
187+
key={resource.id}
188+
logId={resource.id}
189+
onNotFound={onNotFound ? () => onNotFound(resource.id) : undefined}
190+
/>
191+
)
183192

184193
case 'generic':
185194
return (
@@ -618,10 +627,20 @@ function EmbeddedFolder({ workspaceId, folderId }: EmbeddedFolderProps) {
618627

619628
interface EmbeddedLogProps {
620629
logId: string
630+
onNotFound?: () => void
621631
}
622632

623-
function EmbeddedLog({ logId }: EmbeddedLogProps) {
624-
const { data: log, isLoading } = useLogDetail(logId)
633+
function EmbeddedLog({ logId, onNotFound }: EmbeddedLogProps) {
634+
const { data: log, isLoading, error } = useLogDetail(logId)
635+
636+
const onNotFoundRef = useRef(onNotFound)
637+
onNotFoundRef.current = onNotFound
638+
639+
useEffect(() => {
640+
if (isApiClientError(error) && error.status === 404) {
641+
onNotFoundRef.current?.()
642+
}
643+
}, [error])
625644

626645
if (isLoading) return LOADING_SKELETON
627646

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export const MothershipView = memo(
128128
previewSession={previewForActive}
129129
genericResourceData={active.type === 'generic' ? genericResourceData : undefined}
130130
previewContextKey={chatId}
131+
onNotFound={(resourceId) => onRemoveResource('log', resourceId)}
131132
/>
132133
) : (
133134
<div className='flex h-full items-center justify-center text-[var(--text-muted)] text-sm'>

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,18 @@ export function useChat(
14201420
const removeResource = useCallback((resourceType: MothershipResourceType, resourceId: string) => {
14211421
setResources((prev) => prev.filter((r) => !(r.type === resourceType && r.id === resourceId)))
14221422
setActiveResourceId((prev) => (prev === resourceId ? null : prev))
1423+
1424+
const persistChatId = chatIdRef.current ?? selectedChatIdRef.current
1425+
if (persistChatId) {
1426+
// boundary-raw-fetch: fire-and-forget side-effect; intentionally avoids requestJson's response parsing/throw semantics so a transient failure cannot interrupt the caller
1427+
fetch('/api/mothership/chat/resources', {
1428+
method: 'DELETE',
1429+
headers: { 'Content-Type': 'application/json' },
1430+
body: JSON.stringify({ chatId: persistChatId, resourceType, resourceId }),
1431+
}).catch((err) => {
1432+
logger.warn('Failed to persist resource removal', err)
1433+
})
1434+
}
14231435
}, [])
14241436

14251437
const reorderResources = useCallback((newOrder: MothershipResource[]) => {

apps/sim/hooks/queries/logs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
useQuery,
88
useQueryClient,
99
} from '@tanstack/react-query'
10+
import { isApiClientError } from '@/lib/api/client/errors'
1011
import { requestJson } from '@/lib/api/client/request'
1112
import {
1213
cancelWorkflowExecutionContract,
@@ -194,6 +195,8 @@ export function useLogDetail(logId: string | undefined, options?: UseLogDetailOp
194195
enabled: Boolean(logId) && (options?.enabled ?? true),
195196
refetchInterval: options?.refetchInterval ?? false,
196197
staleTime: 30 * 1000,
198+
retry: (failureCount, err) =>
199+
!(isApiClientError(err) && err.status === 404) && failureCount < 3,
197200
})
198201
}
199202

apps/sim/lib/copilot/resources/extraction.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
FunctionExecute,
88
GenerateImage,
99
GenerateVisualization,
10-
GetWorkflowLogs,
1110
Knowledge,
1211
KnowledgeBase,
1312
UserTable,
@@ -30,7 +29,6 @@ const RESOURCE_TOOL_NAMES: Set<string> = new Set([
3029
Knowledge.id,
3130
GenerateVisualization.id,
3231
GenerateImage.id,
33-
GetWorkflowLogs.id,
3432
])
3533

3634
export function isResourceToolName(toolName: string): boolean {
@@ -214,19 +212,6 @@ export function extractResourcesFromToolResult(
214212
return resources
215213
}
216214

217-
case GetWorkflowLogs.id: {
218-
const entries = Array.isArray(output) ? output : Array.isArray(result.data) ? result.data : []
219-
const resources: ChatResource[] = []
220-
for (const entry of entries) {
221-
const rec = asRecord(entry)
222-
const logId = rec.id as string | undefined
223-
if (logId) {
224-
resources.push({ type: 'log', id: logId, title: 'Log' })
225-
}
226-
}
227-
return resources
228-
}
229-
230215
default:
231216
return []
232217
}

0 commit comments

Comments
 (0)