From b3f73287786bf379eec3073913a2ddeb75f1a4b3 Mon Sep 17 00:00:00 2001 From: iven Date: Sat, 11 Apr 2026 12:51:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20'=E6=88=91=E7=9C=BC=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E4=BD=A0'=20=E5=8F=8C=E6=BA=90=E6=B8=B2=E6=9F=93=20?= =?UTF-8?q?=E2=80=94=20=E9=9D=99=E6=80=81Clone=20+=20=E5=8A=A8=E6=80=81Use?= =?UTF-8?q?rProfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RightPanel 增加 userProfile state + fetch 逻辑 - 对话结束后通过 CustomEvent 触发画像刷新 - UserProfile 字段: 行业/角色/沟通偏好/近期话题 桥接 identity 系统 → 前端面板。 --- desktop/src/components/RightPanel.tsx | 45 +++++++++++++++++++++++++++ desktop/src/store/chat/streamStore.ts | 6 ++++ 2 files changed, 51 insertions(+) diff --git a/desktop/src/components/RightPanel.tsx b/desktop/src/components/RightPanel.tsx index d753779..d2c85c5 100644 --- a/desktop/src/components/RightPanel.tsx +++ b/desktop/src/components/RightPanel.tsx @@ -8,6 +8,8 @@ import { useConfigStore } from '../store/configStore'; import { toChatAgent, useChatStore, type CodeBlock } from '../store/chatStore'; import { useConversationStore } from '../store/chat/conversationStore'; import { intelligenceClient, type IdentitySnapshot } from '../lib/intelligence-client'; +import { invoke } from '@tauri-apps/api/core'; +import type { AgentInfo } from '../lib/kernel-types'; import { Wifi, WifiOff, Bot, BarChart3, Plug, RefreshCw, MessageSquare, Cpu, FileText, User, Activity, Brain, @@ -143,6 +145,9 @@ export function RightPanel({ simpleMode = false }: RightPanelProps) { const [restoringSnapshotId, setRestoringSnapshotId] = useState(null); const [confirmRestoreId, setConfirmRestoreId] = useState(null); + // UserProfile from memory store (dynamic, learned from conversations) + const [userProfile, setUserProfile] = useState | null>(null); + const connected = connectionState === 'connected'; const selectedClone = useMemo( () => clones.find((clone) => clone.id === currentAgent?.id), @@ -166,6 +171,28 @@ export function RightPanel({ simpleMode = false }: RightPanelProps) { } }, [connected]); + // Fetch UserProfile from agent data (includes memory-learned profile) + useEffect(() => { + if (!currentAgent?.id) return; + invoke('agent_get', { agentId: currentAgent.id }) + .then(data => setUserProfile(data?.userProfile ?? null)) + .catch(() => setUserProfile(null)); + }, [currentAgent?.id]); + + // Listen for profile updates after conversations + useEffect(() => { + const handler = (e: Event) => { + const detail = (e as CustomEvent).detail; + if (detail?.agentId === currentAgent?.id && currentAgent?.id) { + invoke('agent_get', { agentId: currentAgent.id }) + .then(data => setUserProfile(data?.userProfile ?? null)) + .catch(() => {}); + } + }; + window.addEventListener('zclaw:agent-profile-updated', handler); + return () => window.removeEventListener('zclaw:agent-profile-updated', handler); + }, [currentAgent?.id]); + const handleReconnect = () => { connect().catch(silentErrorHandler('RightPanel')); }; @@ -552,6 +579,24 @@ export function RightPanel({ simpleMode = false }: RightPanelProps) { + {/* Dynamic: UserProfile data (from conversation learning) */} + {userProfile && ( +
+
对话中了解到的
+ {userProfile.industry ? ( + + ) : null} + {userProfile.role ? ( + + ) : null} + {userProfile.communicationStyle ? ( + + ) : null} + {Array.isArray(userProfile.recentTopics) && (userProfile.recentTopics as string[]).length > 0 ? ( + + ) : null} +
+ )} )} diff --git a/desktop/src/store/chat/streamStore.ts b/desktop/src/store/chat/streamStore.ts index 56a0f92..20fdf32 100644 --- a/desktop/src/store/chat/streamStore.ts +++ b/desktop/src/store/chat/streamStore.ts @@ -487,6 +487,12 @@ export const useStreamStore = create()( getMemoryExtractor().extractFromConversation(filtered, agentId, convId ?? undefined).catch(err => { log.warn('Memory extraction failed:', err); }); + // Notify RightPanel to refresh UserProfile after memory extraction + if (typeof window !== 'undefined') { + window.dispatchEvent(new CustomEvent('zclaw:agent-profile-updated', { + detail: { agentId } + })); + } intelligenceClient.reflection.recordConversation().catch(err => { log.warn('Recording conversation failed:', err); });