diff --git a/frontend/src/app/workspace/chats/[thread_id]/page.tsx b/frontend/src/app/workspace/chats/[thread_id]/page.tsx
index 5ae61615..4f1dcf52 100644
--- a/frontend/src/app/workspace/chats/[thread_id]/page.tsx
+++ b/frontend/src/app/workspace/chats/[thread_id]/page.tsx
@@ -14,7 +14,6 @@ import {
DevDialogTitle,
} from "@/components/ui/dev-dialog";
import { useSidebar } from "@/components/ui/sidebar";
-import { Skeleton } from "@/components/ui/skeleton";
import {
ArtifactFileDetail,
ArtifactFileList,
@@ -27,7 +26,6 @@ import { InputBox } from "@/components/workspace/input-box";
import { MessageList } from "@/components/workspace/messages";
import { ThreadContext } from "@/components/workspace/messages/context";
import { ThreadTitle } from "@/components/workspace/thread-title";
-import { TokenUsageIndicator } from "@/components/workspace/token-usage-indicator";
import { Tooltip } from "@/components/workspace/tooltip";
import { useSpecificChatMode } from "@/components/workspace/use-chat-mode";
import { Welcome } from "@/components/workspace/welcome";
@@ -260,7 +258,6 @@ export default function ChatPage() {
)}
- {/*
*/}
);
}
-
-function InputBoxSkeleton() {
- return (
-
- );
-}
diff --git a/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx b/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx
index dcee6279..28710582 100644
--- a/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx
+++ b/frontend/src/components/workspace/artifacts/artifact-file-detail.tsx
@@ -34,7 +34,6 @@ import { CodeEditor } from "@/components/workspace/code-editor";
import { useArtifactContent } from "@/core/artifacts/hooks";
import { urlOfArtifact } from "@/core/artifacts/utils";
import { useI18n } from "@/core/i18n/hooks";
-import { installSkill } from "@/core/skills/api";
import { streamdownPlugins } from "@/core/streamdown";
import { checkCodeFile, getFileName } from "@/core/utils/files";
import { useMarkdownDownload } from "@/core/utils/markdown-download";
@@ -61,7 +60,7 @@ export function ArtifactFileDetail({
}: {
className?: string;
filepath: string;
- threadId: string;
+ threadId?: string;
}) {
const { t } = useI18n();
const { artifacts, setOpen, select, fullscreen, setFullscreen } =
@@ -98,12 +97,18 @@ export function ArtifactFileDetail({
return (language === "html" && !isWriteFile) || language === "markdown";
}, [isWriteFile, language]);
const artifactUrl = useMemo(() => {
+ if (!threadId) {
+ return "";
+ }
return urlOfArtifact({ filepath, threadId });
}, [filepath, threadId]);
const artifactPreviewKind = useMemo(() => {
return getArtifactPreviewKind(filepath);
}, [filepath]);
const artifactViewerSrcDoc = useMemo(() => {
+ if (!artifactUrl) {
+ return "";
+ }
return buildArtifactViewerSrcDoc({
artifactUrl,
fileName,
@@ -113,7 +118,7 @@ export function ArtifactFileDetail({
const { content } = useArtifactContent({
threadId,
filepath: filepathFromProps,
- enabled: isCodeFile && !isWriteFile,
+ enabled: Boolean(threadId) && isCodeFile && !isWriteFile,
});
const displayContent = content ?? "";
@@ -126,7 +131,6 @@ export function ArtifactFileDetail({
}, [artifacts]);
const [viewMode, setViewMode] = useState<"code" | "preview">("code");
- const [isInstalling, setIsInstalling] = useState(false);
const [zoom, setZoom] = useState(80);
// 是否可以转换为docx/pdf(仅markdown文件支持)
@@ -172,28 +176,6 @@ export function ArtifactFileDetail({
}
}, [previewable]);
- const handleInstallSkill = useCallback(async () => {
- if (isInstalling) return;
-
- setIsInstalling(true);
- try {
- const result = await installSkill({
- thread_id: threadId,
- path: filepath,
- });
- if (result.success) {
- toast.success(result.message);
- } else {
- toast.error(result.message ?? "Failed to install skill");
- }
- } catch (error) {
- console.error("Failed to install skill:", error);
- toast.error("Failed to install skill");
- } finally {
- setIsInstalling(false);
- }
- }, [threadId, filepath, isInstalling]);
-
return (
// 给滚动遮挡头部定位relative
handleInstallSkill(e, file)}
>
{installingFile === file ? (
@@ -109,20 +110,27 @@ export function ArtifactFileList({
{t.common.install}
)}
- e.stopPropagation()}
- >
-
+ )}
diff --git a/frontend/src/components/workspace/export-trigger.tsx b/frontend/src/components/workspace/export-trigger.tsx
index b75d4e45..4d0d807d 100644
--- a/frontend/src/components/workspace/export-trigger.tsx
+++ b/frontend/src/components/workspace/export-trigger.tsx
@@ -21,7 +21,7 @@ import type { AgentThread } from "@/core/threads/types";
import { useThread } from "./messages/context";
import { Tooltip } from "./tooltip";
-export function ExportTrigger({ threadId }: { threadId: string }) {
+export function ExportTrigger({ threadId }: { threadId?: string }) {
const { t } = useI18n();
const { thread } = useThread();
@@ -49,7 +49,7 @@ export function ExportTrigger({ threadId }: { threadId: string }) {
[messages, thread.values, threadId, t],
);
- if (messages.length === 0) {
+ if (!threadId || messages.length === 0) {
return null;
}
diff --git a/frontend/src/components/workspace/messages/message-list.tsx b/frontend/src/components/workspace/messages/message-list.tsx
index c83194e2..69c08277 100644
--- a/frontend/src/components/workspace/messages/message-list.tsx
+++ b/frontend/src/components/workspace/messages/message-list.tsx
@@ -39,7 +39,7 @@ export function MessageList({
paddingBottom = 160,
}: {
className?: string;
- threadId: string;
+ threadId?: string;
thread: UseStream;
/** When set (e.g. from onFinish), use instead of thread.messages so SSE end shows complete state. */
messagesOverride?: Message[];
@@ -98,7 +98,9 @@ export function MessageList({
className="mb-4"
/>
)}
-
+ {threadId ? (
+
+ ) : null}
);
} else if (group.type === "assistant:subagent") {
diff --git a/frontend/src/components/workspace/thread-title.tsx b/frontend/src/components/workspace/thread-title.tsx
index 642e4e6f..35e9b57e 100644
--- a/frontend/src/components/workspace/thread-title.tsx
+++ b/frontend/src/components/workspace/thread-title.tsx
@@ -40,6 +40,7 @@ export function ThreadTitle({
t.pages.newChat,
t.pages.untitled,
t.pages.appName,
+ thread,
thread?.isThreadLoading,
thread?.values,
]);
diff --git a/frontend/src/core/artifacts/hooks.ts b/frontend/src/core/artifacts/hooks.ts
index 4df9db70..6d875aba 100644
--- a/frontend/src/core/artifacts/hooks.ts
+++ b/frontend/src/core/artifacts/hooks.ts
@@ -11,7 +11,7 @@ export function useArtifactContent({
enabled,
}: {
filepath: string;
- threadId: string;
+ threadId?: string;
enabled?: boolean;
}) {
const isWriteFile = useMemo(() => {
@@ -25,12 +25,17 @@ export function useArtifactContent({
return null;
}, [filepath, isWriteFile, thread]);
+ const canFetch = Boolean(threadId) && enabled !== false;
const { data, isLoading, error } = useQuery({
queryKey: ["artifact", filepath, threadId, isMock],
queryFn: () => {
- return loadArtifactContent({ filepath, threadId, isMock });
+ return loadArtifactContent({
+ filepath,
+ threadId: threadId ?? "",
+ isMock,
+ });
},
- enabled,
+ enabled: canFetch,
// Cache artifact content for 5 minutes to avoid repeated fetches (especially for .skill ZIP extraction)
staleTime: 5 * 60 * 1000,
});
diff --git a/frontend/src/core/i18n/locales/en-US.ts b/frontend/src/core/i18n/locales/en-US.ts
index a03cc86f..12f68950 100644
--- a/frontend/src/core/i18n/locales/en-US.ts
+++ b/frontend/src/core/i18n/locales/en-US.ts
@@ -1,6 +1,5 @@
import {
CompassIcon,
- GraduationCapIcon,
ImageIcon,
MicroscopeIcon,
PenLineIcon,
diff --git a/frontend/src/core/threads/hooks.ts b/frontend/src/core/threads/hooks.ts
index c05310b8..eacd668a 100644
--- a/frontend/src/core/threads/hooks.ts
+++ b/frontend/src/core/threads/hooks.ts
@@ -456,7 +456,7 @@ export function useThreadStream({
: context.mode === "thinking"
? "low"
: undefined),
- thread_id: resolvedThreadId,
+ ...(resolvedThreadId ? { thread_id: resolvedThreadId } : {}),
},
},
);
@@ -580,7 +580,7 @@ export function useSubmitThread({
},
context: {
...threadContext,
- thread_id: threadId,
+ ...(threadId ? { thread_id: threadId } : {}),
},
},
);
diff --git a/frontend/src/core/utils/markdown-download/converter.ts b/frontend/src/core/utils/markdown-download/converter.ts
index cd503ed4..df81bbb2 100644
--- a/frontend/src/core/utils/markdown-download/converter.ts
+++ b/frontend/src/core/utils/markdown-download/converter.ts
@@ -156,7 +156,6 @@ export async function downloadMarkdownAsPdf(
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
async function loadHtml2Pdf(): Promise {
const html2pdf = await import("html2pdf.js");
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return html2pdf.default;
}
diff --git a/frontend/src/hooks/use-selected-skill-listener.ts b/frontend/src/hooks/use-selected-skill-listener.ts
index fc20d66d..313a6cfd 100644
--- a/frontend/src/hooks/use-selected-skill-listener.ts
+++ b/frontend/src/hooks/use-selected-skill-listener.ts
@@ -25,7 +25,7 @@ interface SkillError {
interface UseSelectedSkillListenerOptions {
/** 当前会话 thread_id,用于调用 bootstrapRemoteSkill */
- threadId: string | null;
+ threadId?: string | null;
}
interface UseSelectedSkillListenerReturn {