feat: improve knowledge sync and entity alignment
This commit is contained in:
1 parent
7dbac9cc56
commit
dea4697ea0
38 files changed
+3742
-634
No files matched your search
@@ -3,7 +3,6 @@
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
DatabaseZap,
|
||||
Replace,
|
||||
SearchIcon,
|
||||
SparklesIcon,
|
||||
@@ -20,7 +19,6 @@ import {
|
||||
WorkspaceHeader,
|
||||
} from "@/components/workspace/workspace-container";
|
||||
import { SkillRow } from "@/components/workspace/settings/skill-settings-page";
|
||||
import { SkillKnowledgePanel } from "@/components/workspace/skills/SkillKnowledgePanel";
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { useAllSkillsAdmin } from "@/core/skills/hooks";
|
||||
import { desensitize } from "@/lib/desensitize";
|
||||
@@ -37,7 +35,7 @@ export default function AdminSkillsPage() {
|
||||
const knowledgeBindings = useSkillKnowledgeBindings();
|
||||
const activeTab = useMemo(() => {
|
||||
const tab = searchParams.get("tab");
|
||||
return tab === "addresses" || tab === "knowledge" ? tab : "skills";
|
||||
return tab === "addresses" ? tab : "skills";
|
||||
}, [searchParams]);
|
||||
|
||||
const changeTab = (value: string) => {
|
||||
@@ -89,10 +87,6 @@ export default function AdminSkillsPage() {
|
||||
<Replace />
|
||||
技能地址管理
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="knowledge">
|
||||
<DatabaseZap />
|
||||
技能到知识库管理
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
</div>
|
||||
@@ -189,12 +183,6 @@ export default function AdminSkillsPage() {
|
||||
>
|
||||
<SkillAddressesPanel />
|
||||
</TabsContent>
|
||||
<TabsContent
|
||||
value="knowledge"
|
||||
className="mt-0 min-h-0 flex-1 overflow-hidden"
|
||||
>
|
||||
<SkillKnowledgePanel />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</WorkspaceBody>
|
||||
</WorkspaceContainer>
|
||||
|
||||
@@ -2,10 +2,12 @@ import {
|
||||
ArrowLeft,
|
||||
BookOpenText,
|
||||
Database,
|
||||
Edit3,
|
||||
Loader2,
|
||||
Plus,
|
||||
RefreshCw,
|
||||
Search,
|
||||
Trash2,
|
||||
Upload,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
@@ -17,12 +19,14 @@ import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { KnowledgeProductNav } from "@/components/workspace/knowledge-product-nav";
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { buildAppHashUrl } from "@/core/llmwiki/source-links";
|
||||
@@ -33,6 +37,7 @@ import {
|
||||
useAssistantKnowledgeBases,
|
||||
useAssistantKnowledgeSources,
|
||||
useAssistantWikiPages,
|
||||
type AssistantKnowledgeBase,
|
||||
} from "@/strategy-components/api/assistant-knowledge";
|
||||
import {
|
||||
WikiLibraryReader,
|
||||
@@ -53,6 +58,8 @@ export default function AssistantKnowledgePage() {
|
||||
const client = useQueryClient();
|
||||
const [tab, setTab] = useState("wiki");
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editingBase, setEditingBase] =
|
||||
useState<AssistantKnowledgeBase | null>(null);
|
||||
const [name, setName] = useState("");
|
||||
const [query, setQuery] = useState("");
|
||||
const [searching, setSearching] = useState(false);
|
||||
@@ -124,6 +131,25 @@ export default function AssistantKnowledgePage() {
|
||||
};
|
||||
const refresh = () =>
|
||||
void client.invalidateQueries({ queryKey: ["assistant-knowledge"] });
|
||||
const removeBase = async (target: AssistantKnowledgeBase) => {
|
||||
if (target.is_global) {
|
||||
toast.error("知识梳理总库承担全库沉淀,不能删除");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!window.confirm(
|
||||
`确定删除助手知识库“${target.name}”吗?库内 Wiki、向量、实体、关系和导入记录都会删除。`,
|
||||
)
|
||||
)
|
||||
return;
|
||||
try {
|
||||
await actions.deleteBase.mutateAsync(target.id);
|
||||
if (baseId === target.id) setParams({});
|
||||
toast.success("助手知识库已删除");
|
||||
} catch (error) {
|
||||
toast.error((error as Error).message);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="flex size-full min-h-0 flex-col bg-background">
|
||||
<KnowledgeProductNav />
|
||||
@@ -150,34 +176,69 @@ export default function AssistantKnowledgePage() {
|
||||
)}
|
||||
<div className="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
|
||||
{bases.data?.map((b) => (
|
||||
<button
|
||||
<div
|
||||
key={b.id}
|
||||
onClick={() => setParams({ base_id: b.id })}
|
||||
className="group rounded-2xl border bg-card p-6 text-left shadow-sm transition hover:border-primary/40 hover:shadow-md"
|
||||
className="group overflow-hidden rounded-2xl border bg-card text-left shadow-sm transition hover:border-primary/40 hover:shadow-md"
|
||||
>
|
||||
<div className="mb-5 flex items-center justify-between">
|
||||
<div className="rounded-xl bg-emerald-100 p-3 text-emerald-700 dark:bg-emerald-950">
|
||||
<Database className="size-6" />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setParams({ base_id: b.id })}
|
||||
className="w-full p-6 text-left"
|
||||
>
|
||||
<div className="mb-5 flex items-center justify-between">
|
||||
<div className="rounded-xl bg-emerald-100 p-3 text-emerald-700 dark:bg-emerald-950">
|
||||
<Database className="size-6" />
|
||||
</div>
|
||||
{b.is_global && (
|
||||
<Badge variant="secondary">全库知识梳理</Badge>
|
||||
)}
|
||||
</div>
|
||||
{b.is_global && (
|
||||
<Badge variant="secondary">全库知识梳理</Badge>
|
||||
)}
|
||||
</div>
|
||||
<h2 className="text-lg font-semibold group-hover:text-primary">
|
||||
{b.name}
|
||||
</h2>
|
||||
<p className="mt-2 line-clamp-2 min-h-10 text-sm text-muted-foreground">
|
||||
{b.is_global
|
||||
? "汇聚普通知识库的分析成果,保留分类、标签和知识关联。"
|
||||
: b.description ||
|
||||
"独立的 Wiki 知识空间,支持导入、导出与向量检索。"}
|
||||
</p>
|
||||
<div className="mt-6 flex gap-5 text-xs text-muted-foreground">
|
||||
<span>{b.page_count || 0} Wiki</span>
|
||||
<span>{b.source_count || 0} 来源</span>
|
||||
<span>{b.relation_count || 0} 关系</span>
|
||||
</div>
|
||||
</button>
|
||||
<h2 className="text-lg font-semibold group-hover:text-primary">
|
||||
{b.name}
|
||||
</h2>
|
||||
<p className="mt-2 line-clamp-2 min-h-10 text-sm text-muted-foreground">
|
||||
{b.description ||
|
||||
(b.is_global
|
||||
? "汇聚普通知识库的分析成果,保留分类、标签和知识关联。"
|
||||
: "独立的 Wiki 知识空间,支持导入、导出与向量检索。")}
|
||||
</p>
|
||||
<div className="mt-6 flex gap-5 text-xs text-muted-foreground">
|
||||
<span>{b.page_count || 0} Wiki</span>
|
||||
<span>{b.source_count || 0} 来源</span>
|
||||
<span>{b.relation_count || 0} 关系</span>
|
||||
</div>
|
||||
</button>
|
||||
{isAdmin && (
|
||||
<div className="flex items-center gap-2 border-t bg-muted/20 px-6 py-3">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={actions.updateBase.isPending}
|
||||
onClick={() => setEditingBase(b)}
|
||||
>
|
||||
<Edit3 className="mr-2 size-4" />
|
||||
编辑
|
||||
</Button>
|
||||
{!b.is_global && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="ml-auto text-destructive hover:bg-destructive/10 hover:text-destructive"
|
||||
disabled={actions.deleteBase.isPending}
|
||||
onClick={() => void removeBase(b)}
|
||||
>
|
||||
<Trash2 className="mr-2 size-4" />
|
||||
删除
|
||||
</Button>
|
||||
)}
|
||||
{b.is_global && (
|
||||
<span className="ml-auto text-xs text-muted-foreground">
|
||||
系统大库不可删除
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{!bases.isLoading && !bases.data?.length && isAdmin && (
|
||||
@@ -222,6 +283,29 @@ export default function AssistantKnowledgePage() {
|
||||
<RefreshCw className="mr-2 size-4" />
|
||||
刷新
|
||||
</Button>
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!base || actions.updateBase.isPending}
|
||||
onClick={() => base && setEditingBase(base)}
|
||||
>
|
||||
<Edit3 className="mr-2 size-4" />
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
{isAdmin && base && !base.is_global && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="text-destructive hover:bg-destructive/10 hover:text-destructive"
|
||||
disabled={actions.deleteBase.isPending}
|
||||
onClick={() => void removeBase(base)}
|
||||
>
|
||||
<Trash2 className="mr-2 size-4" />
|
||||
删除
|
||||
</Button>
|
||||
)}
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -265,7 +349,7 @@ export default function AssistantKnowledgePage() {
|
||||
<TabsTrigger value="wiki">
|
||||
Wiki({base?.page_count || 0})
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="search">向量检索</TabsTrigger>
|
||||
<TabsTrigger value="search">知识检索</TabsTrigger>
|
||||
<TabsTrigger value="sources">来源与同步</TabsTrigger>
|
||||
{isAdmin && (
|
||||
<TabsTrigger value="transfer">导入 / 导出记录</TabsTrigger>
|
||||
@@ -274,6 +358,7 @@ export default function AssistantKnowledgePage() {
|
||||
</div>
|
||||
<TabsContent value="wiki" className="mt-0 flex min-h-0 flex-1">
|
||||
<WikiLibraryReader
|
||||
key={baseId}
|
||||
pages={libraryPages}
|
||||
activePage={active}
|
||||
onNavigate={navigatePage}
|
||||
@@ -285,6 +370,7 @@ export default function AssistantKnowledgePage() {
|
||||
mappingId={
|
||||
active?.origins?.find((o) => o.mapping_id)?.mapping_id
|
||||
}
|
||||
initiallyCollapseTree
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="search" className="overflow-auto p-6">
|
||||
@@ -310,26 +396,36 @@ export default function AssistantKnowledgePage() {
|
||||
<>
|
||||
<Badge variant="outline">
|
||||
{searchResult.retrieval_mode === "vector"
|
||||
? "向量检索 · 余弦相似度"
|
||||
? "知识正文 / 片段 · 向量检索"
|
||||
: searchResult.retrieval_mode === "empty"
|
||||
? "没有匹配结果"
|
||||
: "关键词检索(暂无匹配模型的向量)"}
|
||||
: "知识正文 / 片段 · 关键词检索(暂无匹配模型的向量)"}
|
||||
</Badge>
|
||||
<div className="mt-4 space-y-3">
|
||||
{searchResult.results.map((p) => (
|
||||
<button
|
||||
key={p.id}
|
||||
onClick={() => navigatePage(p.slug)}
|
||||
className="block w-full max-w-4xl rounded-xl border p-5 text-left hover:bg-muted"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (p.page_type !== "chunk") navigatePage(p.slug);
|
||||
}}
|
||||
className={`block w-full max-w-4xl rounded-xl border p-5 text-left ${p.page_type === "chunk" ? "cursor-default" : "hover:bg-muted"}`}
|
||||
>
|
||||
<div className="font-medium">
|
||||
{p.title}
|
||||
{p.page_type === "chunk" && (
|
||||
<Badge variant="secondary" className="ml-2">
|
||||
知识片段
|
||||
</Badge>
|
||||
)}
|
||||
<span className="float-right text-xs text-muted-foreground">
|
||||
{p.score?.toFixed(4)}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-2 line-clamp-3 text-sm text-muted-foreground">
|
||||
{p.summary || p.content_markdown}
|
||||
{p.matched_section?.content ||
|
||||
p.matched_content ||
|
||||
p.content_markdown}
|
||||
</p>
|
||||
</button>
|
||||
))}
|
||||
@@ -425,6 +521,111 @@ export default function AssistantKnowledgePage() {
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
{editingBase && (
|
||||
<EditAssistantBaseDialog
|
||||
key={editingBase.id}
|
||||
base={editingBase}
|
||||
pending={actions.updateBase.isPending}
|
||||
onClose={() => setEditingBase(null)}
|
||||
onSave={async (input) => {
|
||||
try {
|
||||
await actions.updateBase.mutateAsync({
|
||||
id: editingBase.id,
|
||||
...input,
|
||||
});
|
||||
setEditingBase(null);
|
||||
toast.success("助手知识库信息已保存");
|
||||
} catch (error) {
|
||||
toast.error((error as Error).message);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function EditAssistantBaseDialog({
|
||||
base,
|
||||
pending,
|
||||
onClose,
|
||||
onSave,
|
||||
}: {
|
||||
base: AssistantKnowledgeBase;
|
||||
pending: boolean;
|
||||
onClose: () => void;
|
||||
onSave: (input: { name: string; description: string }) => Promise<void>;
|
||||
}) {
|
||||
const [name, setName] = useState(base.name);
|
||||
const [description, setDescription] = useState(base.description || "");
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open
|
||||
onOpenChange={(open) => {
|
||||
if (!open && !pending) onClose();
|
||||
}}
|
||||
>
|
||||
<DialogContent>
|
||||
<form
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (!pending && name.trim()) {
|
||||
void onSave({
|
||||
name: name.trim(),
|
||||
description: description.trim(),
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle>编辑助手知识库</DialogTitle>
|
||||
<DialogDescription>
|
||||
修改知识库名称和描述。知识内容、向量和关联关系不会受到影响。
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium" htmlFor="assistant-base-name">
|
||||
名称
|
||||
</label>
|
||||
<Input
|
||||
id="assistant-base-name"
|
||||
value={name}
|
||||
onChange={(event) => setName(event.target.value)}
|
||||
maxLength={255}
|
||||
disabled={pending}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label
|
||||
className="text-sm font-medium"
|
||||
htmlFor="assistant-base-description"
|
||||
>
|
||||
描述
|
||||
</label>
|
||||
<Textarea
|
||||
id="assistant-base-description"
|
||||
value={description}
|
||||
onChange={(event) => setDescription(event.target.value)}
|
||||
maxLength={2048}
|
||||
rows={4}
|
||||
disabled={pending}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="outline" disabled={pending} onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="submit" disabled={pending || !name.trim()}>
|
||||
{pending && <Loader2 className="mr-2 size-4 animate-spin" />}
|
||||
保存
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,55 @@
|
||||
import { BookOpenCheck, Sparkles } from "lucide-react";
|
||||
import { useMemo } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
import { SkillSettingsPage } from "@/components/workspace/settings/skill-settings-page";
|
||||
import { SkillKnowledgePanel } from "@/components/workspace/skills/SkillKnowledgePanel";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
|
||||
export default function SkillsPage() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const tab = useMemo(
|
||||
() => (searchParams.get("tab") === "knowledge" ? "knowledge" : "skills"),
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
const changeTab = (value: string) => {
|
||||
const next = new URLSearchParams(searchParams);
|
||||
if (value === "knowledge") next.set("tab", "knowledge");
|
||||
else next.delete("tab");
|
||||
setSearchParams(next, { replace: true });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex size-full min-h-0 flex-col overflow-auto p-6">
|
||||
<SkillSettingsPage />
|
||||
</div>
|
||||
<Tabs
|
||||
value={tab}
|
||||
onValueChange={changeTab}
|
||||
className="flex size-full min-h-0 flex-col gap-0 overflow-hidden"
|
||||
>
|
||||
<header className="flex flex-wrap items-center justify-between gap-4 border-b bg-background px-6 py-4">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold">技能</h1>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
浏览和维护技能,也可以把多个技能的知识一次归纳到一个 Wiki 知识库。
|
||||
</p>
|
||||
</div>
|
||||
<TabsList>
|
||||
<TabsTrigger value="skills">
|
||||
<Sparkles className="mr-2 size-4" />
|
||||
技能列表
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="knowledge">
|
||||
<BookOpenCheck className="mr-2 size-4" />
|
||||
归纳到知识库
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</header>
|
||||
<TabsContent value="skills" className="mt-0 min-h-0 flex-1 overflow-auto p-6">
|
||||
<SkillSettingsPage embedded />
|
||||
</TabsContent>
|
||||
<TabsContent value="knowledge" className="mt-0 min-h-0 flex-1 overflow-hidden">
|
||||
<SkillKnowledgePanel />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
@@ -1,85 +1,92 @@
|
||||
import { useEffect, useState, type CSSProperties, type ReactNode } from 'react';
|
||||
import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom';
|
||||
import { useEffect, useState, type CSSProperties, type ReactNode } from "react";
|
||||
import {
|
||||
Navigate,
|
||||
Route,
|
||||
Routes,
|
||||
useLocation,
|
||||
useParams,
|
||||
} from "react-router-dom";
|
||||
|
||||
import { getStoredAuth } from '@/core/auth';
|
||||
import { getAPIClient } from '@/core/api';
|
||||
import { isSentimentAgentVisible } from '@/core/sentiment-agent/config';
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { getAPIClient } from "@/core/api";
|
||||
import { isSentimentAgentVisible } from "@/core/sentiment-agent/config";
|
||||
import {
|
||||
resolveChatsIframeEntryRedirect,
|
||||
resolveStandardChatFallback,
|
||||
} from '@/core/page-layout/chats-iframe-route';
|
||||
import { isEmbeddedHost } from '@/core/embed/frame-context';
|
||||
} from "@/core/page-layout/chats-iframe-route";
|
||||
import { isEmbeddedHost } from "@/core/embed/frame-context";
|
||||
|
||||
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
|
||||
import { PromptInputProvider } from '@/components/ai-elements/prompt-input';
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
|
||||
import {
|
||||
CompactShortcutButtons,
|
||||
LayoutModeSwitcher,
|
||||
ThemeSwitcher,
|
||||
} from '@/components/workspace/appearance-controls';
|
||||
import { WorkspaceSidebar } from '@/components/workspace/workspace-sidebar';
|
||||
import { UserIdentityBadge } from '@/components/workspace/user-identity-badge';
|
||||
import { CommandPalette } from '@/components/workspace/command-palette';
|
||||
import { Toaster } from 'sonner';
|
||||
import { SubtasksProvider } from '@/core/tasks/context';
|
||||
import { ArtifactsProvider } from '@/components/workspace/artifacts';
|
||||
import { DocumentRewritePresentationProvider } from '@/core/document-rewrite/context';
|
||||
} from "@/components/workspace/appearance-controls";
|
||||
import { WorkspaceSidebar } from "@/components/workspace/workspace-sidebar";
|
||||
import { UserIdentityBadge } from "@/components/workspace/user-identity-badge";
|
||||
import { CommandPalette } from "@/components/workspace/command-palette";
|
||||
import { Toaster } from "sonner";
|
||||
import { SubtasksProvider } from "@/core/tasks/context";
|
||||
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
||||
import { DocumentRewritePresentationProvider } from "@/core/document-rewrite/context";
|
||||
|
||||
import { RouteBaseProvider } from '@/core/route-base';
|
||||
import { agentRefOfThread } from '@/core/threads/utils';
|
||||
import { RouteBaseProvider } from "@/core/route-base";
|
||||
import { agentRefOfThread } from "@/core/threads/utils";
|
||||
|
||||
import ChatsPage from './ChatsPage';
|
||||
import ChatPage from './ChatPage';
|
||||
import ArtifactLibraryPage from './ArtifactLibraryPage';
|
||||
import IframeChatPage from './IframeChatPage';
|
||||
import AgentsPage from './AgentsPage';
|
||||
import AgentChatPage from './AgentChatPage';
|
||||
import SentimentAgentChatPage from './SentimentAgentChatPage';
|
||||
import NewAgentPage from './NewAgentPage';
|
||||
import AdminAgentsPage from './AdminAgentsPage';
|
||||
import AdminScheduledTasksPage from './AdminScheduledTasksPage';
|
||||
import AdminSkillsPage from './AdminSkillsPage';
|
||||
import ScheduledTaskRunDetailPage from './ScheduledTaskRunDetailPage';
|
||||
import ScheduledTasksPage from './ScheduledTasksPage';
|
||||
import LlmWikiKnowledgePage from './LlmWikiKnowledgePage';
|
||||
import AssistantKnowledgePage from './AssistantKnowledgePage';
|
||||
import WeKnoraWikiManagementPage from '@/strategy-components/components/resource-management/llmwiki/WeKnoraWikiManagementPage';
|
||||
import WeKnoraWikiPageView from '@/strategy-components/components/resource-management/llmwiki/WeKnoraWikiPageView';
|
||||
import MarkdownDocxEditorPage from './MarkdownDocxEditorPage';
|
||||
import LlmMetricsPage from './LlmMetricsPage';
|
||||
import CheckpointMigrationPage from './CheckpointMigrationPage';
|
||||
import MemoryPage from './MemoryPage';
|
||||
import PromptPrefixSettingsPage from './PromptPrefixSettingsPage';
|
||||
import PrivateSquareSettingsPage from './PrivateSquareSettingsPage';
|
||||
import ModelConcurrencySettingsPage from './ModelConcurrencySettingsPage';
|
||||
import ModelManagementPage from './ModelManagementPage';
|
||||
import PublishSquaresSettingsPage from './PublishSquaresSettingsPage';
|
||||
import SkillCompressionSettingsPage from './SkillCompressionSettingsPage';
|
||||
import SkillEvolutionPage from './SkillEvolutionPage';
|
||||
import SkillsPage from './SkillsPage';
|
||||
import UsersPage from './UsersPage';
|
||||
import AdminUserActivityPage from './AdminUserActivityPage';
|
||||
import AdminMemoryPage from './AdminMemoryPage';
|
||||
import AdminUserHubPage from './AdminUserHubPage';
|
||||
import TagsPage from './TagsPage';
|
||||
import PositionsPage from './PositionsPage';
|
||||
import PositionRolesPage from './PositionRolesPage';
|
||||
import PluginManagementPage from './PluginManagementPage';
|
||||
import RecommendedQuestionsPage from './RecommendedQuestionsPage';
|
||||
import AIWritingPage from '@/open-canvas/pages/AIWritingPage';
|
||||
import DeepResearchPage from './DeepResearchPage';
|
||||
import ReportStructureCreatePage from './deep-research/ReportStructureCreatePage';
|
||||
import EnterpriseResearchPage from './EnterpriseResearchPage';
|
||||
import StudioNotebooksPage from './StudioNotebooksPage';
|
||||
import StudioNotebookDetailPage from './StudioNotebookDetailPage';
|
||||
import RoundtablePlanningPage from '@/roundtable-planning/pages/RoundtablePlanningPage';
|
||||
import PositionRoundtablePage from '@/position-roundtable/pages/PositionRoundtablePage';
|
||||
import EightBfRoundtablePage from '@/eightbf-roundtable/pages/EightBfRoundtablePage';
|
||||
import BusinessChainEditorPage from '@/roundtable-planning/pages/BusinessChainEditorPage';
|
||||
import BusinessChainListPage from '@/roundtable-planning/pages/BusinessChainListPage';
|
||||
import DispatchChainPreviewPage from '@/roundtable-planning/pages/DispatchChainPreviewPage';
|
||||
import '@/roundtable-planning/styles/roundtable-planning.css';
|
||||
import { cn } from '@/lib/utils';
|
||||
import ChatsPage from "./ChatsPage";
|
||||
import ChatPage from "./ChatPage";
|
||||
import ArtifactLibraryPage from "./ArtifactLibraryPage";
|
||||
import IframeChatPage from "./IframeChatPage";
|
||||
import AgentsPage from "./AgentsPage";
|
||||
import AgentChatPage from "./AgentChatPage";
|
||||
import SentimentAgentChatPage from "./SentimentAgentChatPage";
|
||||
import NewAgentPage from "./NewAgentPage";
|
||||
import AdminAgentsPage from "./AdminAgentsPage";
|
||||
import AdminScheduledTasksPage from "./AdminScheduledTasksPage";
|
||||
import AdminSkillsPage from "./AdminSkillsPage";
|
||||
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
|
||||
import ScheduledTasksPage from "./ScheduledTasksPage";
|
||||
import LlmWikiKnowledgePage from "./LlmWikiKnowledgePage";
|
||||
import AssistantKnowledgePage from "./AssistantKnowledgePage";
|
||||
import WeKnoraWikiManagementPage from "@/strategy-components/components/resource-management/llmwiki/WeKnoraWikiManagementPage";
|
||||
import WeKnoraWikiPageView from "@/strategy-components/components/resource-management/llmwiki/WeKnoraWikiPageView";
|
||||
import WeKnoraPackageTransfersPage from "@/strategy-components/components/resource-management/llmwiki/WeKnoraPackageTransfersPage";
|
||||
import MarkdownDocxEditorPage from "./MarkdownDocxEditorPage";
|
||||
import LlmMetricsPage from "./LlmMetricsPage";
|
||||
import CheckpointMigrationPage from "./CheckpointMigrationPage";
|
||||
import MemoryPage from "./MemoryPage";
|
||||
import PromptPrefixSettingsPage from "./PromptPrefixSettingsPage";
|
||||
import PrivateSquareSettingsPage from "./PrivateSquareSettingsPage";
|
||||
import ModelConcurrencySettingsPage from "./ModelConcurrencySettingsPage";
|
||||
import ModelManagementPage from "./ModelManagementPage";
|
||||
import PublishSquaresSettingsPage from "./PublishSquaresSettingsPage";
|
||||
import SkillCompressionSettingsPage from "./SkillCompressionSettingsPage";
|
||||
import SkillEvolutionPage from "./SkillEvolutionPage";
|
||||
import SkillsPage from "./SkillsPage";
|
||||
import UsersPage from "./UsersPage";
|
||||
import AdminUserActivityPage from "./AdminUserActivityPage";
|
||||
import AdminMemoryPage from "./AdminMemoryPage";
|
||||
import AdminUserHubPage from "./AdminUserHubPage";
|
||||
import TagsPage from "./TagsPage";
|
||||
import PositionsPage from "./PositionsPage";
|
||||
import PositionRolesPage from "./PositionRolesPage";
|
||||
import PluginManagementPage from "./PluginManagementPage";
|
||||
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
|
||||
import AIWritingPage from "@/open-canvas/pages/AIWritingPage";
|
||||
import DeepResearchPage from "./DeepResearchPage";
|
||||
import ReportStructureCreatePage from "./deep-research/ReportStructureCreatePage";
|
||||
import EnterpriseResearchPage from "./EnterpriseResearchPage";
|
||||
import StudioNotebooksPage from "./StudioNotebooksPage";
|
||||
import StudioNotebookDetailPage from "./StudioNotebookDetailPage";
|
||||
import RoundtablePlanningPage from "@/roundtable-planning/pages/RoundtablePlanningPage";
|
||||
import PositionRoundtablePage from "@/position-roundtable/pages/PositionRoundtablePage";
|
||||
import EightBfRoundtablePage from "@/eightbf-roundtable/pages/EightBfRoundtablePage";
|
||||
import BusinessChainEditorPage from "@/roundtable-planning/pages/BusinessChainEditorPage";
|
||||
import BusinessChainListPage from "@/roundtable-planning/pages/BusinessChainListPage";
|
||||
import DispatchChainPreviewPage from "@/roundtable-planning/pages/DispatchChainPreviewPage";
|
||||
import "@/roundtable-planning/styles/roundtable-planning.css";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function NotebookDetailPageWithKey() {
|
||||
const { notebookId } = useParams<{ notebookId: string }>();
|
||||
@@ -94,12 +101,12 @@ function NewAgentPageWithKey() {
|
||||
|
||||
function shouldShowCompactTopActions(pathname: string): boolean {
|
||||
return (
|
||||
pathname === '/page/workspace/agents' ||
|
||||
pathname === '/page/workspace/skills' ||
|
||||
pathname === '/page/workspace/memory' ||
|
||||
pathname === '/page/workspace/library' ||
|
||||
pathname === '/page/workspace/knowledge' ||
|
||||
pathname.startsWith('/page/workspace/knowledge/')
|
||||
pathname === "/page/workspace/agents" ||
|
||||
pathname === "/page/workspace/skills" ||
|
||||
pathname === "/page/workspace/memory" ||
|
||||
pathname === "/page/workspace/library" ||
|
||||
pathname === "/page/workspace/knowledge" ||
|
||||
pathname.startsWith("/page/workspace/knowledge/")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -157,47 +164,52 @@ export function WorkspaceLayout({
|
||||
// 全量模式下通用问答(/page/workspace/chats*)的历史侧栏默认展开;其余紧凑页
|
||||
// (如智能体对话,为聊天区更宽而默认收起)维持原默认。
|
||||
const pathname = useLocation().pathname;
|
||||
const isGeneralQa = pathname.startsWith('/page/workspace/chats');
|
||||
const isGeneralQa = pathname.startsWith("/page/workspace/chats");
|
||||
const showCompactTopActions =
|
||||
headerHidden && !compactActionsHidden && shouldShowCompactTopActions(pathname);
|
||||
headerHidden &&
|
||||
!compactActionsHidden &&
|
||||
shouldShowCompactTopActions(pathname);
|
||||
|
||||
const pageSidebarWidth = pageSidebarHidden
|
||||
? '0rem'
|
||||
? "0rem"
|
||||
: pageSidebarDark
|
||||
? pageSidebarCollapsed
|
||||
? '0rem'
|
||||
: '118px'
|
||||
? "0rem"
|
||||
: "118px"
|
||||
: pageSidebarCollapsed
|
||||
? '4rem'
|
||||
: '16rem';
|
||||
? "4rem"
|
||||
: "16rem";
|
||||
|
||||
return (
|
||||
<SidebarProvider
|
||||
className={[
|
||||
'relative h-full w-full overflow-x-hidden',
|
||||
'[&_[data-slot=sidebar-container]]:absolute',
|
||||
'[&_[data-slot=sidebar-container]]:left-0',
|
||||
'[&_[data-slot=sidebar-container]]:top-0',
|
||||
].join(' ')}
|
||||
"relative h-full w-full overflow-x-hidden",
|
||||
"[&_[data-slot=sidebar-container]]:absolute",
|
||||
"[&_[data-slot=sidebar-container]]:left-0",
|
||||
"[&_[data-slot=sidebar-container]]:top-0",
|
||||
].join(" ")}
|
||||
style={
|
||||
{
|
||||
'--page-sidebar-width': pageSidebarWidth,
|
||||
'--header-height': headerHidden ? '0rem' : '4rem',
|
||||
"--page-sidebar-width": pageSidebarWidth,
|
||||
"--header-height": headerHidden ? "0rem" : "4rem",
|
||||
} as CSSProperties
|
||||
}
|
||||
// Agent and general-chat routes share this layout component. Keep their
|
||||
// sidebar state separate: otherwise React preserves the collapsed agent
|
||||
// state when a history item switches to `/chats/:thread_id`, while the
|
||||
// new page's header button is meant to control GeneralQaSidebar.
|
||||
key={`${String(compactWorkspaceSidebar)}:${isGeneralQa ? 'general' : 'workspace'}`}
|
||||
key={`${String(compactWorkspaceSidebar)}:${isGeneralQa ? "general" : "workspace"}`}
|
||||
data-page-sidebar-collapsed={pageSidebarCollapsed}
|
||||
defaultOpen={
|
||||
forceWorkspaceSidebarCollapsed
|
||||
? false
|
||||
: (defaultHistorySidebarOpen ?? (isGeneralQa || !compactWorkspaceSidebar))
|
||||
: (defaultHistorySidebarOpen ??
|
||||
(isGeneralQa || !compactWorkspaceSidebar))
|
||||
}
|
||||
open={forceWorkspaceSidebarCollapsed ? false : undefined}
|
||||
onOpenChange={forceWorkspaceSidebarCollapsed ? () => undefined : undefined}
|
||||
onOpenChange={
|
||||
forceWorkspaceSidebarCollapsed ? () => undefined : undefined
|
||||
}
|
||||
disableToggle={forceWorkspaceSidebarCollapsed}
|
||||
>
|
||||
{!workspaceSidebarHidden && (
|
||||
@@ -207,7 +219,7 @@ export function WorkspaceLayout({
|
||||
/>
|
||||
)}
|
||||
<SidebarInset
|
||||
className={cn('min-w-0', insetOverflowHidden && 'overflow-hidden')}
|
||||
className={cn("min-w-0", insetOverflowHidden && "overflow-hidden")}
|
||||
>
|
||||
{showCompactTopActions ? (
|
||||
<>
|
||||
@@ -244,9 +256,14 @@ export function ChatRuntime({ children }: { children: ReactNode }) {
|
||||
*/
|
||||
function NewChatContent() {
|
||||
const location = useLocation();
|
||||
const agentId = new URLSearchParams(location.search).get('agent');
|
||||
const agentId = new URLSearchParams(location.search).get("agent");
|
||||
if (agentId) {
|
||||
return <AgentChatPage key={`${agentId}:${location.key}`} embeddedAgentId={agentId} />;
|
||||
return (
|
||||
<AgentChatPage
|
||||
key={`${agentId}:${location.key}`}
|
||||
embeddedAgentId={agentId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <ChatPage />;
|
||||
}
|
||||
@@ -393,8 +410,8 @@ function AgentAwareChatThreadContent() {
|
||||
};
|
||||
// Task-bound threads need their task host to preserve the purpose gate,
|
||||
// action partitioning, and other task-specific controls.
|
||||
const isTaskThread = typeof record.metadata?.taskId === 'string';
|
||||
setAgentId(isTaskThread ? null : agentRefOfThread(record) ?? null);
|
||||
const isTaskThread = typeof record.metadata?.taskId === "string";
|
||||
setAgentId(isTaskThread ? null : (agentRefOfThread(record) ?? null));
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setAgentId(null);
|
||||
@@ -537,11 +554,18 @@ export default function WorkspaceRoutes({
|
||||
/>
|
||||
<Route
|
||||
path="chats_iframe/new"
|
||||
element={<IframeChatEntryRoute layoutProps={layoutProps} hasThreadParam={false} />}
|
||||
element={
|
||||
<IframeChatEntryRoute
|
||||
layoutProps={layoutProps}
|
||||
hasThreadParam={false}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="chats_iframe/:thread_id"
|
||||
element={<IframeChatEntryRoute layoutProps={layoutProps} hasThreadParam />}
|
||||
element={
|
||||
<IframeChatEntryRoute layoutProps={layoutProps} hasThreadParam />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="agents"
|
||||
@@ -575,7 +599,10 @@ export default function WorkspaceRoutes({
|
||||
path="agents/sentiment-analysis/chats"
|
||||
element={
|
||||
isSentimentAgentVisible() ? (
|
||||
<Navigate to="/page/workspace/agents/sentiment-analysis/chats/new" replace />
|
||||
<Navigate
|
||||
to="/page/workspace/agents/sentiment-analysis/chats/new"
|
||||
replace
|
||||
/>
|
||||
) : (
|
||||
<Navigate to="/page/workspace/agents" replace />
|
||||
)
|
||||
@@ -605,7 +632,9 @@ export default function WorkspaceRoutes({
|
||||
<AgentChatPage
|
||||
showAgentList
|
||||
compactAppearanceActions={
|
||||
headerHidden && !compactActionsHidden ? <CompactAppearanceActions /> : undefined
|
||||
headerHidden && !compactActionsHidden ? (
|
||||
<CompactAppearanceActions />
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
</ChatRuntime>
|
||||
@@ -704,7 +733,9 @@ export default function WorkspaceRoutes({
|
||||
element={
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<ChatRuntime>
|
||||
<RoundtablePlanningPage compactChrome={headerHidden && !compactActionsHidden} />
|
||||
<RoundtablePlanningPage
|
||||
compactChrome={headerHidden && !compactActionsHidden}
|
||||
/>
|
||||
</ChatRuntime>
|
||||
</WorkspaceLayout>
|
||||
}
|
||||
@@ -714,7 +745,9 @@ export default function WorkspaceRoutes({
|
||||
element={
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<ChatRuntime>
|
||||
<EightBfRoundtablePage compactChrome={headerHidden && !compactActionsHidden} />
|
||||
<EightBfRoundtablePage
|
||||
compactChrome={headerHidden && !compactActionsHidden}
|
||||
/>
|
||||
</ChatRuntime>
|
||||
</WorkspaceLayout>
|
||||
}
|
||||
@@ -724,7 +757,9 @@ export default function WorkspaceRoutes({
|
||||
element={
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<ChatRuntime>
|
||||
<PositionRoundtablePage compactChrome={headerHidden && !compactActionsHidden} />
|
||||
<PositionRoundtablePage
|
||||
compactChrome={headerHidden && !compactActionsHidden}
|
||||
/>
|
||||
</ChatRuntime>
|
||||
</WorkspaceLayout>
|
||||
}
|
||||
@@ -794,6 +829,14 @@ export default function WorkspaceRoutes({
|
||||
</WorkspaceLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="knowledge/:noteId/packages"
|
||||
element={
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<WeKnoraPackageTransfersPage />
|
||||
</WorkspaceLayout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="knowledge/markdown-editor"
|
||||
element={
|
||||
@@ -818,7 +861,9 @@ export default function WorkspaceRoutes({
|
||||
path="scheduled/tasks"
|
||||
element={
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<ScheduledTasksPage compactChrome={headerHidden && !compactActionsHidden} />
|
||||
<ScheduledTasksPage
|
||||
compactChrome={headerHidden && !compactActionsHidden}
|
||||
/>
|
||||
</WorkspaceLayout>
|
||||
}
|
||||
/>
|
||||
@@ -834,7 +879,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps} pageSidebarHidden>
|
||||
<AdminUserHubPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -859,7 +904,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin/scheduled-tasks"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<AdminScheduledTasksPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -871,7 +916,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin/agents"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<AdminAgentsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -883,7 +928,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin/skills"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<AdminSkillsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -903,7 +948,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin/plugins"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<PluginManagementPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -915,7 +960,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin/positions"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<PositionsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -927,7 +972,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin/position-roles"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<PositionRolesPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -939,7 +984,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/recommended-questions"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<RecommendedQuestionsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -951,7 +996,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/prompt-prefix"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<PromptPrefixSettingsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -963,7 +1008,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/private-square"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<PrivateSquareSettingsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -975,7 +1020,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="admin/models"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<ModelManagementPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -987,7 +1032,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/model-concurrency"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<ModelConcurrencySettingsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -999,7 +1044,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/publish-squares"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<PublishSquaresSettingsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -1011,7 +1056,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/skill-compression"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<SkillCompressionSettingsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -1023,7 +1068,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/llm-metrics"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<LlmMetricsPage />
|
||||
</WorkspaceLayout>
|
||||
@@ -1035,7 +1080,7 @@ export default function WorkspaceRoutes({
|
||||
<Route
|
||||
path="settings/checkpoint-migration"
|
||||
element={
|
||||
getStoredAuth()?.system_role === 'admin' ? (
|
||||
getStoredAuth()?.system_role === "admin" ? (
|
||||
<WorkspaceLayout {...layoutProps}>
|
||||
<CheckpointMigrationPage />
|
||||
</WorkspaceLayout>
|
||||
|
||||
Reference in new issue
Block a user