diff --git a/apps/mail/components/create/ai-chat.tsx b/apps/mail/components/create/ai-chat.tsx index e9c4051040..ea0fe02b03 100644 --- a/apps/mail/components/create/ai-chat.tsx +++ b/apps/mail/components/create/ai-chat.tsx @@ -1,4 +1,3 @@ -import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'; import { useAIFullScreen, useAISidebar } from '../ui/ai-sidebar'; import { VoiceProvider } from '@/providers/voice-provider'; @@ -14,25 +13,26 @@ import { VoiceButton } from '../voice-button'; import { EditorContent } from '@tiptap/react'; import { CurvedArrow } from '../icons/icons'; import { Tools } from '../../types/tools'; -import { InfoIcon } from 'lucide-react'; import { Button } from '../ui/button'; import { format } from 'date-fns-tz'; import { useQueryState } from 'nuqs'; -const renderThread = (thread: { id: string; title: string; snippet: string }) => { +const ThreadPreview = ({ threadId }: { threadId: string }) => { const [, setThreadId] = useQueryState('threadId'); - const { data: getThread } = useThread(thread.id); + const { data: getThread } = useThread(threadId); const [, setIsFullScreen] = useQueryState('isFullScreen'); const handleClick = () => { - setThreadId(thread.id); + setThreadId(threadId); setIsFullScreen(null); }; - return getThread?.latest ? ( + if (!getThread?.latest) return null; + + return (
@@ -65,15 +65,7 @@ const renderThread = (thread: { id: string; title: string; snippet: string }) =>
- ) : null; -}; - -const RenderThreads = ({ - threads, -}: { - threads: { id: string; title: string; snippet: string }[]; -}) => { - return
{threads.map(renderThread)}
; + ); }; const ExampleQueries = ({ onQueryClick }: { onQueryClick: (query: string) => void }) => { @@ -148,82 +140,55 @@ export interface AIChatProps { onModelChange?: (model: string) => void; } -declare global { - var DEBUG: boolean; -} - -const ToolResponse = ({ toolName, result, args }: { toolName: string; result: any; args: any }) => { - const renderContent = () => { - switch (toolName) { - case Tools.ListThreads: - case Tools.AskZeroMailbox: - return result?.threads ? : null; - - case Tools.GetThread: - return result?.thread ? ( -
-
- - - {result.thread.sender?.name?.[0]?.toUpperCase()} - -
-

{result.thread.sender?.name}

-

{result.thread.subject}

-
-
-
- {result.thread.body} -
-
- ) : null; - - case Tools.GetUserLabels: - return result?.labels ? ( -
- {result.labels.map((label: any) => ( - - ))} -
- ) : null; - - case Tools.ComposeEmail: - return result?.newBody ? ( -
-
- {result.newBody} -
-
- ) : null; - - default: - return null; - } - }; +// Subcomponents for ToolResponse +const GetThreadToolResponse = ({ result, args }: { result: any; args: any }) => { + // Extract threadId from result or args + let threadId: string | null = null; + if (typeof result === 'string') { + const match = result.match(//); + if (match?.[1]) threadId = match[1]; + } + if (!threadId && args?.id && typeof args.id === 'string') threadId = args.id; + if (!threadId) return null; + return ; +}; - const content = renderContent(); - if (!content) return null; +const GetUserLabelsToolResponse = ({ result }: { result: any }) => { + if (!result?.labels) return null; + return ( +
+ {result.labels.map((label: any) => ( + + ))} +
+ ); +}; +const ComposeEmailToolResponse = ({ result }: { result: any }) => { + if (!result?.newBody) return null; return ( -
- {globalThis.DEBUG ? ( - - - - - -
-

Tool Arguments:

-
{JSON.stringify(args, null, 2)}
-
-
-
- ) : null} - {content} +
+
+ {result.newBody} +
); }; +// Main ToolResponse switcher +const ToolResponse = ({ toolName, result, args }: { toolName: string; result: any; args: any }) => { + switch (toolName) { + case Tools.GetThread: + return ; + case Tools.GetUserLabels: + return ; + case Tools.ComposeEmail: + return ; + default: + return null; + } +}; + export function AIChat({ messages, setInput, @@ -320,28 +285,22 @@ export function AIChat({ messages.map((message, index) => { const textParts = message.parts.filter((part) => part.type === 'text'); const toolParts = message.parts.filter((part) => part.type === 'tool-invocation'); - const streamingTools = new Set([Tools.WebSearch]); - const doesIncludeStreamingTool = toolParts.some( - (part) => - streamingTools.has(part.toolInvocation?.toolName as Tools) && - part.toolInvocation?.result, - ); + return ( -
- {toolParts.map((part) => - part.toolInvocation && - part.toolInvocation.result && - !streamingTools.has(part.toolInvocation.toolName as Tools) ? ( - - ) : null, +
+ {toolParts.map( + (part, index) => + part.toolInvocation?.result && ( + + ), )} - {!doesIncludeStreamingTool && textParts.length > 0 && ( -

0 && ( +

@@ -382,7 +340,7 @@ export function AIChat({ ), )} -

+
)}
); @@ -390,12 +348,10 @@ export function AIChat({ )} {(status === 'submitted' || status === 'streaming') && ( -
-
- - zero is thinking... - -
+
+ + zero is thinking... +
)} {(status === 'error' || !!error) && ( diff --git a/apps/mail/components/mail/mail-display.tsx b/apps/mail/components/mail/mail-display.tsx index 25fd702890..49a35203a8 100644 --- a/apps/mail/components/mail/mail-display.tsx +++ b/apps/mail/components/mail/mail-display.tsx @@ -297,7 +297,7 @@ const ThreadAttachments = ({ attachments }: { attachments: Attachment[] }) => {
{attachments.map((attachment) => (