diff --git a/frontend/src/app/workspace/chats/[thread_id]/layout.tsx b/frontend/src/app/workspace/chats/[thread_id]/layout.tsx
index b855034ec..eeee68347 100644
--- a/frontend/src/app/workspace/chats/[thread_id]/layout.tsx
+++ b/frontend/src/app/workspace/chats/[thread_id]/layout.tsx
@@ -1,8 +1,12 @@
+import { isStaticWebsiteOnly } from "@/core/static-mode";
import { DEMO_THREAD_IDS } from "@/core/threads/static-demo";
import { ChatProviders } from "./providers";
export function generateStaticParams() {
+ if (!isStaticWebsiteOnly()) {
+ return [];
+ }
return DEMO_THREAD_IDS.map((thread_id) => ({ thread_id }));
}
diff --git a/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx b/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx
index 99292fbd1..93130c44f 100644
--- a/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx
+++ b/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx
@@ -325,11 +325,7 @@ export function ArtifactFilePreview({
diff --git a/frontend/src/core/artifacts/utils.ts b/frontend/src/core/artifacts/utils.ts
index 3dc8aa1c3..e205b739a 100644
--- a/frontend/src/core/artifacts/utils.ts
+++ b/frontend/src/core/artifacts/utils.ts
@@ -13,7 +13,10 @@ export function urlOfArtifact({
download?: boolean;
isMock?: boolean;
}) {
- if (isMock || isStaticWebsiteOnly()) {
+ if (isStaticWebsiteOnly()) {
+ return staticDemoArtifactURL({ filepath, threadId, download });
+ }
+ if (isMock) {
return `${getBackendBaseURL()}/mock/api/threads/${threadId}/artifacts${filepath}${download ? "?download=true" : ""}`;
}
return `${getBackendBaseURL()}/api/threads/${threadId}/artifacts${filepath}${download ? "?download=true" : ""}`;
@@ -25,7 +28,20 @@ export function extractArtifactsFromThread(thread: AgentThread) {
export function resolveArtifactURL(absolutePath: string, threadId: string) {
if (isStaticWebsiteOnly()) {
- return `${getBackendBaseURL()}/mock/api/threads/${threadId}/artifacts${absolutePath}`;
+ return staticDemoArtifactURL({ filepath: absolutePath, threadId });
}
return `${getBackendBaseURL()}/api/threads/${threadId}/artifacts${absolutePath}`;
}
+
+function staticDemoArtifactURL({
+ filepath,
+ threadId,
+ download = false,
+}: {
+ filepath: string;
+ threadId: string;
+ download?: boolean;
+}) {
+ const demoPath = filepath.replace(/^\/mnt\//, "/");
+ return `${getBackendBaseURL()}/demo/threads/${threadId}${demoPath}${download ? "?download=true" : ""}`;
+}
diff --git a/frontend/tests/unit/core/artifacts/utils.test.ts b/frontend/tests/unit/core/artifacts/utils.test.ts
new file mode 100644
index 000000000..c0400b371
--- /dev/null
+++ b/frontend/tests/unit/core/artifacts/utils.test.ts
@@ -0,0 +1,69 @@
+import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
+
+const ENV_KEYS = [
+ "NEXT_PUBLIC_BACKEND_BASE_URL",
+ "NEXT_PUBLIC_STATIC_WEBSITE_ONLY",
+] as const;
+
+type EnvSnapshot = Partial<
+ Record<(typeof ENV_KEYS)[number], string | undefined>
+>;
+
+function snapshotEnv(): EnvSnapshot {
+ const snapshot: EnvSnapshot = {};
+ for (const key of ENV_KEYS) {
+ snapshot[key] = process.env[key];
+ }
+ return snapshot;
+}
+
+function setEnv(key: (typeof ENV_KEYS)[number], value: string | undefined) {
+ const env = process.env as Record;
+ if (value === undefined) {
+ delete env[key];
+ } else {
+ env[key] = value;
+ }
+}
+
+function restoreEnv(snapshot: EnvSnapshot) {
+ for (const key of ENV_KEYS) {
+ setEnv(key, snapshot[key]);
+ }
+}
+
+async function loadFreshArtifactUtils() {
+ vi.resetModules();
+ return await import("@/core/artifacts/utils");
+}
+
+describe("artifact URL helpers", () => {
+ let saved: EnvSnapshot;
+
+ beforeEach(() => {
+ saved = snapshotEnv();
+ setEnv("NEXT_PUBLIC_BACKEND_BASE_URL", undefined);
+ setEnv("NEXT_PUBLIC_STATIC_WEBSITE_ONLY", undefined);
+ });
+
+ afterEach(() => {
+ restoreEnv(saved);
+ });
+
+ test("maps static demo artifact paths to bundled public files", async () => {
+ setEnv("NEXT_PUBLIC_STATIC_WEBSITE_ONLY", "true");
+
+ const { resolveArtifactURL, urlOfArtifact } =
+ await loadFreshArtifactUtils();
+
+ expect(
+ urlOfArtifact({
+ filepath: "/mnt/user-data/outputs/index.html",
+ threadId: "thread-1",
+ }),
+ ).toBe("/demo/threads/thread-1/user-data/outputs/index.html");
+ expect(
+ resolveArtifactURL("/mnt/user-data/outputs/style.css", "thread-1"),
+ ).toBe("/demo/threads/thread-1/user-data/outputs/style.css");
+ });
+});