From 26b774bb04461fddad32e6cd515fbdb2c5aee081 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Sun, 12 Oct 2025 00:39:26 +0200 Subject: [PATCH] Add standalone mode for HTML artifact downloads When downloading HTML artifacts, the generated HTML now works standalone without requiring the extension runtime. Changes: - Add PrepareHtmlOptions config object to SandboxedIframe.prepareHtmlDocument() - Add isStandalone flag to skip runtime bridge and navigation interceptor - When isStandalone=true: - window.sendRuntimeMessage is NOT defined - Navigation interceptor is NOT injected - Artifact runtime providers fall back to embedded data - HtmlArtifact download button now uses isStandalone: true This fixes the issue where downloaded HTML artifacts would: - Try to call window.sendRuntimeMessage (which would fail silently) - Try to postMessage to non-existent parent window - Not work when opened via file:// protocol Now downloaded artifacts work completely standalone with embedded data. --- packages/ai/src/agent/agent-loop.ts | 2 +- .../web-ui/src/components/SandboxedIframe.ts | 83 ++++++++++++++----- .../src/tools/artifacts/HtmlArtifact.ts | 5 +- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/packages/ai/src/agent/agent-loop.ts b/packages/ai/src/agent/agent-loop.ts index d51876f1..876e5e93 100644 --- a/packages/ai/src/agent/agent-loop.ts +++ b/packages/ai/src/agent/agent-loop.ts @@ -61,7 +61,7 @@ export function agentLoop( queuedMessages = []; } - console.log("agent-loop: ", [...currentContext.messages]); + // console.log("agent-loop: ", [...currentContext.messages]); // Stream assistant response const message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn); diff --git a/packages/web-ui/src/components/SandboxedIframe.ts b/packages/web-ui/src/components/SandboxedIframe.ts index fba7b7d8..211570f6 100644 --- a/packages/web-ui/src/components/SandboxedIframe.ts +++ b/packages/web-ui/src/components/SandboxedIframe.ts @@ -25,6 +25,16 @@ export interface SandboxResult { */ export type SandboxUrlProvider = () => string; +/** + * Configuration for prepareHtmlDocument + */ +export interface PrepareHtmlOptions { + /** True if this is an HTML artifact (inject into existing HTML), false if REPL (wrap in HTML) */ + isHtmlArtifact: boolean; + /** True if this is a standalone download (no runtime bridge, no navigation interceptor) */ + isStandalone?: boolean; +} + /** * Escape HTML special sequences in code to prevent premature tag closure * @param code Code that will be injected into `; } } diff --git a/packages/web-ui/src/tools/artifacts/HtmlArtifact.ts b/packages/web-ui/src/tools/artifacts/HtmlArtifact.ts index 3022bac3..81f5370f 100644 --- a/packages/web-ui/src/tools/artifacts/HtmlArtifact.ts +++ b/packages/web-ui/src/tools/artifacts/HtmlArtifact.ts @@ -48,7 +48,10 @@ export class HtmlArtifact extends ArtifactElement { const sandbox = this.sandboxIframeRef.value; const sandboxId = `artifact-${this.filename}`; const downloadContent = - sandbox?.prepareHtmlDocument(sandboxId, this._content, this.runtimeProviders || [], true) || this._content; + sandbox?.prepareHtmlDocument(sandboxId, this._content, this.runtimeProviders || [], { + isHtmlArtifact: true, + isStandalone: true, // Skip runtime bridge and navigation interceptor for standalone downloads + }) || this._content; return html`