重构聊天会话管理,支持会话历史和存储
This commit is contained in:
@@ -5,6 +5,7 @@ import { Box, Drawer, alpha, useTheme } from "@mui/material";
|
||||
|
||||
import { AgentComposer } from "./AgentComposer";
|
||||
import { AgentHeader } from "./AgentHeader";
|
||||
import { AgentHistoryPanel } from "./AgentHistoryPanel";
|
||||
import { AgentWorkspace } from "./AgentWorkspace";
|
||||
import { Blob } from "./GlobalChatbox.parts";
|
||||
import type { Props } from "./GlobalChatbox.types";
|
||||
@@ -17,7 +18,7 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
|
||||
const [input, setInput] = useState("");
|
||||
const [width, setWidth] = useState(520);
|
||||
const [isResizing, setIsResizing] = useState(false);
|
||||
const [headerMenuAnchorEl, setHeaderMenuAnchorEl] = useState<HTMLElement | null>(null);
|
||||
const [isHistoryOpen, setIsHistoryOpen] = useState(false);
|
||||
|
||||
const bottomRef = useRef<HTMLDivElement>(null);
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
@@ -47,15 +48,20 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
|
||||
const handleToolCall = useAgentToolActions();
|
||||
const {
|
||||
messages,
|
||||
chatSessions,
|
||||
activeStorageSessionId,
|
||||
branchGroups,
|
||||
branchTransition,
|
||||
isHydrating,
|
||||
isStreaming,
|
||||
sendPrompt,
|
||||
regenerate,
|
||||
editAndResubmit,
|
||||
cycleBranch,
|
||||
abort,
|
||||
reset,
|
||||
createSession,
|
||||
removeSession,
|
||||
switchSession,
|
||||
} = useAgentChatSession({
|
||||
onToolCall: handleToolCall,
|
||||
onBeforeSend: stopListening,
|
||||
@@ -88,24 +94,34 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
|
||||
}, 0);
|
||||
}, []);
|
||||
|
||||
const handleHeaderMenuOpen = useCallback((event: React.MouseEvent<HTMLElement>) => {
|
||||
setHeaderMenuAnchorEl(event.currentTarget);
|
||||
}, []);
|
||||
|
||||
const handleHeaderMenuClose = useCallback(() => {
|
||||
setHeaderMenuAnchorEl(null);
|
||||
}, []);
|
||||
|
||||
const handleNewConversation = useCallback(() => {
|
||||
handleStopSpeech();
|
||||
stopListening();
|
||||
reset();
|
||||
void createSession();
|
||||
setInput("");
|
||||
handleHeaderMenuClose();
|
||||
window.setTimeout(() => {
|
||||
inputRef.current?.focus();
|
||||
}, 0);
|
||||
}, [handleHeaderMenuClose, handleStopSpeech, reset, stopListening]);
|
||||
}, [createSession, handleStopSpeech, stopListening]);
|
||||
|
||||
const handleHistoryToggle = useCallback(() => {
|
||||
setIsHistoryOpen((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const handleSelectSession = useCallback(
|
||||
(storageSessionId: string) => {
|
||||
setInput("");
|
||||
void switchSession(storageSessionId);
|
||||
},
|
||||
[switchSession],
|
||||
);
|
||||
|
||||
const handleDeleteSession = useCallback(
|
||||
(storageSessionId: string) => {
|
||||
void removeSession(storageSessionId);
|
||||
},
|
||||
[removeSession],
|
||||
);
|
||||
|
||||
const handleMouseDown = useCallback((event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
@@ -198,45 +214,91 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
|
||||
|
||||
<AgentHeader
|
||||
isStreaming={isStreaming}
|
||||
menuAnchorEl={headerMenuAnchorEl}
|
||||
onMenuOpen={handleHeaderMenuOpen}
|
||||
onMenuClose={handleHeaderMenuClose}
|
||||
isHistoryOpen={isHistoryOpen}
|
||||
onHistoryToggle={handleHistoryToggle}
|
||||
onNewConversation={handleNewConversation}
|
||||
onClose={onClose}
|
||||
/>
|
||||
|
||||
<AgentWorkspace
|
||||
messages={messages}
|
||||
branchGroups={branchGroups}
|
||||
branchTransition={branchTransition}
|
||||
isStreaming={isStreaming}
|
||||
bottomRef={bottomRef}
|
||||
speakingMessageId={speakingMessageId}
|
||||
speechState={speechState}
|
||||
onSpeak={handleSpeak}
|
||||
onPauseSpeech={handlePauseSpeech}
|
||||
onResumeSpeech={handleResumeSpeech}
|
||||
onStopSpeech={handleStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onRegenerate={regenerate}
|
||||
onEditResubmit={editAndResubmit}
|
||||
onCycleBranch={cycleBranch}
|
||||
/>
|
||||
<Box sx={{ flex: 1, display: "flex", minHeight: 0, position: "relative", overflow: "hidden" }}>
|
||||
<Box
|
||||
onClick={() => setIsHistoryOpen(false)}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
bgcolor: alpha("#000", 0.05),
|
||||
backdropFilter: "blur(2px)",
|
||||
opacity: isHistoryOpen ? 1 : 0,
|
||||
pointerEvents: isHistoryOpen ? "auto" : "none",
|
||||
transition: "opacity 0.3s ease",
|
||||
zIndex: 10,
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: 268,
|
||||
zIndex: 20,
|
||||
transform: isHistoryOpen ? "translateX(0)" : "translateX(-100%)",
|
||||
transition: "transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1)",
|
||||
boxShadow: isHistoryOpen ? `4px 0 24px ${alpha("#000", 0.08)}` : "none",
|
||||
}}
|
||||
>
|
||||
<AgentHistoryPanel
|
||||
sessions={chatSessions}
|
||||
activeSessionId={activeStorageSessionId}
|
||||
isHydrating={isHydrating}
|
||||
onNewSession={() => {
|
||||
handleNewConversation();
|
||||
setIsHistoryOpen(false);
|
||||
}}
|
||||
onSelectSession={(id) => {
|
||||
handleSelectSession(id);
|
||||
setIsHistoryOpen(false);
|
||||
}}
|
||||
onDeleteSession={handleDeleteSession}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<AgentComposer
|
||||
input={input}
|
||||
inputRef={inputRef}
|
||||
isStreaming={isStreaming}
|
||||
isListening={isListening}
|
||||
isSttSupported={isSttSupported}
|
||||
presets={PRESET_PROMPTS}
|
||||
onInputChange={setInput}
|
||||
onSend={handleSend}
|
||||
onAbort={abort}
|
||||
onStartListening={startListening}
|
||||
onStopListening={stopListening}
|
||||
onPresetSelect={handlePresetPromptSelect}
|
||||
/>
|
||||
<Box sx={{ flex: 1, display: "flex", minWidth: 0, flexDirection: "column" }}>
|
||||
<AgentWorkspace
|
||||
messages={messages}
|
||||
branchGroups={branchGroups}
|
||||
branchTransition={branchTransition}
|
||||
isStreaming={isStreaming}
|
||||
bottomRef={bottomRef}
|
||||
speakingMessageId={speakingMessageId}
|
||||
speechState={speechState}
|
||||
onSpeak={handleSpeak}
|
||||
onPauseSpeech={handlePauseSpeech}
|
||||
onResumeSpeech={handleResumeSpeech}
|
||||
onStopSpeech={handleStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onRegenerate={regenerate}
|
||||
onEditResubmit={editAndResubmit}
|
||||
onCycleBranch={cycleBranch}
|
||||
/>
|
||||
|
||||
<AgentComposer
|
||||
input={input}
|
||||
inputRef={inputRef}
|
||||
isHydrating={isHydrating}
|
||||
isStreaming={isStreaming}
|
||||
isListening={isListening}
|
||||
isSttSupported={isSttSupported}
|
||||
presets={PRESET_PROMPTS}
|
||||
onInputChange={setInput}
|
||||
onSend={handleSend}
|
||||
onAbort={abort}
|
||||
onStartListening={startListening}
|
||||
onStopListening={stopListening}
|
||||
onPresetSelect={handlePresetPromptSelect}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user