From 2eee14f1ab3a7743e16c926151aa71c51cd3f03f Mon Sep 17 00:00:00 2001 From: Acbox Date: Sun, 11 Jan 2026 14:46:52 +0800 Subject: [PATCH] docs: add README --- FIXES_SUMMARY.md | 190 -------- README.md | 97 ++++ packages/api/AGENT_API.md | 383 --------------- packages/api/API_CHANGES.md | 251 ---------- packages/api/AUTH_README.md | 277 ----------- packages/api/SETTINGS_API.md | 281 ----------- packages/api/USER_MANAGEMENT.md | 480 ------------------- packages/api/examples/agent-stream-client.ts | 164 ------- 8 files changed, 97 insertions(+), 2026 deletions(-) delete mode 100644 FIXES_SUMMARY.md delete mode 100644 packages/api/AGENT_API.md delete mode 100644 packages/api/API_CHANGES.md delete mode 100644 packages/api/AUTH_README.md delete mode 100644 packages/api/SETTINGS_API.md delete mode 100644 packages/api/USER_MANAGEMENT.md delete mode 100644 packages/api/examples/agent-stream-client.ts diff --git a/FIXES_SUMMARY.md b/FIXES_SUMMARY.md deleted file mode 100644 index 613b30bf..00000000 --- a/FIXES_SUMMARY.md +++ /dev/null @@ -1,190 +0,0 @@ -# 数据库和API修复总结 - -本次修复解决了数据库表设计和后端API的6个主要问题。 - -## ✅ 已完成的修复 - -### 1. 修复 isActive 数据类型 ✓ - -**问题**: `users.isActive` 字段使用 `text` 类型而不是 `boolean` - -**修复**: -- 文件: `packages/db/src/users.ts` -- 将 `isActive: text('is_active').notNull().default('true')` 改为 `isActive: boolean('is_active').notNull().default(true)` - -### 2. 添加外键约束 ✓ - -**问题**: 缺少重要的外键约束 - -**修复**: -- 文件: `packages/db/src/settings.ts` - - `userId` 字段从 `text` 改为 `uuid`,并添加外键引用 `users.id` -- 文件: `packages/db/src/history.ts` - - `user` 字段从 `text` 改为 `uuid`,并添加外键引用 `users.id` - -### 3. 重构 JWT 中间件消除重复代码 ✓ - -**问题**: JWT 配置在多个模块中重复定义 - -**修复**: -- 文件: `packages/api/src/middlewares/auth.ts` - - 创建共享的 `jwtPlugin` 包含 JWT 和 Bearer token 配置 - - 所有中间件复用这个插件,消除重复代码 -- 更新的模块: - - `packages/api/src/modules/auth/index.ts` - - `packages/api/src/modules/memory/index.ts` - - `packages/api/src/modules/settings/index.ts` - - `packages/api/src/modules/agent/index.ts` - -### 4. 实现统一错误处理中间件 ✓ - -**问题**: 缺少统一的错误处理机制 - -**修复**: -- 文件: `packages/api/src/middlewares/error.ts` (新建) - - 创建统一的错误处理中间件 - - 定义标准的错误响应格式 `ErrorResponse` - - 定义标准的成功响应格式 `SuccessResponse` - - 自动根据错误类型设置合适的 HTTP 状态码 - - 支持的错误类型: - - `VALIDATION` (400) - - `NOT_FOUND` (404) - - `PARSE` (400) - - `UNAUTHORIZED` (401) - - `FORBIDDEN` (403) - - `CONFLICT` (409) - - `INTERNAL_SERVER_ERROR` (500) -- 文件: `packages/api/src/index.ts` - - 在主应用中启用错误处理中间件 - -### 5. 为 model 模块添加权限控制 ✓ - -**问题**: model 模块的创建、更新、删除操作没有权限检查 - -**修复**: -- 文件: `packages/api/src/modules/model/index.ts` - - 读取操作 (GET) 使用 `optionalAuthMiddleware`(公开或可选认证) - - 写入操作 (POST, PUT, DELETE) 使用 `adminMiddleware`(仅管理员) - - 使用 `guard` 分离不同权限级别的路由 - -### 6. 添加分页功能到列表接口 ✓ - -**问题**: 列表接口缺少分页、排序功能 - -**修复**: -- 文件: `packages/api/src/utils/pagination.ts` (新建) - - 创建通用的分页工具函数 - - `parsePaginationParams()` - 解析分页参数 - - `createPaginatedResult()` - 创建分页结果 - - `calculateOffset()` - 计算偏移量 - - 标准分页响应格式: - ```typescript - { - items: T[], - pagination: { - page: number, - limit: number, - total: number, - totalPages: number, - hasNext: boolean, - hasPrev: boolean - } - } - ``` - -- 文件: `packages/api/src/modules/user/service.ts` - - 更新 `getUsers()` 支持分页和排序 - - 支持参数: `page`, `limit`, `sortBy`, `sortOrder` - -- 文件: `packages/api/src/modules/user/index.ts` - - GET `/user` 接口支持分页查询参数 - -- 文件: `packages/api/src/modules/model/service.ts` - - 更新 `getModels()` 支持分页 - - 支持参数: `page`, `limit`, `sortOrder` - -- 文件: `packages/api/src/modules/model/index.ts` - - GET `/model` 接口支持分页查询参数 - -## 📋 API 使用示例 - -### 分页查询用户 -```bash -GET /user?page=1&limit=10&sortBy=createdAt&sortOrder=desc -``` - -响应: -```json -{ - "success": true, - "items": [...], - "pagination": { - "page": 1, - "limit": 10, - "total": 50, - "totalPages": 5, - "hasNext": true, - "hasPrev": false - } -} -``` - -### 分页查询模型 -```bash -GET /model?page=1&limit=10&sortOrder=desc -``` - -### 错误响应格式 -```json -{ - "success": false, - "error": "Error message", - "code": "ERROR_CODE", - "details": { ... } -} -``` - -## 🔄 数据库迁移 - -修改了数据库 schema 后,需要运行迁移: - -```bash -cd packages/db -pnpm run generate # 生成迁移文件 -pnpm run push # 执行迁移 -``` - -## ⚠️ 注意事项 - -1. **数据库迁移**: 修改了 `users.isActive`, `settings.userId`, `history.user` 字段,需要迁移现有数据 -2. **API 响应格式变化**: 列表接口现在返回分页格式,前端需要适配 -3. **权限控制**: model 的写入操作现在需要管理员权限 - -## 📚 相关文件 - -### 数据库 Schema -- `packages/db/src/users.ts` -- `packages/db/src/settings.ts` -- `packages/db/src/history.ts` - -### 中间件 -- `packages/api/src/middlewares/auth.ts` -- `packages/api/src/middlewares/error.ts` -- `packages/api/src/middlewares/index.ts` - -### API 模块 -- `packages/api/src/modules/user/index.ts` -- `packages/api/src/modules/user/service.ts` -- `packages/api/src/modules/model/index.ts` -- `packages/api/src/modules/model/service.ts` -- `packages/api/src/modules/auth/index.ts` -- `packages/api/src/modules/memory/index.ts` -- `packages/api/src/modules/settings/index.ts` -- `packages/api/src/modules/agent/index.ts` - -### 工具函数 -- `packages/api/src/utils/pagination.ts` - -### 主应用 -- `packages/api/src/index.ts` - diff --git a/README.md b/README.md index e69de29b..f1a55695 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,97 @@ +
+

MemoHome

+

Long-memory, self-hosted, AI-powered personal housekeeper and lifemate.

+
+ +Memohome是一个专属于你的AI私人管家,你可以把它跑在你的NAS,路由器等个人设备上,24小时的为你提供服务。 + +## Features + +- [x] 长记忆:Memohome拥有长记忆能力,可以为你的家庭成员提供个性化的服务。他会存储最近一段时间(默认最近15个小时)的上下文,超出时间后则会根据你的需求按需加载记忆 +- [x] 定时任务:Memohome可以帮你创建智能的定时任务,比如:每天早上七点生成一个早餐菜谱,通过Telegram发送给我 +- [ ] 聊天软件支持:Memohome可以支持多种聊天软件,比如:Telegram,微信,QQ等常用社交软件,通过直接发送消息与Memohome进行交互,同时Memohome也可以通过事件触发,选择工具主动给你发送消息 +- [ ] 文件系统管理:Memohome可以帮你管理你的文件系统,比如:文件搜索,图片分类,文件分享等。他可以创建文件,也可以通过聊天软件发送文件给你;你也可以通过发送文件给他帮你处理。 +- [ ] MCP支持:Memohome可以支持多种MCP接口,与多种外部工具进行交互。 +- More... + +## Quick Start + +环境: +- PostgreSQL 16+ +- Bun 1.2+ +- PNPM +- Qdrant + +```bash +cp .env.example .env +pnpm install +``` + +
+Environment Variables +- `DATABASE_URL`: PostgreSQL 连接字符串 +- `ROOT_USER`: 超级管理员用户名 +- `ROOT_USER_PASSWORD`: 超级管理员密码 +- `JWT_SECRET`: JWT 签名密钥 +- `QDRANT_URL`: Qdrant 连接字符串 +
+ +### 数据库初始化 + +```bash +pnpm run db:push +``` + +### API Server + +```bash +pnpm run api:dev +``` + +API服务将在 `http://localhost:7002` 启动。 + +### 命令行工具 + +首先你需要登录: +```bash +pnpm cli auth login +``` + +按照提示输入管理员用户名和密码。 + + +直接运行以下命令会进入Agent交互模式 + +```bash +pnpm cli +``` + +在此之前你需要配置模型,你至少需要配置一个聊天模型,一个嵌入模型,一个摘要模型。 + +```bash +pnpm run model:create --name "GPT-4" --model-id "gpt-4" --base-url "https://api.openai.com/v1" --api-key "your-api-key" --client-type "openai" --type "chat" +``` +- `--name`: 模型显示名称 +- `--model-id`: 模型ID +- `--base-url`: 模型API地址 +- `--api-key`: 模型API密钥 +- `--client-type`: 模型提供者类型, 可选值为 `openai` 或 `anthropic` 或 `google` +- `--type`: 模型类型,可选值为 `chat` 或 `embedding` + +创建成功后你会得到一个uuid,你可以通过这个uuid来配置你的设置: + +```bash +pnpm cli config set --chat-model --summary-model --embedding-model +``` +- `--chat-model`: 聊天模型uuid +- `--summary-model`: 摘要模型uuid +- `--embedding-model`: 嵌入模型uuid + +然后你就可以正常的使用Memohome了。 + +你可以设置你的最大上下文加载时间,默认是900分钟,你可以通过以下命令来设置: + +```bash +pnpm cli config set --max-context-time +``` +- `--max-context-time`: 最大上下文加载时间,单位为分钟 \ No newline at end of file diff --git a/packages/api/AGENT_API.md b/packages/api/AGENT_API.md deleted file mode 100644 index cedfd24a..00000000 --- a/packages/api/AGENT_API.md +++ /dev/null @@ -1,383 +0,0 @@ -# Agent API 文档 - -## 概述 - -Agent API 提供了一个智能对话代理接口,支持流式响应、记忆管理和工具调用。 - -## 端点 - -### POST `/agent/stream` 🔒 需要认证 - -与 AI Agent 进行流式对话。 - -#### 权限要求 - -- 需要有效的 Bearer token -- 自动使用当前登录用户的身份 - -#### 请求 - -**Headers:** -``` -Authorization: Bearer -Content-Type: application/json -``` - -**Body:** -```json -{ - "message": "你好,请介绍一下你自己", - "maxContextLoadTime": 60, - "language": "Chinese" -} -``` - -**参数说明:** - -| 字段 | 类型 | 必需 | 默认值 | 说明 | -|------|------|------|--------|------| -| message | string | 是 | - | 用户消息内容 | -| maxContextLoadTime | number | 否 | 从设置读取或60 | 加载上下文的时间范围(分钟,1-1440) | -| language | string | 否 | 从设置读取或"Same as user input" | Agent 回复的首选语言 | - -**注意**: `maxContextLoadTime` 和 `language` 如果在请求中未指定,将从用户设置(Settings)中读取。如果设置中也没有,则使用默认值。 - -#### 响应 - -返回 Server-Sent Events (SSE) 流式响应。 - -**Content-Type:** `text/event-stream` - -**事件格式:** - -每个事件以 `data: ` 开头,后跟 JSON 格式的数据: - -``` -data: {"type":"text-delta","text":"你"} - -data: {"type":"text-delta","text":"好"} - -data: {"type":"tool-call","toolName":"search_memory","args":{...}} - -data: [DONE] -``` - -**事件类型:** - -1. **text-delta** - 文本增量 -```json -{ - "type": "text-delta", - "text": "文本片段" -} -``` - -2. **tool-call** - 工具调用 -```json -{ - "type": "tool-call", - "toolName": "search_memory", - "args": { - "query": "搜索内容" - } -} -``` - -3. **[DONE]** - 流结束标记 - -4. **error** - 错误事件 -```json -{ - "type": "error", - "error": "错误消息" -} -``` - -#### 错误响应 - -**400 Bad Request** - 模型配置未找到 -```json -{ - "success": false, - "error": "Model configuration not found. Please configure your models in settings." -} -``` - -**401 Unauthorized** - 未认证 -```json -{ - "success": false, - "error": "No bearer token provided" -} -``` - -**500 Internal Server Error** - 服务器错误 -```json -{ - "success": false, - "error": "Failed to process request" -} -``` - ---- - -## 使用示例 - -### JavaScript/TypeScript (EventSource) - -```typescript -async function streamAgentChat(message: string, token: string) { - const response = await fetch('http://localhost:7002/agent/stream', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - message, - maxContextLoadTime: 60, - language: 'Chinese', - }), - }) - - if (!response.ok) { - const error = await response.json() - throw new Error(error.error) - } - - const reader = response.body?.getReader() - const decoder = new TextDecoder() - - if (!reader) throw new Error('No reader available') - - while (true) { - const { done, value } = await reader.read() - if (done) break - - const chunk = decoder.decode(value) - const lines = chunk.split('\n') - - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = line.slice(6) - - if (data === '[DONE]') { - console.log('\n✅ Stream completed') - return - } - - try { - const event = JSON.parse(data) - - if (event.type === 'text-delta' && event.text) { - process.stdout.write(event.text) - } else if (event.type === 'tool-call') { - console.log(`\n[Tool: ${event.toolName}]`) - } else if (event.type === 'error') { - console.error('\n❌ Error:', event.error) - } - } catch (e) { - // Skip invalid JSON - } - } - } - } -} - -// 使用示例 -const token = 'your_jwt_token_here' -await streamAgentChat('你好,请介绍一下你自己', token) -``` - -### curl 示例 - -```bash -# 1. 登录获取 token -TOKEN=$(curl -X POST http://localhost:7002/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"admin","password":"your_password"}' \ - | jq -r '.data.token') - -# 2. 流式对话 -curl -N -X POST http://localhost:7002/agent/stream \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "message": "你好,请介绍一下你自己", - "maxContextLoadTime": 60, - "language": "Chinese" - }' -``` - -### Python 示例 - -```python -import requests -import json - -def stream_agent_chat(message: str, token: str): - url = 'http://localhost:7002/agent/stream' - headers = { - 'Authorization': f'Bearer {token}', - 'Content-Type': 'application/json', - } - data = { - 'message': message, - 'maxContextLoadTime': 60, - 'language': 'Chinese', - } - - with requests.post(url, headers=headers, json=data, stream=True) as response: - response.raise_for_status() - - for line in response.iter_lines(): - if line: - line_str = line.decode('utf-8') - if line_str.startswith('data: '): - data = line_str[6:] - - if data == '[DONE]': - print('\n✅ Stream completed') - break - - try: - event = json.loads(data) - - if event.get('type') == 'text-delta' and event.get('text'): - print(event['text'], end='', flush=True) - elif event.get('type') == 'tool-call': - print(f"\n[Tool: {event['toolName']}]") - elif event.get('type') == 'error': - print(f"\n❌ Error: {event['error']}") - except json.JSONDecodeError: - pass - -# 使用示例 -token = 'your_jwt_token_here' -stream_agent_chat('你好,请介绍一下你自己', token) -``` - ---- - -## 工作原理 - -### 1. 认证验证 - -- 验证 JWT token -- 提取用户信息 - -### 2. 模型配置获取 - -从用户设置中获取: -- Chat Model(对话模型) -- Embedding Model(嵌入模型) -- Summary Model(摘要模型) - -### 3. Agent 创建 - -- 创建 Memory 实例(用于记忆管理) -- 创建 Agent 实例,配置回调函数: - - `onReadMemory`: 从数据库加载历史对话 - - `onSearchMemory`: 搜索相关记忆 - - `onFinish`: 保存对话到记忆 - -### 4. 流式响应 - -- Agent 处理用户消息 -- 实时流式返回生成的文本 -- 报告工具调用事件 -- 完成后自动保存到记忆 - -### 5. 记忆管理 - -- 自动加载近期对话历史作为上下文 -- 使用向量搜索查找相关记忆 -- 对话结束后自动保存 - ---- - -## 特性 - -### ✅ 流式响应 - -- 实时返回生成的文本 -- 无需等待完整响应 -- 更好的用户体验 - -### ✅ 记忆管理 - -- 自动保存对话历史 -- 智能加载相关上下文 -- 向量搜索相关记忆 - -### ✅ 工具调用 - -- 支持搜索记忆工具 -- 可扩展其他工具 -- 实时报告工具使用 - -### ✅ 个性化配置 - -- 每个用户使用自己的模型配置 -- 可自定义语言偏好 -- 可配置上下文加载时间 - ---- - -## 前置条件 - -### 1. 配置模型和 Agent 设置 - -使用 Settings API 配置默认模型和 Agent 参数: - -```bash -curl -X PUT http://localhost:7002/settings \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "defaultChatModel": "chat-model-uuid", - "defaultEmbeddingModel": "embedding-model-uuid", - "defaultSummaryModel": "summary-model-uuid", - "maxContextLoadTime": 60, - "language": "Chinese" - }' -``` - -详见 [Settings API 文档](./SETTINGS_API.md) - -### 2. 创建模型配置 - -使用 Model API 创建模型: - -```bash -curl -X POST http://localhost:7002/model \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "modelId": "gpt-4", - "baseUrl": "https://api.openai.com/v1", - "apiKey": "your-api-key", - "clientType": "openai", - "name": "GPT-4" - }' -``` - ---- - -## 限制和注意事项 - -1. **模型配置必需**: 用户必须先配置好模型才能使用 Agent -2. **流式连接**: 需要支持 Server-Sent Events 的客户端 -3. **超时处理**: 长时间无响应可能导致连接超时 -4. **并发限制**: 建议每个用户同时只维护一个对话流 - ---- - -## 相关文档 - -- [认证系统](./AUTH_README.md) -- [用户管理](./USER_MANAGEMENT.md) -- [Settings API](./API_CHANGES.md) -- [Model API](./README.md) -- [Agent 包文档](../agent/README.md) - diff --git a/packages/api/API_CHANGES.md b/packages/api/API_CHANGES.md deleted file mode 100644 index d9c8b27e..00000000 --- a/packages/api/API_CHANGES.md +++ /dev/null @@ -1,251 +0,0 @@ -# API 变更说明 - -## 🔒 Settings 和 Memory 模块现已使用认证 - -### 概述 - -Settings 和 Memory 模块现在使用 JWT 认证中间件,自动从 token 中获取当前用户信息,**不再需要手动传入 userId**。 - ---- - -## Settings 模块变更 - -### ❌ 旧 API(已废弃) - -```bash -# 获取用户设置 -GET /settings/:userId - -# 创建用户设置 -POST /settings -{ - "userId": "user123", - "defaultChatModel": "uuid-here" -} - -# 更新用户设置 -PUT /settings/:userId -{ - "defaultChatModel": "uuid-here" -} -``` - -### ✅ 新 API(需要认证) - -```bash -# 获取当前用户的设置 -GET /settings -Authorization: Bearer - -# 更新或创建当前用户的设置 -PUT /settings -Authorization: Bearer -{ - "defaultChatModel": "uuid-here", - "defaultEmbeddingModel": "uuid-here", - "defaultSummaryModel": "uuid-here", - "maxContextLoadTime": 60, - "language": "Chinese" -} -``` - -### 使用示例 - -```bash -# 1. 登录获取 token -TOKEN=$(curl -X POST http://localhost:7002/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"user","password":"pass"}' \ - | jq -r '.data.token') - -# 2. 获取我的设置 -curl http://localhost:7002/settings \ - -H "Authorization: Bearer $TOKEN" - -# 3. 更新我的设置 -curl -X PUT http://localhost:7002/settings \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "defaultChatModel": "123e4567-e89b-12d3-a456-426614174000", - "maxContextLoadTime": 60, - "language": "Chinese" - }' -``` - ---- - -## Memory 模块变更 - -### ❌ 旧 API(已废弃) - -```bash -# 添加记忆 -POST /memory -{ - "messages": [...], - "timestamp": "2024-01-10T10:00:00Z", - "user": "user123" -} - -# 搜索记忆 -GET /memory/search?query=hello&userId=user123 - -# 获取消息历史 -GET /memory/message?page=1&limit=10&userId=user123 - -# 按日期过滤消息 -GET /memory/message/filter?from=2024-01-01&to=2024-01-31&userId=user123 -``` - -### ✅ 新 API(需要认证) - -```bash -# 添加记忆(自动使用当前用户) -POST /memory -Authorization: Bearer -{ - "messages": [...], - "timestamp": "2024-01-10T10:00:00Z" -} - -# 搜索当前用户的记忆 -GET /memory/search?query=hello -Authorization: Bearer - -# 获取当前用户的消息历史 -GET /memory/message?page=1&limit=10 -Authorization: Bearer - -# 按日期过滤当前用户的消息 -GET /memory/message/filter?from=2024-01-01&to=2024-01-31 -Authorization: Bearer -``` - -### 使用示例 - -```bash -# 1. 登录获取 token -TOKEN=$(curl -X POST http://localhost:7002/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"user","password":"pass"}' \ - | jq -r '.data.token') - -# 2. 添加记忆 -curl -X POST http://localhost:7002/memory \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "messages": [ - {"role": "user", "content": "Hello"}, - {"role": "assistant", "content": "Hi there!"} - ], - "timestamp": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'" - }' - -# 3. 搜索记忆 -curl "http://localhost:7002/memory/search?query=hello" \ - -H "Authorization: Bearer $TOKEN" - -# 4. 获取消息历史(分页) -curl "http://localhost:7002/memory/message?page=1&limit=10" \ - -H "Authorization: Bearer $TOKEN" - -# 5. 按日期范围过滤 -curl "http://localhost:7002/memory/message/filter?from=2024-01-01&to=2024-01-31" \ - -H "Authorization: Bearer $TOKEN" -``` - ---- - -## 安全优势 - -### ✅ 更安全 - -- 用户只能访问自己的数据 -- 无法通过修改 userId 参数访问其他用户的数据 -- 所有操作都需要有效的认证 token - -### ✅ 更简洁 - -- API 调用更简单,无需手动传递 userId -- 减少了参数验证和错误处理 -- 代码更清晰易维护 - -### ✅ 一致性 - -- 与其他需要认证的模块保持一致 -- 统一的认证流程和错误处理 -- 符合 RESTful 最佳实践 - ---- - -## 迁移指南 - -### 1. 更新客户端代码 - -#### 之前: -```javascript -// 需要手动传入 userId -const settings = await fetch(`/settings/${userId}`) -const memories = await fetch(`/memory/search?query=hello&userId=${userId}`) -``` - -#### 现在: -```javascript -// 自动使用 token 中的用户信息 -const settings = await fetch('/settings', { - headers: { 'Authorization': `Bearer ${token}` } -}) - -const memories = await fetch('/memory/search?query=hello', { - headers: { 'Authorization': `Bearer ${token}` } -}) -``` - -### 2. 错误处理 - -新增错误响应: - -```json -// 401 Unauthorized - 未提供 token 或 token 无效 -{ - "success": false, - "error": "No bearer token provided" -} - -// 401 Unauthorized - Token 过期 -{ - "success": false, - "error": "Invalid or expired token" -} -``` - ---- - -## API 端点总结 - -### Settings 模块 `/settings` 🔒 - -| 方法 | 路径 | 说明 | 认证 | -|------|------|------|------| -| GET | `/` | 获取当前用户设置 | ✅ 必需 | -| PUT | `/` | 更新当前用户设置 | ✅ 必需 | - -### Memory 模块 `/memory` 🔒 - -| 方法 | 路径 | 说明 | 认证 | -|------|------|------|------| -| POST | `/` | 添加记忆 | ✅ 必需 | -| GET | `/search` | 搜索记忆 | ✅ 必需 | -| GET | `/message` | 获取消息列表(分页) | ✅ 必需 | -| GET | `/message/filter` | 按日期范围过滤消息 | ✅ 必需 | - ---- - -## 相关文档 - -- [认证系统文档](./AUTH_README.md) -- [用户管理文档](./USER_MANAGEMENT.md) -- [项目设置指南](../../SETUP.md) - diff --git a/packages/api/AUTH_README.md b/packages/api/AUTH_README.md deleted file mode 100644 index 95e48959..00000000 --- a/packages/api/AUTH_README.md +++ /dev/null @@ -1,277 +0,0 @@ -# 认证系统使用文档 - -## 概述 - -本项目使用 JWT (JSON Web Token) 进行用户认证,集成了 Elysia 官方插件: -- [@elysiajs/jwt](https://elysiajs.com/plugins/jwt.html) - JWT token 生成和验证 -- [@elysiajs/bearer](https://elysiajs.com/plugins/bearer.html) - Bearer token 提取 - -## 环境变量配置 - -在项目根目录的 `.env` 文件中配置以下变量: - -```bash -# Root 超级用户配置 -ROOT_USER=admin -ROOT_USER_PASSWORD=your_secure_password - -# JWT 配置 -JWT_SECRET=your-jwt-secret-key-change-in-production -JWT_EXPIRES_IN=7d # Token 有效期,可选 - -# API 服务器端口 -API_SERVER_PORT=7002 -``` - -## API 端点 - -### 1. 登录 POST `/auth/login` - -用户登录并获取 JWT token。 - -**请求体:** -```json -{ - "username": "admin", - "password": "your_password" -} -``` - -**成功响应:** -```json -{ - "success": true, - "data": { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "user": { - "id": "root", - "username": "admin", - "role": "admin", - "displayName": "Root User", - "email": null - } - } -} -``` - -**失败响应:** -```json -{ - "success": false, - "error": "Invalid username or password" -} -``` - -### 2. 验证 Token GET `/auth/verify` - -验证 JWT token 是否有效。 - -**请求头:** -``` -Authorization: Bearer -``` - -**成功响应:** -```json -{ - "success": true, - "data": { - "userId": "root", - "username": "admin", - "role": "admin" - } -} -``` - -**失败响应:** -```json -{ - "success": false, - "error": "Invalid or expired token" -} -``` - -### 3. 获取当前用户信息 GET `/auth/me` - -获取当前登录用户的信息。 - -**请求头:** -``` -Authorization: Bearer -``` - -**成功响应:** -```json -{ - "success": true, - "data": { - "userId": "root", - "username": "admin", - "role": "admin" - } -} -``` - -## 使用示例 - -### JavaScript/TypeScript 客户端 - -```typescript -// 1. 登录 -const loginResponse = await fetch('http://localhost:7002/auth/login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - username: 'admin', - password: 'your_password', - }), -}) - -const loginData = await loginResponse.json() -const token = loginData.data.token - -// 2. 使用 token 访问受保护的资源 -const meResponse = await fetch('http://localhost:7002/auth/me', { - headers: { - 'Authorization': `Bearer ${token}`, - }, -}) - -const userData = await meResponse.json() -console.log(userData.data) // 用户信息 -``` - -### curl 示例 - -```bash -# 1. 登录 -curl -X POST http://localhost:7002/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"admin","password":"your_password"}' - -# 2. 使用返回的 token 访问受保护资源 -TOKEN="" -curl http://localhost:7002/auth/me \ - -H "Authorization: Bearer $TOKEN" -``` - -## 在其他模块中使用认证 - -### 使用认证中间件 - -项目提供了三个认证中间件: - -#### 1. `authMiddleware` - 强制认证 - -要求请求必须包含有效的 Bearer token,否则返回 401。 - -```typescript -import Elysia from 'elysia' -import { authMiddleware } from './middlewares' - -export const protectedModule = new Elysia({ prefix: '/protected' }) - .use(authMiddleware) - .get('/data', ({ user }) => { - // user 包含: { userId, username, role } - return { - success: true, - message: `Hello ${user.username}!`, - } - }) -``` - -#### 2. `optionalAuthMiddleware` - 可选认证 - -如果有 token 则验证,没有 token 也允许访问(user 为 null)。 - -```typescript -import Elysia from 'elysia' -import { optionalAuthMiddleware } from './middlewares' - -export const publicModule = new Elysia({ prefix: '/public' }) - .use(optionalAuthMiddleware) - .get('/data', ({ user }) => { - if (user) { - return { message: `Welcome back, ${user.username}!` } - } - return { message: 'Welcome, guest!' } - }) -``` - -#### 3. `adminMiddleware` - 管理员权限 - -要求用户必须是 admin 角色,否则返回 403。 - -```typescript -import Elysia from 'elysia' -import { adminMiddleware } from './middlewares' - -export const adminModule = new Elysia({ prefix: '/admin' }) - .use(adminMiddleware) - .get('/users', ({ user }) => { - // 只有 admin 才能访问 - return { success: true, data: [] } - }) -``` - -## Root 用户说明 - -Root 用户是通过环境变量配置的超级管理员: - -- **优先级最高**:登录时优先检查是否为 Root 用户 -- **不存储在数据库**:直接通过环境变量验证 -- **始终是 admin 角色**:拥有最高权限 -- **用于系统初始化**:可用于创建其他管理员用户 - -## 数据库用户 - -除了 Root 用户外,系统支持在数据库中创建普通用户: - -```typescript -import { createUser } from '@memohome/db/src/user-helpers' - -// 创建新用户 -const newUser = await createUser({ - username: 'john_doe', - email: 'john@example.com', - passwordHash: await Bun.password.hash('password123'), - role: 'member', - displayName: 'John Doe', -}) -``` - -用户密码使用 `Bun.password.hash` 加密存储,登录时使用 `Bun.password.verify` 验证。 - -## 安全建议 - -1. **生产环境配置**: - - 使用强密码作为 `ROOT_USER_PASSWORD` - - 设置随机的 `JWT_SECRET`(至少 32 字符) - - 不要将 `.env` 文件提交到代码仓库 - -2. **Token 管理**: - - Token 默认有效期为 7 天 - - 前端应安全存储 token(如 httpOnly cookie 或安全的 localStorage) - - Token 过期后需要重新登录 - -3. **密码策略**: - - 要求用户使用强密码 - - 考虑实现密码复杂度验证 - - 考虑添加密码重置功能 - -## 技术栈 - -- **Elysia**:Web 框架 -- **@elysiajs/jwt**:JWT token 生成和验证插件 -- **@elysiajs/bearer**:Bearer token 提取插件 -- **Bun.password**:密码加密和验证(基于 bcrypt) -- **Drizzle ORM**:数据库操作 - -## 相关文档 - -- [Elysia JWT Plugin](https://elysiajs.com/plugins/jwt.html) -- [Elysia Bearer Plugin](https://elysiajs.com/plugins/bearer.html) -- [用户表设计文档](../db/USERS_SCHEMA.md) - diff --git a/packages/api/SETTINGS_API.md b/packages/api/SETTINGS_API.md deleted file mode 100644 index 64d6bfba..00000000 --- a/packages/api/SETTINGS_API.md +++ /dev/null @@ -1,281 +0,0 @@ -# Settings API 文档 - -## 概述 - -Settings API 用于管理用户的个性化设置,包括默认模型配置和 Agent 行为设置。 - -## 端点 - -### GET `/settings` 🔒 需要认证 - -获取当前用户的设置。 - -#### 请求 - -**Headers:** -``` -Authorization: Bearer -``` - -#### 成功响应 (200 OK) - -```json -{ - "success": true, - "data": { - "userId": "user-id", - "defaultChatModel": "123e4567-e89b-12d3-a456-426614174000", - "defaultEmbeddingModel": "223e4567-e89b-12d3-a456-426614174001", - "defaultSummaryModel": "323e4567-e89b-12d3-a456-426614174002", - "maxContextLoadTime": 60, - "language": "Chinese" - } -} -``` - -#### 错误响应 (404 Not Found) - -```json -{ - "success": false, - "error": "Settings not found" -} -``` - ---- - -### PUT `/settings` 🔒 需要认证 - -更新或创建当前用户的设置(Upsert 操作)。 - -#### 请求 - -**Headers:** -``` -Authorization: Bearer -Content-Type: application/json -``` - -**Body:** -```json -{ - "defaultChatModel": "123e4567-e89b-12d3-a456-426614174000", - "defaultEmbeddingModel": "223e4567-e89b-12d3-a456-426614174001", - "defaultSummaryModel": "323e4567-e89b-12d3-a456-426614174002", - "maxContextLoadTime": 60, - "language": "Chinese" -} -``` - -**参数说明:** - -| 字段 | 类型 | 必需 | 默认值 | 说明 | -|------|------|------|--------|------| -| defaultChatModel | string (uuid) | 否 | null | 默认聊天模型 ID | -| defaultEmbeddingModel | string (uuid) | 否 | null | 默认嵌入模型 ID | -| defaultSummaryModel | string (uuid) | 否 | null | 默认摘要模型 ID | -| maxContextLoadTime | number | 否 | 60 | Agent 加载上下文的时间范围(分钟,1-1440) | -| language | string | 否 | "Same as user input" | Agent 回复的首选语言 | - -#### 成功响应 (200 OK) - -```json -{ - "success": true, - "data": { - "userId": "user-id", - "defaultChatModel": "123e4567-e89b-12d3-a456-426614174000", - "defaultEmbeddingModel": "223e4567-e89b-12d3-a456-426614174001", - "defaultSummaryModel": "323e4567-e89b-12d3-a456-426614174002", - "maxContextLoadTime": 60, - "language": "Chinese" - } -} -``` - ---- - -## 使用示例 - -### 完整工作流 - -```bash -# 1. 登录获取 token -TOKEN=$(curl -X POST http://localhost:7002/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"admin","password":"your_password"}' \ - | jq -r '.data.token') - -# 2. 获取当前设置 -curl http://localhost:7002/settings \ - -H "Authorization: Bearer $TOKEN" - -# 3. 更新设置 -curl -X PUT http://localhost:7002/settings \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "defaultChatModel": "123e4567-e89b-12d3-a456-426614174000", - "defaultEmbeddingModel": "223e4567-e89b-12d3-a456-426614174001", - "defaultSummaryModel": "323e4567-e89b-12d3-a456-426614174002", - "maxContextLoadTime": 120, - "language": "English" - }' - -# 4. 只更新部分字段 -curl -X PUT http://localhost:7002/settings \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "maxContextLoadTime": 30, - "language": "Chinese" - }' -``` - -### JavaScript/TypeScript 示例 - -```typescript -// 获取设置 -async function getSettings(token: string) { - const response = await fetch('http://localhost:7002/settings', { - headers: { - 'Authorization': `Bearer ${token}`, - }, - }) - - const data = await response.json() - return data -} - -// 更新设置 -async function updateSettings(token: string, settings: { - defaultChatModel?: string - defaultEmbeddingModel?: string - defaultSummaryModel?: string - maxContextLoadTime?: number - language?: string -}) { - const response = await fetch('http://localhost:7002/settings', { - method: 'PUT', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(settings), - }) - - const data = await response.json() - return data -} - -// 使用示例 -const token = 'your_jwt_token' - -// 获取当前设置 -const currentSettings = await getSettings(token) -console.log(currentSettings) - -// 更新 Agent 设置 -await updateSettings(token, { - maxContextLoadTime: 90, - language: 'Chinese', -}) -``` - ---- - -## Agent 设置说明 - -### maxContextLoadTime - -控制 Agent 加载历史对话上下文的时间范围。 - -- **类型**: 整数(分钟) -- **范围**: 1-1440(1分钟到24小时) -- **默认值**: 60(1小时) -- **说明**: - - 值越大,Agent 能访问更久远的对话历史 - - 但也会增加 token 使用量和响应时间 - - 建议根据实际需求调整 - -**示例:** -- `30` - 加载最近30分钟的对话 -- `60` - 加载最近1小时的对话(默认) -- `1440` - 加载最近24小时的对话 - -### language - -设置 Agent 回复的首选语言。 - -- **类型**: 字符串 -- **默认值**: "Same as user input"(与用户输入相同) -- **说明**: - - 可以设置为任何语言名称 - - Agent 会尽量使用指定语言回复 - - 特殊值 "Same as user input" 表示跟随用户输入语言 - -**常用值:** -- `"Same as user input"` - 自动匹配用户语言(默认) -- `"Chinese"` - 中文 -- `"English"` - 英文 -- `"Japanese"` - 日文 -- `"Spanish"` - 西班牙语 - ---- - -## Agent 使用优先级 - -当使用 Agent API 时,配置的优先级为: - -1. **请求参数** - `/agent/stream` 请求中直接指定的参数 -2. **用户设置** - Settings 中保存的默认值 -3. **系统默认** - 内置的默认值 - -**示例:** - -```bash -# 情况1: 使用请求参数(最高优先级) -curl -X POST http://localhost:7002/agent/stream \ - -H "Authorization: Bearer $TOKEN" \ - -d '{ - "message": "Hello", - "maxContextLoadTime": 30, - "language": "English" - }' -# 使用: maxContextLoadTime=30, language="English" - -# 情况2: 使用用户设置(如果请求中未指定) -# 假设用户设置: maxContextLoadTime=60, language="Chinese" -curl -X POST http://localhost:7002/agent/stream \ - -H "Authorization: Bearer $TOKEN" \ - -d '{"message": "Hello"}' -# 使用: maxContextLoadTime=60, language="Chinese" - -# 情况3: 使用系统默认(如果都未设置) -# 使用: maxContextLoadTime=60, language="Same as user input" -``` - ---- - -## 数据库 Schema - -```sql -CREATE TABLE settings ( - user_id TEXT PRIMARY KEY, - default_chat_model UUID REFERENCES model(id), - default_embedding_model UUID REFERENCES model(id), - default_summary_model UUID REFERENCES model(id), - max_context_load_time INTEGER DEFAULT 60, - language TEXT DEFAULT 'Same as user input' -); -``` - ---- - -## 相关文档 - -- [Agent API](./AGENT_API.md) -- [Model API](./README.md) -- [认证系统](./AUTH_README.md) -- [API 变更说明](./API_CHANGES.md) - diff --git a/packages/api/USER_MANAGEMENT.md b/packages/api/USER_MANAGEMENT.md deleted file mode 100644 index 887a6758..00000000 --- a/packages/api/USER_MANAGEMENT.md +++ /dev/null @@ -1,480 +0,0 @@ -# 用户管理 API 文档 - -## 概述 - -用户管理模块提供了完整的用户 CRUD 操作接口,**仅限管理员访问**。所有端点都需要携带有效的管理员 JWT token。 - -## 权限要求 - -所有用户管理接口都受 `adminMiddleware` 保护: -- 必须提供有效的 Bearer token -- 用户角色必须是 `admin` -- 否则返回 `403 Forbidden` 错误 - -## API 端点 - -### 基础 URL - -``` -http://localhost:7002/user -``` - -### 请求头 - -所有请求都需要包含认证 token: - -``` -Authorization: Bearer -``` - ---- - -## 1. 获取所有用户 GET `/user` - -获取系统中所有用户的列表。 - -### 请求示例 - -```bash -curl http://localhost:7002/user \ - -H "Authorization: Bearer " -``` - -### 成功响应 (200 OK) - -```json -{ - "success": true, - "data": [ - { - "id": "123e4567-e89b-12d3-a456-426614174000", - "username": "john_doe", - "email": "john@example.com", - "role": "member", - "displayName": "John Doe", - "avatarUrl": "https://example.com/avatar.jpg", - "isActive": "true", - "createdAt": "2024-01-10T10:00:00Z", - "updatedAt": "2024-01-10T10:00:00Z", - "lastLoginAt": "2024-01-10T12:00:00Z" - } - ] -} -``` - ---- - -## 2. 获取单个用户 GET `/user/:id` - -根据用户 ID 获取用户详细信息。 - -### 路径参数 - -| 参数 | 类型 | 必需 | 说明 | -|------|------|------|------| -| id | UUID | 是 | 用户的唯一标识符 | - -### 请求示例 - -```bash -curl http://localhost:7002/user/123e4567-e89b-12d3-a456-426614174000 \ - -H "Authorization: Bearer " -``` - -### 成功响应 (200 OK) - -```json -{ - "success": true, - "data": { - "id": "123e4567-e89b-12d3-a456-426614174000", - "username": "john_doe", - "email": "john@example.com", - "role": "member", - "displayName": "John Doe", - "avatarUrl": "https://example.com/avatar.jpg", - "isActive": "true", - "createdAt": "2024-01-10T10:00:00Z", - "updatedAt": "2024-01-10T10:00:00Z", - "lastLoginAt": "2024-01-10T12:00:00Z" - } -} -``` - -### 错误响应 (404 Not Found) - -```json -{ - "success": false, - "error": "User not found" -} -``` - ---- - -## 3. 创建用户 POST `/user` - -创建新用户账户。 - -### 请求体 - -| 字段 | 类型 | 必需 | 说明 | -|------|------|------|------| -| username | string | 是 | 用户名(3-50字符,唯一) | -| email | string | 否 | 邮箱地址(必须是有效格式,唯一) | -| password | string | 是 | 密码(至少6个字符) | -| role | string | 否 | 用户角色:`admin` 或 `member`(默认 `member`) | -| displayName | string | 否 | 显示名称 | -| avatarUrl | string | 否 | 头像 URL(必须是有效的 URL) | - -### 请求示例 - -```bash -curl -X POST http://localhost:7002/user \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{ - "username": "jane_smith", - "email": "jane@example.com", - "password": "secure_password123", - "role": "member", - "displayName": "Jane Smith" - }' -``` - -### 成功响应 (201 Created) - -```json -{ - "success": true, - "data": { - "id": "223e4567-e89b-12d3-a456-426614174001", - "username": "jane_smith", - "email": "jane@example.com", - "role": "member", - "displayName": "Jane Smith", - "avatarUrl": null, - "isActive": "true", - "createdAt": "2024-01-10T15:00:00Z" - } -} -``` - -**注意**: 创建用户时会自动创建一个默认的 settings 条目,包含: -- `maxContextLoadTime`: 60(分钟) -- `language`: "Same as user input" -- 所有模型配置为 `null`(需要用户后续配置) - -### 错误响应 (409 Conflict) - -```json -{ - "success": false, - "error": "Username already exists" -} -``` - -或 - -```json -{ - "success": false, - "error": "Email already exists" -} -``` - ---- - -## 4. 更新用户 PUT `/user/:id` - -更新用户信息(不包括密码)。 - -### 路径参数 - -| 参数 | 类型 | 必需 | 说明 | -|------|------|------|------| -| id | UUID | 是 | 用户的唯一标识符 | - -### 请求体(所有字段都是可选的) - -| 字段 | 类型 | 说明 | -|------|------|------| -| email | string | 邮箱地址 | -| role | string | 用户角色:`admin` 或 `member` | -| displayName | string | 显示名称 | -| avatarUrl | string | 头像 URL | -| isActive | string | 账户状态:`true` 或 `false` | - -### 请求示例 - -```bash -curl -X PUT http://localhost:7002/user/223e4567-e89b-12d3-a456-426614174001 \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{ - "displayName": "Jane Smith (Updated)", - "role": "admin", - "isActive": "true" - }' -``` - -### 成功响应 (200 OK) - -```json -{ - "success": true, - "data": { - "id": "223e4567-e89b-12d3-a456-426614174001", - "username": "jane_smith", - "email": "jane@example.com", - "role": "admin", - "displayName": "Jane Smith (Updated)", - "avatarUrl": null, - "isActive": "true", - "createdAt": "2024-01-10T15:00:00Z", - "updatedAt": "2024-01-10T16:00:00Z", - "lastLoginAt": null - } -} -``` - -### 错误响应 (404 Not Found) - -```json -{ - "success": false, - "error": "User not found" -} -``` - ---- - -## 5. 删除用户 DELETE `/user/:id` - -删除用户账户。 - -### 路径参数 - -| 参数 | 类型 | 必需 | 说明 | -|------|------|------|------| -| id | UUID | 是 | 用户的唯一标识符 | - -### 请求示例 - -```bash -curl -X DELETE http://localhost:7002/user/223e4567-e89b-12d3-a456-426614174001 \ - -H "Authorization: Bearer " -``` - -### 成功响应 (200 OK) - -```json -{ - "success": true, - "data": { - "id": "223e4567-e89b-12d3-a456-426614174001", - "username": "jane_smith" - } -} -``` - -### 错误响应 (404 Not Found) - -```json -{ - "success": false, - "error": "User not found" -} -``` - ---- - -## 6. 更新用户密码 PATCH `/user/:id/password` - -重置或更新用户密码。 - -### 路径参数 - -| 参数 | 类型 | 必需 | 说明 | -|------|------|------|------| -| id | UUID | 是 | 用户的唯一标识符 | - -### 请求体 - -| 字段 | 类型 | 必需 | 说明 | -|------|------|------|------| -| password | string | 是 | 新密码(至少6个字符) | - -### 请求示例 - -```bash -curl -X PATCH http://localhost:7002/user/223e4567-e89b-12d3-a456-426614174001/password \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{ - "password": "new_secure_password456" - }' -``` - -### 成功响应 (200 OK) - -```json -{ - "success": true, - "data": { - "id": "223e4567-e89b-12d3-a456-426614174001", - "username": "jane_smith" - }, - "message": "Password updated successfully" -} -``` - -### 错误响应 (404 Not Found) - -```json -{ - "success": false, - "error": "User not found" -} -``` - ---- - -## 错误响应 - -### 401 Unauthorized - -未提供 token 或 token 无效: - -```json -{ - "success": false, - "error": "No bearer token provided" -} -``` - -### 403 Forbidden - -非管理员用户尝试访问: - -```json -{ - "success": false, - "error": "Forbidden: Admin access required" -} -``` - -### 400 Bad Request - -请求数据验证失败: - -```json -{ - "success": false, - "error": "Username must be at least 3 characters" -} -``` - ---- - -## 使用示例 - -### 完整工作流 - -```bash -# 1. 管理员登录获取 token -TOKEN=$(curl -X POST http://localhost:7002/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"admin","password":"your_admin_password"}' \ - | jq -r '.data.token') - -# 2. 创建新用户 -curl -X POST http://localhost:7002/user \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "username": "new_user", - "email": "newuser@example.com", - "password": "password123", - "role": "member", - "displayName": "New User" - }' - -# 3. 获取所有用户 -curl http://localhost:7002/user \ - -H "Authorization: Bearer $TOKEN" - -# 4. 获取特定用户 -USER_ID="123e4567-e89b-12d3-a456-426614174000" -curl http://localhost:7002/user/$USER_ID \ - -H "Authorization: Bearer $TOKEN" - -# 5. 更新用户信息 -curl -X PUT http://localhost:7002/user/$USER_ID \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "displayName": "Updated Name", - "role": "admin" - }' - -# 6. 重置用户密码 -curl -X PATCH http://localhost:7002/user/$USER_ID/password \ - -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "password": "new_password123" - }' - -# 7. 删除用户 -curl -X DELETE http://localhost:7002/user/$USER_ID \ - -H "Authorization: Bearer $TOKEN" -``` - ---- - -## 自动化行为 - -### 创建用户时的自动操作 - -当创建新用户时,系统会自动执行以下操作: - -1. **密码加密**: 使用 bcrypt 算法加密密码 -2. **创建 Settings**: 自动为用户创建默认设置条目 - - `maxContextLoadTime`: 60 分钟 - - `language`: "Same as user input" - - 模型配置: 全部为 null(需要用户后续配置) - -这确保每个用户都有完整的配置,可以立即使用系统功能。 - ---- - -## 安全注意事项 - -1. **管理员权限**: - - 所有接口仅限管理员访问 - - 确保 Root 用户的密码强度足够 - - 定期审计管理员账户 - -2. **密码安全**: - - 密码使用 bcrypt 加密存储 - - 最少 6 个字符(建议更高要求) - - 重置密码后建议通知用户 - -3. **数据验证**: - - 所有输入都经过严格验证 - - 邮箱和用户名必须唯一 - - URL 格式必须有效 - -4. **用户状态**: - - 使用 `isActive` 字段禁用用户而非直接删除 - - 保留用户数据用于审计 - ---- - -## 相关文档 - -- [认证系统文档](./AUTH_README.md) -- [用户表设计](../db/USERS_SCHEMA.md) -- [项目设置指南](../../SETUP.md) - diff --git a/packages/api/examples/agent-stream-client.ts b/packages/api/examples/agent-stream-client.ts deleted file mode 100644 index 2eda32fa..00000000 --- a/packages/api/examples/agent-stream-client.ts +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Agent Stream Client Example - * - * This example demonstrates how to use the /agent/stream API endpoint - * to have a streaming conversation with the AI agent. - * - * Usage: - * bun run agent-stream-client.ts - */ - -const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:7002' - -interface LoginResponse { - success: boolean - data?: { - token: string - user: { - id: string - username: string - role: string - } - } - error?: string -} - -async function login(username: string, password: string): Promise { - const response = await fetch(`${API_BASE_URL}/auth/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ username, password }), - }) - - const data: LoginResponse = await response.json() - - if (!data.success || !data.data?.token) { - throw new Error(data.error || 'Login failed') - } - - return data.data.token -} - -async function streamAgentChat(message: string, token: string) { - console.log(`\n📤 User: ${message}`) - console.log('🤖 Agent: ', { end: '' }) - - const response = await fetch(`${API_BASE_URL}/agent/stream`, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - message, - maxContextLoadTime: 60, - language: 'Same as user input', - }), - }) - - if (!response.ok) { - const error = await response.json() - throw new Error(error.error || 'Stream request failed') - } - - const reader = response.body?.getReader() - const decoder = new TextDecoder() - - if (!reader) { - throw new Error('No reader available') - } - - let hasOutput = false - - try { - while (true) { - const { done, value } = await reader.read() - if (done) break - - const chunk = decoder.decode(value, { stream: true }) - const lines = chunk.split('\n') - - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = line.slice(6).trim() - - if (data === '[DONE]') { - console.log('\n\n✅ Stream completed') - return - } - - if (!data) continue - - try { - const event = JSON.parse(data) - - if (event.type === 'text-delta' && event.text) { - process.stdout.write(event.text) - hasOutput = true - } else if (event.type === 'tool-call') { - console.log(`\n[🔧 Tool: ${event.toolName}]`) - hasOutput = true - } else if (event.type === 'error') { - console.error('\n❌ Error:', event.error) - throw new Error(event.error) - } - } catch (e) { - if (e instanceof SyntaxError) { - // Skip invalid JSON - continue - } - throw e - } - } - } - } - } finally { - reader.releaseLock() - } - - if (!hasOutput) { - console.log('(No response)') - } -} - -async function main() { - try { - // Get credentials from environment or use defaults - const username = process.env.USERNAME || 'admin' - const password = process.env.PASSWORD || 'admin' - - console.log('🔐 Logging in...') - const token = await login(username, password) - console.log('✅ Login successful') - - // Example conversations - const messages = [ - '你好,请介绍一下你自己', - '你能帮我做什么?', - '记住:我的名字是张三', - '我的名字是什么?', - ] - - for (const message of messages) { - await streamAgentChat(message, token) - // Wait a bit between messages - await new Promise(resolve => setTimeout(resolve, 1000)) - } - - console.log('\n🎉 All conversations completed!') - } catch (error) { - console.error('\n❌ Error:', error instanceof Error ? error.message : String(error)) - process.exit(1) - } -} - -// Handle Ctrl+C gracefully -process.on('SIGINT', () => { - console.log('\n\n👋 Goodbye!') - process.exit(0) -}) - -main() -