Studio: address chat artifact review follow-ups
This commit is contained in:
parent
b6faf7ffcd
commit
bc0ccc6768
7 changed files with 32 additions and 13 deletions
|
|
@ -268,7 +268,6 @@ _ARTIFACT_PREVIEW_FRAME_HTML = """<!doctype html>
|
|||
if (!data || data.type !== "unsloth:artifact-html" || typeof data.html !== "string") return;
|
||||
render(data.html);
|
||||
});
|
||||
parent.postMessage({ chatArtifactReady: true }, "*");
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ const RenderHtmlToolUIImpl: ToolCallMessagePartComponent = ({
|
|||
title={title}
|
||||
source="tool"
|
||||
sourceToolCallId={toolCallId}
|
||||
preview={false}
|
||||
autoOpen={true}
|
||||
isStreaming={isRunning || codeIsStreaming}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ import { useAuiState } from "@assistant-ui/react";
|
|||
import { CheckIcon, CopyIcon, DownloadIcon } from "lucide-react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useChatRuntimeStore } from "../stores/chat-runtime-store";
|
||||
import { useChatArtifactsStore } from "./store";
|
||||
import {
|
||||
hasAutoOpenedArtifact,
|
||||
rememberAutoOpenedArtifact,
|
||||
useChatArtifactsStore,
|
||||
} from "./store";
|
||||
import {
|
||||
type ChatArtifact,
|
||||
type ChatArtifactSource,
|
||||
|
|
@ -18,7 +22,6 @@ import {
|
|||
} from "./types";
|
||||
|
||||
const COPY_RESET_MS = 2000;
|
||||
const autoOpenedArtifactIds = new Set<string>();
|
||||
|
||||
function downloadTextFile(filename: string, text: string): void {
|
||||
const blob = new Blob([text], { type: "text/html;charset=utf-8" });
|
||||
|
|
@ -74,7 +77,6 @@ export function ArtifactCard({
|
|||
sourceToolCallId?: string | null;
|
||||
sourceMessageId?: string | null;
|
||||
className?: string;
|
||||
preview?: boolean;
|
||||
autoOpen?: boolean;
|
||||
isStreaming?: boolean;
|
||||
}) {
|
||||
|
|
@ -119,8 +121,8 @@ export function ArtifactCard({
|
|||
|
||||
useEffect(() => {
|
||||
if (!autoOpen) return;
|
||||
if (!autoOpenedArtifactIds.has(artifact.id)) {
|
||||
autoOpenedArtifactIds.add(artifact.id);
|
||||
if (!hasAutoOpenedArtifact(artifact.id)) {
|
||||
rememberAutoOpenedArtifact(artifact.id);
|
||||
openArtifact(artifact, { surface });
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ export function ArtifactHtmlFrame({
|
|||
[code],
|
||||
);
|
||||
const postArtifactHtml = useCallback(() => {
|
||||
// The sandboxed frame intentionally has an opaque origin ("null").
|
||||
// A wildcard target is required here;
|
||||
// the payload is sent only to this iframe's contentWindow.
|
||||
iframeRef.current?.contentWindow?.postMessage(
|
||||
{ type: "unsloth:artifact-html", html: artifactHtml },
|
||||
"*",
|
||||
|
|
@ -60,9 +63,7 @@ export function ArtifactHtmlFrame({
|
|||
useEffect(() => {
|
||||
const handler = (event: MessageEvent) => {
|
||||
if (event.source !== iframeRef.current?.contentWindow) return;
|
||||
if (event.data?.chatArtifactReady === true) {
|
||||
postArtifactHtml();
|
||||
}
|
||||
if (event.origin !== "null") return;
|
||||
if (typeof event.data?.chatArtifactHeight !== "number") return;
|
||||
setHeight(
|
||||
Math.min(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,20 @@
|
|||
import { create } from "zustand";
|
||||
import type { ChatArtifact, ChatArtifactSurface } from "./types";
|
||||
|
||||
const autoOpenedArtifactIds = new Set<string>();
|
||||
|
||||
export function hasAutoOpenedArtifact(artifactId: string): boolean {
|
||||
return autoOpenedArtifactIds.has(artifactId);
|
||||
}
|
||||
|
||||
export function rememberAutoOpenedArtifact(artifactId: string): void {
|
||||
autoOpenedArtifactIds.add(artifactId);
|
||||
}
|
||||
|
||||
export function clearAutoOpenedArtifacts(): void {
|
||||
autoOpenedArtifactIds.clear();
|
||||
}
|
||||
|
||||
type ChatArtifactsState = {
|
||||
artifactsById: Record<string, ChatArtifact>;
|
||||
selectedArtifactId: string | null;
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ import { useExternalProvidersStore } from "./stores/external-providers-store";
|
|||
import { buildChatTourSteps } from "./tour";
|
||||
import { ArtifactSurface } from "./artifacts/artifact-surface";
|
||||
import {
|
||||
clearAutoOpenedArtifacts,
|
||||
useChatArtifactsStore,
|
||||
useSelectedChatArtifact,
|
||||
} from "./artifacts/store";
|
||||
|
|
@ -962,6 +963,7 @@ export function ChatPage(): ReactElement {
|
|||
: `compare:${view.pairId}`;
|
||||
|
||||
useEffect(() => {
|
||||
clearAutoOpenedArtifacts();
|
||||
closeArtifactSurface();
|
||||
}, [artifactViewKey, closeArtifactSurface]);
|
||||
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ type ChatRuntimeStore = {
|
|||
setToolsEnabled: (enabled: boolean, options?: { persist?: boolean }) => void;
|
||||
setCodeToolsEnabled: (enabled: boolean) => void;
|
||||
setImageToolsEnabled: (enabled: boolean) => void;
|
||||
setArtifactsEnabled: (enabled: boolean) => void;
|
||||
setArtifactsEnabled: (enabled: boolean, options?: { persist?: boolean }) => void;
|
||||
setToolStatus: (status: string | null) => void;
|
||||
setGeneratingStatus: (status: string | null) => void;
|
||||
setAutoHealToolCalls: (enabled: boolean) => void;
|
||||
|
|
@ -811,9 +811,11 @@ export const useChatRuntimeStore = create<ChatRuntimeStore>((set, get) => ({
|
|||
saveBool(CHAT_IMAGE_TOOLS_ENABLED_KEY, imageToolsEnabled);
|
||||
return { imageToolsEnabled };
|
||||
}),
|
||||
setArtifactsEnabled: (artifactsEnabled) =>
|
||||
setArtifactsEnabled: (artifactsEnabled, options) =>
|
||||
set(() => {
|
||||
saveBool(CHAT_ARTIFACTS_ENABLED_KEY, artifactsEnabled);
|
||||
if (options?.persist !== false) {
|
||||
saveBool(CHAT_ARTIFACTS_ENABLED_KEY, artifactsEnabled);
|
||||
}
|
||||
return { artifactsEnabled };
|
||||
}),
|
||||
setToolStatus: (toolStatus) => set({ toolStatus }),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue