docs/new-session-mechanism.md
Chatbox 的首页(/路由)是用户创建新对话的入口。本文档详细说明了新会话的创建机制,特别是临时状态的管理和转移过程。
在用户真正发送第一条消息之前,首页使用一个特殊的会话 ID "new" 来标识这是一个尚未创建的临时会话。
const [session, setSession] = useState<Session>({
id: 'new',
...initEmptyChatSession(),
})
为了管理新会话的临时状态(如知识库选择、网页浏览模式等),系统使用了专门的 atom:
// src/renderer/stores/atoms/uiAtoms.ts
export const newSessionStateAtom = atom<{
knowledgeBase?: Pick<KnowledgeBase, 'id' | 'name'>
webBrowsing?: boolean
}>({})
这个 atom 专门存储用户在发送第一条消息前的各种选择和设置。
当用户在首页进行以下操作时,状态都保存在临时存储中:
newSessionStateAtom.knowledgeBasesession state 中session state 中InputBox 组件会根据 sessionId 智能选择存储位置:
const isNewSession = currentSessionId === 'new'
const knowledgeBase = isNewSession
? newSessionState.knowledgeBase
: sessionKnowledgeBaseMap[currentSessionId]
const setKnowledgeBase = useCallback((value) => {
if (isNewSession) {
setNewSessionState(prev => ({ ...prev, knowledgeBase: value }))
} else {
// 更新实际会话的知识库映射
setSessionKnowledgeBaseMap(prev => ({
...prev,
[currentSessionId]: value
}))
}
}, [currentSessionId, isNewSession])
当用户发送第一条消息时,handleSubmit 函数执行以下步骤:
const handleSubmit = async (payload: InputBoxPayload) => {
// 1. 创建真正的会话
const newSession = await createSession({
name: session.name,
type: 'chat',
picUrl: session.picUrl,
messages: session.messages,
copilotId: session.copilotId,
settings: session.settings,
})
// 2. 转移临时状态到新会话
if (newSessionState.knowledgeBase) {
setSessionKnowledgeBaseMap({
...sessionKnowledgeBaseMap,
[newSession.id]: newSessionState.knowledgeBase,
})
// 清空临时状态
setNewSessionState({})
}
// 3. 切换到新会话
sessionActions.switchCurrentSession(newSession.id)
// 4. 发送消息
// ...
}
状态转移发生在会话创建成功后、切换会话之前。这确保了:
用户操作 → newSessionStateAtom (临时存储)
↓
发送消息 → 创建会话
↓
状态转移 → sessionKnowledgeBaseMap[newSessionId] (持久存储)
↓
清空临时状态 → newSessionStateAtom = {}
/src/renderer/routes/index.tsx - 首页组件/src/renderer/components/InputBox.tsx - 输入框组件/src/renderer/stores/atoms/uiAtoms.ts - UI 状态定义/src/renderer/stores/sessionActions.ts - 会话相关操作