feat: AI 대화 DB 영속 + 다중 대화/기록 목록
- AiConversation·AiMessage 엔티티(user/conversation CASCADE), 제목 자동 생성 - 대화 스코프 API: GET/POST /ai/conversations, GET/:id, POST/:id/messages, DELETE/:id (전부 본인 소유 스코프 → IDOR 차단) - 클라는 새 메시지 1건만 전송, 서버가 DB 이력으로 Claude 호출(무상태 /ai/chat 폐기) - Claude 실패 시 사용자 메시지·빈 대화 롤백(고아 데이터 방지) - 프론트: AgentChatPanel 채팅↔지난 대화 목록 뷰(열기/삭제), ai.store 재작성(목록·현재 대화) - 다른 기기·재로그인·새로고침에도 기록 유지 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,53 @@
|
||||
import { useApi } from './useApi'
|
||||
import type { ChatMessage, ChatResult } from '@/types/ai'
|
||||
import type {
|
||||
ConversationDetail,
|
||||
ConversationSummary,
|
||||
SendResult,
|
||||
} from '@/types/ai'
|
||||
import type { Paginated } from '@/types/pagination'
|
||||
|
||||
// AI 도메인 API Composable — 대화 이력 전체를 전달(서버 무상태)
|
||||
// AI 도메인 API Composable — 대화/메시지는 서버(DB)에서 관리(본인 소유 스코프)
|
||||
export function useAi() {
|
||||
const api = useApi()
|
||||
|
||||
async function chat(messages: ChatMessage[]): Promise<ChatResult> {
|
||||
return (await api.post('/ai/chat', { messages })) as unknown as ChatResult
|
||||
async function listConversations(
|
||||
page = 1,
|
||||
size = 30,
|
||||
): Promise<Paginated<ConversationSummary>> {
|
||||
return (await api.get('/ai/conversations', {
|
||||
params: { page, size },
|
||||
})) as unknown as Paginated<ConversationSummary>
|
||||
}
|
||||
|
||||
return { chat }
|
||||
async function getConversation(id: string): Promise<ConversationDetail> {
|
||||
return (await api.get(
|
||||
`/ai/conversations/${id}`,
|
||||
)) as unknown as ConversationDetail
|
||||
}
|
||||
|
||||
// 새 대화 시작(첫 메시지)
|
||||
async function startConversation(content: string): Promise<SendResult> {
|
||||
return (await api.post('/ai/conversations', {
|
||||
content,
|
||||
})) as unknown as SendResult
|
||||
}
|
||||
|
||||
// 기존 대화에 메시지 추가
|
||||
async function sendMessage(id: string, content: string): Promise<SendResult> {
|
||||
return (await api.post(`/ai/conversations/${id}/messages`, {
|
||||
content,
|
||||
})) as unknown as SendResult
|
||||
}
|
||||
|
||||
async function deleteConversation(id: string): Promise<void> {
|
||||
await api.delete(`/ai/conversations/${id}`)
|
||||
}
|
||||
|
||||
return {
|
||||
listConversations,
|
||||
getConversation,
|
||||
startConversation,
|
||||
sendMessage,
|
||||
deleteConversation,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user