feat: 智能体创建流程优化与管理员记忆页面

- 创建智能体页面:保存后自动跳转列表页、技能列表增加搜索过滤框
- Bootstrap 模式:开放全部技能可见性,注入专属提示词(skill_list 匹配意图、禁止 skill_manage)
- 管理员记忆页面:新增 AdminMemoryPage 及路由,支持查看/编辑用户记忆条目
- 内存配置与管理员用户接口同步更新

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
xuhdandClaude Sonnet 4.6 committed 2026-05-21 11:43:59 +08:00
1 parent 18c2a4122f
commit 3748513996
12 files changed
+692 -143

No files matched your search

@@ -0,0 +1,5 @@
import AdminMemoryComponent from "@/components/workspace/admin/admin-memory-page";
export default function AdminMemoryPage() {
return <AdminMemoryComponent />;
}
+30 -2
View File
@@ -5,6 +5,7 @@ import {
CheckCircleIcon,
InfoIcon,
SaveIcon,
SearchIcon,
} from "lucide-react";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useMemo, useState } from "react";
@@ -76,6 +77,7 @@ export default function NewAgentPage() {
const [selectedSkills, setSelectedSkills] = useState<string[]>([]);
const [isSkillSelectionTouched, setIsSkillSelectionTouched] = useState(false);
const [detailSkillName, setDetailSkillName] = useState<string | null>(null);
const [skillSearch, setSkillSearch] = useState("");
const [threadPrepared, setThreadPrepared] = useState(false);
const { skills, isLoading: isSkillsLoading } = useSkills();
const { models, isLoading: isModelsLoading } = useModels();
@@ -85,6 +87,16 @@ export default function NewAgentPage() {
[skills],
);
const filteredSkills = useMemo(() => {
const q = skillSearch.trim().toLowerCase();
if (!q) return enabledSkills;
return enabledSkills.filter(
(skill) =>
skill.name.toLowerCase().includes(q) ||
(skill.description ?? "").toLowerCase().includes(q),
);
}, [enabledSkills, skillSearch]);
useEffect(() => {
if (isSkillSelectionTouched) {
return;
@@ -230,7 +242,8 @@ export default function NewAgentPage() {
return;
}
toast.success(`智能体「${saved.name}」已保存`);
}, [ensureAgent]);
router.push("/page/workspace/agents");
}, [ensureAgent, router]);
const handleChatSubmit = useCallback(
async (text: string) => {
@@ -439,6 +452,17 @@ export default function NewAgentPage() {
已选 {selectedSkills.length} 个
</span>
</div>
{enabledSkills.length > 0 && (
<div className="relative">
<SearchIcon className="text-muted-foreground absolute left-2 top-1/2 size-3.5 -translate-y-1/2" />
<Input
placeholder="搜索技能名称或描述…"
value={skillSearch}
onChange={(e) => setSkillSearch(e.currentTarget.value)}
className="h-8 pl-7 text-xs"
/>
</div>
)}
<div className="max-h-[240px] overflow-y-auto rounded-md border p-2">
{isSkillsLoading ? (
<p className="text-muted-foreground text-sm">技能加载中...</p>
@@ -446,9 +470,13 @@ export default function NewAgentPage() {
<p className="text-muted-foreground text-sm">
当前没有可用技能。
</p>
) : filteredSkills.length === 0 ? (
<p className="text-muted-foreground text-sm">
没有匹配的技能。
</p>
) : (
<div className="flex flex-wrap gap-2">
{enabledSkills.map((skill) => {
{filteredSkills.map((skill) => {
const checked = selectedSkills.includes(skill.name);
return (
<div
@@ -28,6 +28,7 @@ import SkillEvolutionPage from "./SkillEvolutionPage";
import SkillsPage from "./SkillsPage";
import UsersPage from "./UsersPage";
import AdminUserActivityPage from "./AdminUserActivityPage";
import AdminMemoryPage from "./AdminMemoryPage";
import TagsPage from "./TagsPage";
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
@@ -223,6 +224,18 @@ export default function WorkspaceRoutes({
)
}
/>
<Route
path="admin/memory"
element={
getStoredAuth()?.system_role === "admin" ? (
<WorkspaceLayout {...layoutProps}>
<AdminMemoryPage />
</WorkspaceLayout>
) : (
<Navigate to="/page/workspace/chats/new" replace />
)
}
/>
<Route
path="admin/tags"
element={