From e6656b9288dd3c62d443b0511c19d2afb05acf05 Mon Sep 17 00:00:00 2001 From: spencrmartin Date: Mon, 17 Nov 2025 16:26:52 -0500 Subject: [PATCH] feat: add @goose off commands to disable AI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added support for turning AI off after enabling it: useChatEngine.ts: - Added detection for @goose off/disable/stop/quiet/sleep commands - When AI is enabled and user sends @goose off, AI gets disabled - Message is added to chat without triggering AI response - Console logging shows when AI is disabled EnhancedMentionPopover.tsx: - Added multiple @goose command options in autocomplete: - @goose (enable AI) - @goose off (disable AI) - @goose stop (stop AI) - @goose quiet (make AI quiet) - Updated icons to show different emojis for off commands (🦆💤) - All goose commands get green styling and 'Mention' action hint Now users can: 1. Start DM (AI disabled by default) 2. Send @goose to enable AI 3. Send @goose off to disable AI again 4. Autocomplete shows all available @goose commands --- .../src/components/EnhancedMentionPopover.tsx | 62 ++++++++++++++----- ui/desktop/src/hooks/useChatEngine.ts | 29 ++++++++- 2 files changed, 72 insertions(+), 19 deletions(-) diff --git a/ui/desktop/src/components/EnhancedMentionPopover.tsx b/ui/desktop/src/components/EnhancedMentionPopover.tsx index 5e486a024b..c63373132d 100644 --- a/ui/desktop/src/components/EnhancedMentionPopover.tsx +++ b/ui/desktop/src/components/EnhancedMentionPopover.tsx @@ -84,19 +84,44 @@ const EnhancedMentionPopover = forwardRef< const mentionItems = useMemo((): MentionItem[] => { const items: MentionItem[] = []; - // Add "goose" as a special mention for AI reinitialization - const gooseScore = fuzzyMatch(query, 'goose'); - if (gooseScore > 0 || !query.trim()) { - items.push({ - id: 'goose', - type: 'friend', // Use friend type for consistent styling - name: 'goose', - displayText: 'goose', - secondaryText: 'Reinitialize AI assistance', - userId: 'goose', - matchScore: gooseScore + 100, // Highest priority for goose - }); - } + // Add "goose" commands as special mentions for AI control + const gooseCommands = [ + { + command: 'goose', + description: 'Enable AI assistance', + emoji: '🦆' + }, + { + command: 'goose off', + description: 'Disable AI assistance', + emoji: '🦆💤' + }, + { + command: 'goose stop', + description: 'Stop AI assistance', + emoji: '🦆🛑' + }, + { + command: 'goose quiet', + description: 'Make AI quiet', + emoji: '🦆🤫' + } + ]; + + gooseCommands.forEach(({ command, description, emoji }) => { + const score = fuzzyMatch(query, command); + if (score > 0 || !query.trim()) { + items.push({ + id: command, + type: 'friend', // Use friend type for consistent styling + name: command, + displayText: command, + secondaryText: description, + userId: command, + matchScore: score + 100, // Highest priority for goose commands + }); + } + }); // Add friends (prioritize if connected) if (isConnected && friends.length > 0) { @@ -251,9 +276,12 @@ const EnhancedMentionPopover = forwardRef< {/* Icon */}
{item.type === 'friend' ? ( - item.userId === 'goose' ? ( + item.userId?.startsWith('goose') ? (
- 🦆 + + {item.userId === 'goose' ? '🦆' : + item.userId.includes('off') || item.userId.includes('stop') || item.userId.includes('quiet') ? '🦆💤' : '🦆'} +
) : (
@@ -286,11 +314,11 @@ const EnhancedMentionPopover = forwardRef<
- {item.userId === 'goose' ? 'Mention' : 'Invite'} + {item.userId?.startsWith('goose') ? 'Mention' : 'Invite'}
)}
diff --git a/ui/desktop/src/hooks/useChatEngine.ts b/ui/desktop/src/hooks/useChatEngine.ts index dd30a2a868..56edb3c5cc 100644 --- a/ui/desktop/src/hooks/useChatEngine.ts +++ b/ui/desktop/src/hooks/useChatEngine.ts @@ -185,8 +185,33 @@ export const useChatEngine = ({ : ''; const containsGooseMention = /@goose\b/i.test(messageText); - // If @goose is mentioned, enable AI for this session - if (containsGooseMention && !aiEnabled) { + // Check for @goose off/disable/stop commands + const gooseOffPattern = /@goose\s+(off|disable|stop|quiet|sleep)\b/i; + const isGooseOffCommand = gooseOffPattern.test(messageText); + + // If @goose off is mentioned, disable AI for this session + if (isGooseOffCommand && aiEnabled) { + console.log('🦆💤 @goose off mentioned - disabling AI for session:', { + sessionId: chat.sessionId, + messageId: message.id, + contentPreview: messageText.substring(0, 50) + '...' + }); + + // Update the chat to disable AI + setChat((prevChat: ChatType) => ({ ...prevChat, aiEnabled: false })); + + // Add the message to the chat without triggering AI response + setMessages(prevMessages => [...prevMessages, message]); + + // Store in history if it's a user message + storeMessageInHistory(message); + + // Return a promise that resolves immediately (to match originalAppend's interface) + return Promise.resolve(); + } + + // If @goose is mentioned (but not an off command), enable AI for this session + if (containsGooseMention && !isGooseOffCommand && !aiEnabled) { console.log('🦆 @goose mentioned - enabling AI for session:', { sessionId: chat.sessionId, messageId: message.id,