docs: add README

This commit is contained in:
Acbox
2026-01-11 14:46:52 +08:00
parent 5f632ea0f7
commit 2eee14f1ab
8 changed files with 97 additions and 2026 deletions
-383
View File
@@ -1,383 +0,0 @@
# Agent API 文档
## 概述
Agent API 提供了一个智能对话代理接口,支持流式响应、记忆管理和工具调用。
## 端点
### POST `/agent/stream` 🔒 需要认证
与 AI Agent 进行流式对话。
#### 权限要求
- 需要有效的 Bearer token
- 自动使用当前登录用户的身份
#### 请求
**Headers:**
```
Authorization: Bearer <your_jwt_token>
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)
-251
View File
@@ -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 <token>
# 更新或创建当前用户的设置
PUT /settings
Authorization: Bearer <token>
{
"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 <token>
{
"messages": [...],
"timestamp": "2024-01-10T10:00:00Z"
}
# 搜索当前用户的记忆
GET /memory/search?query=hello
Authorization: Bearer <token>
# 获取当前用户的消息历史
GET /memory/message?page=1&limit=10
Authorization: Bearer <token>
# 按日期过滤当前用户的消息
GET /memory/message/filter?from=2024-01-01&to=2024-01-31
Authorization: Bearer <token>
```
### 使用示例
```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)
-277
View File
@@ -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 <your_jwt_token>
```
**成功响应:**
```json
{
"success": true,
"data": {
"userId": "root",
"username": "admin",
"role": "admin"
}
}
```
**失败响应:**
```json
{
"success": false,
"error": "Invalid or expired token"
}
```
### 3. 获取当前用户信息 GET `/auth/me`
获取当前登录用户的信息。
**请求头:**
```
Authorization: Bearer <your_jwt_token>
```
**成功响应:**
```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="<your_jwt_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)
-281
View File
@@ -1,281 +0,0 @@
# Settings API 文档
## 概述
Settings API 用于管理用户的个性化设置,包括默认模型配置和 Agent 行为设置。
## 端点
### GET `/settings` 🔒 需要认证
获取当前用户的设置。
#### 请求
**Headers:**
```
Authorization: Bearer <your_jwt_token>
```
#### 成功响应 (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 <your_jwt_token>
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-14401分钟到24小时)
- **默认值**: 601小时)
- **说明**:
- 值越大,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)
-480
View File
@@ -1,480 +0,0 @@
# 用户管理 API 文档
## 概述
用户管理模块提供了完整的用户 CRUD 操作接口,**仅限管理员访问**。所有端点都需要携带有效的管理员 JWT token。
## 权限要求
所有用户管理接口都受 `adminMiddleware` 保护:
- 必须提供有效的 Bearer token
- 用户角色必须是 `admin`
- 否则返回 `403 Forbidden` 错误
## API 端点
### 基础 URL
```
http://localhost:7002/user
```
### 请求头
所有请求都需要包含认证 token
```
Authorization: Bearer <your_admin_jwt_token>
```
---
## 1. 获取所有用户 GET `/user`
获取系统中所有用户的列表。
### 请求示例
```bash
curl http://localhost:7002/user \
-H "Authorization: Bearer <admin_token>"
```
### 成功响应 (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 <admin_token>"
```
### 成功响应 (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 <admin_token>" \
-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 <admin_token>" \
-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 <admin_token>"
```
### 成功响应 (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 <admin_token>" \
-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)
@@ -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<string> {
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()