feat: 完善 Server 层并添加 CLI 和 Web 前端

Server 层增强:
- 添加 Agent 适配层,支持动态加载 core 模块
- 实现 Token 认证机制,支持本地/远程模式
- WebSocket 集成 Agent 实时对话

CLI 模块 (packages/cli):
- serve 命令启动 HTTP Server
- attach 命令连接远程 Server
- API Client 封装

Web 前端 (packages/web):
- React 18 + Vite + Tailwind CSS
- 会话管理侧边栏
- WebSocket 实时聊天界面
- 流式消息显示
This commit is contained in:
2025-12-12 11:22:25 +08:00
parent 5e32375f0e
commit 168996a475
35 changed files with 4028 additions and 52 deletions
+8 -32
View File
@@ -6,6 +6,7 @@
import type { WSContext } from 'hono/ws';
import { getSessionManager } from './session/manager.js';
import { processMessage, cancelProcessing } from './agent/index.js';
import type { ClientMessage, ServerMessage } from './types.js';
// 存储活跃的 WebSocket 连接
@@ -103,9 +104,10 @@ export async function handleWebSocketMessage(
switch (message.type) {
case 'message': {
// 用户发送消息
const content = message.payload?.content || '';
const userMessage = sessionManager.addMessage(sessionId, {
role: 'user',
content: message.payload?.content || '',
content,
});
if (userMessage) {
@@ -116,48 +118,22 @@ export async function handleWebSocketMessage(
payload: userMessage,
});
// 更新状态为处理中
sessionManager.updateStatus(sessionId, 'busy');
// TODO: 调用 Agent 处理消息并流式返回
// 这里需要集成 core 模块的 Agent
// const agent = createAgent();
// for await (const chunk of agent.stream(message.payload.content)) {
// broadcastToSession(sessionId, {
// type: 'chunk',
// sessionId,
// payload: { content: chunk },
// });
// }
// 模拟响应 (后续替换为真实 Agent 调用)
setTimeout(() => {
const assistantMessage = sessionManager.addMessage(sessionId, {
role: 'assistant',
content: 'This is a placeholder response. Agent integration coming soon.',
});
broadcastToSession(sessionId, {
type: 'done',
sessionId,
payload: assistantMessage,
});
sessionManager.updateStatus(sessionId, 'idle');
}, 1000);
// 调用 Agent 处理消息(异步,不阻塞)
processMessage(sessionId, content).catch((error) => {
console.error('[WS] Agent processing error:', error);
});
}
break;
}
case 'cancel': {
// 取消当前操作
// TODO: 实现取消逻辑
cancelProcessing(sessionId);
broadcastToSession(sessionId, {
type: 'cancelled',
sessionId,
payload: { message: 'Operation cancelled' },
});
sessionManager.updateStatus(sessionId, 'idle');
break;
}