From 2f6cadb8b005d01d7945adb9ad2a7fd74faa4844 Mon Sep 17 00:00:00 2001 From: Baldwinzc <56501736+Baldwinzc@users.noreply.github.com> Date: Sat, 1 Aug 2026 21:59:27 +0800 Subject: [PATCH] fix(frontend): stop matching
as in HTML preview base injection (#4625) appendHtmlPreviewBaseHref detected the head tag with /]*>/i, which also matches
. For a fragment with no that opens with
- a common shape in agent-generated report pages - the element was injected after the
opening tag instead of being prepended, so relative assets appearing before that point (e.g. a leading ) resolved without the base and failed to load in the sandboxed iframe. Use the word-boundary-safe /]*)?>/i that the sibling appendHtmlPreviewScrollRestoration already uses, keeping the two injectors consistent. --- frontend/src/core/artifacts/preview.ts | 10 ++++-- .../tests/unit/core/artifacts/preview.test.ts | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/frontend/src/core/artifacts/preview.ts b/frontend/src/core/artifacts/preview.ts index da222a88a..1884dc1f3 100644 --- a/frontend/src/core/artifacts/preview.ts +++ b/frontend/src/core/artifacts/preview.ts @@ -175,8 +175,14 @@ export function appendHtmlPreviewBaseHref( const baseHref = htmlBaseHref(url, currentHref); const baseElement = ``; - if (/]*>/i.exec(content)) { - return content.replace(/]*)>/i, `${baseElement}`); + // "(?:\s[^>]*)?" keeps the tag-name boundary so `
` (a common + // leading tag in agent-generated fragments) is not mistaken for ``; + // mirrors appendHtmlPreviewScrollRestoration below. + if (/]*)?>/i.test(content)) { + return content.replace( + /]*)?>/i, + (headTag) => `${headTag}${baseElement}`, + ); } return `${baseElement}${content}`; } diff --git a/frontend/tests/unit/core/artifacts/preview.test.ts b/frontend/tests/unit/core/artifacts/preview.test.ts index 8544188be..4d68d890c 100644 --- a/frontend/tests/unit/core/artifacts/preview.test.ts +++ b/frontend/tests/unit/core/artifacts/preview.test.ts @@ -282,6 +282,39 @@ test("preserves existing head elements when injecting scroll restoration", () => ); }); +test("does not mistake
for when injecting the base href", () => { + // Agent-generated fragments often have no but open with
; + // the base must then be prepended so assets before the tag resolve too. + const html = + '
Report
content
'; + + const result = appendHtmlPreviewBaseHref( + html, + "/demo/threads/thread-1/user-data/outputs/report.html", + "http://localhost/workspace/chats/thread-1", + ); + + expect(result).toBe( + '' + + html, + ); +}); + +test("injects the base href inside an attributed tag", () => { + const html = + 'x'; + + const result = appendHtmlPreviewBaseHref( + html, + "/demo/threads/thread-1/user-data/outputs/report.html", + "http://localhost/workspace/chats/thread-1", + ); + + expect(result).toContain( + '', + ); +}); + test("does not duplicate HTML scroll restoration script", () => { const html = appendHtmlPreviewScrollRestoration( "x",