mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
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
This commit is contained in:
+23
-4
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { lazy, memo, Suspense, useEffect, useMemo } from 'react'
|
||||
import { lazy, memo, Suspense, useEffect, useMemo, useRef } from 'react'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { Square } from 'lucide-react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
SquareArrowUpRight,
|
||||
WorkflowX,
|
||||
} from '@/components/emcn/icons'
|
||||
import { isApiClientError } from '@/lib/api/client/errors'
|
||||
import type { FilePreviewSession } from '@/lib/copilot/request/session'
|
||||
import {
|
||||
cancelRunToolExecution,
|
||||
@@ -70,6 +71,7 @@ interface ResourceContentProps {
|
||||
previewSession?: FilePreviewSession | null
|
||||
genericResourceData?: GenericResourceData
|
||||
previewContextKey?: string
|
||||
onNotFound?: (resourceId: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,6 +88,7 @@ export const ResourceContent = memo(function ResourceContent({
|
||||
previewSession,
|
||||
genericResourceData,
|
||||
previewContextKey,
|
||||
onNotFound,
|
||||
}: ResourceContentProps) {
|
||||
const streamFileName = previewSession?.fileName || 'file.md'
|
||||
const syntheticFile = useMemo(() => {
|
||||
@@ -179,7 +182,13 @@ export const ResourceContent = memo(function ResourceContent({
|
||||
return <EmbeddedFolder key={resource.id} workspaceId={workspaceId} folderId={resource.id} />
|
||||
|
||||
case 'log':
|
||||
return <EmbeddedLog key={resource.id} logId={resource.id} />
|
||||
return (
|
||||
<EmbeddedLog
|
||||
key={resource.id}
|
||||
logId={resource.id}
|
||||
onNotFound={onNotFound ? () => onNotFound(resource.id) : undefined}
|
||||
/>
|
||||
)
|
||||
|
||||
case 'generic':
|
||||
return (
|
||||
@@ -618,10 +627,20 @@ function EmbeddedFolder({ workspaceId, folderId }: EmbeddedFolderProps) {
|
||||
|
||||
interface EmbeddedLogProps {
|
||||
logId: string
|
||||
onNotFound?: () => void
|
||||
}
|
||||
|
||||
function EmbeddedLog({ logId }: EmbeddedLogProps) {
|
||||
const { data: log, isLoading } = useLogDetail(logId)
|
||||
function EmbeddedLog({ logId, onNotFound }: EmbeddedLogProps) {
|
||||
const { data: log, isLoading, error } = useLogDetail(logId)
|
||||
|
||||
const onNotFoundRef = useRef(onNotFound)
|
||||
onNotFoundRef.current = onNotFound
|
||||
|
||||
useEffect(() => {
|
||||
if (isApiClientError(error) && error.status === 404) {
|
||||
onNotFoundRef.current?.()
|
||||
}
|
||||
}, [error])
|
||||
|
||||
if (isLoading) return LOADING_SKELETON
|
||||
|
||||
|
||||
+1
@@ -128,6 +128,7 @@ export const MothershipView = memo(
|
||||
previewSession={previewForActive}
|
||||
genericResourceData={active.type === 'generic' ? genericResourceData : undefined}
|
||||
previewContextKey={chatId}
|
||||
onNotFound={(resourceId) => onRemoveResource('log', resourceId)}
|
||||
/>
|
||||
) : (
|
||||
<div className='flex h-full items-center justify-center text-[var(--text-muted)] text-sm'>
|
||||
|
||||
@@ -1420,6 +1420,18 @@ export function useChat(
|
||||
const removeResource = useCallback((resourceType: MothershipResourceType, resourceId: string) => {
|
||||
setResources((prev) => prev.filter((r) => !(r.type === resourceType && r.id === resourceId)))
|
||||
setActiveResourceId((prev) => (prev === resourceId ? null : prev))
|
||||
|
||||
const persistChatId = chatIdRef.current ?? selectedChatIdRef.current
|
||||
if (persistChatId) {
|
||||
// boundary-raw-fetch: fire-and-forget side-effect; intentionally avoids requestJson's response parsing/throw semantics so a transient failure cannot interrupt the caller
|
||||
fetch('/api/mothership/chat/resources', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ chatId: persistChatId, resourceType, resourceId }),
|
||||
}).catch((err) => {
|
||||
logger.warn('Failed to persist resource removal', err)
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const reorderResources = useCallback((newOrder: MothershipResource[]) => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
import { isApiClientError } from '@/lib/api/client/errors'
|
||||
import { requestJson } from '@/lib/api/client/request'
|
||||
import {
|
||||
cancelWorkflowExecutionContract,
|
||||
@@ -194,6 +195,8 @@ export function useLogDetail(logId: string | undefined, options?: UseLogDetailOp
|
||||
enabled: Boolean(logId) && (options?.enabled ?? true),
|
||||
refetchInterval: options?.refetchInterval ?? false,
|
||||
staleTime: 30 * 1000,
|
||||
retry: (failureCount, err) =>
|
||||
!(isApiClientError(err) && err.status === 404) && failureCount < 3,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
FunctionExecute,
|
||||
GenerateImage,
|
||||
GenerateVisualization,
|
||||
GetWorkflowLogs,
|
||||
Knowledge,
|
||||
KnowledgeBase,
|
||||
UserTable,
|
||||
@@ -30,7 +29,6 @@ const RESOURCE_TOOL_NAMES: Set<string> = new Set([
|
||||
Knowledge.id,
|
||||
GenerateVisualization.id,
|
||||
GenerateImage.id,
|
||||
GetWorkflowLogs.id,
|
||||
])
|
||||
|
||||
export function isResourceToolName(toolName: string): boolean {
|
||||
@@ -214,19 +212,6 @@ export function extractResourcesFromToolResult(
|
||||
return resources
|
||||
}
|
||||
|
||||
case GetWorkflowLogs.id: {
|
||||
const entries = Array.isArray(output) ? output : Array.isArray(result.data) ? result.data : []
|
||||
const resources: ChatResource[] = []
|
||||
for (const entry of entries) {
|
||||
const rec = asRecord(entry)
|
||||
const logId = rec.id as string | undefined
|
||||
if (logId) {
|
||||
resources.push({ type: 'log', id: logId, title: 'Log' })
|
||||
}
|
||||
}
|
||||
return resources
|
||||
}
|
||||
|
||||
default:
|
||||
return []
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user