diff --git a/src/app/conversations/[projectId]/page.tsx b/src/app/conversations/[projectId]/page.tsx index 39bda48..335cc45 100644 --- a/src/app/conversations/[projectId]/page.tsx +++ b/src/app/conversations/[projectId]/page.tsx @@ -5,6 +5,7 @@ import { AppShell, ChatBubble, ChatComposer, + MasterAgentChatMenu, MasterIdentityPill, PageNav, ProjectHeaderActions, @@ -45,7 +46,18 @@ export default async function ProjectChatPage({ : undefined} + rightNode={ + detail.masterIdentity ? ( +
+ + {detail.project.id === "master-agent" ? ( + + ) : null} +
+ ) : detail.project.id === "master-agent" ? ( + + ) : undefined + } />
diff --git a/src/components/app-ui.tsx b/src/components/app-ui.tsx index c93e343..b089290 100644 --- a/src/components/app-ui.tsx +++ b/src/components/app-ui.tsx @@ -14,6 +14,7 @@ import { popAppHistoryEntry, resolveAppBackAction, } from "@/lib/boss-app-client"; +import { getMasterAgentChatMenuItems } from "@/lib/master-agent-chat-menu"; import { extractApprovedTargetProjectIds, summarizeDispatchPlan, @@ -810,6 +811,52 @@ export function MasterIdentityPill({ identity }: { identity: MasterIdentitySumma ); } +export function MasterAgentChatMenu({ projectId }: { projectId: string }) { + const router = useRouter(); + const items = getMasterAgentChatMenuItems(projectId); + + if (items.length === 0) { + return null; + } + + return ( +
+ + … + +
+ {items.map((item) => + item.href ? ( + + {item.label} + + ) : ( + + ), + )} +
+
+ ); +} + type PendingDispatchPlanState = { planId: string; summary?: string; diff --git a/src/components/master-agent-prompt-memory-client.tsx b/src/components/master-agent-prompt-memory-client.tsx index d3f4270..bfeae9c 100644 --- a/src/components/master-agent-prompt-memory-client.tsx +++ b/src/components/master-agent-prompt-memory-client.tsx @@ -326,7 +326,7 @@ export function MasterAgentPromptMemoryClient({ return (
-
+
主 Agent 提示词
管理员全局主提示词不可被覆盖;用户提示词和当前对话提示词只会追加在后面。 @@ -453,7 +453,7 @@ export function MasterAgentPromptMemoryClient({
-
+
新增记忆
支持自动沉淀后的手动增补、编辑和归档。项目记忆需要绑定到真实项目,而不是 master-agent 会话本身。 diff --git a/src/lib/master-agent-chat-menu.ts b/src/lib/master-agent-chat-menu.ts new file mode 100644 index 0000000..eac069b --- /dev/null +++ b/src/lib/master-agent-chat-menu.ts @@ -0,0 +1,30 @@ +export type MasterAgentChatMenuItem = { + key: "prompt" | "memory" | "refresh"; + label: string; + href?: string; + action?: "refresh"; +}; + +export function getMasterAgentChatMenuItems(projectId: string): MasterAgentChatMenuItem[] { + if (projectId !== "master-agent") { + return []; + } + + return [ + { + key: "prompt", + label: "提示词", + href: "/me/master-agent#prompt-section", + }, + { + key: "memory", + label: "记忆", + href: "/me/master-agent#memory-section", + }, + { + key: "refresh", + label: "刷新", + action: "refresh", + }, + ]; +} diff --git a/tests/master-agent-chat-menu.test.ts b/tests/master-agent-chat-menu.test.ts new file mode 100644 index 0000000..87bf884 --- /dev/null +++ b/tests/master-agent-chat-menu.test.ts @@ -0,0 +1,19 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { getMasterAgentChatMenuItems } from "../src/lib/master-agent-chat-menu"; + +test("master-agent 聊天页菜单包含提示词、记忆和刷新", () => { + const items = getMasterAgentChatMenuItems("master-agent"); + assert.deepEqual( + items.map((item) => item.key), + ["prompt", "memory", "refresh"], + ); + assert.equal(items[0]?.href, "/me/master-agent#prompt-section"); + assert.equal(items[1]?.href, "/me/master-agent#memory-section"); + assert.equal(items[2]?.action, "refresh"); +}); + +test("普通会话不返回主 Agent 专属菜单", () => { + const items = getMasterAgentChatMenuItems("boss-console"); + assert.deepEqual(items, []); +});