From e75a7683a7d0e0907826f99583d185dca2845309 Mon Sep 17 00:00:00 2001 From: danielhanchen Date: Sun, 19 Jul 2026 11:47:15 +0000 Subject: [PATCH] Studio: fix Deep Research SSE framing, source counts, and favicon privacy - Normalize the whole SSE buffer so a CRLF split across transport chunks still frames events. - Count web and document sources together in the activity header so a RAG-only run is not shown as zero sources. - Cap the plan editor at the run's configured maxSteps instead of a hard-coded 30. - Add an allowRemoteIcons opt-out to the sources components and disable third-party favicon requests for research sources so visited domains are not leaked. --- .../src/components/assistant-ui/sources.tsx | 27 +++++++++++++------ .../src/features/chat/api/research-api.ts | 4 ++- .../components/research-activity-panel.tsx | 9 +++++-- .../chat/components/research-message.tsx | 2 +- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/studio/frontend/src/components/assistant-ui/sources.tsx b/studio/frontend/src/components/assistant-ui/sources.tsx index 94dda86ff6..9fb86ec913 100644 --- a/studio/frontend/src/components/assistant-ui/sources.tsx +++ b/studio/frontend/src/components/assistant-ui/sources.tsx @@ -40,14 +40,16 @@ function SourceIcon({ url, className, size = 3, + allowRemoteIcons = true, ...props -}: ComponentProps<"span"> & { url: string; size?: number }) { +}: ComponentProps<"span"> & { url: string; size?: number; allowRemoteIcons?: boolean }) { const [hasError, setHasError] = useState(false); const domain = extractDomain(url); const SIZE_CLASSES: Record = { 3: "size-3", 4: "size-4", 5: "size-5" }; const sizeClass = SIZE_CLASSES[size] ?? "size-3"; - if (hasError) { + // When disabled, render the letter fallback instead of fetching a third-party favicon. + if (hasError || !allowRemoteIcons) { return ( = ({ source }) => { +const SourceBadge: FC<{ source: SourceData; allowRemoteIcons?: boolean }> = ({ + source, + allowRemoteIcons = true, +}) => { const domain = extractDomain(source.url); const displayTitle = source.title || domain; @@ -146,7 +151,7 @@ const SourceBadge: FC<{ source: SourceData }> = ({ source }) => { - + {displayTitle} @@ -158,7 +163,12 @@ const SourceBadge: FC<{ source: SourceData }> = ({ source }) => { style={{ animation: "none" }} >
- +

{source.title || domain} @@ -178,8 +188,9 @@ const SourceBadge: FC<{ source: SourceData }> = ({ source }) => { // ── Grouped sources with 2-row collapse ───────────────────── -const SourcesGroup: FC<{ sources?: SourceData[] }> = ({ +const SourcesGroup: FC<{ sources?: SourceData[]; allowRemoteIcons?: boolean }> = ({ sources: suppliedSources, + allowRemoteIcons = true, }) => { const message = useMessage(); const containerRef = useRef(null); @@ -280,7 +291,7 @@ const SourcesGroup: FC<{ sources?: SourceData[] }> = ({ {sources.map((source) => ( - + {source.title || extractDomain(source.url)} @@ -291,7 +302,7 @@ const SourcesGroup: FC<{ sources?: SourceData[] }> = ({ {/* Visible container */}

{displayedSources.map((source) => ( - + ))} {shouldCollapse && !expanded && (
);