From e0db74be2a538f4dfd48d010cd366cbeaef9edd1 Mon Sep 17 00:00:00 2001 From: Omkar Bansod Date: Tue, 16 Sep 2025 21:04:26 +0530 Subject: [PATCH] Improve Chat Mode UX with better action guidance and fixed examples (#95) * update chatmode to say use Agent mode for perform actions * fixed default examples * clean up --- src/lib/agent/ChatAgent.prompt.ts | 36 ++++++- src/sidepanel/components/MessageList.tsx | 124 ++--------------------- 2 files changed, 43 insertions(+), 117 deletions(-) diff --git a/src/lib/agent/ChatAgent.prompt.ts b/src/lib/agent/ChatAgent.prompt.ts index 842f3aaa..3dec7c24 100644 --- a/src/lib/agent/ChatAgent.prompt.ts +++ b/src/lib/agent/ChatAgent.prompt.ts @@ -30,7 +30,41 @@ export function generateSystemPrompt(): string { - Always refer to the content within tags when answering questions about the page - This browser state is automatically updated when tabs change -## Instructions +## CRITICAL: Chat Mode Limitations +You are currently in **Chat Mode**, which is READ-ONLY and designed for Q&A only. + +### Action Detection Rules +If the user's request involves ANY of these action types, you MUST respond with the Agent Mode guidance template: + +**Direct Actions:** +- Clicking, tapping, or selecting elements +- Typing, filling forms, entering text +- Navigating, opening URLs, going to pages +- Submitting forms, pressing buttons +- Uploading or downloading files +- Making purchases, adding to cart, checkout +- Signing in, logging in, registering +- Playing, pausing, controlling media +- Creating, sending, or posting content +- Booking, applying, subscribing to services +- Installing, deleting, or managing content + +**Intent Indicators:** +- Commands starting with action verbs: "click the button", "open this link" +- Polite requests: "can you please click", "could you help me navigate" +- Task requests: "help me fill out this form", "assist me in buying this" +- Page interaction: "click on this page", "navigate to the next section" + +### Required Response Template +When you detect ANY action request, respond EXACTLY with this template: + +You’re in Chat Mode right now, which is great for asking questions or understanding page content. +To actually execute actions, please switch to Agent Mode. + +I can still help you understand what's on the page or answer questions about the content though! + +## Q&A Instructions +For legitimate questions (not action requests): 1. Be concise and direct in your responses 2. Answer based on the page content within tags 3. Use tools only when necessary for answering the question diff --git a/src/sidepanel/components/MessageList.tsx b/src/sidepanel/components/MessageList.tsx index fc9f659a..7644a4f2 100644 --- a/src/sidepanel/components/MessageList.tsx +++ b/src/sidepanel/components/MessageList.tsx @@ -25,63 +25,16 @@ interface MessageListProps { containerRef?: React.RefObject } -// Example prompts grouped by category -const ALL_EXAMPLES = [ - // Tab Management - "Group my tabs by app or purpose", - "Find tabs related to machine learning", - // "Close tabs I haven't touched in 7 days", - "Highlight the tab where I was last shopping", - "Save all Facebook tabs to a reading list", - // "Pin tabs I use daily", - // "Archive tabs from last week's research", - // "Reopen the tab I accidentally closed", - // "Mute all tabs except the one playing music", - - // Page Analysis - "Summarize this article for me", - "What are the key points on this page?", - // "Check if this article is AI-generated", - "Extract all links and sources from this page", - "Extract all news headlines from this page", - // "List all images and their alt text", - // "Detect the reading level of this article", - // "Highlight quotes or cited studies", - // "Compare this page to another tab I'm viewing", - - // Search & Discovery - "Find top-rated headphones under $100", - // "Find the cheapest flight to San Francisco", - "Search YouTube for videos explaining BrowserOS", - // "Look up reviews for this product", - "Search Reddit for discussions about this topic", - // "Find recipes using the ingredients in my tabs", - // "Show me recent news about this company", - // "Search for open-source alternatives to this tool", - - // Actions & Automation +// Example prompts - showcasing BrowserOS capabilities +const EXAMPLES = [ "Open amazon.com and order Sensodyne toothpaste", - "Write a tweet saying Hello World", - // "Add this page to my bookmarks", - // "Download the PDF linked on this page", - // "Translate this page to Spanish", - // "Email this article to myself", - // "Create a calendar event based on this page", - // "Copy all code snippets from this tab", - - // AI & Content Tools - // "Rewrite this paragraph to be more concise", - "Generate a summary tweet for this article", - // "Explain this code like I'm five", - // "Draft a reply to this comment", - "Rate the tone of this blog post", - // "Suggest improvements to this documentation", + "Find top-rated headphones under $100", + "Go to GitHub and Star BrowserOS", "Turn this article into a LinkedIn post", - // "Detect bias or opinionated language in this page", ] // Animation constants -const DEFAULT_DISPLAY_COUNT = 5 // Default number of examples to show +const DEFAULT_DISPLAY_COUNT = 4 // Fixed number of examples to show /** * MessageList component @@ -91,10 +44,9 @@ export function MessageList({ messages, isProcessing = false, onScrollStateChang const { containerRef: internalContainerRef, isUserScrolling, scrollToBottom } = useAutoScroll([messages], externalContainerRef) const { trackFeature } = useAnalytics() const [, setIsAtBottom] = useState(true) - const [currentExamples, setCurrentExamples] = useState([]) - const [shuffledPool, setShuffledPool] = useState([]) + const [currentExamples] = useState(EXAMPLES) const [isAnimating] = useState(false) - const [displayCount, setDisplayCount] = useState(DEFAULT_DISPLAY_COUNT) + const [displayCount] = useState(DEFAULT_DISPLAY_COUNT) // Track previously seen message IDs to determine which are new const previousMessageIdsRef = useRef>(new Set()) @@ -103,19 +55,8 @@ export function MessageList({ messages, isProcessing = false, onScrollStateChang // Use external container ref if provided, otherwise use internal one const containerRef = externalContainerRef || internalContainerRef - // Adjust display count based on viewport height - useEffect(() => { - const updateDisplayCount = () => { - const height = window.innerHeight - setDisplayCount(height < 700 ? 3 : DEFAULT_DISPLAY_COUNT) - } - - updateDisplayCount() - window.addEventListener('resize', updateDisplayCount) - return () => window.removeEventListener('resize', updateDisplayCount) - }, []) - // Track new messages for animation + // Track new messages for animation useEffect(() => { const currentMessageIds = new Set(messages.map(msg => msg.msgId)) const previousIds = previousMessageIdsRef.current @@ -208,55 +149,6 @@ export function MessageList({ messages, isProcessing = false, onScrollStateChang return blocks }, [messages]) - // Initialize shuffled pool and current examples - useEffect(() => { - const shuffled = [...ALL_EXAMPLES].sort(() => 0.5 - Math.random()) - setShuffledPool(shuffled) - - // Get initial examples based on display count - const initialExamples: string[] = [] - for (let i = 0; i < displayCount; i++) { - if (shuffled.length > 0) { - initialExamples.push(shuffled.pop()!) - } - } - setCurrentExamples(initialExamples) - }, [displayCount]) - - // Function to get random examples from pool - const _getRandomExample = useCallback((count: number = 1): string[] => { - const result: string[] = [] - let pool = [...shuffledPool] - - while (result.length < count) { - // If exhausted, reshuffle - if (pool.length === 0) { - pool = [...ALL_EXAMPLES].sort(() => 0.5 - Math.random()) - } - result.push(pool.pop()!) - } - - // Update the pool - setShuffledPool(pool) - return result - }, [shuffledPool]) - - // Refresh examples only when the welcome view is shown (on mount or when messages become empty) - const wasEmptyRef = useRef(messages.length === 0) - useEffect(() => { - const isEmpty = messages.length === 0 - if (isEmpty && !wasEmptyRef.current) { - // Reinitialize examples when transitioning back to empty state - const shuffled = [...ALL_EXAMPLES].sort(() => 0.5 - Math.random()) - setShuffledPool(shuffled) - const initialExamples: string[] = [] - for (let i = 0; i < displayCount; i++) { - if (shuffled.length > 0) initialExamples.push(shuffled.pop()!) - } - setCurrentExamples(initialExamples) - } - wasEmptyRef.current = isEmpty - }, [messages.length, displayCount]) // Check if we're at the bottom of the scroll container useEffect(() => {