From 236d1b3e9c00de7bce26a70ca37b9bdf7f248d16 Mon Sep 17 00:00:00 2001 From: chenhaoli Date: Mon, 13 Oct 2025 20:13:50 +0800 Subject: [PATCH] feat(tarko-agent-ui): add workspace environment mismatch warning - Add useWorkspaceEnvironmentCheck hook to detect workspace mismatches - Add WorkspaceEnvironmentWarning component for visual warnings - Disable chat input when session workspace differs from server workspace - Update ChatPanel and ChatInput to handle workspace environment checks - Show preview mode message when environment mismatch detected --- .../hooks/useWorkspaceEnvironmentCheck.ts | 72 +++++++++++++++++ .../src/standalone/chat/ChatPanel.tsx | 13 ++- .../chat/MessageInput/ChatInput.tsx | 14 ++-- .../WorkspaceEnvironmentWarning.tsx | 80 +++++++++++++++++++ 4 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 multimodal/tarko/agent-ui/src/common/hooks/useWorkspaceEnvironmentCheck.ts create mode 100644 multimodal/tarko/agent-ui/src/standalone/chat/components/WorkspaceEnvironmentWarning.tsx diff --git a/multimodal/tarko/agent-ui/src/common/hooks/useWorkspaceEnvironmentCheck.ts b/multimodal/tarko/agent-ui/src/common/hooks/useWorkspaceEnvironmentCheck.ts new file mode 100644 index 0000000000..5dbc8602d8 --- /dev/null +++ b/multimodal/tarko/agent-ui/src/common/hooks/useWorkspaceEnvironmentCheck.ts @@ -0,0 +1,72 @@ +import { useEffect, useState } from 'react'; +import { useSession } from './useSession'; +import { apiService } from '../services/apiService'; + +/** + * Hook to check if the current session's workspace differs from the server's current workspace + * Returns warning state when there's a mismatch, indicating the session is in preview-only mode + */ +export function useWorkspaceEnvironmentCheck() { + const { activeSessionId, sessions } = useSession(); + const [isWorkspaceMismatch, setIsWorkspaceMismatch] = useState(false); + const [sessionWorkspace, setSessionWorkspace] = useState(''); + const [serverWorkspace, setServerWorkspace] = useState(''); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!activeSessionId) { + setIsWorkspaceMismatch(false); + setSessionWorkspace(''); + setServerWorkspace(''); + return; + } + + const checkWorkspaceEnvironment = async () => { + try { + setLoading(true); + + // Get current session's workspace + const currentSession = sessions.find(session => session.id === activeSessionId); + if (!currentSession) { + setIsWorkspaceMismatch(false); + return; + } + + const sessionWorkspacePath = currentSession.workspace; + + // Get server's current workspace + const serverWorkspaceInfo = await apiService.getWorkspaceInfo(); + const serverWorkspacePath = serverWorkspaceInfo.path; + + setSessionWorkspace(sessionWorkspacePath); + setServerWorkspace(serverWorkspacePath); + + // Check if workspaces match + const mismatch = sessionWorkspacePath !== serverWorkspacePath; + setIsWorkspaceMismatch(mismatch); + + if (mismatch) { + console.warn('Workspace environment mismatch detected:', { + sessionWorkspace: sessionWorkspacePath, + serverWorkspace: serverWorkspacePath, + }); + } + } catch (error) { + console.error('Failed to check workspace environment:', error); + // On error, assume no mismatch to avoid false positives + setIsWorkspaceMismatch(false); + } finally { + setLoading(false); + } + }; + + checkWorkspaceEnvironment(); + }, [activeSessionId, sessions]); + + return { + isWorkspaceMismatch, + sessionWorkspace, + serverWorkspace, + loading, + }; +} \ No newline at end of file diff --git a/multimodal/tarko/agent-ui/src/standalone/chat/ChatPanel.tsx b/multimodal/tarko/agent-ui/src/standalone/chat/ChatPanel.tsx index 0019a3b6e7..1e41448004 100644 --- a/multimodal/tarko/agent-ui/src/standalone/chat/ChatPanel.tsx +++ b/multimodal/tarko/agent-ui/src/standalone/chat/ChatPanel.tsx @@ -1,6 +1,7 @@ import React, { useRef } from 'react'; import { useParams } from 'react-router-dom'; import { useSession } from '@/common/hooks/useSession'; +import { useWorkspaceEnvironmentCheck } from '@/common/hooks/useWorkspaceEnvironmentCheck'; import { MessageGroup } from './Message/components/MessageGroup'; import { ChatInput } from './MessageInput'; import { useAtomValue } from 'jotai'; @@ -12,6 +13,7 @@ import { ScrollToBottomButton } from './components/ScrollToBottomButton'; import { EmptyState } from './components/EmptyState'; import { OfflineBanner } from './components/OfflineBanner'; import { SessionCreatingState } from './components/SessionCreatingState'; +import { WorkspaceEnvironmentWarning } from './components/WorkspaceEnvironmentWarning'; import './ChatPanel.css'; @@ -19,6 +21,7 @@ export const ChatPanel: React.FC = () => { const { sessionId: urlSessionId } = useParams<{ sessionId: string }>(); const { activeSessionId, isProcessing, connectionStatus, checkServerStatus, sendMessage } = useSession(); + const { isWorkspaceMismatch, sessionWorkspace, serverWorkspace } = useWorkspaceEnvironmentCheck(); const currentSessionId = urlSessionId || activeSessionId; const groupedMessages = useAtomValue(groupedMessagesAtom); @@ -60,6 +63,12 @@ export const ChatPanel: React.FC = () => { onReconnect={checkServerStatus} /> + + {showEmptyState ? ( ) : ( @@ -90,7 +99,8 @@ export const ChatPanel: React.FC = () => { currentSessionId === 'creating' || isProcessing || !connectionStatus.connected || - isReplayMode + isReplayMode || + isWorkspaceMismatch } isProcessing={isProcessing} connectionStatus={connectionStatus} @@ -100,6 +110,7 @@ export const ChatPanel: React.FC = () => { showContextualSelector={true} autoFocus={false} showHelpText={true} + isWorkspaceMismatch={isWorkspaceMismatch} /> )} diff --git a/multimodal/tarko/agent-ui/src/standalone/chat/MessageInput/ChatInput.tsx b/multimodal/tarko/agent-ui/src/standalone/chat/MessageInput/ChatInput.tsx index 70c4d5cd43..15669bcaa4 100644 --- a/multimodal/tarko/agent-ui/src/standalone/chat/MessageInput/ChatInput.tsx +++ b/multimodal/tarko/agent-ui/src/standalone/chat/MessageInput/ChatInput.tsx @@ -41,6 +41,7 @@ interface ChatInputProps { autoFocus?: boolean; showHelpText?: boolean; variant?: 'default' | 'home'; + isWorkspaceMismatch?: boolean; } export const ChatInput: React.FC = ({ @@ -58,6 +59,7 @@ export const ChatInput: React.FC = ({ autoFocus = true, showHelpText = true, variant = 'default', + isWorkspaceMismatch = false, }) => { const [uploadedImages, setUploadedImages] = useState([]); const [isAborting, setIsAborting] = useState(false); @@ -379,11 +381,13 @@ export const ChatInput: React.FC = ({ const defaultPlaceholder = connectionStatus && !connectionStatus.connected ? 'Server disconnected...' - : isProcessing - ? `${getAgentTitle()} is running...` - : contextualSelectorEnabled - ? `Ask ${getAgentTitle()} something... (Use @ to reference files/folders, Ctrl+Enter to send)` - : `Ask ${getAgentTitle()} something... (Ctrl+Enter to send)`; + : isWorkspaceMismatch + ? 'Preview mode - workspace environment mismatch' + : isProcessing + ? `${getAgentTitle()} is running...` + : contextualSelectorEnabled + ? `Ask ${getAgentTitle()} something... (Use @ to reference files/folders, Ctrl+Enter to send)` + : `Ask ${getAgentTitle()} something... (Ctrl+Enter to send)`; return (
diff --git a/multimodal/tarko/agent-ui/src/standalone/chat/components/WorkspaceEnvironmentWarning.tsx b/multimodal/tarko/agent-ui/src/standalone/chat/components/WorkspaceEnvironmentWarning.tsx new file mode 100644 index 0000000000..deaa3b1a30 --- /dev/null +++ b/multimodal/tarko/agent-ui/src/standalone/chat/components/WorkspaceEnvironmentWarning.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { FiAlertTriangle, FiEye } from 'react-icons/fi'; +import { motion, AnimatePresence } from 'framer-motion'; + +interface WorkspaceEnvironmentWarningProps { + isVisible: boolean; + sessionWorkspace: string; + serverWorkspace: string; +} + +/** + * Warning banner component for workspace environment mismatch + * Displays when session workspace differs from server workspace + */ +export const WorkspaceEnvironmentWarning: React.FC = ({ + isVisible, + sessionWorkspace, + serverWorkspace, +}) => { + if (!isVisible) return null; + + const getWorkspaceName = (path: string) => { + if (!path) return 'Unknown'; + return path.split('/').pop() || path; + }; + + return ( + + {isVisible && ( + +
+
+ {/* Warning icon */} +
+ +
+ + {/* Content */} +
+
+ +

+ Preview Mode - Environment Mismatch +

+
+ +

+ This session was created in a different workspace environment. + You can view the conversation history, but cannot send new messages. +

+ + {/* Workspace comparison */} +
+
+ Session: + + {getWorkspaceName(sessionWorkspace)} + +
+
+ Current: + + {getWorkspaceName(serverWorkspace)} + +
+
+
+
+
+
+ )} +
+ ); +}; \ No newline at end of file