Support durable assistant image attachments in Agent clients

This commit is contained in:
2026-10-20 14:14:09 -07:00
parent 7b48201e28
commit 489c347976
15 changed files with 227 additions and 40 deletions
@@ -11,6 +11,8 @@ type Props = {
mode?: MarkdownMode;
resolveCitationIndex?: (href: string) => number | undefined;
openLinksInNewTab?: boolean;
/** Agent images are delivered only through authenticated attachment IDs. */
allowImages?: boolean;
};
function replaceMarkdownLinksWithCitationTokens(markdown: string, resolveCitationIndex?: (href: string) => number | undefined) {
@@ -35,24 +37,28 @@ function setNewTabLinkAttributes(currentNode: Element) {
currentNode.setAttribute("rel", "noopener noreferrer");
}
function renderMarkdown(markdown: string, openLinksInNewTab: boolean) {
function renderMarkdown(markdown: string, openLinksInNewTab: boolean, allowImages: boolean) {
const rawHtml = marked.parse(markdown, { gfm: true, breaks: true, renderer: markdownRenderer }) as string;
if (!openLinksInNewTab) return DOMPurify.sanitize(rawHtml, { ADD_ATTR: ["class", "target", "rel"] });
const config = { ADD_ATTR: ["class", "target", "rel"], ...(!allowImages ? {
FORBID_TAGS: ["img", "picture", "source", "video", "audio", "svg", "math", "style"],
FORBID_ATTR: ["style", "srcset", "background", "poster"],
} : {}) };
if (!openLinksInNewTab) return DOMPurify.sanitize(rawHtml, config);
DOMPurify.addHook("afterSanitizeAttributes", setNewTabLinkAttributes);
try {
return DOMPurify.sanitize(rawHtml, { ADD_ATTR: ["class", "target", "rel"] });
return DOMPurify.sanitize(rawHtml, config);
} finally {
DOMPurify.removeHook("afterSanitizeAttributes", setNewTabLinkAttributes);
}
}
export function MarkdownContent({ markdown, className, mode = "default", resolveCitationIndex, openLinksInNewTab = false }: Props) {
export function MarkdownContent({ markdown, className, mode = "default", resolveCitationIndex, openLinksInNewTab = false, allowImages = true }: Props) {
const html = useMemo(() => {
const prepared =
mode === "citationTokens" ? replaceMarkdownLinksWithCitationTokens(markdown, resolveCitationIndex) : markdown;
return renderMarkdown(prepared, openLinksInNewTab);
}, [markdown, mode, openLinksInNewTab, resolveCitationIndex]);
return renderMarkdown(prepared, openLinksInNewTab, allowImages);
}, [markdown, mode, openLinksInNewTab, resolveCitationIndex, allowImages]);
return <div className={cn("md-content", className)} dangerouslySetInnerHTML={{ __html: html }} />;
}