refactor(storage): 统一消息存储到 Core 层
问题:Server 端只存储最终文本响应,工具调用的中间消息丢失。 解决方案: - Agent.chat() 返回 ChatResult,包含完整消息链 - Server SessionManager 简化为只管理会话元数据 - 消息 API 改为从 Core Storage 读取 - 移除 Server 端的消息存储和 addMessage 方法 影响范围: - core: Agent.chat() 返回类型变更 - server: SessionManager 接口变更,移除消息存储 - server: GET /sessions/:id/messages 从 Core 读取 - server: 移除 POST /sessions/:id/messages 端点
This commit is contained in:
@@ -39,12 +39,20 @@ export interface CompressionResult {
|
||||
summaryTokens?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat 返回结果
|
||||
*/
|
||||
interface ChatResult {
|
||||
text: string;
|
||||
messages: unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent 实例接口
|
||||
*/
|
||||
interface AgentInstance {
|
||||
setRegistry(registry: unknown): void;
|
||||
chat(message: string, onStream?: (chunk: string) => void): Promise<string>;
|
||||
chat(message: string, onStream?: (chunk: string) => void): Promise<ChatResult>;
|
||||
getToolCount(): { core: number; discovered: number; total: number };
|
||||
getContextUsageFormatted(): string;
|
||||
getContextUsage(): TokenUsage;
|
||||
@@ -52,6 +60,7 @@ interface AgentInstance {
|
||||
getCompressionManager(): {
|
||||
shouldCompress(messages: unknown[]): boolean;
|
||||
};
|
||||
getHistory(): unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,23 +265,17 @@ export async function processMessage(sessionId: string, content: string): Promis
|
||||
}
|
||||
|
||||
// Core 模块不可用,返回占位响应
|
||||
const errorContent = 'Agent core module not available. Please build @ai-assistant/core first.';
|
||||
broadcastToSession(sessionId, {
|
||||
type: 'chunk',
|
||||
sessionId,
|
||||
payload: {
|
||||
content: 'Agent core module not available. Please build @ai-assistant/core first.',
|
||||
},
|
||||
});
|
||||
|
||||
const assistantMessage = await sessionManager.addMessage(sessionId, {
|
||||
role: 'assistant',
|
||||
content: 'Agent core module not available. Please build @ai-assistant/core first.',
|
||||
payload: { content: errorContent },
|
||||
});
|
||||
|
||||
broadcastToSession(sessionId, {
|
||||
type: 'done',
|
||||
sessionId,
|
||||
payload: assistantMessage,
|
||||
payload: { text: errorContent, hasToolCalls: false, messageCount: 0 },
|
||||
});
|
||||
|
||||
sessionManager.updateStatus(sessionId, 'idle' as SessionStatus);
|
||||
@@ -282,7 +285,7 @@ export async function processMessage(sessionId: string, content: string): Promis
|
||||
|
||||
try {
|
||||
// 调用 Agent 的 chat 方法,使用流式回调
|
||||
const response = await agent.chat(content, (chunk: string) => {
|
||||
const result = await agent.chat(content, (chunk: string) => {
|
||||
// 推送流式内容
|
||||
broadcastToSession(sessionId, {
|
||||
type: 'chunk',
|
||||
@@ -299,31 +302,41 @@ export async function processMessage(sessionId: string, content: string): Promis
|
||||
}
|
||||
});
|
||||
|
||||
// 保存助手消息
|
||||
const assistantMessage = await sessionManager.addMessage(sessionId, {
|
||||
role: 'assistant',
|
||||
content: response,
|
||||
// 消息已由 Core Agent 自动持久化,这里只更新 Server 端的会话计数
|
||||
const session = sessionManager.get(sessionId);
|
||||
if (session) {
|
||||
// 从 Agent 获取实际消息数
|
||||
const history = agent.getHistory();
|
||||
session.messageCount = history.length;
|
||||
session.updatedAt = new Date().toISOString();
|
||||
}
|
||||
|
||||
// 检查是否有工具调用
|
||||
const hasToolCalls = result.messages.some((m: unknown) => {
|
||||
const msg = m as { content?: unknown };
|
||||
return Array.isArray(msg.content) && msg.content.some((c: unknown) => {
|
||||
const block = c as { type?: string };
|
||||
return block.type === 'tool-call';
|
||||
});
|
||||
});
|
||||
|
||||
// 发送完成消息
|
||||
broadcastToSession(sessionId, {
|
||||
type: 'done',
|
||||
sessionId,
|
||||
payload: assistantMessage,
|
||||
payload: {
|
||||
text: result.text,
|
||||
hasToolCalls,
|
||||
messageCount: result.messages.length,
|
||||
},
|
||||
});
|
||||
|
||||
// 检查是否需要生成会话标题(首次对话完成后)
|
||||
const session = sessionManager.get(sessionId);
|
||||
const messages = sessionManager.getMessages(sessionId);
|
||||
if (session && !session.name && messages.length === 2) {
|
||||
// 首条用户消息 + 首条 AI 回复 = 2 条消息
|
||||
const userMessage = messages.find(m => m.role === 'user');
|
||||
if (userMessage) {
|
||||
// 异步生成标题,不阻塞响应
|
||||
generateSessionTitle(sessionId, userMessage.content, response).catch(err => {
|
||||
console.error('[Agent] Failed to generate session title:', err);
|
||||
});
|
||||
}
|
||||
if (session && !session.name) {
|
||||
// 异步生成标题,不阻塞响应
|
||||
generateSessionTitle(sessionId, content, result.text).catch(err => {
|
||||
console.error('[Agent] Failed to generate session title:', err);
|
||||
});
|
||||
}
|
||||
|
||||
emitStatusEvent(sessionId, 'idle');
|
||||
|
||||
Reference in New Issue
Block a user