/** * NAC Knowledge Engine - AI智能体对话历史持久化 * * MongoDB集合设计: * agent_conversations: 会话元数据(id, userId, agentType, title, createdAt, updatedAt, messageCount) * agent_messages: 消息记录(id, conversationId, role, content, confidence, sources, createdAt) * * 无Manus依赖,直接操作MongoDB */ import { ObjectId } from "mongodb"; import { getMongoDb, COLLECTIONS } from "./mongodb"; import type { AgentType } from "./aiAgents"; // ─── 类型定义 ───────────────────────────────────────────────────── export interface AgentConversation { _id?: ObjectId; conversationId: string; userId: number; userEmail: string; agentType: AgentType; title: string; // 取自第一条用户消息的前50字 messageCount: number; createdAt: Date; updatedAt: Date; } export interface AgentMessageRecord { _id?: ObjectId; messageId: string; conversationId: string; role: "user" | "assistant"; content: string; confidence?: number; // 仅assistant消息有 sources?: string[]; // 引用的知识库条目 suggestions?: string[]; // 后续建议 createdAt: Date; } // ─── 工具函数 ───────────────────────────────────────────────────── function generateId(): string { return new ObjectId().toHexString(); } function extractTitle(message: string): string { return message.slice(0, 50).replace(/\n/g, " ").trim() + (message.length > 50 ? "..." : ""); } // ─── 会话管理 ───────────────────────────────────────────────────── /** * 创建新会话 */ export async function createConversation( userId: number, userEmail: string, agentType: AgentType, firstMessage: string ): Promise { const db = await getMongoDb(); if (!db) throw new Error("MongoDB不可用"); const conversationId = generateId(); const now = new Date(); const conversation: AgentConversation = { conversationId, userId, userEmail, agentType, title: extractTitle(firstMessage), messageCount: 0, createdAt: now, updatedAt: now, }; await db.collection(COLLECTIONS.AGENT_CONVERSATIONS).insertOne(conversation); return conversationId; } /** * 获取用户的会话列表(按最近更新排序) */ export async function listConversations( userId: number, agentType?: AgentType, limit = 20, skip = 0 ): Promise<{ conversations: AgentConversation[]; total: number }> { const db = await getMongoDb(); if (!db) return { conversations: [], total: 0 }; const filter: Record = { userId }; if (agentType) filter.agentType = agentType; const [conversations, total] = await Promise.all([ db.collection(COLLECTIONS.AGENT_CONVERSATIONS) .find(filter) .sort({ updatedAt: -1 }) .skip(skip) .limit(limit) .toArray() as Promise, db.collection(COLLECTIONS.AGENT_CONVERSATIONS).countDocuments(filter), ]); return { conversations, total }; } /** * 获取单个会话信息 */ export async function getConversation( conversationId: string, userId: number ): Promise { const db = await getMongoDb(); if (!db) return null; return db.collection(COLLECTIONS.AGENT_CONVERSATIONS) .findOne({ conversationId, userId }) as Promise; } /** * 删除会话及其所有消息 */ export async function deleteConversation( conversationId: string, userId: number ): Promise { const db = await getMongoDb(); if (!db) return false; const result = await db.collection(COLLECTIONS.AGENT_CONVERSATIONS) .deleteOne({ conversationId, userId }); if (result.deletedCount > 0) { await db.collection(COLLECTIONS.AGENT_MESSAGES) .deleteMany({ conversationId }); return true; } return false; } // ─── 消息管理 ───────────────────────────────────────────────────── /** * 保存一对消息(用户消息 + AI回复)到数据库 */ export async function saveMessagePair( conversationId: string, userMessage: string, assistantMessage: string, confidence: number, sources?: string[], suggestions?: string[] ): Promise { const db = await getMongoDb(); if (!db) return; const now = new Date(); const userRecord: AgentMessageRecord = { messageId: generateId(), conversationId, role: "user", content: userMessage, createdAt: now, }; const assistantRecord: AgentMessageRecord = { messageId: generateId(), conversationId, role: "assistant", content: assistantMessage, confidence, sources, suggestions, createdAt: new Date(now.getTime() + 1), // 确保顺序 }; await db.collection(COLLECTIONS.AGENT_MESSAGES).insertMany([userRecord, assistantRecord]); // 更新会话的消息计数和最后更新时间 await db.collection(COLLECTIONS.AGENT_CONVERSATIONS).updateOne( { conversationId }, { $inc: { messageCount: 2 }, $set: { updatedAt: new Date() }, } ); } /** * 加载会话的消息历史(用于续接对话) */ export async function loadConversationMessages( conversationId: string, userId: number, limit = 20 ): Promise { const db = await getMongoDb(); if (!db) return []; // 先验证会话属于该用户 const conv = await getConversation(conversationId, userId); if (!conv) return []; return db.collection(COLLECTIONS.AGENT_MESSAGES) .find({ conversationId }) .sort({ createdAt: 1 }) .limit(limit) .toArray() as Promise; } /** * 将消息历史转换为Agent可用的格式 */ export function messagesToAgentHistory( messages: AgentMessageRecord[] ): Array<{ role: "user" | "assistant"; content: string }> { return messages.map(m => ({ role: m.role, content: m.content, })); }