diff --git a/backend/src/agents/middlewares/uploads_middleware.py b/backend/src/agents/middlewares/uploads_middleware.py index 5fd01f0..3703f3a 100644 --- a/backend/src/agents/middlewares/uploads_middleware.py +++ b/backend/src/agents/middlewares/uploads_middleware.py @@ -53,12 +53,15 @@ class UploadsMiddleware(AgentMiddleware[UploadsMiddlewareState]): lines.append("The following files were uploaded in this message:") lines.append("") - for file in new_files: - size_kb = file["size"] / 1024 - size_str = f"{size_kb:.1f} KB" if size_kb < 1024 else f"{size_kb / 1024:.1f} MB" - lines.append(f"- {file['filename']} ({size_str})") - lines.append(f" Path: {file['path']}") - lines.append("") + if new_files: + for file in new_files: + size_kb = file["size"] / 1024 + size_str = f"{size_kb:.1f} KB" if size_kb < 1024 else f"{size_kb / 1024:.1f} MB" + lines.append(f"- {file['filename']} ({size_str})") + lines.append(f" Path: {file['path']}") + lines.append("") + else: + lines.append("(empty)") if historical_files: lines.append("The following files were uploaded in previous messages and are still available:") diff --git a/backend/tests/test_uploads_middleware_core_logic.py b/backend/tests/test_uploads_middleware_core_logic.py index 864424a..960a162 100644 --- a/backend/tests/test_uploads_middleware_core_logic.py +++ b/backend/tests/test_uploads_middleware_core_logic.py @@ -188,6 +188,13 @@ class TestCreateFilesMessage: msg = mw._create_files_message([self._new_file()], []) assert "read_file" in msg + def test_empty_new_files_produces_empty_marker(self, tmp_path): + mw = _middleware(tmp_path) + msg = mw._create_files_message([], []) + assert "(empty)" in msg + assert "" in msg + assert "" in msg + # --------------------------------------------------------------------------- # before_agent diff --git a/frontend/src/components/workspace/artifacts/context.tsx b/frontend/src/components/workspace/artifacts/context.tsx index 22ccb1d..3dcf71a 100644 --- a/frontend/src/components/workspace/artifacts/context.tsx +++ b/frontend/src/components/workspace/artifacts/context.tsx @@ -1,4 +1,10 @@ -import { createContext, useContext, useState, type ReactNode } from "react"; +import { + createContext, + useCallback, + useContext, + useState, + type ReactNode, +} from "react"; import { useSidebar } from "@/components/ui/sidebar"; import { env } from "@/env"; @@ -35,20 +41,23 @@ export function ArtifactsProvider({ children }: ArtifactsProviderProps) { const [autoOpen, setAutoOpen] = useState(true); const { setOpen: setSidebarOpen } = useSidebar(); - const select = (artifact: string, autoSelect = false) => { - setSelectedArtifact(artifact); - if (env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true") { - setSidebarOpen(false); - } - if (!autoSelect) { - setAutoSelect(false); - } - }; + const select = useCallback( + (artifact: string, autoSelect = false) => { + setSelectedArtifact(artifact); + if (env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true") { + setSidebarOpen(false); + } + if (!autoSelect) { + setAutoSelect(false); + } + }, + [setSidebarOpen, setSelectedArtifact, setAutoSelect], + ); - const deselect = () => { + const deselect = useCallback(() => { setSelectedArtifact(null); setAutoSelect(true); - }; + }, []); const value: ArtifactsContextType = { artifacts, diff --git a/frontend/src/components/workspace/chats/chat-box.tsx b/frontend/src/components/workspace/chats/chat-box.tsx index f47eaec..1fe0bc3 100644 --- a/frontend/src/components/workspace/chats/chat-box.tsx +++ b/frontend/src/components/workspace/chats/chat-box.tsx @@ -34,12 +34,19 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({ setOpen: setArtifactsOpen, setArtifacts, select: selectArtifact, + deselect, selectedArtifact, } = useArtifacts(); const [autoSelectFirstArtifact, setAutoSelectFirstArtifact] = useState(true); useEffect(() => { setArtifacts(thread.values.artifacts); + if ( + thread.values.artifacts?.length === 0 || + (selectedArtifact && !thread.values.artifacts?.includes(selectedArtifact)) + ) { + deselect(); + } if ( env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" && autoSelectFirstArtifact @@ -51,7 +58,9 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({ } }, [ autoSelectFirstArtifact, + deselect, selectArtifact, + selectedArtifact, setArtifacts, thread.values.artifacts, ]); diff --git a/frontend/src/core/messages/utils.ts b/frontend/src/core/messages/utils.ts index c95ad49..e9ab38b 100644 --- a/frontend/src/core/messages/utils.ts +++ b/frontend/src/core/messages/utils.ts @@ -300,6 +300,11 @@ export function parseUploadedFiles(content: string): FileInMessage[] { return []; } + // Check if the backend reported no new files were uploaded in this message + if (uploadedFilesContent?.includes("(empty)")) { + return []; + } + // Parse file list // Format: - filename (size)\n Path: /path/to/file const fileRegex = /- ([^\n(]+)\s*\(([^)]+)\)\s*\n\s*Path:\s*([^\n]+)/g;