137 lines
4.4 KiB
TypeScript
137 lines
4.4 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { View, ViewOptions } from '../utils/navigationUtils';
|
|
import BaseChat from './BaseChat';
|
|
import { useRecipeManager } from '../hooks/useRecipeManager';
|
|
import { useIsMobile } from '../hooks/use-mobile';
|
|
import { useSidebar } from './ui/sidebar';
|
|
import { AgentState, InitializationContext } from '../hooks/useAgent';
|
|
import 'react-toastify/dist/ReactToastify.css';
|
|
import { cn } from '../utils';
|
|
|
|
import { ChatType } from '../types/chat';
|
|
import { useSearchParams } from 'react-router-dom';
|
|
|
|
export interface PairRouteState {
|
|
resumeSessionId?: string;
|
|
initialMessage?: string;
|
|
}
|
|
|
|
interface PairProps {
|
|
chat: ChatType;
|
|
setChat: (chat: ChatType) => void;
|
|
setView: (view: View, viewOptions?: ViewOptions) => void;
|
|
setIsGoosehintsModalOpen: (isOpen: boolean) => void;
|
|
setFatalError: (value: ((prevState: string | null) => string | null) | string | null) => void;
|
|
setAgentWaitingMessage: (msg: string | null) => void;
|
|
agentState: AgentState;
|
|
loadCurrentChat: (context: InitializationContext) => Promise<ChatType>;
|
|
}
|
|
|
|
export default function Pair({
|
|
chat,
|
|
setChat,
|
|
setView,
|
|
setIsGoosehintsModalOpen,
|
|
setFatalError,
|
|
setAgentWaitingMessage,
|
|
agentState,
|
|
loadCurrentChat,
|
|
resumeSessionId,
|
|
initialMessage,
|
|
}: PairProps & PairRouteState) {
|
|
const isMobile = useIsMobile();
|
|
const { state: sidebarState } = useSidebar();
|
|
const [hasProcessedInitialInput, setHasProcessedInitialInput] = useState(false);
|
|
const [shouldAutoSubmit, setShouldAutoSubmit] = useState(false);
|
|
const [messageToSubmit, setMessageToSubmit] = useState<string | null>(null);
|
|
const [isTransitioningFromHub, setIsTransitioningFromHub] = useState(false);
|
|
const [loadingChat, setLoadingChat] = useState(false);
|
|
const [_searchParams, setSearchParams] = useSearchParams();
|
|
|
|
useEffect(() => {
|
|
const initializeFromState = async () => {
|
|
setLoadingChat(true);
|
|
try {
|
|
const chat = await loadCurrentChat({
|
|
resumeSessionId,
|
|
setAgentWaitingMessage,
|
|
});
|
|
setChat(chat);
|
|
setSearchParams((prev) => {
|
|
prev.set('resumeSessionId', chat.sessionId);
|
|
return prev;
|
|
});
|
|
} catch (error) {
|
|
console.log(error);
|
|
setFatalError(`Agent init failure: ${error instanceof Error ? error.message : '' + error}`);
|
|
} finally {
|
|
setLoadingChat(false);
|
|
}
|
|
};
|
|
initializeFromState();
|
|
}, [
|
|
agentState,
|
|
setChat,
|
|
setFatalError,
|
|
setAgentWaitingMessage,
|
|
loadCurrentChat,
|
|
resumeSessionId,
|
|
setSearchParams,
|
|
]);
|
|
|
|
// Followed by sending the initialMessage if we have one. This will happen
|
|
// only once, unless we reset the chat in step one.
|
|
useEffect(() => {
|
|
if (agentState !== AgentState.INITIALIZED || !initialMessage || hasProcessedInitialInput) {
|
|
return;
|
|
}
|
|
|
|
setIsTransitioningFromHub(true);
|
|
setHasProcessedInitialInput(true);
|
|
setMessageToSubmit(initialMessage);
|
|
setShouldAutoSubmit(true);
|
|
}, [agentState, initialMessage, hasProcessedInitialInput]);
|
|
|
|
useEffect(() => {
|
|
if (agentState === AgentState.NO_PROVIDER) {
|
|
setView('welcome');
|
|
}
|
|
}, [agentState, setView]);
|
|
|
|
const { initialPrompt: recipeInitialPrompt } = useRecipeManager(chat, chat.recipe || null);
|
|
|
|
const handleMessageSubmit = (message: string) => {
|
|
// Clean up any auto submit state:
|
|
setShouldAutoSubmit(false);
|
|
setIsTransitioningFromHub(false);
|
|
setMessageToSubmit(null);
|
|
console.log('Message submitted:', message);
|
|
};
|
|
|
|
const recipePrompt =
|
|
agentState === 'initialized' && chat.messages.length === 0 && recipeInitialPrompt;
|
|
|
|
const initialValue = messageToSubmit || recipePrompt || undefined;
|
|
|
|
const customChatInputProps = {
|
|
// Pass initial message from Hub or recipe prompt
|
|
initialValue,
|
|
};
|
|
|
|
return (
|
|
<BaseChat
|
|
chat={chat}
|
|
loadingChat={loadingChat}
|
|
autoSubmit={shouldAutoSubmit}
|
|
setChat={setChat}
|
|
setView={setView}
|
|
setIsGoosehintsModalOpen={setIsGoosehintsModalOpen}
|
|
onMessageSubmit={handleMessageSubmit}
|
|
customChatInputProps={customChatInputProps}
|
|
contentClassName={cn('pr-1 pb-10', (isMobile || sidebarState === 'collapsed') && 'pt-11')} // Use dynamic content class with mobile margin and sidebar state
|
|
showPopularTopics={!isTransitioningFromHub} // Don't show popular topics while transitioning from Hub
|
|
suppressEmptyState={isTransitioningFromHub} // Suppress all empty state content while transitioning from Hub
|
|
/>
|
|
);
|
|
}
|