diff --git a/src/api/chat.ts b/src/api/chat.ts index 24e36ab..b068a0b 100644 --- a/src/api/chat.ts +++ b/src/api/chat.ts @@ -42,21 +42,20 @@ export interface ChatHistoryResp { } export const ChatAPI = { - history: (agentId: string, sessionId?: string) => - api.get(`/chat/${agentId}/messages`, { params: sessionId ? { sessionId } : {} }).then((r) => r.data), - send: (agentId: string, content: string, sessionId?: string, model?: string, imageUrls?: string[]) => + history: (roomId: string) => + api.get(`/rooms/${roomId}/messages`).then((r) => r.data), + send: (roomId: string, content: string, targetAgentId: string, model?: string, model_id?: string, imageUrls?: string[]) => api - .post<{ user: ChatMessage; assistant: ChatMessage }>(`/chat/${agentId}/messages`, { + .post<{ user: ChatMessage; assistant: ChatMessage }>(`/rooms/${roomId}/messages`, { content, - sessionId, + targetAgentId, model, + model_id, imageUrls }) .then((r) => r.data), - clear: (agentId: string, sessionId?: string) => - api.delete(`/chat/${agentId}/messages`, { params: sessionId ? { sessionId } : {} }).then((r) => r.data), - switchBranch: (agentId: string, userMsgId: string, branchId: string) => - api.post(`/chat/${agentId}/messages/${userMsgId}/switch-branch`, { branchId }).then((r) => r.data) + clear: (roomId: string) => + api.delete(`/rooms/${roomId}/messages`).then((r) => r.data) }; export interface ChatAttachment { diff --git a/src/api/sessions.ts b/src/api/sessions.ts index bc03ae0..547f8db 100644 --- a/src/api/sessions.ts +++ b/src/api/sessions.ts @@ -30,18 +30,18 @@ export interface SearchResult { export const SessionAPI = { list: (agentId: string, archived: '0' | '1' | 'all' = '0') => - api.get(`/agents/${agentId}/sessions`, { params: { archived } }).then((r) => r.data), - create: (agentId: string, title?: string) => api.post(`/agents/${agentId}/sessions`, { title }).then((r) => r.data), - rename: (agentId: string, sessionId: string, title: string) => api.put(`/agents/${agentId}/sessions/${sessionId}`, { title }).then((r) => r.data), - remove: (agentId: string, sessionId: string) => api.delete(`/agents/${agentId}/sessions/${sessionId}`).then((r) => r.data), + api.get(`/agents/${agentId}/rooms`, { params: { archived } }).then((r) => r.data), + create: (agentId: string, title?: string) => api.post(`/agents/${agentId}/rooms`, { title: title || '新会话' }).then((r) => r.data), + rename: (agentId: string, sessionId: string, title: string) => api.put(`/agents/${agentId}/rooms/${sessionId}`, { title }).then((r) => r.data), + remove: (agentId: string, sessionId: string) => api.delete(`/agents/${agentId}/rooms/${sessionId}`).then((r) => r.data), archive: (agentId: string, sessionId: string, archived: boolean) => - api.post(`/agents/${agentId}/sessions/${sessionId}/archive`, { archived }).then((r) => r.data), + api.post(`/agents/${agentId}/rooms/${sessionId}/archive`, { archived }).then((r) => r.data), share: (agentId: string, sessionId: string, ttlHours = 0) => - api.post<{ token: string; expiresAt?: number }>(`/agents/${agentId}/sessions/${sessionId}/share`, { ttlHours }).then((r) => r.data), - revokeShare: (agentId: string, sessionId: string) => api.delete(`/agents/${agentId}/sessions/${sessionId}/share`).then((r) => r.data), + api.post<{ token: string; expiresAt?: number }>(`/agents/${agentId}/rooms/${sessionId}/share`, { ttlHours }).then((r) => r.data), + revokeShare: (agentId: string, sessionId: string) => api.delete(`/agents/${agentId}/rooms/${sessionId}/share`).then((r) => r.data), search: (agentId: string, q: string, opts: { includeArchived?: boolean; limit?: number } = {}) => api - .get(`/agents/${agentId}/sessions/search`, { + .get(`/agents/${agentId}/rooms/search`, { params: { q, includeArchived: opts.includeArchived ? '1' : '0', @@ -50,7 +50,7 @@ export const SessionAPI = { }) .then((r) => r.data), exportSession: (agentId: string, sessionId: string, format: 'md' | 'json' = 'md') => { - const url = withApiBase(`/agents/${agentId}/sessions/${sessionId}/export?format=${format}`); + const url = withApiBase(`/agents/${agentId}/rooms/${sessionId}/export?format=${format}`); const a = document.createElement('a'); a.href = url; a.rel = 'noopener'; diff --git a/src/api/streamChat.ts b/src/api/streamChat.ts index 4b28176..dd23d4f 100644 --- a/src/api/streamChat.ts +++ b/src/api/streamChat.ts @@ -21,21 +21,21 @@ export interface ModelOverrides { } export async function streamChat( - agentId: string, + roomId: string, + targetAgentId: string, content: string, handlers: StreamEvents, signal?: AbortSignal, - sessionId?: string, model?: string, modelId?: string, imageUrls?: string[] ) { - const resp = await fetch(`https://api.hoyidata.com/aura/v1/chat/${agentId}/messages/stream`, { + const resp = await fetch(`https://api.hoyidata.com/aura/v1/rooms/${roomId}/messages/stream`, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'text/event-stream' }, body: JSON.stringify({ content, - sessionId, + targetAgentId, model, model_id: modelId, imageUrls: imageUrls ?? [] diff --git a/src/components/ChatPreview.tsx b/src/components/ChatPreview.tsx index db9a0c9..776d031 100644 --- a/src/components/ChatPreview.tsx +++ b/src/components/ChatPreview.tsx @@ -75,8 +75,11 @@ export default function ChatPreview({ agent, agentId }: Props) { setSessionId(sid); } const model = String(agent?.model || '').split(',')[0]?.trim() || undefined; + const modelId = model ? undefined : undefined; + const targetAgentId = agentId; await streamChat( - agentId, + sid, + targetAgentId, text, { onMeta: (m) => setStreaming((s) => ({ ...s, retrieved: m.retrieved || [] })), @@ -104,7 +107,7 @@ export default function ChatPreview({ agent, agentId }: Props) { }), onDone: (data) => { setMessages((m) => [...m.filter((x) => x.id !== tempUser.id), data.user, data.assistant]); - setStreaming({ active: false, text: '', retrieved: [], toolCalls: [] }); + setStreaming({ active: false, text: '', retrieved: [], toolCalls: [] }); scrollBottom(); }, onError: (errMsg) => { @@ -114,8 +117,8 @@ export default function ChatPreview({ agent, agentId }: Props) { } }, ctrl.signal, - sid, - model + model, + modelId ); } catch (e: any) { if (e?.name !== 'AbortError') { diff --git a/src/pages/chat/ChatPage.tsx b/src/pages/chat/ChatPage.tsx index 2dc2c7b..a74ce78 100644 --- a/src/pages/chat/ChatPage.tsx +++ b/src/pages/chat/ChatPage.tsx @@ -14,7 +14,7 @@ import { useChatData } from './hooks/useChatData'; import { useChatSender } from './hooks/useChatSender'; import { markdownToPlainText } from './utils/copy'; -const lastSessionKey = (agentId: string) => `chat:lastSession:${agentId}`; +const lastRoomKey = (agentId: string) => `chat:lastRoom:${agentId}`; export default function ChatPage() { const { id } = useParams(); @@ -22,7 +22,7 @@ export default function ChatPage() { const [searchParams, setSearchParams] = useSearchParams(); const { message } = AntApp.useApp(); - const [sessionId, setSessionId] = useState(null); + const [roomId, setRoomId] = useState(null); const [highlightId, setHighlightId] = useState(null); const [overrides, setOverrides] = useState({}); @@ -41,9 +41,9 @@ export default function ChatPage() { const m = searchParams.get('msg'); if (s) { - setSessionId(s); + setRoomId(s); try { - localStorage.setItem(lastSessionKey(id), s); + localStorage.setItem(lastRoomKey(id), s); } catch { // ignore } @@ -58,13 +58,13 @@ export default function ChatPage() { const saved = (() => { try { - return localStorage.getItem(lastSessionKey(id)); + return localStorage.getItem(lastRoomKey(id)); } catch { return null; } })(); if (saved) { - setSessionId(saved); + setRoomId(saved); return; } @@ -72,37 +72,37 @@ export default function ChatPage() { try { const list = await SessionAPI.list(id, '0'); if (list.length > 0) { - setSessionId(list[0].id); + setRoomId(list[0].id); return; } const created = await SessionAPI.create(id); - setSessionId(created.id); + setRoomId(created.id); } catch (e: any) { - message.error('加载会话失败:' + (e?.message ?? e)); + message.error('加载房间失败:' + (e?.message ?? e)); } })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [id]); useEffect(() => { - if (!id || !sessionId) return; + if (!id || !roomId) return; try { - localStorage.setItem(lastSessionKey(id), sessionId); + localStorage.setItem(lastRoomKey(id), roomId); } catch { // ignore } const cur = searchParams.get('session'); - if (cur === sessionId) return; + if (cur === roomId) return; const next = new URLSearchParams(searchParams); - next.set('session', sessionId); + next.set('session', roomId); next.delete('msg'); setSearchParams(next, { replace: true }); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [id, sessionId]); + }, [id, roomId]); const { agent, agentList, messages, setMessages, branches, setBranches, loadMessages } = useChatData({ agentId: id, - sessionId, + roomId, highlightId, setHighlightId, scrollBottom, @@ -115,7 +115,7 @@ export default function ChatPage() { agentId: id, agent, agentList, - sessionId, + roomId, overrides, setOverrides: (updater) => setOverrides(updater), messages, @@ -213,9 +213,9 @@ export default function ChatPage() { setHighlightId(null); setMessages(() => []); setBranches({}); - setSessionId(created.id); + setRoomId(created.id); } catch (e: any) { - message.error('创建会话失败:' + (e?.message ?? e)); + message.error('创建房间失败:' + (e?.message ?? e)); } }} agentList={agentList} @@ -232,8 +232,8 @@ export default function ChatPage() { setInput={(updater) => sender.setInput(updater(sender.input))} overrides={overrides} setOverrides={(updater) => setOverrides(updater)} - sessionId={sessionId} - setSessionId={setSessionId} + roomId={roomId} + setRoomId={setRoomId} setHighlightId={setHighlightId} sessionRefresh={sender.sessionRefresh} mcpDrawerOpen={mcpDrawerOpen} diff --git a/src/pages/chat/components/ChatDrawers.tsx b/src/pages/chat/components/ChatDrawers.tsx index 05e8491..b5f2ad1 100644 --- a/src/pages/chat/components/ChatDrawers.tsx +++ b/src/pages/chat/components/ChatDrawers.tsx @@ -11,8 +11,8 @@ export default function ChatDrawers(props: { setInput: (updater: (prev: string) => string) => void; overrides: ModelOverrides; setOverrides: (updater: (prev: ModelOverrides) => ModelOverrides) => void; - sessionId: string | null; - setSessionId: (v: string | null) => void; + roomId: string | null; + setRoomId: (v: string | null) => void; setHighlightId: (v: string | null) => void; sessionRefresh: number; mcpDrawerOpen: boolean; @@ -31,8 +31,8 @@ export default function ChatDrawers(props: { setInput, overrides, setOverrides, - sessionId, - setSessionId, + roomId, + setRoomId, setHighlightId, sessionRefresh, mcpDrawerOpen, @@ -165,9 +165,9 @@ export default function ChatDrawers(props: { {agentId ? ( { - setSessionId(sid); + setRoomId(sid); setHighlightId(opts?.highlightMessageId || null); setHistoryDrawerOpen(false); }} diff --git a/src/pages/chat/hooks/useChatData.ts b/src/pages/chat/hooks/useChatData.ts index 02dcb99..0f60eb5 100644 --- a/src/pages/chat/hooks/useChatData.ts +++ b/src/pages/chat/hooks/useChatData.ts @@ -5,7 +5,7 @@ import { parseAgentModels } from '../utils/agentModels'; export function useChatData(args: { agentId?: string; - sessionId: string | null; + roomId: string | null; highlightId: string | null; setHighlightId: (v: string | null) => void; scrollBottom: (force?: boolean) => void; @@ -13,7 +13,7 @@ export function useChatData(args: { setOverrides: (updater: (prev: ModelOverrides) => ModelOverrides) => void; abort: () => void; }) { - const { agentId, sessionId, highlightId, setHighlightId, scrollBottom, initialScrollDoneRef, setOverrides, abort } = args; + const { agentId, roomId, highlightId, setHighlightId, scrollBottom, initialScrollDoneRef, setOverrides, abort } = args; const [agent, setAgent] = useState(null); const [agentList, setAgentList] = useState([]); const [messages, setMessages] = useState([]); @@ -48,8 +48,8 @@ export function useChatData(args: { }; const loadMessages = async () => { - if (!agentId || !sessionId) return; - const his = await ChatAPI.history(agentId, sessionId || undefined); + if (!roomId) return; + const his = await ChatAPI.history(roomId); setMessages(Array.isArray(his.messages) ? his.messages : []); setBranches(his.branches || {}); requestAnimationFrame(() => { @@ -92,10 +92,10 @@ export function useChatData(args: { }, [agentId]); useEffect(() => { - if (!agentId || !sessionId) return; + if (!roomId) return; loadMessages(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sessionId, highlightId, agentId]); + }, [roomId, highlightId, agentId]); return { agent, diff --git a/src/pages/chat/hooks/useChatSender.ts b/src/pages/chat/hooks/useChatSender.ts index 4a387ef..e4ce94d 100644 --- a/src/pages/chat/hooks/useChatSender.ts +++ b/src/pages/chat/hooks/useChatSender.ts @@ -84,7 +84,7 @@ export function useChatSender(args: { agentId?: string; agent: Agent | null; agentList: Agent[]; - sessionId: string | null; + roomId: string | null; overrides: ModelOverrides; setOverrides: (updater: (prev: ModelOverrides) => ModelOverrides) => void; messages: ChatMessage[]; @@ -95,7 +95,7 @@ export function useChatSender(args: { notify: { success: (t: string) => void; error: (t: string) => void }; abortRef: { current: AbortController | null }; }) { - const { agentId, agent, agentList, sessionId, overrides, setOverrides, setBranches, loadMessages, scrollBottom, notify, abortRef } = args; + const { agentId, agent, agentList, roomId, overrides, setOverrides, setBranches, loadMessages, scrollBottom, notify, abortRef } = args; const [input, setInput] = useState(''); const [sending, setSending] = useState(false); const [useStream, setUseStream] = useState(true); @@ -153,7 +153,12 @@ export function useChatSender(args: { const content = attText ? `${text}\n\n${attText}` : text; try { + if (!roomId) { + notify.error('房间未初始化'); + return; + } await streamChat( + roomId, targetAgentId, content, { @@ -230,7 +235,6 @@ export function useChatSender(args: { } }, ctrl.signal, - sessionId, targetModel, targetModelId, imageUrls @@ -253,8 +257,8 @@ export function useChatSender(args: { const handleSendNonStream = async (text: string) => { if (!agentId) return; - if (!sessionId) { - notify.error('会话未初始化,请稍后重试'); + if (!roomId) { + notify.error('房间未初始化,请稍后重试'); return; } const tempUser: ChatMessage = { id: 'tmp-' + Date.now(), role: 'user', content: text, createdAt: Date.now() }; @@ -267,17 +271,20 @@ export function useChatSender(args: { // 如果提及了其他 Agent,使用该 Agent 的第一个模型 let targetModel: string; + let targetModelId: string; if (targetAgent && targetAgent.id !== agentId) { const models = parseAgentModels(targetAgent.model); targetModel = models[0]?.name || ''; + targetModelId = models[0]?.id || ''; } else { targetModel = overrides.model || agentModels[0]?.name || ''; + targetModelId = overrides.model_id || agentModels[0]?.id || ''; } const attText = buildAttachmentsText(attachments); const content = attText ? `${text}\n\n${attText}` : text; try { - const res = await ChatAPI.send(targetAgentId, content, sessionId, targetModel, imageUrls); + const res = await ChatAPI.send(roomId, content, targetAgentId, targetModel, targetModelId, imageUrls); args.setMessages((m) => [...(m || []).filter((x) => x.id !== tempUser.id), res.user, res.assistant]); setSessionRefresh((t) => t + 1); setAttachments([]); @@ -309,11 +316,11 @@ export function useChatSender(args: { const handleClear = async () => { if (!agentId) return; - if (!sessionId) { - notify.error('会话未初始化,请稍后重试'); + if (!roomId) { + notify.error('房间未初始化,请稍后重试'); return; } - await ChatAPI.clear(agentId, sessionId); + await ChatAPI.clear(roomId); args.setMessages(() => []); setBranches({}); notify.success('对话已清空');