import React from 'react'; export const stringifyContent = (content: any, seen = new WeakSet()): string => { if (typeof content === 'string') { return content; } if (content === null) { return 'null'; } if (content === undefined) { return 'undefined'; } if (typeof content === 'number' || typeof content === 'boolean') { return content.toString(); } if (typeof content === 'function') { return content.toString(); } if (typeof content === 'symbol') { return content.toString(); } if (typeof content === 'bigint') { return content.toString() + 'n'; } if (React.isValidElement(content)) { return React.Children.toArray((content as React.ReactElement).props.children) .map(child => stringifyContent(child, seen)) .join(''); } if (Array.isArray(content)) { return '[' + content.map(item => stringifyContent(item, seen)).join(', ') + ']'; } if (typeof content === 'object') { if (seen.has(content)) { return '[Circular]'; } seen.add(content); try { const pairs = Object.entries(content).map( ([key, value]) => `${key}: ${stringifyContent(value, seen)}` ); return '{' + pairs.join(', ') + '}'; } catch (error) { return Object.prototype.toString.call(content); } } return String(content); }; export const copyToClipboard = (text: string, setCopiedText: (text: string | null) => void) => { navigator.clipboard.writeText(text).then(() => { setCopiedText(text); setTimeout(() => setCopiedText(null), 2000); }); }; export const handleSend = async ( input: string, context: string | null, messages: any[], setMessages: React.Dispatch>, setInput: React.Dispatch>, setIsContextExpanded: React.Dispatch>, setIsGenerating: React.Dispatch>, setIsLoading: React.Dispatch>, abortControllerRef: React.MutableRefObject, activeFileContent: string ) => { if (input.trim() === '' && !context) return; const newMessage = { role: 'user' as const, content: input, context: context || undefined }; const updatedMessages = [...messages, newMessage]; setMessages(updatedMessages); setInput(''); setIsContextExpanded(false); setIsGenerating(true); setIsLoading(true); abortControllerRef.current = new AbortController(); try { const anthropicMessages = updatedMessages.map(msg => ({ role: msg.role === 'user' ? 'human' : 'assistant', content: msg.content })); const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ messages: anthropicMessages, context: context || undefined, activeFileContent: activeFileContent, }), signal: abortControllerRef.current.signal, }); if (!response.ok) { throw new Error('Failed to get AI response'); } const reader = response.body?.getReader(); const decoder = new TextDecoder(); const assistantMessage = { role: 'assistant' as const, content: '' }; setMessages([...updatedMessages, assistantMessage]); setIsLoading(false); let buffer = ''; const updateInterval = 100; let lastUpdateTime = Date.now(); if (reader) { while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const currentTime = Date.now(); if (currentTime - lastUpdateTime > updateInterval) { setMessages(prev => { const updatedMessages = [...prev]; const lastMessage = updatedMessages[updatedMessages.length - 1]; lastMessage.content = buffer; return updatedMessages; }); lastUpdateTime = currentTime; } } setMessages(prev => { const updatedMessages = [...prev]; const lastMessage = updatedMessages[updatedMessages.length - 1]; lastMessage.content = buffer; return updatedMessages; }); } } catch (error: any) { if (error.name === 'AbortError') { console.log('Generation aborted'); } else { console.error('Error fetching AI response:', error); const errorMessage = { role: 'assistant' as const, content: 'Sorry, I encountered an error. Please try again.' }; setMessages(prev => [...prev, errorMessage]); } } finally { setIsGenerating(false); setIsLoading(false); abortControllerRef.current = null; } }; export const handleStopGeneration = (abortControllerRef: React.MutableRefObject) => { if (abortControllerRef.current) { abortControllerRef.current.abort(); } };