/** * Sessions API Routes * * 会话管理相关的 REST API */ import { Hono } from 'hono'; import { getSessionManager } from '../session/manager.js'; import { CreateSessionInputSchema, type ToolCallInfo, type MergedMessage } from '../types.js'; export const sessionsRouter = new Hono(); const sessionManager = getSessionManager(); /** * GET /sessions - 列出所有会话 */ sessionsRouter.get('/', (c) => { const sessions = sessionManager.list(); return c.json({ success: true, data: sessions, }); }); /** * POST /sessions - 创建新会话 */ sessionsRouter.post('/', async (c) => { try { const body = await c.req.json(); const input = CreateSessionInputSchema.parse(body); const session = await sessionManager.create(input); return c.json( { success: true, data: session, }, 201 ); } catch (error) { return c.json( { success: false, error: error instanceof Error ? error.message : 'Invalid input', }, 400 ); } }); /** * GET /sessions/:id - 获取单个会话 */ sessionsRouter.get('/:id', (c) => { const id = c.req.param('id'); const session = sessionManager.get(id); if (!session) { return c.json( { success: false, error: 'Session not found', }, 404 ); } return c.json({ success: true, data: session, }); }); /** * DELETE /sessions/:id - 删除会话 */ sessionsRouter.delete('/:id', async (c) => { const id = c.req.param('id'); if (!sessionManager.exists(id)) { return c.json( { success: false, error: 'Session not found', }, 404 ); } await sessionManager.delete(id); return c.json({ success: true, message: 'Session deleted', }); }); /** * GET /sessions/:id/messages - 获取会话消息 * * 从 Core 存储读取消息,直接返回(存储层已经是 2-message 格式) * * 存储格式: * - user 消息:TextPart(文本内容) * - assistant 消息:TextPart(文本) + ToolPart(工具调用,含状态机) */ sessionsRouter.get('/:id/messages', async (c) => { const id = c.req.param('id'); if (!sessionManager.exists(id)) { return c.json( { success: false, error: 'Session not found', }, 404 ); } try { // 动态导入 Core 存储 API const corePath = '@ai-assistant/core'; type MessageInfo = { id: string; sessionId: string; role: 'user' | 'assistant'; parentId?: string; createdAt: number; partIds: string[]; }; type Part = { id: string; createdAt: number; type: string; text?: string; toolCallId?: string; toolName?: string; state?: { status: 'pending' | 'running' | 'completed' | 'error'; input?: Record; output?: unknown; error?: string; time?: { start: number; end?: number }; }; }; const { MessageStorage, PartStorage } = (await import(/* webpackIgnore: true */ corePath)) as { MessageStorage: { listBySession(sessionId: string): Promise; }; PartStorage: { getByIds(messageId: string, partIds: string[]): Promise; }; }; // 获取消息列表(按创建时间排序) const messageInfos = await MessageStorage.listBySession(id); // 转换为前端格式 const messages: MergedMessage[] = []; for (const msgInfo of messageInfos) { const parts = await PartStorage.getByIds(msgInfo.id, msgInfo.partIds); // 提取文本内容 const textContent = parts .filter((p) => p.type === 'text') .map((p) => p.text ?? '') .join(''); // 提取工具调用 const toolCalls: ToolCallInfo[] = parts .filter((p) => p.type === 'tool' && p.state) .map((p) => { const state = p.state!; const startTime = state.time?.start; const endTime = state.time?.end; return { id: p.toolCallId ?? '', name: p.toolName ?? '', arguments: state.input ?? {}, status: state.status, result: state.status === 'completed' ? state.output : undefined, error: state.status === 'error' ? state.error : undefined, duration: startTime && endTime ? endTime - startTime : undefined, }; }); messages.push({ id: msgInfo.id, sessionId: msgInfo.sessionId, role: msgInfo.role, content: textContent, timestamp: new Date(msgInfo.createdAt).toISOString(), toolCalls: toolCalls.length > 0 ? toolCalls : undefined, }); } return c.json({ success: true, data: messages, }); } catch (error) { console.error('[Sessions] Failed to load messages:', error); return c.json({ success: true, data: [], }); } });