WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s

This commit is contained in:
yawan
2026-09-22 16:19:06 +08:00
commit f7fc992f57
3929 changed files with 1006607 additions and 0 deletions
+228
View File
@@ -0,0 +1,228 @@
# API 总览
本节介绍 WeKnora HTTP API 的通用约定:Base URL、认证方式、响应结构、错误码、分页、SSE 与限流。
## Base URL 与版本前缀
- 所有业务 API 挂载在 `/api/v1` 前缀下(`router.go` 中 `r.Group("/api/v1")`)。
- 健康检查:`GET /health`(无需认证),返回 `{"status":"ok"}`。
- Swagger UI:`GET /swagger/*any`,仅在非 `release` 模式(`GIN_MODE != release`)下注册。
- 认证之外的特殊路径:`GET|HEAD /r/:token`(短时效资源授权 URL)、`GET /files`(认证后文件代理)、`GET|HEAD /api/v1/files/presigned`(HMAC 签名 URL,无需认证)、`GET /api/v1/files/presigned-preview`(Admin 诊断)。
```
BASE=http://localhost:8080
```
## 认证方式
认证由 `internal/middleware/auth.go` 的 `Auth` 中间件统一处理,按以下顺序尝试:
### 1. JWT Bearer(Web 用户)
```
Authorization: Bearer <access_token>
```
- 通过 `POST /api/v1/auth/login`(或 register / auto-setup / OIDC)获得 `token` 与 `refresh_token`;`POST /api/v1/auth/refresh` 换发新 token。
- 可选请求头 `X-Tenant-ID: <tenant_id>`:在 JWT 指向的空间之外切换目标空间(须为该空间活跃成员,或具备 `CanAccessAllTenants` 跨空间超管属性)。畸形或 `0` 值直接返回 400。
- 若 JWT 未解析出任何空间且接口非“无空间可用”白名单(如 `/auth/me`、`/me/invitations` 等),返回 409 `{"code":"TENANT_REQUIRED"}`。
### 2. API Key(机器主体)
```
X-API-Key: <api_key>
```
- 空间级(workspace)key:在 `POST /api/v1/tenants/:id/api-keys` 创建,绑定到单一空间;携带 `X-Tenant-ID` 指向其它空间会得到 403。
- 平台级(platform)key:在 `POST /api/v1/system/admin/api-keys` 创建,必须携带 `X-Tenant-ID` 选择目标空间(`/system/admin/*`、`/tenants/all|search`、`POST /tenants` 除外),否则返回 409 `TENANT_REQUIRED`。
- 授权模型(`internal/middleware/api_key_gate.go`,默认拒绝):每个 `/api/v1` 路由必须显式声明 API key 策略,未声明的路由对任何 key 一律 403。
- `full_access` key:空间内全权(等效 Owner 的机器形态)。
- 受限(scoped)key:按 capability 放行,并受 `knowledge_base_ids` 白名单约束。Capability 常量见 `internal/types/tenant_api_key.go`:`retrieve`、`ingest`、`chat`、`read_agents`、`manage_kbs`、`manage_agents`、`message_history`、`manage_models`、`manage_mcp_services`、`manage_datasources`、`manage_channels`、`manage_vector_stores`、`manage_storage_backends`、`manage_web_search`、`run_evaluations`、`manage_members`、`manage_spaces`、`manage_tenant_settings`;平台能力:`system_tenants_read/manage`、`system_settings_read/manage`、`system_runtime_read/manage`、`system_audit_read`。
- 外部用户主体(可选,按空间 `api-principal-config` 配置):
- `direct` 模式:`X-External-User-ID: <外部用户ID>`(≤128 字符)。
- `signed_token` 模式:`X-External-User-Token: <HS256 JWT>`,要求 `aud=weknora`、`exp`(生存期 ≤24h)、`tenant_id` claim 与目标空间一致、`sub` 为外部用户 ID。
### 3. Embed publish token(匿名嵌入端)
`/api/v1/embed/:channel_id/*` 公开路由使用独立的 `EmbedAuth` 中间件(`internal/middleware/embed_auth.go`):
```
Authorization: Embed <publish_token 或 session_token>
```
- `POST /embed/:channel_id/exchange` 用 publish token 换取短时效 session token;会话级操作还需 `X-Embed-Session: <sig>`(创建会话时返回的签名句柄)。
- IM 回调路由(`/api/v1/im/callback/:channel_id`)注册在全局认证中间件之前,使用各 IM 平台自身的签名验证。
### 认证流程图
```mermaid
flowchart TD
A["客户端请求"] --> B{"路径在免认证白名单?<br/>(login/register/oidc/presigned...)"}
B -- "是" --> H["直接进入 Handler"]
B -- "否" --> C{"Authorization: Bearer <JWT>?"}
C -- "有效" --> D{"X-Tenant-ID 请求头?"}
D -- "无" --> E["使用 JWT 内 tenant_id"]
D -- "有" --> F{"IsTenantAccessible?<br/>(成员/跨空间超管)"}
F -- "否" --> G["403 Forbidden"]
F -- "是" --> E
E --> R{"resolveTenantRole<br/>(成员表 → 超管 → 孤儿空间自愈 → EnableRBAC 兜底)"}
R -- "无角色且 RBAC 强制" --> G
R -- "得到角色" --> P["注入 tenant/user/role 上下文"]
C -- "无/无效" --> K{"X-API-Key?"}
K -- "无" --> U["401 Unauthorized"]
K -- "有" --> L{"key 类型"}
L -- "platform key" --> M{"X-Tenant-ID?"}
M -- "缺失且非平台白名单路由" --> V["409 TENANT_REQUIRED"]
M -- "有" --> P2["注入平台机器主体 + 目标空间"]
L -- "workspace key" --> N{"X-Tenant-ID 与 key 空间一致?"}
N -- "不一致" --> G
N -- "一致/未携带" --> P3["注入空间机器主体<br/>(可选外部用户主体 Header)"]
P --> Q["RBAC 角色守卫 (rbac.go)"]
P2 --> S["APIKeyGate: 路由策略<br/>(full_access / capability / KB 白名单, 默认拒绝)"]
P3 --> S
Q --> H
S --> H
```
## 角色与权限模型(RBAC)
`internal/middleware/rbac.go` + `internal/middleware/access.go`:
| 角色 | 说明 |
| --- | --- |
| `owner` | 空间所有者:空间生命周期、API key、成员管理 |
| `admin` | 空间管理员:模型/基础设施/渠道等空间级配置 |
| `contributor` | 贡献者:可创建 KB/Agent,可修改**自己创建**的资源 |
| `viewer` | 只读成员:读取与会话使用 |
| SystemAdmin | 平台级管理员(`User.IsSystemAdmin`),独立于空间角色,守卫 `/system/admin/*`,始终强制 |
- 文档中“Viewer+ / Contributor+ / Admin+ / Owner”表示最低角色要求;“创建者 OR Admin+”对应 `RequireOwnershipOrRole`(Contributor 只能改自己创建的 KB/Agent/内容)。
- `cfg.Tenant.EnableRBAC=false` 时角色守卫只记录日志不拦截(rollout fail-open);SystemAdmin 守卫不受此开关影响。
- KB 级访问守卫 `KBAccessRead/Write`(`internal/middleware/kb_access.go`):解析“自有 / 组织共享 / 经共享 Agent 可见”三类访问,并把请求上下文的 tenant 重写为 KB 属主空间。
- API key 主体会短路 JWT 角色守卫,其真实权限完全由 APIKeyGate(capability + KB 白名单)决定。
- 被拒绝的请求会写入审计日志(`middleware.AuditServiceProvider`,1 分钟滑动窗口去重)。
## 通用响应格式与错误码
多数 handler 返回:
```json
{ "success": true, "data": { ... } }
```
列表类接口常见附加字段:`total`、`page`、`page_size`。少数例外:`/system/admin/*` 的部分读取接口直接返回原始行/数组(不含包装),`/system/info` 等使用 `{"code":0,"msg":"success","data":...}`。
错误统一由 `internal/middleware/error_handler.go` 输出(`internal/errors/errors.go` 的 `AppError`):
```json
{ "success": false, "error": { "code": 1003, "message": "...", "details": null } }
```
中间件层(认证/RBAC)直接返回 `{"error": "..."}`(部分带 `"code"` 字符串,如 `TENANT_REQUIRED`)。
| 错误码 | 含义 | HTTP |
| --- | --- | --- |
| 1000 | ErrBadRequest 请求错误 | 400 |
| 1001 | ErrUnauthorized 未认证 | 401 |
| 1002 | ErrForbidden 无权限 | 403 |
| 1003 | ErrNotFound 资源不存在 | 404 |
| 1004 | ErrMethodNotAllowed | 405 |
| 1005 | ErrConflict 冲突 | 409 |
| 1006 | ErrTooManyRequests 限流/配额 | 429 |
| 1007 | ErrInternalServer 内部错误 | 500 |
| 1008 | ErrServiceUnavailable 暂不可用 | 503 |
| 1009 | ErrTimeout 超时 | — |
| 1010 | ErrValidation 参数校验失败 | 400 |
| 2000-2005 | 空间类:不存在/已存在/停用/名称必填/状态非法/自助创建被禁用 | 404/409/403/… |
| 2100-2103 | Agent 类:缺思考模型/缺允许工具/迭代次数非法(1-20)/温度非法(0-2) | 400 |
| 2200-2201 | VectorStore 绑定非法 / 当前不可用 | 400 |
另有非编码错误:`types.StorageQuotaExceededError`(存储配额超限)、`types.DuplicateKnowledgeError`(重复文件/URL,上传接口返回 409 且 `data` 携带已存在的 Knowledge)。
## 分页规范
`internal/handler/list_pagination.go`:
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `page` | int | 否 | 页码,默认 1,必须 ≥1 |
| `page_size` | int | 否 | 每页条数,默认 20,范围 1-100 |
超范围或非法值返回校验错误(code 1010)。列表响应携带 `total/page/page_size`。部分接口使用游标分页:审计日志(`after_id`+`limit`,响应带 `next_cursor`)、系统运行时任务(`cursor`+`page_size`,响应带 `next_cursor/has_more`)、Wiki index/log(`cursor`+`limit`)。
## 流式接口协议(SSE)
聊天类接口(`POST /api/v1/knowledge-chat/:session_id`、`POST /api/v1/agent-chat/:session_id`、`GET /api/v1/sessions/continue-stream/:session_id`,以及 embed 端对应路由)返回 Server-Sent Events:
```
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no
```
每个事件为 `event: message`,`data:` 为 `types.StreamResponse` JSON:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | string | 请求 ID |
| `response_type` | string | `answer` / `references` / `thinking` / `tool_call` / `tool_result` / `reflection` / `session_title` / `agent_query` / `tool_approval_required` / `tool_approval_resolved` / `mcp_oauth_required` / `mcp_oauth_resolved` / `error` / `complete` |
| `content` | string | 增量文本 |
| `done` | bool | 该类型事件是否结束 |
| `knowledge_references` | []SearchResult | `references` 事件携带的引用 |
| `tool_calls` | []LLMToolCall | 工具调用事件 |
| `session_id` / `assistant_message_id` | string | `agent_query` 事件携带 |
| `usage` | TokenUsage | `prompt_tokens/completion_tokens/total_tokens/cache_*` |
| `finish_reason` | string | 结束原因 |
流以 `response_type:"complete"`(`done:true`)终止;出错时以 `response_type:"error"`(`done:true`)终止。`continue-stream` 采用重放 + 100ms 轮询追增量的续传语义(`?message_id=` 必填)。
## 文件引用形式(resource_urls)
回答与检索结果里引用到的图片/附件,默认以内部句柄 `resource://<handle>` 返回,客户端要再调一次带鉴权的 `/files` 代理才能拿到内容。第三方 App 想拿到「拿来即可渲染」的链接时,可以切换成直链模式:
| 作用范围 | 用法 |
| --- | --- |
| 单次请求 | 在 URL 上加 `?resource_urls=public` |
| 整个部署 | 环境变量 `RESOURCE_URL_MODE=public` |
取值只有 `handle`(默认)与 `public`,传其它值返回 400。单次请求参数优先于环境变量,所以把部署默认设成 `public` 之后,仍可以用 `?resource_urls=handle` 单独退回。
支持该参数的接口:`POST /knowledge-chat/{session_id}`、`POST /agent-chat/{session_id}`、`GET /sessions/continue-stream/{session_id}`、`GET /messages/{session_id}/load`、`POST /knowledge-search`、`POST /knowledge-bases/{id}/hybrid-search`(兼容 GET)。改写覆盖答案正文、检索结果 `content` / `image_info`、`knowledge_references`、Agent 执行步骤与工具结果,以及消息上的图片附件;流式回答里跨 chunk 截断的引用会先缓冲再改写,客户端拿到的始终是完整链接。
使用前需要知道的几件事:
- **需要具备外链能力**:直链来自存储后端预签名,或 `APP_EXTERNAL_URL` + `/r/<token>`。两者都没有时(如 local 存储且未设 `APP_EXTERNAL_URL`),该引用保持 `resource://` 原样,客户端仍可回退到 `/files`;
- **直链是限时匿名可读的**(WeKnora 签发的 grant 2 小时,MinIO 预签名 24 小时),任何拿到链接的人在过期前都能读取,不要写进日志或转发给不该看的人;
- **嵌入渠道不支持**:`/api/v1/embed/...` 下的接口强制 `handle`,访客图片继续走渠道维度的鉴权代理;
- **限定知识库的 API Key 用 `public` 会返回 403**:这类 Key 本身就被禁止访问 `/files` 代理,能拿到匿名直链等于绕过同一道限制;
- **同一文件的直链在有效期内复用**,重复请求不会反复签发凭证,客户端与 CDN 缓存因此能命中。
各渠道(Web / IM / 嵌入挂件 / API)分别拿到哪种形式、以及图片加载不出来时怎么排查,见[图片与文件的对外访问](../03-features/21-file-access.md)。
## 限流说明
| 面 | 限制 | 来源 |
| --- | --- | --- |
| 公开分享链接接口(`/auth/invitations/lookup`、`/auth/register-by-invite`) | 每 IP 30 次/分钟(两个端点共享额度),超限 429(code 1006) | `internal/middleware/auth_public_ratelimit.go` |
| Embed 公开路由 | 每 (channel, IP) `rate_limit_per_minute`(默认 30)/分钟;channel 级 `rate_limit_per_minute*20`(下限 120)/分钟;channel 级 `rate_limit_per_day`(默认 10000)/天;超限 429 | `internal/middleware/embed_auth.go` |
| 反代信任 | 仅信任 `WEKNORA_TRUSTED_PROXIES`(默认回环+内网段)的 `X-Forwarded-For`,防止伪造 IP 绕过限流 | `router.go` `trustedProxies()` |
其余业务接口无全局限流;自助创建空间等配额类拒绝同样使用 429(code 1006)。
## API 分组导航
| 分组 | 文档 | 主要前缀 |
| --- | --- | --- |
| 认证与用户 | [02-api-auth.md](./02-api-auth.md) | `/auth`、`/me/invitations` |
| 租户(空间)与成员 | [02-api-tenant.md](./02-api-tenant.md) | `/tenants` |
| 组织与共享 | [02-api-org.md](./02-api-org.md) | `/organizations`、`/shared-*`、`/knowledge-bases/:id/shares`、`/agents/:id/shares` |
| 知识库与知识 | [02-api-knowledge.md](./02-api-knowledge.md) | `/knowledge-bases`、`/knowledge`、知识库文件夹 |
| 分块与标签 | [02-api-chunks.md](./02-api-chunks.md) | `/chunks`、`/knowledge-bases/:id/tags`、`/chunker/preview` |
| FAQ 与 Wiki | [02-api-faq-wiki.md](./02-api-faq-wiki.md) | `/knowledge-bases/:id/faq`、`/faq`、`/knowledgebase/:kb_id/wiki` |
| 会话、消息与聊天 | [02-api-chat.md](./02-api-chat.md) | `/sessions`、`/messages`、`/knowledge-chat`、`/agent-chat`、`/knowledge-search` |
| 模型与初始化 | [02-api-model-system.md](./02-api-model-system.md) | `/models`、`/initialization`、`/evaluation`、`/weknoracloud` |
| 系统与平台管理 | [02-api-system.md](./02-api-system.md) | `/system`、`/system/admin` |
| 基础设施与数据源 | [02-api-infra.md](./02-api-infra.md) | `/vector-stores`、`/storage-backends`、`/web-search-providers`、`/datasource` |
| Agent、MCP、技能与记忆 | [02-api-agent-mcp.md](./02-api-agent-mcp.md) | `/agents`、`/mcp-services`、`/agent`、`/skills`、`/sandbox-configs`、`/memory`、`/user/favorites` |
| IM、Embed 与文件服务 | [02-api-channels.md](./02-api-channels.md) | `/im`、`/im-channels`、`/wechat`、`/embed-channels`、`/embed`、`/files`、`/r/:token` |
+400
View File
@@ -0,0 +1,400 @@
# API 参考:Agent、MCP 与技能
路由注册:`internal/router/router.go` 的 `RegisterCustomAgentRoutes`、`RegisterMCPServiceRoutes`、`RegisterSkillRoutes`、`RegisterUserFavoriteRoutes`。Handler:`internal/handler/custom_agent.go`、`internal/handler/mcp_service.go`、`internal/handler/mcp_credentials.go`、`internal/handler/mcp_oauth.go`、`internal/handler/skill_handler.go`、`internal/handler/user_resource_favorite.go`。
## Agent(/api/v1/agents)
读:Viewer+(API key `read_agents`/`manage_agents`/`chat`/full);写:创建者 OR Admin+(API key `manage_agents`/full);内置 Agent(`is_builtin=true`)始终 Admin+。
### GET /api/v1/agents/placeholders
用途:提示词占位符定义(须先于 `/:id` 注册)。权限:Viewer+。
响应:200 `{"success":true,"data":{"all":{...},"system_prompt":{...},"agent_system_prompt":{...},"context_template":{...},"rewrite_system_prompt":{...},"rewrite_prompt":{...},"fallback_prompt":{...}}}`
```bash
curl $BASE/api/v1/agents/placeholders -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/agents/type-presets
用途:智能推理 Agent 类型预设(rag-qa / wiki-qa / hybrid / custom 等)。权限:Viewer+。
响应:200 `{"success":true,"data":[{type,system_prompt,allowed_tools,kb_compatibility}]}`
```bash
curl $BASE/api/v1/agents/type-presets -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/agents
用途:创建自定义 Agent。权限:Contributor+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是(`binding:"required"`) | 名称 |
| `description` | string | 否 | 描述 |
| `avatar` | string | 否 | 头像/emoji |
| `config` | object | 否 | Agent 配置(`types.CustomAgentConfig`,见下) |
`config` 主要字段:`agent_mode`(`quick-answer`/`smart-reasoning`)、`agent_type`(`rag-qa/wiki-qa/hybrid-rag-wiki/data-analysis/custom`)、`system_prompt`、`model_id`、`temperature`(0-2,非法返回 code 2103)、`max_iterations`(1-20,非法返回 code 2102)、`allowed_tools`(智能推理必填至少一个,code 2101)、`mcp_selection_mode`/`mcp_services`、`skills_selection_mode`、`kb_selection_mode`/`knowledge_bases`、`web_search_enabled`、`question_suggestions` 等(完整定义见 `internal/types/custom_agent.go`)。
响应:201 `{"success":true,"data":{id,name,description,avatar,is_builtin,created_by,config,creator_name,...}}`
```bash
curl -X POST $BASE/api/v1/agents -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"售后助手","config":{"agent_mode":"quick-answer","kb_selection_mode":"selected","knowledge_bases":["kb-1"]}}'
```
### GET /api/v1/agents
用途:Agent 列表(含内置)。权限:Viewer+。查询参数:`creator`(`mine`/`others`,可选)。
响应:200 `{"success":true,"data":[Agent],"disabled_own_agent_ids":[...]}`
```bash
curl $BASE/api/v1/agents -H "X-API-Key: $API_KEY"
```
### GET /api/v1/agents/:id
用途:Agent 详情。权限:Viewer+。
响应:200 `{"success":true,"data":{Agent}}`
```bash
curl $BASE/api/v1/agents/agent-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/agents/:id
用途:更新 Agent。权限:创建者 OR Admin+。请求体:`name/description/avatar/config`(均可选)。
响应:200 `{"success":true,"data":{Agent}}`
```bash
curl -X PUT $BASE/api/v1/agents/agent-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"description":"更新描述"}'
```
### DELETE /api/v1/agents/:id
用途:删除 Agent。权限:创建者 OR Admin+。
响应:200 `{"success":true,"message":"Agent deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/agents/agent-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/agents/:id/copy
用途:复制 Agent(副本归调用者)。权限:Contributor+。无请求体。
响应:201 `{"success":true,"data":{新 Agent}}`
```bash
curl -X POST $BASE/api/v1/agents/agent-1/copy -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/agents/:id/suggested-questions
用途:Agent 起始建议问题(注册在组外以避免与 `/agents/:id/shares` 冲突)。权限:Viewer+;API key `read_agents`/`manage_agents`/`chat`/full。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `knowledge_base_ids` | string | 否 | 逗号分隔 KB |
| `knowledge_ids` | string | 否 | 逗号分隔知识 ID |
| `tag_scopes` | string | 否 | JSON 数组的标签范围 |
| `limit` | int | 否 | 上限 30 |
响应:200 `{"success":true,"data":{"questions":[{question,source,knowledge_base_id}]}}`
```bash
curl "$BASE/api/v1/agents/agent-1/suggested-questions?limit=6" -H "X-API-Key: $API_KEY"
```
## MCP 服务(/api/v1/mcp-services)
空间级外部工具服务集成。读:Viewer+;写/测试/审批策略:Admin+。API key:`manage_mcp_services`/full。Handler: `internal/handler/mcp_service.go`
### POST /api/v1/mcp-services
用途:创建 MCP 服务。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是 | 名称 |
| `description` | string | 否 | 描述 |
| `enabled` | bool | 否 | 启用 |
| `transport_type` | string | 是 | `sse` / `http-streamable` / `stdio` |
| `url` | *string | 否 | 服务 URL(SSE/HTTP) |
| `headers` | map[string]string | 否 | HTTP 头 |
| `auth_config` | object | 否 | `auth_type`(`api_key/bearer/oauth`)、`api_key_header`、`custom_headers`、`scopes`、`auth_server_metadata_url`(密钥走 credentials 子资源) |
| `advanced_config` | object | 否 | 超时/重试 |
| `stdio_config` | object | 否 | stdio 命令与参数 |
| `env_vars` | map[string]string | 否 | 环境变量 |
响应:200 `{"success":true,"data":{MCPServiceResponse}}`(含 `credentials:{api_key:{configured},token:{configured}}`)
```bash
curl -X POST $BASE/api/v1/mcp-services -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"github","transport_type":"sse","url":"https://mcp.example.com/sse"}'
```
### GET /api/v1/mcp-services
用途:MCP 服务列表。权限:Viewer+。响应:200 `{"success":true,"data":[MCPServiceResponse]}`
```bash
curl $BASE/api/v1/mcp-services -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/mcp-services/:id
用途:详情。权限:Viewer+。响应:200 `{"success":true,"data":{MCPServiceResponse}}`
```bash
curl $BASE/api/v1/mcp-services/mcp-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/mcp-services/:id
用途:部分更新(map 语义;`auth_config` 中不可携带 api_key/token)。权限:Admin+。字段同创建(均可选)。
响应:200 `{"success":true,"data":{MCPServiceResponse}}`
```bash
curl -X PUT $BASE/api/v1/mcp-services/mcp-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"enabled":false}'
```
### DELETE /api/v1/mcp-services/:id
用途:删除。权限:Admin+。响应:200 `{"success":true,"message":"MCP service deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/mcp-services/mcp-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/mcp-services/:id/test
用途:连接测试(探测外部服务)。权限:Admin+。响应:200 `{"success":true,"data":{"success","message","oauth_required","tools":[...],"resources":[...]}}`
```bash
curl -X POST $BASE/api/v1/mcp-services/mcp-1/test -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/mcp-services/:id/tools
用途:工具列表。权限:Viewer+。响应:200 `{"success":true,"data":[{name,description,inputSchema,require_approval}]}`
```bash
curl $BASE/api/v1/mcp-services/mcp-1/tools -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/mcp-services/:id/resources
用途:资源列表。权限:Viewer+。响应:200 `{"success":true,"data":[{uri,name,description,mimeType}]}`
```bash
curl $BASE/api/v1/mcp-services/mcp-1/resources -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/mcp-services/:id/credentials
用途:设置密钥(`api_key`/`token`,指针字段,省略保留)。权限:Admin+。Handler: `internal/handler/mcp_credentials.go`
响应:200 `{"success":true,"data":{"fields":{"api_key":{"configured"},"token":{"configured"}}}}`
```bash
curl -X PUT $BASE/api/v1/mcp-services/mcp-1/credentials -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"token":"ghp_..."}'
```
### DELETE /api/v1/mcp-services/:id/credentials/:field
用途:删除凭证字段(`api_key` 或 `token`)。权限:Admin+。响应:204。
```bash
curl -X DELETE $BASE/api/v1/mcp-services/mcp-1/credentials/token -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/mcp-services/:id/tool-approvals
用途:工具人工审批策略列表。权限:Viewer+。响应:200 `{"success":true,"data":[{service_id,tool_name,require_approval,...}]}`
```bash
curl $BASE/api/v1/mcp-services/mcp-1/tool-approvals -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/mcp-services/:id/tool-approvals/:tool_name
用途:设置某工具是否需人工审批。权限:Admin+。请求体:`{"require_approval":true}`(必填)。
响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/mcp-services/mcp-1/tool-approvals/create_issue \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"require_approval":true}'
```
## MCP OAuth
Handler: `internal/handler/mcp_oauth.go`
### GET /api/v1/mcp-oauth/callback
用途:第三方 OAuth 授权回调(免认证,靠单次 `state` 参数认证;注册在 `/mcp-services` 组之外)。查询参数:`code`、`state`、`error`。
响应:302 重定向到前端(成功 `#mcp_oauth_result=success`,失败 `#mcp_oauth_error=<code>`)。
```bash
curl -i "$BASE/api/v1/mcp-oauth/callback?code=xxx&state=yyy"
```
### POST /api/v1/mcp-services/:id/oauth/authorize-url
用途:生成用户级授权 URL。权限:Viewer+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `redirect_uri` | string | 是 | 后端回调 URL(绝对地址) |
| `frontend_redirect` | string | 否 | 回调后前端跳转(默认 `/`) |
响应:200 `{"success":true,"data":{"authorization_url","authorization_attempt"}}`
```bash
curl -X POST $BASE/api/v1/mcp-services/mcp-1/oauth/authorize-url -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"redirect_uri":"'$BASE'/api/v1/mcp-oauth/callback"}'
```
### GET /api/v1/mcp-services/:id/oauth/status
用途:查询本人授权状态。权限:Viewer+。查询参数:`authorization_attempt`(可选)。
响应:200 `{"success":true,"data":{"authorized","state":"authorized|pending","refresh_available","expires_at"}}`
```bash
curl $BASE/api/v1/mcp-services/mcp-1/oauth/status -H "Authorization: Bearer $TOKEN"
```
### DELETE /api/v1/mcp-services/:id/oauth/token
用途:吊销本人 OAuth token。权限:Viewer+。响应:204。
```bash
curl -X DELETE $BASE/api/v1/mcp-services/mcp-1/oauth/token -H "Authorization: Bearer $TOKEN"
```
## Agent 运行时交互(/api/v1/agent)
对话中的人工审批与 OAuth 恢复;权限均 Viewer+(发起会话的人才有上下文),API key 默认拒绝。
### POST /api/v1/agent/tool-approvals/:pending_id
用途:裁决待审批的工具调用。Handler: `internal/handler/mcp_service.go` 的 `ResolveToolApproval`。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `decision` | string | 是(`binding:"required"`) | `approve` / `reject` |
| `modified_args` | JSON | 否 | 修改后的工具参数 |
| `reason` | string | 否 | 理由 |
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/agent/tool-approvals/p-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"decision":"approve"}'
```
### POST /api/v1/agent/mcp-oauth-resolutions/:pending_id
用途:恢复因 MCP OAuth 暂停的 Agent 运行。Handler: `internal/handler/mcp_oauth.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `service_id` | string | 是(`binding:"required"`) | MCP 服务 ID |
| `decision` | string | 否 | `authorize`(默认)/ `cancel` |
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/agent/mcp-oauth-resolutions/p-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"service_id":"mcp-1"}'
```
### POST /api/v1/agent/mcp-oauth-resolutions/:pending_id/cancel
用途:取消暂停中的 OAuth 流程。无请求体。
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/agent/mcp-oauth-resolutions/p-1/cancel -H "Authorization: Bearer $TOKEN"
```
## 技能(/api/v1/skills)
### GET /api/v1/skills
用途:预加载技能列表(只读)。权限:Viewer+,仅 JWT。Handler: `internal/handler/skill_handler.go`
响应:200 `{"success":true,"data":[{name,description}],"skills_available":bool}`
```bash
curl $BASE/api/v1/skills -H "Authorization: Bearer $TOKEN"
```
安装、停用、文件浏览与环境变量走沙箱配置前缀 `/api/v1/sandbox-configs/{id}/skills*` 以及 `/api/v1/me/env-vars*`,完整示例见仓库 [`docs/api/skill.md`](../../docs/api/skill.md)。
## 长期记忆(/api/v1/memory)
跨会话记忆始终绑定当前调用者,路径里没有 subject id。权限:Viewer+;API Key 必须 full-access。Handler: `internal/handler/memory.go`
| 方法 | 路径 | 用途 |
| --- | --- | --- |
| GET/PUT | `/memory/settings` | 个人开关(空间级开关由管理员在租户设置里改) |
| GET/POST/DELETE | `/memory/items` | 列出 / 手动新增 / 清空 |
| PUT/DELETE | `/memory/items/{id}` | 修改 / 删除 |
| POST | `/memory/items/{id}/confirm` `/reject` | 确认或否决推断出的记忆 |
| GET | `/memory/topics` `/memory/documents` | 主题计数、文档亲和度 |
| GET | `/memory/export` | JSON 导出 |
| POST | `/memory/consolidate` | 立刻整理 |
完整字段与 curl 见仓库 [`docs/api/memory.md`](../../docs/api/memory.md)。
## 用户收藏(/api/v1/user/favorites)
按用户维度存储(非资源创建者维度);权限均 Viewer+,仅 JWT(API key 默认拒绝)。Handler: `internal/handler/user_resource_favorite.go`
### GET /api/v1/user/favorites
用途:收藏列表。查询参数:`type`(必填,`kb` 或 `agent`)。
响应:200 `{"success":true,"data":[{type,id,created_at}]}`
```bash
curl "$BASE/api/v1/user/favorites?type=kb" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/user/favorites
用途:添加收藏。请求体:`{"type":"kb|agent","id":"<资源ID>"}`(均必填)。
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/user/favorites -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"type":"kb","id":"kb-1"}'
```
### DELETE /api/v1/user/favorites/:type/:id
用途:取消收藏。路径参数:`type`、`id`。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/user/favorites/kb/kb-1 -H "Authorization: Bearer $TOKEN"
```
+269
View File
@@ -0,0 +1,269 @@
# API 参考:认证与用户
路由注册:`internal/router/router.go` 的 `RegisterAuthRoutes` 与 `RegisterMyInvitationRoutes`。Handler:`internal/handler/auth.go`、`internal/handler/auth_register_by_invite.go`、`internal/handler/tenant_invitation.go`。
除特别标注外,本组接口在认证中间件之后仅要求“已登录”(无角色下限)。免认证接口见各条目。
## 认证(/api/v1/auth)
### POST /api/v1/auth/register
用途:注册新用户(自助注册模式)。免认证。Handler: `internal/handler/auth.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `username` | string | 是(`binding:"required"`) | 用户名 |
| `email` | string | 是(`binding:"required"`) | 邮箱 |
| `password` | string | 是(`binding:"required"`) | 密码 |
| `tenant_provisioning` | string | 否 | 空间开通策略 |
响应:201 `{"success":true,"message":"...","user":{User}}`
```bash
curl -X POST $BASE/api/v1/auth/register -H 'Content-Type: application/json' \
-d '{"username":"alice","email":"a@ex.com","password":"secret123"}'
```
### POST /api/v1/auth/register-by-invite
用途:通过邀请/分享链接 token 注册并加入空间。免认证,IP 限流 30 次/分钟。Handler: `internal/handler/auth_register_by_invite.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `token` | string | 是(`binding:"required"`) | 邀请 token |
| `email` | string | 是(`binding:"required,email"`) | 邮箱 |
| `username` | string | 是(`binding:"required"`) | 用户名 |
| `password` | string | 是(`binding:"required,min=6"`) | 密码(≥6 位) |
响应:201,同 Login(`user/active_tenant/memberships/token/refresh_token`)。
```bash
curl -X POST $BASE/api/v1/auth/register-by-invite -H 'Content-Type: application/json' \
-d '{"token":"<invite_token>","email":"a@ex.com","username":"alice","password":"secret123"}'
```
### POST /api/v1/auth/invitations/lookup
用途:匿名查询邀请 token 对应的空间信息(注册前预览)。免认证,IP 限流。Handler: `internal/handler/auth_register_by_invite.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `token` | string | 是(`binding:"required"`) | 邀请 token |
响应:200 `{"success":true,"data":{"tenant_id","tenant_name","role","expires_at"}}`
```bash
curl -X POST $BASE/api/v1/auth/invitations/lookup -H 'Content-Type: application/json' -d '{"token":"<invite_token>"}'
```
### POST /api/v1/auth/login
用途:邮箱密码登录。免认证。Handler: `internal/handler/auth.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `email` | string | 是(`binding:"required"`) | 邮箱 |
| `password` | string | 是(`binding:"required"`) | 密码 |
响应:200 `{"success":true,"user":{...},"active_tenant":{...},"memberships":[...],"token":"...","refresh_token":"..."}`
```bash
curl -X POST $BASE/api/v1/auth/login -H 'Content-Type: application/json' -d '{"email":"a@ex.com","password":"secret123"}'
```
### POST /api/v1/auth/auto-setup
用途:一键初始化(本地/Lite 场景自动建号建空间)。免认证,无请求体。Handler: `internal/handler/auth.go`
响应:200,同 Login。
```bash
curl -X POST $BASE/api/v1/auth/auto-setup
```
### GET /api/v1/auth/config
用途:查询注册模式等认证配置。免认证。Handler: `internal/handler/auth.go`
响应:200 `{"success":true,"registration_mode":"self_serve|invite_only"}`
```bash
curl $BASE/api/v1/auth/config
```
### POST /api/v1/auth/switch-tenant
用途:切换当前活跃空间并换发 token。需登录(无空间也可调用)。Handler: `internal/handler/auth.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `tenant_id` | uint64 | 是(`binding:"required"`) | 目标空间 ID |
| `refresh_token` | string | 否 | 用于换发新 token |
响应:200,同 Login。
换签成功会把目标空间写入账号级「最近活跃租户」偏好,下次登录(密码/OIDC/换设备)与 refresh 都回到该空间。refresh JWT 不含 `tenant_id`,因此偏好写入失败则整次换签失败、不会发出新 token。API 客户端无需再补发 `PUT /auth/me/preferences`。Web UI 切空间不走本接口。一次换签会改变该用户所有设备的下次落点。
```bash
curl -X POST $BASE/api/v1/auth/switch-tenant -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"tenant_id":2}'
```
### GET /api/v1/auth/oidc/config
用途:查询 OIDC 是否启用及显示名。免认证。Handler: `internal/handler/auth.go`
响应:200 `{"success":true,"enabled":bool,"provider_display_name":"..."}`
```bash
curl $BASE/api/v1/auth/oidc/config
```
### GET /api/v1/auth/oidc/url
用途:获取 OIDC 授权跳转 URL。免认证。Handler: `internal/handler/auth.go`
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `redirect_uri` | string | 是 | 回调地址 |
响应:200 `{"success":true,"authorization_url":"...","nonce":"..."}`
```bash
curl "$BASE/api/v1/auth/oidc/url?redirect_uri=https://app.example.com/callback"
```
### GET /api/v1/auth/oidc/callback
用途:OIDC 授权回调(浏览器重定向进入)。免认证。Handler: `internal/handler/auth.go`
查询参数:`code`、`state`、`error`、`error_description`(均由 OIDC 提供方带回)。
响应:302 重定向到前端,成功携带 `#oidc_result=<base64url>`,失败携带 `#oidc_error=...`。
```bash
curl -i "$BASE/api/v1/auth/oidc/callback?code=xxx&state=yyy"
```
### POST /api/v1/auth/refresh
用途:用 refresh token 换发新 token。免认证。Handler: `internal/handler/auth.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `refreshToken` | string | 是(`binding:"required"`) | refresh token |
响应:200 `{"success":true,"access_token":"...","refresh_token":"..."}`
```bash
curl -X POST $BASE/api/v1/auth/refresh -H 'Content-Type: application/json' -d '{"refreshToken":"<rt>"}'
```
### GET /api/v1/auth/validate
用途:校验当前 token 是否有效。需登录(无空间可调用)。Handler: `internal/handler/auth.go`
响应:200 `{"success":true,"message":"Token is valid","user":{UserInfo}}`
```bash
curl $BASE/api/v1/auth/validate -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/auth/logout
用途:登出(失效当前 token)。需登录。无请求体。Handler: `internal/handler/auth.go`
响应:200 `{"success":true,"message":"Logout successful"}`
```bash
curl -X POST $BASE/api/v1/auth/logout -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/auth/me
用途:查询当前调用者身份(用户/空间/成员关系/能力)。需登录;API key 亦可(策略 `apiKeyAny()`,任何有效 key)。Handler: `internal/handler/auth.go`
响应:200 `{"success":true,"data":{"user":{UserInfo},"tenant":{TenantResponse},"memberships":[...],"tenant_required":bool,"capabilities":{"can_create_tenant":bool}}}`
```bash
curl $BASE/api/v1/auth/me -H "X-API-Key: $API_KEY"
```
### PUT /api/v1/auth/me/preferences
用途:更新个人偏好(最近活跃空间)。需登录。Handler: `internal/handler/auth.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `last_active_tenant_id` | *uint64 | 否 | 正整数设置/替换;`0` 清除(下次登录回 home);省略则不改。`POST /auth/switch-tenant` 成功时服务端会写同一字段。 |
响应:200 `{"success":true,"data":{UserPreferences}}`
```bash
curl -X PUT $BASE/api/v1/auth/me/preferences -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"last_active_tenant_id":2}'
```
### POST /api/v1/auth/change-password
用途:修改密码。需登录。Handler: `internal/handler/auth.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `old_password` | string | 是(`binding:"required"`) | 旧密码 |
| `new_password` | string | 是(`binding:"required,min=6"`) | 新密码(≥6 位) |
响应:200 `{"success":true,"message":"Password changed successfully"}`
```bash
curl -X POST $BASE/api/v1/auth/change-password -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"old_password":"old","new_password":"newpass1"}'
```
## 我的邀请(/api/v1/me/invitations)
服务层保证“仅被邀请人可接受/拒绝”;无角色下限(无空间的新用户也可用)。Handler: `internal/handler/tenant_invitation.go`
### GET /api/v1/me/invitations
用途:列出发给我的邀请。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `include_terminal` | bool | 否 | `true` 时包含已完结的邀请 |
响应:200 `{"success":true,"data":{"invitations":[TenantInvitationResponse],"total":N}}`
```bash
curl $BASE/api/v1/me/invitations -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/me/invitations/pending-count
用途:待处理邀请计数(轻量轮询)。
响应:200 `{"success":true,"data":{"pending_count":N}}`
```bash
curl $BASE/api/v1/me/invitations/pending-count -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/me/invitations/:inv_id/accept
用途:接受邀请,写入成员关系。路径参数:`inv_id` 邀请 ID。无请求体。
响应:200 `{"success":true,"data":{"membership":{"tenant_id","role","status","joined_at"}}}`
```bash
curl -X POST $BASE/api/v1/me/invitations/12/accept -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/me/invitations/:inv_id/decline
用途:拒绝邀请。路径参数:`inv_id`。无请求体。
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/me/invitations/12/decline -H "Authorization: Bearer $TOKEN"
```
+443
View File
@@ -0,0 +1,443 @@
# API 参考:IM、Embed 与文件服务
路由注册:`internal/router/router.go` 的 `RegisterIMRoutes`、`RegisterIMChannelRoutes`、`RegisterEmbedChannelRoutes`、`RegisterEmbedPublicRoutes`、`serveFilesWithResources`、`servePresignedFiles`、`servePresignedPreview`、`serveResourceGrants`。Handler:`internal/handler/im.go`、`internal/handler/wechat_qrcode.go`、`internal/handler/embed_channel.go`。
## IM 回调(免全局认证)
### GET|POST /api/v1/im/callback/:channel_id
用途:IM 平台(WeChat/Feishu/Slack/Telegram/DingTalk/QQBot/云之家等)事件回调与 URL 验证。注册在认证中间件之前,使用各平台自身的签名验证;验签失败 403,渠道不存在 404。收到消息立即 ACK,异步处理。Handler: `internal/handler/im.go`
响应:200 `{"success":true}` 或平台要求的 ACK 格式。
```bash
curl -X POST $BASE/api/v1/im/callback/ch-1 -H 'Content-Type: application/json' -d '{"event":"..."}'
```
## IM 渠道管理(需认证)
API key:`manage_channels`/full。IM 渠道携带外部 bot 凭证:列表 Viewer+,变更/开关/扫码登录 Admin+。
### POST /api/v1/agents/:id/im-channels
用途:为 Agent 创建 IM 渠道。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `platform` | string | 是 | `wecom/feishu/lark/slack/telegram/dingtalk/mattermost/wechat/qqbot/yunzhijia` |
| `name` | string | 否 | 显示名 |
| `mode` | string | 否 | `websocket`(默认)/`webhook`/`longpoll`(wechat 强制 longpoll) |
| `output_mode` | string | 否 | `stream`(默认)/`full`(wechat 强制 full) |
| `knowledge_base_id` | string | 否 | 关联 KB |
| `credentials` | object | 否 | 平台凭证 |
| `enabled` | bool | 否 | 默认 true |
响应:200 `{"data":{IMChannel}}`;同渠道 bot 已存在返回 409。
```bash
curl -X POST $BASE/api/v1/agents/agent-1/im-channels -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"platform":"feishu","name":"飞书客服"}'
```
### GET /api/v1/agents/:id/im-channels
用途:某 Agent 的 IM 渠道列表(摘要)。权限:Viewer+。
响应:200 `{"data":[IMChannel]}`
```bash
curl $BASE/api/v1/agents/agent-1/im-channels -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/im-channels
用途:全空间 IM 渠道总览(不含凭证)。权限:Viewer+。
响应:200 `{"data":[IMChannel]}`
```bash
curl $BASE/api/v1/im-channels -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/im-channels/:id
用途:更新渠道(局部更新:`name/mode/output_mode/knowledge_base_id/credentials/enabled/agent_id` 均可选)。权限:Admin+。
响应:200 `{"data":{IMChannel}}`
```bash
curl -X PUT $BASE/api/v1/im-channels/ch-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"enabled":false}'
```
### DELETE /api/v1/im-channels/:id
用途:删除渠道。权限:Admin+。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/im-channels/ch-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/im-channels/:id/toggle
用途:启停切换。权限:Admin+。无请求体。
响应:200 `{"data":{IMChannel}}`
```bash
curl -X POST $BASE/api/v1/im-channels/ch-1/toggle -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/wechat/qrcode
用途:生成 WeChat 登录二维码(绑定个人微信到空间)。权限:Admin+。无请求体。Handler: `internal/handler/wechat_qrcode.go`
响应:200 `{"data":{"qrcode_url","qrcode"}}`
```bash
curl -X POST $BASE/api/v1/wechat/qrcode -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/wechat/qrcode/status
用途:轮询扫码状态;确认后返回凭证。权限:Admin+。请求体:`{"qrcode":"<标识>"}`(必填)。
响应:200 `{"data":{"status":"pending|scanned|confirmed|expired","credentials":{bot_token,ilink_bot_id,ilink_user_id,baseurl}}}`
```bash
curl -X POST $BASE/api/v1/wechat/qrcode/status -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"qrcode":"qr-1"}'
```
## Embed 渠道管理(需认证)
API key:`manage_channels`/full。Handler: `internal/handler/embed_channel.go`
### POST /api/v1/agents/:id/embed-channels
用途:为 Agent 创建 Web 嵌入渠道。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 否 | 名称 |
| `enabled` | bool | 否 | 默认 true |
| `allowed_origins` | []string | 是 | 至少一个来源(精确 URL / `*.domain`;生产禁止 `*`) |
| `welcome_message` | string | 否 | 欢迎语 |
| `rate_limit_per_minute` | int | 否 | 每 IP/分钟,默认 30 |
| `rate_limit_per_day` | int | 否 | 渠道/天,默认 10000 |
| `primary_color` / `page_title` / `widget_position` | string | 否 | 外观(position: `bottom-right` 默认等四角) |
| `header_title_mode` | string | 否 | `channel`(默认)/`session` |
| `show_suggested_questions` | bool | 否 | 默认 true |
| `allow_web_search` / `allow_file_upload` | bool | 否 | 默认 false |
| `default_locale` | string | 否 | `zh-CN/en-US/ko-KR/ru-RU`/空(跟随浏览器) |
| `webhook_url` / `webhook_secret` | string | 否 | 访客事件 webhook |
| `agent_id` | string | 否 | 绑定 Agent |
响应:201 `{"success":true,"data":{embedChannelResponse 含 publish_token}}`
```bash
curl -X POST $BASE/api/v1/agents/agent-1/embed-channels -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"官网客服","allowed_origins":["https://example.com"]}'
```
### GET /api/v1/agents/:id/embed-channels
用途:某 Agent 的嵌入渠道列表。权限:Viewer+。
响应:200 `{"success":true,"data":[embedChannelResponse]}`
```bash
curl $BASE/api/v1/agents/agent-1/embed-channels -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/embed-channels
用途:全空间嵌入渠道列表(不含 publish token)。权限:Viewer+。
响应:200 `{"success":true,"data":[embedChannelResponse]}`
```bash
curl $BASE/api/v1/embed-channels -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/embed-channels/:channel_id
用途:渠道详情(含 publish token,用于复制部署代码)。权限:Viewer+。
响应:200 `{"success":true,"data":{embedChannelResponse}}`
```bash
curl $BASE/api/v1/embed-channels/ec-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/embed-channels/:channel_id
用途:更新渠道(字段同创建,均可选)。权限:Admin+。
响应:200 `{"success":true,"data":{embedChannelResponse}}`
```bash
curl -X PUT $BASE/api/v1/embed-channels/ec-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"enabled":false}'
```
### DELETE /api/v1/embed-channels/:channel_id
用途:删除渠道。权限:Admin+。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/embed-channels/ec-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/embed-channels/:channel_id/rotate-token
用途:轮换 publish token(旧 token 失效)。权限:Admin+。无请求体。
响应:200 `{"success":true,"data":{embedChannelResponse 含新 publish_token}}`
```bash
curl -X POST $BASE/api/v1/embed-channels/ec-1/rotate-token -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/embed-channels/:channel_id/preview-session
用途:签发管理端预览用短时效 session token(无需 publish token)。权限:Viewer+。
响应:200 `{"success":true,"data":{"session_token","expires_in"}}`;渠道禁用 403。
```bash
curl -X POST $BASE/api/v1/embed-channels/ec-1/preview-session -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/embed-channels/:channel_id/stats
用途:渠道用量统计。权限:Viewer+。
响应:200 `{"success":true,"data":{"session_count":N}}`
```bash
curl $BASE/api/v1/embed-channels/ec-1/stats -H "Authorization: Bearer $TOKEN"
```
## Embed 公开路由(/api/v1/embed/:channel_id,EmbedAuth)
认证:`Authorization: Embed <publish_token|session_token>`;会话级操作附加 `X-Embed-Session: <sig>`。限流与 Origin 校验见总览。Handler: `internal/handler/embed_channel.go`;中间件:`internal/middleware/embed_auth.go`
以下 `$ET` 表示 Embed token 头:`-H "Authorization: Embed $EMBED_TOKEN"`。
### POST /api/v1/embed/:channel_id/exchange
用途:用 publish token 换取短时效 session token(session token 不可再次 exchange)。无请求体。
响应:200 `{"success":true,"data":{"session_token","expires_in"}}`
```bash
curl -X POST $BASE/api/v1/embed/ec-1/exchange -H "Authorization: Embed $PUBLISH_TOKEN"
```
### GET /api/v1/embed/:channel_id/config
用途:渠道公开配置(无密钥)。
响应:200 `{"success":true,"data":{channel_id,name,display_title,knowledge_base_ids,agent_id,agent_name,welcome_message,primary_color,widget_position,allow_web_search,allow_file_upload,default_locale,...}}`
```bash
curl $BASE/api/v1/embed/ec-1/config -H "Authorization: Embed $EMBED_TOKEN"
```
### GET /api/v1/embed/:channel_id/suggested-questions
用途:起始建议问题。查询参数:`limit`(≤12)。
响应:200 `{"success":true,"data":{"questions":[...]}}`
```bash
curl "$BASE/api/v1/embed/ec-1/suggested-questions?limit=6" -H "Authorization: Embed $EMBED_TOKEN"
```
### GET /api/v1/embed/:channel_id/chunks/:chunk_id
用途:查看引用分块(内容脱敏;越权 403)。
响应:200 `{"success":true,"data":{chunk}}`
```bash
curl $BASE/api/v1/embed/ec-1/chunks/c-1 -H "Authorization: Embed $EMBED_TOKEN"
```
### POST /api/v1/embed/:channel_id/sessions
用途:创建访客会话,返回会话 ID 与签名句柄。无请求体。
响应:201 `{"success":true,"data":{"id":"<session_id>","sig":"<签名>"}}`
```bash
curl -X POST $BASE/api/v1/embed/ec-1/sessions -H "Authorization: Embed $EMBED_TOKEN"
```
### POST /api/v1/embed/:channel_id/knowledge-chat/:session_id
用途:访客知识问答(SSE;payload 会被渠道约束改写后委托给 KnowledgeQA)。需 `X-Embed-Session`。请求体同 `/knowledge-chat`(`query` 必填)。
```bash
curl -N -X POST $BASE/api/v1/embed/ec-1/knowledge-chat/s-1 \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG" \
-H 'Content-Type: application/json' -d '{"query":"营业时间?"}'
```
### POST /api/v1/embed/:channel_id/agent-chat/:session_id
用途:访客 Agent 问答(SSE)。需 `X-Embed-Session`。请求体同上。
```bash
curl -N -X POST $BASE/api/v1/embed/ec-1/agent-chat/s-1 \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG" \
-H 'Content-Type: application/json' -d '{"query":"帮我下单"}'
```
### GET /api/v1/embed/:channel_id/messages/:session_id/load
用途:加载访客会话消息(委托 `LoadMessages`,查询参数 `limit/before_time`)。需 `X-Embed-Session`。
响应:200 `{"success":true,"data":[Message]}`
```bash
curl "$BASE/api/v1/embed/ec-1/messages/s-1/load?limit=20" \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG"
```
### POST /api/v1/embed/:channel_id/sessions/:session_id/stop
用途:停止生成(委托 StopSession;请求体 `{"message_id":"..."}`)。需 `X-Embed-Session`。
```bash
curl -X POST $BASE/api/v1/embed/ec-1/sessions/s-1/stop \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG" \
-H 'Content-Type: application/json' -d '{"message_id":"m-1"}'
```
### GET|POST /api/v1/embed/:channel_id/sessions/:session_id/messages/:message_id/suggestions
用途:读取 / 触发生成消息建议(渠道关闭建议时返回 `suppressed`)。需 `X-Embed-Session`。
响应:200 `{"success":true,"data":{"status","questions":[...]}}`
```bash
curl $BASE/api/v1/embed/ec-1/sessions/s-1/messages/m-1/suggestions \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG"
```
### POST /api/v1/embed/:channel_id/sessions/:session_id/suggestion-events
用途:上报建议交互事件(委托 RecordEvent,字段同认证版)。需 `X-Embed-Session`。响应:204。
```bash
curl -X POST $BASE/api/v1/embed/ec-1/sessions/s-1/suggestion-events \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG" \
-H 'Content-Type: application/json' -d '{"suggestion_set_id":"ss-1","event_type":"impression"}'
```
### POST /api/v1/embed/:channel_id/sessions/:session_id/events
用途:转发访客事件到渠道 webhook。需 `X-Embed-Session`。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `type` | string | 是 | `message_sent` / `message_received` |
| `query` / `content` | string | 否 | 用户问题 / 机器人回复 |
响应:200 `{"success":true}`;不支持的类型 400。
```bash
curl -X POST $BASE/api/v1/embed/ec-1/sessions/s-1/events \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG" \
-H 'Content-Type: application/json' -d '{"type":"message_sent","query":"你好"}'
```
### MCP OAuth 与工具审批(访客侧)
以下路由均需 `X-Embed-Session`,委托到对应认证版 handler(`internal/handler/mcp_oauth.go`、`internal/handler/mcp_service.go`):
| 方法+路径 | 用途 |
| --- | --- |
| `POST /api/v1/embed/:channel_id/sessions/:session_id/mcp-oauth-resolutions/:pending_id` | 恢复 OAuth 暂停的运行(体:`service_id` 必填,`decision` 可选) |
| `POST /api/v1/embed/:channel_id/sessions/:session_id/mcp-oauth-resolutions/:pending_id/cancel` | 取消 OAuth 流程 |
| `POST /api/v1/embed/:channel_id/sessions/:session_id/mcp-services/:id/oauth/authorize-url` | 生成授权 URL(体:`redirect_uri` 必填) |
| `GET /api/v1/embed/:channel_id/sessions/:session_id/mcp-services/:id/oauth/status` | 查询授权状态 |
| `POST /api/v1/embed/:channel_id/sessions/:session_id/tool-approvals/:pending_id` | 工具审批(体:`decision` 必填) |
```bash
curl -X POST $BASE/api/v1/embed/ec-1/sessions/s-1/tool-approvals/p-1 \
-H "Authorization: Embed $EMBED_TOKEN" -H "X-Embed-Session: $SIG" \
-H 'Content-Type: application/json' -d '{"decision":"approve"}'
```
### GET /api/v1/embed/:channel_id/files
用途:访客侧图片代理(机器人回复内嵌图片;EmbedAuth 注入渠道空间,handler 强制同空间路径)。查询参数:`file_path`(必填)。
响应:200 文件流。
```bash
curl "$BASE/api/v1/embed/ec-1/files?file_path=local://1/exports/chart.png" \
-H "Authorization: Embed $EMBED_TOKEN" -o chart.png
```
## 文件服务
实现于 `internal/router/router.go`(非 handler 包)。
### GET /files
用途:认证后的统一文件代理(本地/MinIO/COS/TOS 等)。权限:任意已认证空间成员;API key 需非 KB 受限(full-access 或全空间 retrieve,`middleware.AllowFileServeAPIKey()`);路径强制同空间(`ValidateStoragePathTenant`)。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `file_path` | string | 是 | `provider://...` 路径(禁止 `..`;跨空间 403) |
响应:200 文件流(`X-Content-Type-Options: nosniff`;非白名单类型强制 `Content-Disposition: attachment`)。
```bash
curl "$BASE/files?file_path=local://1/docs/a.png" -H "Authorization: Bearer $TOKEN" -o a.png
```
### GET|HEAD /api/v1/files/presigned
用途:HMAC 签名 URL 文件访问(IM 平台内嵌图片;免认证,验签+过期校验,`SYSTEM_AES_KEY` 参与签名)。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `file_path` | string | 是 | 存储路径 |
| `tenant_id` | uint64 | 是 | 空间 ID |
| `expires` | string | 是 | Unix 过期时间 |
| `sig` | string | 是 | HMAC 签名 |
响应:200 文件流(HEAD 仅返回头);签名无效/过期 403。
```bash
curl "$BASE/api/v1/files/presigned?file_path=local://1/x.png&tenant_id=1&expires=1790000000&sig=abc" -o x.png
```
### GET /api/v1/files/presigned-preview
用途:诊断端点:返回给定路径将生成的预签名 HTTP URL。权限:Admin+,显式拒绝 API key(`DenyAPIKeyPrincipal`)。查询参数:`file_path`(必填)。
响应:200 `{"file_path","provider","url","rewritten":bool,"hint"}`
```bash
curl "$BASE/api/v1/files/presigned-preview?file_path=local://1/x.png" -H "Authorization: Bearer $TOKEN"
```
### GET|HEAD /r/:token
用途:短时效资源授权 URL(IM 等无法携带认证头的客户端)。免认证,token 即能力凭证;无效/过期 404。
响应:200 文件流(`Cache-Control: private, max-age=300`)。
```bash
curl $BASE/r/abc123 -o file.png
```
+367
View File
@@ -0,0 +1,367 @@
# API 参考:会话、消息与聊天
路由注册:`internal/router/router.go` 的 `RegisterSessionRoutes`、`RegisterChatRoutes`、`RegisterMessageRoutes`。Handler:`internal/handler/session/`(handler.go、qa.go、stream.go、title.go、temporary_document.go)、`internal/handler/message.go`、`internal/handler/message_suggestion.go`。
会话为“用户私有”资源,handler 内部强制归属校验;路由层为 Viewer+。API key:会话/聊天需 `chat` capability(或 full-access);消息搜索需 `message_history`;知识检索需 `retrieve`。
## 会话(/api/v1/sessions)
### POST /api/v1/sessions
用途:创建会话。Handler: `internal/handler/session/handler.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `title` | string | 否 | 标题 |
| `description` | string | 否 | 描述 |
响应:201 `{"success":true,"data":{Session}}`(`id,title,description,tenant_id,user_id,is_pinned,last_request_state,created_at,...`)
```bash
curl -X POST $BASE/api/v1/sessions -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' -d '{"title":"新对话"}'
```
### GET /api/v1/sessions
用途:会话列表。Handler: `internal/handler/session/handler.go`
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `page` / `page_size` | int | 否 | 分页 |
| `keyword` | string | 否 | 标题模糊搜索 |
| `source` | string | 否 | 来源过滤(web/embed/api/feishu/wechat/slack/...) |
| `agent_id` | string | 否 | 按 Agent 过滤(IM 会话) |
响应:200 `{"success":true,"data":[SessionListItem],"total","page","page_size"}`
```bash
curl "$BASE/api/v1/sessions?page=1" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/sessions/:id
用途:会话详情。
响应:200 `{"success":true,"data":{Session}}`
```bash
curl $BASE/api/v1/sessions/s-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/sessions/:id
用途:更新会话(标题/描述/置顶)。请求体:`title`、`description`、`is_pinned`(均可选)。
响应:200 `{"success":true,"data":{Session}}`
```bash
curl -X PUT $BASE/api/v1/sessions/s-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"title":"重命名"}'
```
### DELETE /api/v1/sessions/:id
用途:删除会话。
响应:200 `{"success":true,"message":"Session deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/sessions/s-1 -H "Authorization: Bearer $TOKEN"
```
### DELETE /api/v1/sessions/batch
用途:批量删除会话。请求体:`{"ids":["s-1"],"delete_all":false}`(二选一:`ids` 或 `delete_all:true`)。
响应:200 `{"success":true,"message":"Sessions deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/sessions/batch -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"ids":["s-1","s-2"]}'
```
### DELETE /api/v1/sessions/:id/messages
用途:清空会话消息。
响应:200 `{"success":true,"message":"Session messages cleared successfully"}`
```bash
curl -X DELETE $BASE/api/v1/sessions/s-1/messages -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/sessions/:session_id/generate_title
用途:根据上下文消息生成会话标题。Handler: `internal/handler/session/title.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `messages` | []Message | 是(`binding:"required"`) | 用作上下文的消息 |
响应:200 `{"success":true,"data":"生成的标题"}`
```bash
curl -X POST $BASE/api/v1/sessions/s-1/generate_title -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"messages":[{"role":"user","content":"介绍下产品"}]}'
```
### POST /api/v1/sessions/:session_id/stop
用途:停止正在生成的回答。Handler: `internal/handler/session/stream.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `message_id` | string | 是(`binding:"required"`) | 助手消息 ID |
响应:200 `{"success":true,"message":"Generation stopped"}`
```bash
curl -X POST $BASE/api/v1/sessions/s-1/stop -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"message_id":"m-1"}'
```
### POST /api/v1/sessions/:session_id/pin 与 DELETE /api/v1/sessions/:id/pin
用途:置顶 / 取消置顶会话。无请求体。Handler: `internal/handler/session/handler.go`
响应:200 `{"success":true,"is_pinned":true|false}`
```bash
curl -X POST $BASE/api/v1/sessions/s-1/pin -H "Authorization: Bearer $TOKEN"
curl -X DELETE $BASE/api/v1/sessions/s-1/pin -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/sessions/continue-stream/:session_id
用途:断线续传活跃流(重放历史事件 + 100ms 轮询新增量)。Handler: `internal/handler/session/stream.go`
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `message_id` | string | 是 | 要续传的助手消息 ID |
响应:200 SSE(`text/event-stream`,事件格式见总览“流式接口协议”)。
```bash
curl -N "$BASE/api/v1/sessions/continue-stream/s-1?message_id=m-1" -H "Authorization: Bearer $TOKEN"
```
## 会话附件(临时文档)
Handler: `internal/handler/session/temporary_document.go`
### POST /api/v1/sessions/:session_id/attachments
用途:上传会话级临时文档(异步解析)。multipart 字段:`file`(必填)、`agent_id`(可选,决定解析引擎/ASR 模型)、`parser_engine`(可选)。
响应:202 `{"success":true,"data":{TemporaryDocument}}`(`id,session_id,file_name,file_type,file_size,status(uploaded/processing/ready/failed),resource_ref,...`)
```bash
curl -X POST $BASE/api/v1/sessions/s-1/attachments -H "Authorization: Bearer $TOKEN" -F 'file=@notes.pdf'
```
### GET /api/v1/sessions/:id/attachments
用途:附件列表。
响应:200 `{"success":true,"data":[TemporaryDocument]}`
```bash
curl $BASE/api/v1/sessions/s-1/attachments -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/sessions/:id/attachments/:attachment_id
用途:附件详情(含解析状态)。
响应:200 `{"success":true,"data":{TemporaryDocument}}`
```bash
curl $BASE/api/v1/sessions/s-1/attachments/a-1 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/sessions/:id/attachments/:attachment_id/preview
用途:附件原文件预览。
响应:200 文件流(`Content-Disposition: inline|attachment`,`Cache-Control: private`)。
```bash
curl $BASE/api/v1/sessions/s-1/attachments/a-1/preview -H "Authorization: Bearer $TOKEN" -o preview.pdf
```
### DELETE /api/v1/sessions/:id/attachments/:attachment_id
用途:删除附件。
响应:204 No Content
```bash
curl -X DELETE $BASE/api/v1/sessions/s-1/attachments/a-1 -H "Authorization: Bearer $TOKEN"
```
## 回答建议(Suggestions)
Handler: `internal/handler/message_suggestion.go`
### GET /api/v1/sessions/:id/messages/:message_id/suggestions
用途:读取某助手消息的追问建议。
响应:200 `{"success":true,"data":{MessageSuggestionSet}}`(`status(generating/ready/suppressed/failed),questions:[{id,text,category,source,knowledge_base_ids}],allow_regenerate,...`)
```bash
curl $BASE/api/v1/sessions/s-1/messages/m-1/suggestions -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/sessions/:session_id/messages/:message_id/suggestions
用途:确保生成建议(幂等触发)。请求体:`{"regenerate":true}`(可选,强制重新生成)。
响应:200(就绪)或 202(生成中)`{"success":true,"data":{MessageSuggestionSet|null}}`
```bash
curl -X POST $BASE/api/v1/sessions/s-1/messages/m-1/suggestions -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{}'
```
### POST /api/v1/sessions/:session_id/suggestion-events
用途:上报建议交互事件(埋点)。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `suggestion_set_id` | string | 是(`binding:"required"`) | 建议集 ID |
| `question_id` | string | 否 | click/regenerate 时必填 |
| `event_type` | string | 是(`binding:"required"`) | `impression/click/dismiss/regenerate` |
响应:204 No Content
```bash
curl -X POST $BASE/api/v1/sessions/s-1/suggestion-events -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"suggestion_set_id":"ss-1","event_type":"impression"}'
```
## 聊天与检索
Handler: `internal/handler/session/qa.go`。API key:聊天需 `chat`/full;`knowledge-search` 需 `retrieve`/full。
### POST /api/v1/knowledge-chat/:session_id
用途:知识库问答(SSE 流式)。
请求体(KnowledgeQA/AgentQA 共用):
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query` | string | 是(`binding:"required"`) | 用户问题 |
| `knowledge_base_ids` | []string | 否 | 检索的 KB |
| `knowledge_ids` | []string | 否 | 限定知识文件 |
| `agent_enabled` | bool | 否 | 是否启用 Agent 模式 |
| `agent_id` | string | 否 | 自定义 Agent ID |
| `web_search_enabled` | bool | 否 | 联网搜索 |
| `summary_model_id` | string | 否 | 总结模型 |
| `mcp_service_ids` | []string | 否 | @提及的 MCP 服务 |
| `skill_names` | []string | 否 | @提及的技能 |
| `tag_ids` | []string | 否 | 标签过滤 |
| `mentioned_items` | []object | 否 | @提及项(type/kb_id/kb_name/service_id/skill_name) |
| `disable_title` | bool | 否 | 禁用自动标题 |
| `images` | []object | 否 | 图片(`data` base64 / `url` / `caption`) |
| `attachment_uploads` | []object | 否 | 内联附件(`data` base64、`file_name`、`file_size`) |
| `attachment_ids` | []string | 否 | 已上传的会话附件 ID |
| `channel` | string | 否 | 来源渠道 |
| `suggestion_attribution` | object | 否 | 点击建议的归因信息 |
响应:200 SSE 流,`event: message` + `data: StreamResponse`(见总览),以 `complete` 事件结束。
```bash
curl -N -X POST $BASE/api/v1/knowledge-chat/s-1 -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"query":"退款政策是什么?","knowledge_base_ids":["kb-1"]}'
```
### POST /api/v1/agent-chat/:session_id
用途:Agent 问答(SSE 流式,含 `thinking/tool_call/tool_result/tool_approval_required/mcp_oauth_required` 等事件)。请求体同上。
```bash
curl -N -X POST $BASE/api/v1/agent-chat/s-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"query":"分析上季度数据","agent_id":"agent-1"}'
```
### POST /api/v1/knowledge-search
用途:无会话知识检索(非流式)。Handler: `internal/handler/session/qa.go` 的 `SearchKnowledge`。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query` | string | 是(`binding:"required"`) | 查询 |
| `knowledge_base_id` | string | 否 | 单 KB(兼容旧版) |
| `knowledge_base_ids` | []string | 否 | 多 KB |
| `knowledge_ids` | []string | 否 | 限定文件 |
| `tag_ids` | []string | 否 | 标签过滤 |
| `mentioned_items` | []object | 否 | 带 KB 范围的标签提及 |
响应:200 `{"success":true,"data":[SearchResult]}`(`id,content,knowledge_id,knowledge_title,score,chunk_type,knowledge_base_id,...`)
```bash
curl -X POST $BASE/api/v1/knowledge-search -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' -d '{"query":"部署要求","knowledge_base_ids":["kb-1"]}'
```
## 消息(/api/v1/messages)
Handler: `internal/handler/message.go`
### POST /api/v1/messages/search
用途:聊天历史搜索。权限:Viewer+;API key `message_history`/full。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query` | string | 是(`binding:"required"`) | 查询 |
| `mode` | string | 否 | `keyword/vector/hybrid`(默认 hybrid) |
| `limit` | int | 否 | 默认 20 |
| `session_ids` | []string | 否 | 限定会话 |
响应:200 `{"success":true,"data":{"total":N,"results":[{session_id,message_id,role,content,created_at,score}]}}`
```bash
curl -X POST $BASE/api/v1/messages/search -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"query":"报价"}'
```
### GET /api/v1/messages/chat-history-stats
用途:聊天历史索引统计。权限:Viewer+;API key `message_history`/full。
响应:200 `{"success":true,"data":{indexed_message_count,knowledge_base_size,last_indexed_at,...}}`
```bash
curl $BASE/api/v1/messages/chat-history-stats -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/messages/:session_id/load
用途:加载会话消息(时间游标向前翻页)。权限:Viewer+;API key `chat`/full。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `limit` | int | 否 | 默认 20 |
| `before_time` | string | 否 | RFC3339/RFC3339Nano 时间戳 |
响应:200 `{"success":true,"data":[Message]}`(`id,session_id,role,content,is_completed,images,attachments,agent_steps,...`)
```bash
curl "$BASE/api/v1/messages/s-1/load?limit=20" -H "X-API-Key: $API_KEY"
```
### DELETE /api/v1/messages/:session_id/:id
用途:删除单条消息。权限:Viewer+(handler 校验会话归属);API key `chat`/full。
响应:200 `{"success":true,"message":"Message deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/messages/s-1/m-1 -H "Authorization: Bearer $TOKEN"
```
+218
View File
@@ -0,0 +1,218 @@
# API 参考:分块与标签
分块(chunk)是检索的最小单元,标签用于给文档分类。两组接口都挂在知识库之下,与[知识库与知识](./02-api-knowledge.md)共用同一套权限规则:读为 Viewer+ 且对父 KB 有 read 权限(API key `retrieve`),写为「KB 创建者 OR Admin+」且有 write 权限(API key `ingest`),均受 API key 的 KB 白名单约束。
路由注册:`internal/router/routes_knowledge.go` 的 `RegisterChunkRoutes`、`RegisterKnowledgeTagRoutes`、`RegisterChunkerDebugRoutes`。
通用约定(Base URL、认证、错误码、分页)见 [API 总览](./01-api-overview.md)。
## 分块(/api/v1/chunks)
Handler: `internal/handler/chunk.go`。读:Viewer+ 且父 KB read(API key `retrieve`/full);写:KB 创建者 OR Admin+ 且父 KB write(API key `ingest`/full)。
### GET /api/v1/chunks/:knowledge_id
用途:知识的分块列表。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `page` | int | 否 | 默认 1 |
| `page_size` | int | 否 | 默认 10,上限 100 |
| `chunk_type` | string | 否 | 可重复,按分块类型过滤 |
响应:200 `{"success":true,"data":[Chunk],"total","page","page_size"}`
```bash
curl "$BASE/api/v1/chunks/k-1?page=1" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/chunks/by-id/:id
用途:按 chunk ID 获取单个分块(无需 knowledge_id)。
响应:200 `{"success":true,"data":{Chunk}}`
```bash
curl $BASE/api/v1/chunks/by-id/c-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/chunks/:knowledge_id/:id
用途:编辑分块内容或启停状态(migration `000078` 起为带版本的乐观更新)。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `content` | string | 否 | 新内容,去除首尾空白后不得为空,长度上限 200000 字节 |
| `is_enabled` | bool | 否 | 启用/停用该分块 |
| `expected_revision` | int | 否 | 期望的 `content_revision`,用于乐观并发控制 |
约束与副作用:
- 仅 `text` 类型分块可编辑,其它类型返回 400;
- `expected_revision` 与当前 `content_revision` 不一致时返回 **409**(`Chunk was modified by another user; refresh and retry`);
- 不允许在编辑中引入源内容里没有的图片 URL;删除 Markdown 图片会同步停用对应的 OCR/caption 子分块;
- 编辑成功后 `content_revision` +1,旧版本写入 `chunk_revisions` 表,`index_status` 依次经历 `processing` → `ready`;重建检索索引失败时行仍保存但 `index_status = failed`,可再次提交同样内容触发重试;
- 子分块编辑会按偏移量回写父分块内容(父分块的 `source_content` 保持不可变);
- 内容或启停状态变化会入队一次文档摘要刷新。
响应:200 `{"success":true,"data":{Chunk},"summary_status":"pending","description":"..."}`
```bash
curl -X PUT $BASE/api/v1/chunks/k-1/c-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"content":"修正后的内容","expected_revision":2}'
```
### GET /api/v1/chunks/:knowledge_id/:id/revisions
用途:分块的历史版本列表(`chunk_revisions` 表,按 revision 倒序)。
响应:200 `{"success":true,"data":[{ChunkRevision}]}`,单条包含 `revision`、`content`、`is_enabled`、`editor_id`、`edit_source`、`edited_at`。
```bash
curl $BASE/api/v1/chunks/k-1/c-1/revisions -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/chunks/:knowledge_id/:id/revert
用途:回滚到某个历史版本。回滚本身也是一次新编辑:`content_revision` 继续递增,当前内容会被存为新的历史版本。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `revision` | int | 是 | 目标历史版本号(非负) |
| `expected_revision` | int | 否 | 乐观锁,语义同上,冲突返回 409 |
响应:200 `{"success":true,"data":{Chunk},"summary_status":"...","description":"..."}`
```bash
curl -X POST $BASE/api/v1/chunks/k-1/c-1/revert -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"revision":1}'
```
### DELETE /api/v1/chunks/:knowledge_id/:id
用途:删除单个分块。
响应:200 `{"success":true,"message":"Chunk deleted"}`
```bash
curl -X DELETE $BASE/api/v1/chunks/k-1/c-1 -H "Authorization: Bearer $TOKEN"
```
### DELETE /api/v1/chunks/:knowledge_id
用途:删除知识下全部分块。
响应:200 `{"success":true,"message":"All chunks under knowledge deleted"}`
```bash
curl -X DELETE $BASE/api/v1/chunks/k-1 -H "Authorization: Bearer $TOKEN"
```
### DELETE /api/v1/chunks/by-id/:id/questions
用途:删除该分块下某条生成的问题。请求体:`{"question_id":"..."}`(`binding:"required"`)。
响应:200 `{"success":true,"message":"Generated question deleted"}`
```bash
curl -X DELETE $BASE/api/v1/chunks/by-id/c-1/questions -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"question_id":"q-1"}'
```
### PUT /api/v1/chunks/by-id/:id/questions
用途:新增或修改该分块的一条生成问题。请求体:`{"question":"...","question_id":"..."}`,`question` 必填;`question_id` 留空表示新增。
响应:200 `{"success":true,"data":{GeneratedQuestion}}`
```bash
curl -X PUT $BASE/api/v1/chunks/by-id/c-1/questions -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"question_id":"q-1","question":"WeKnora 如何配置向量库?"}'
```
### POST /api/v1/chunks/by-id/:id/questions/regenerate
用途:基于分块当前内容重新生成检索问题。内容编辑后原有问题不会被删除,而是标记为「过期」(revision 与当前正文不匹配),可用本接口刷新。
响应:200 `{"success":true,"data":[{GeneratedQuestion}]}`
```bash
curl -X POST $BASE/api/v1/chunks/by-id/c-1/questions/regenerate -H "Authorization: Bearer $TOKEN"
```
## 标签(/api/v1/knowledge-bases/:id/tags)
Handler: `internal/handler/tag.go`。读:Viewer+ + KB read(API key `retrieve`/full);写:KB 创建者 OR Admin+ + KB write(API key `ingest`/full)。
### GET /api/v1/knowledge-bases/:id/tags
用途:标签列表。查询参数:`page`、`page_size`、`keyword`(均可选)。
响应:200 `{"success":true,"data":[KnowledgeTag]}`
```bash
curl $BASE/api/v1/knowledge-bases/kb-1/tags -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledge-bases/:id/tags
用途:创建标签。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是(`binding:"required"`) | 标签名 |
| `color` | string | 否 | 颜色 |
| `sort_order` | int | 否 | 排序 |
响应:200 `{"success":true,"data":{KnowledgeTag}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/tags -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"售后"}'
```
### PUT /api/v1/knowledge-bases/:id/tags/:tag_id
用途:更新标签(`tag_id` 支持 UUID 或整数 seq_id)。请求体:`name`/`color`/`sort_order`(指针字段,均可选)。
响应:200 `{"success":true,"data":{KnowledgeTag}}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/tags/t-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"售后支持"}'
```
### DELETE /api/v1/knowledge-bases/:id/tags/:tag_id
用途:删除标签。查询参数:`force`(bool,强制删除)、`content_only`(bool,仅删内容保留标签)。请求体(可选):`{"exclude_ids":[int64]}`。
响应:200 `{"success":true}`
```bash
curl -X DELETE "$BASE/api/v1/knowledge-bases/kb-1/tags/t-1?force=true" -H "Authorization: Bearer $TOKEN"
```
## 分块调试
### POST /api/v1/chunker/preview
用途:无状态分块预览(KB 编辑器调试面板)。权限:Viewer+;API key `retrieve`/`ingest`/full。Handler: `internal/handler/chunker_debug.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `text` | string | 是(代码校验非空,≤64k 字符) | 样例文本 |
| `chunking_config.chunk_size` | int | 否 | 分块字符数 |
| `chunking_config.chunk_overlap` | int | 否 | 重叠 |
| `chunking_config.separators` | []string | 否 | 分隔符 |
| `chunking_config.strategy` | string | 否 | `auto/heading/heuristic/recursive/legacy` |
| `chunking_config.token_limit` | int | 否 | token 上限 |
| `chunking_config.languages` | []string | 否 | 语言提示 |
| `chunking_config.enable_parent_child` | bool | 否 | 按父子分块试切,返回的是子块(与检索粒度一致) |
| `chunking_config.parent_chunk_size` / `child_chunk_size` | int | 否 | 父/子块大小,缺省 4096 / 384 |
响应:200 `{"success":true,"data":{"selected_tier","tier_chain","rejected","profile","chunks":[...],"stats":{count,avg_chars,min_chars,max_chars,stddev_chars,truncated_to}}}`;文本超长 413;分块超时(5s)504。
```bash
curl -X POST $BASE/api/v1/chunker/preview -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"text":"# 标题\n正文...","chunking_config":{"chunk_size":512}}'
```
+457
View File
@@ -0,0 +1,457 @@
# API 参考:FAQ 与 Wiki
路由注册:`internal/router/router.go` 的 `RegisterFAQRoutes` 与 `RegisterWikiPageRoutes`。Handler:`internal/handler/faq.go`、`internal/handler/wiki_page.go`。
两组均为 KB 内容子资源:读为 Viewer+ 且 KB read(API key `retrieve`/full);写为“KB 创建者 OR Admin+”且 KB write(API key `ingest`/full),并受 KB 白名单约束。
## FAQ(/api/v1/knowledge-bases/:id/faq)
### GET /api/v1/knowledge-bases/:id/faq/entries
用途:FAQ 条目列表。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `page` / `page_size` | int | 否 | 分页 |
| `tag_id` | int | 否 | 旧版单标签 seq_id |
| `tag_ids` | string | 否 | 逗号分隔标签 UUID |
| `keyword` | string | 否 | 关键字 |
| `search_field` | string | 否 | `standard_question`/`similar_questions`/`answers`(默认全字段) |
| `sort_order` | string | 否 | `asc`(默认按更新时间倒序) |
响应:200 `{"success":true,"data":{分页 FAQEntry 列表}}`
```bash
curl "$BASE/api/v1/knowledge-bases/kb-1/faq/entries?page=1" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge-bases/:id/faq/entries/export
用途:导出 FAQ。查询参数:`format`(`csv` 默认 / `json`)。
响应:200 文件下载(`text/csv` 或 `application/json`)。
```bash
curl -OJ "$BASE/api/v1/knowledge-bases/kb-1/faq/entries/export?format=csv" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge-bases/:id/faq/entries/:entry_id
用途:FAQ 条目详情(`entry_id` 为整数 seq_id)。
响应:200 `{"success":true,"data":{FAQEntry}}`
```bash
curl $BASE/api/v1/knowledge-bases/kb-1/faq/entries/12 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledge-bases/:id/faq/entries
用途:批量 upsert / 导入(异步任务)。Handler 方法 `UpsertEntries`。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `entries` | []FAQEntryPayload | 是(`binding:"required"`) | 批量条目 |
| `mode` | string | 是(`binding:"oneof=append replace"`) | 追加或替换 |
| `knowledge_id` | string | 否 | FAQ 知识实体 ID |
| `task_id` | string | 否 | 自定义任务 ID |
| `dry_run` | bool | 否 | 仅校验不落库 |
响应:200 `{"success":true,"data":{"task_id"}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/entries -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"mode":"append","entries":[{"standard_question":"如何退款?","answers":["联系客服"]}]}'
```
### POST /api/v1/knowledge-bases/:id/faq/entry
用途:创建单条 FAQ。请求体(`types.FAQEntryPayload`):
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `standard_question` | string | 是(`binding:"required"`) | 标准问 |
| `similar_questions` | []string | 否 | 相似问 |
| `negative_questions` | []string | 否 | 负样例问 |
| `answers` | []string | 否 | 答案列表 |
| `answer_strategy` | string | 否 | `all` / `random` |
| `tag_id` | int64 | 否 | 标签 seq_id |
| `tag_name` | string | 否 | 标签名 |
| `is_enabled` / `is_recommended` | *bool | 否 | 启用/推荐 |
响应:200 `{"success":true,"data":{FAQEntry}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/entry -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"standard_question":"如何退款?","answers":["7 天内可退"]}'
```
### PUT /api/v1/knowledge-bases/:id/faq/entries/:entry_id
用途:更新单条 FAQ(请求体同创建)。
响应:200 `{"success":true,"data":{FAQEntry}}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/entries/12 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"standard_question":"如何退款?","answers":["30 天内可退"]}'
```
### POST /api/v1/knowledge-bases/:id/faq/entries/:entry_id/similar-questions
用途:追加相似问。请求体:`{"similar_questions":["..."]}`(`binding:"required,min=1"`)。
响应:200 `{"success":true,"data":{FAQEntry}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/entries/12/similar-questions \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"similar_questions":["退款怎么操作"]}'
```
### PUT /api/v1/knowledge-bases/:id/faq/entries/fields
用途:批量更新条目字段(`is_enabled`/`is_recommended`/`tag_id`)。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `by_id` | map[int64]object | 否 | 按条目 seq_id 更新 |
| `by_tag` | map[int64]object | 否 | 按标签批量更新 |
| `exclude_ids` | []int64 | 否 | `by_tag` 时排除的条目 |
响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/entries/fields -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"by_id":{"12":{"is_enabled":false}}}'
```
### PUT /api/v1/knowledge-bases/:id/faq/entries/tags
用途:批量改条目标签。请求体:`{"updates":{"<entry_id>":<tag_id|null>}}`(`binding:"required,min=1"`;null 移除标签)。
响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/entries/tags -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"updates":{"12":3}}'
```
### DELETE /api/v1/knowledge-bases/:id/faq/entries
用途:批量删除条目。请求体:`{"ids":[int64]}`(`binding:"required,min=1"`)。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/knowledge-bases/kb-1/faq/entries -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"ids":[12,13]}'
```
### POST /api/v1/knowledge-bases/:id/faq/search
用途:FAQ 检索(只读语义,scoped key 用 `retrieve` 亦可调用)。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query_text` | string | 是(`binding:"required"`) | 查询 |
| `vector_threshold` | float64 | 否 | 向量阈值 |
| `match_count` | int | 否 | 默认 10,上限 200 |
| `first_priority_tag_ids` / `second_priority_tag_ids` | []int64 | 否 | 标签优先级过滤 |
| `only_recommended` | bool | 否 | 仅推荐条目 |
响应:200 `{"success":true,"data":[FAQEntry(含 match_type/score)]}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/search -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' -d '{"query_text":"退款"}'
```
### PUT /api/v1/knowledge-bases/:id/faq/import/last-result/display
用途:设置最近一次导入结果面板的显示状态。请求体:`{"display_status":"open|close"}`(`binding:"required,oneof=open close"`)。
响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/import/last-result/display \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"display_status":"close"}'
```
### GET /api/v1/faq/import/progress/:task_id
用途:查询 FAQ 导入/dry-run 进度(任务按空间隔离)。权限:Viewer+;API key `retrieve`/`ingest`/full。
响应:200 `{"success":true,"data":{status,progress,failed_entries,...}}`
```bash
curl $BASE/api/v1/faq/import/progress/task-1 -H "X-API-Key: $API_KEY"
```
## Wiki(/api/v1/knowledgebase/:kb_id/wiki)
注意此组前缀为 `/knowledgebase/:kb_id/wiki`(单数,无连字符)。Handler: `internal/handler/wiki_page.go`。本组响应多为**原始对象**(不带 `success` 包装)。
### GET /api/v1/knowledgebase/:kb_id/wiki/pages
用途:Wiki 页面列表。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `page_type` | string | 否 | 逗号分隔类型 |
| `status` | string | 否 | 页面状态 |
| `query` | string | 否 | 全文搜索 |
| `category_path` | string | 否 | `/` 分隔路径过滤 |
| `folder_id` | string | 否 | 精确目录过滤(空串=根) |
| `category_depth` | int | 否 | 目录深度 |
| `page` / `page_size` | int | 否 | 分页(默认 1/20) |
| `sort_by` / `sort_order` | string | 否 | 排序(默认 `updated_at` desc) |
响应:200 `WikiPageListResponse`
```bash
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/pages?page=1" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledgebase/:kb_id/wiki/pages
用途:创建页面。请求体(`types.WikiPage`):`slug`、`title`、`content`、`folder_id`、`page_type` 等(均可选,slug 缺省自动生成)。
响应:201 `WikiPage`
```bash
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/pages -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"title":"架构概览","content":"# 概览"}'
```
### PUT /api/v1/knowledgebase/:kb_id/wiki/move-page
用途:移动页面到目录。请求体:`{"slug":"<页面slug>","folder_id":"<目录ID|空=根>"}`(slug 必填)。
响应:200 `WikiPage`
```bash
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/move-page -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"slug":"overview","folder_id":"f-1"}'
```
### GET /api/v1/knowledgebase/:kb_id/wiki/pages/*slug
用途:获取页面(`*slug` 为通配路径)。
响应:200 `WikiPage`
```bash
curl $BASE/api/v1/knowledgebase/kb-1/wiki/pages/overview -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledgebase/:kb_id/wiki/pages/*slug
用途:更新页面(请求体同创建)。旧版本会先整份快照进 `wiki_page_revisions`,`version` 递增,`last_edit_source` 记为 `user`(Agent 工具写入时为 `agent`)。
响应:200 `WikiPage`
```bash
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/pages/overview -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"content":"# 更新后的概览"}'
```
### GET /api/v1/knowledgebase/:kb_id/wiki/revisions/*slug
用途:页面版本历史(migration `000075`)。权限:Viewer+ + KBAccessRead。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `version` | int | 否 | 传入时返回**该版本全文**(用于 diff),无效或 < 1 返回 400,找不到返回 404 |
| `limit` | int | 否 | 默认 50,上限 200;仅列表模式生效 |
| `offset` | int | 否 | 分页偏移 |
不带 `version` 时返回历史列表(版本号倒序、**不含正文**)加上页面当前版本号;每条含 `edit_source`(`pipeline` / `agent` / `user` / `revert`)、`editor_id`、`edited_at`。
历史保留是两级上限:软上限 50 版只裁剪 `pipeline` 与空来源的快照,硬上限 200 版对所有来源生效,因此人工编辑不会被管道刷掉。
```bash
# 历史列表
curl $BASE/api/v1/knowledgebase/kb-1/wiki/revisions/entity/acme-corp -H "Authorization: Bearer $TOKEN"
# 取第 3 版全文
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/revisions/entity/acme-corp?version=3" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledgebase/:kb_id/wiki/revert
用途:把页面回滚到某个历史版本。权限:KB owner 或 Admin+ + KBAccessWrite。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `slug` | string | 是 | 目标页面 |
| `version` | int | 是 | 目标版本号(≥ 1) |
回滚**不会把版本号退回去**:目标版本的内容会作为一个新版本写入,`last_edit_source` 记为 `revert`,所以回滚也能被回滚。回滚到当前版本返回 400(一般是前端历史列表过期)。
响应:200 `WikiPage`
```bash
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/revert -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"slug":"entity/acme-corp","version":3}'
```
### DELETE /api/v1/knowledgebase/:kb_id/wiki/pages/*slug
用途:删除页面。
响应:204 No Content
```bash
curl -X DELETE $BASE/api/v1/knowledgebase/kb-1/wiki/pages/overview -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledgebase/:kb_id/wiki/folders
用途:目录列表。查询参数:`parent_id`(空=根)、`page_types`(逗号分隔)。
响应:200 `WikiFolderListResponse`
```bash
curl $BASE/api/v1/knowledgebase/kb-1/wiki/folders -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledgebase/:kb_id/wiki/folders
用途:创建目录。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是 | 目录名 |
| `parent_id` | string | 否 | 父目录 |
响应:201 `WikiFolder`
```bash
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/folders -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"设计文档"}'
```
### PUT /api/v1/knowledgebase/:kb_id/wiki/folders/:folder_id
用途:重命名/移动目录。请求体:`name`、`parent_id`、`move_parent`(bool),均可选。
响应:200 `WikiFolder`
```bash
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/folders/f-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"架构设计"}'
```
### DELETE /api/v1/knowledgebase/:kb_id/wiki/folders/:folder_id
用途:删除目录。
响应:204 No Content
```bash
curl -X DELETE $BASE/api/v1/knowledgebase/kb-1/wiki/folders/f-1 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledgebase/:kb_id/wiki/index
用途:Wiki 索引页(按类型分组窗口)。查询参数:`types`(逗号分隔)、`limit`(1-200,默认 50)、`cursor`(游标)。
响应:200 `WikiIndexResponse`
```bash
curl $BASE/api/v1/knowledgebase/kb-1/wiki/index -H "Authorization: Bearer $TOKEN"
```
::: warning 已移除
`GET /api/v1/knowledgebase/:kb_id/wiki/log`(Wiki 变更日志)已随 migration `000077_remove_wiki_log` 一并下线,`wiki_log_entries` 表被删除。Wiki 变更现在统一投影到知识库活动流,改用 `GET /api/v1/knowledge-bases/:id/activity`。
:::
### GET /api/v1/knowledgebase/:kb_id/wiki/graph
用途:页面关系图。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `mode` | string | 否 | `overview`(默认)/ `ego` |
| `center` | string | 否 | ego 模式中心 slug(ego 时必填) |
| `depth` | int | 否 | 1-3,默认 1 |
| `types` | string | 否 | page_type 过滤 |
| `limit` | int | 否 | 默认 500,上限 2000 |
响应:200 `WikiGraphData`
```bash
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/graph?mode=overview" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledgebase/:kb_id/wiki/stats
用途:Wiki 统计。
响应:200 `WikiStats`
```bash
curl $BASE/api/v1/knowledgebase/kb-1/wiki/stats -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledgebase/:kb_id/wiki/search
用途:页面搜索。查询参数:`q`(必填)、`limit`(默认 10)。
响应:200 `{"pages":[WikiPage]}`
```bash
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/search?q=部署" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledgebase/:kb_id/wiki/rebuild-links
用途:重建页面互链。写权限。无请求体。
响应:200 `{"message":"Links rebuilt successfully"}`
```bash
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/rebuild-links -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledgebase/:kb_id/wiki/lint
用途:Wiki 一致性检查报告。
响应:200 `WikiLintReport`
```bash
curl $BASE/api/v1/knowledgebase/kb-1/wiki/lint -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledgebase/:kb_id/wiki/auto-fix
用途:自动修复 lint 问题。写权限。无请求体。
响应:200 `{"fixed":N,"message":"Auto-fixed N issues"}`
```bash
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/auto-fix -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledgebase/:kb_id/wiki/issues
用途:问题列表。查询参数:`slug`(按页面过滤)、`status`(`pending/ignored/resolved`)。
响应:200 `[WikiPageIssue]`
```bash
curl $BASE/api/v1/knowledgebase/kb-1/wiki/issues -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledgebase/:kb_id/wiki/issues/:issue_id/status
用途:更新问题状态。写权限。请求体:`{"status":"pending|ignored|resolved"}`(`binding:"required"`)。
响应:200 `{"message":"Issue status updated successfully"}`
```bash
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/issues/i-1/status -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"status":"resolved"}'
```
+470
View File
@@ -0,0 +1,470 @@
# API 参考:基础设施与数据源
路由注册:`internal/router/router.go` 的 `RegisterVectorStoreRoutes`、`RegisterStorageBackendRoutes`、`RegisterWebSearchRoutes`、`RegisterWebSearchProviderRoutes`、`RegisterDataSourceRoutes`。Handler:`internal/handler/vectorstore.go`、`internal/handler/storagebackend.go`、`internal/handler/web_search.go`、`internal/handler/web_search_provider.go`、`internal/handler/web_search_provider_credentials.go`、`internal/handler/datasource.go`、`internal/handler/datasource_credentials.go`。
统一约定:读 Viewer+,写/连接测试 Admin+(凭证探测外部系统)。API key capability:向量库 `manage_vector_stores`、存储后端 `manage_storage_backends`、Web 搜索 `manage_web_search`、数据源 `manage_datasources`(均可 full-access)。
## 向量存储(/api/v1/vector-stores)
### GET /api/v1/vector-stores/types
用途:可用引擎类型与配置 schema。权限:Viewer+。
响应:200 `{"success":true,"data":[类型定义]}`
```bash
curl $BASE/api/v1/vector-stores/types -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/vector-stores/test
用途:用原始配置测试连接(不落库)。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `engine_type` | string | 是(`binding:"required"`) | 引擎类型 |
| `connection_config` | object | 是(`binding:"required"`) | 连接配置 |
响应:200 `{"success":true|false,"version":"...","error":"..."}`
```bash
curl -X POST $BASE/api/v1/vector-stores/test -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"engine_type":"qdrant","connection_config":{"addr":"qdrant:6334"}}'
```
### POST /api/v1/vector-stores
用途:创建向量库配置。权限:Admin+。字段:`name`(必填)、`engine_type`(必填)、`connection_config`(必填)、`index_config`(可选)。
响应:201 `{"success":true,"data":{VectorStoreResponse}}`(`id,tenant_id,name,engine_type,connection_config,index_config,...`)
```bash
curl -X POST $BASE/api/v1/vector-stores -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"qdrant-main","engine_type":"qdrant","connection_config":{"addr":"qdrant:6334"}}'
```
### GET /api/v1/vector-stores
用途:向量库列表(环境变量注入的 `__env_*` store 在前)。权限:Viewer+。
响应:200 `{"success":true,"data":[VectorStoreResponse]}`
```bash
curl $BASE/api/v1/vector-stores -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/vector-stores/:id
用途:向量库详情(支持 `__env_*` ID)。权限:Viewer+。
响应:200 `{"success":true,"data":{VectorStoreResponse}}`
```bash
curl $BASE/api/v1/vector-stores/vs-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/vector-stores/:id
用途:更新(仅重命名;env store 不可改)。权限:Admin+。请求体:`{"name":"..."}`(`binding:"required"`)。
响应:200 `{"success":true,"data":{VectorStoreResponse}}`
```bash
curl -X PUT $BASE/api/v1/vector-stores/vs-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"qdrant-prod"}'
```
### DELETE /api/v1/vector-stores/:id
用途:删除(env store 不可删)。权限:Admin+。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/vector-stores/vs-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/vector-stores/:id/test
用途:测试已保存/env 向量库。权限:Admin+。
响应:200 `{"success":true|false,"version","error"}`
```bash
curl -X POST $BASE/api/v1/vector-stores/vs-1/test -H "Authorization: Bearer $TOKEN"
```
## 存储后端(/api/v1/storage-backends)
请求体(Create/Update/TestRaw 共用 `storageBackendRequest`):
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是(`binding:"required"`) | 名称 |
| `provider` | string | 是(`binding:"required"`) | 提供方(minio/cos/tos/s3/oss/ks3/obs…) |
| `config` | object | 否 | 提供方配置(响应中凭证掩码) |
| `status` | string | 否 | 状态 |
### GET /api/v1/storage-backends/types
用途:允许的存储类型。权限:Viewer+。响应:200 `{"success":true,"data":[...]}`
```bash
curl $BASE/api/v1/storage-backends/types -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/storage-backends/test
用途:原始配置连接测试。权限:Admin+。响应:200 `{"success":bool,"error"}`
```bash
curl -X POST $BASE/api/v1/storage-backends/test -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"t","provider":"minio","config":{"endpoint":"minio:9000"}}'
```
### POST /api/v1/storage-backends
用途:创建存储后端。权限:Admin+。响应:201 `{"success":true,"data":{StorageBackend}}`
```bash
curl -X POST $BASE/api/v1/storage-backends -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"minio-main","provider":"minio","config":{"endpoint":"minio:9000"}}'
```
### GET /api/v1/storage-backends
用途:列表(含 `default_storage_backend_id`)。权限:Viewer+。响应:200 `{"success":true,"data":[...],"default_storage_backend_id":"..."}`
```bash
curl $BASE/api/v1/storage-backends -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/storage-backends/:id
用途:详情(凭证掩码)。权限:Viewer+。响应:200 `{"success":true,"data":{StorageBackend}}`
```bash
curl $BASE/api/v1/storage-backends/sb-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/storage-backends/:id
用途:更新。权限:Admin+。响应:200 `{"success":true,"data":{StorageBackend}}`
```bash
curl -X PUT $BASE/api/v1/storage-backends/sb-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"minio-prod","provider":"minio"}'
```
### DELETE /api/v1/storage-backends/:id
用途:删除。权限:Admin+。响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/storage-backends/sb-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/storage-backends/:id/test
用途:测试已保存后端。权限:Admin+。响应:200 `{"success":bool,"error"}`
```bash
curl -X POST $BASE/api/v1/storage-backends/sb-1/test -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/storage-backends/:id/default
用途:设为默认后端。权限:Admin+。响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/storage-backends/sb-1/default -H "Authorization: Bearer $TOKEN"
```
## Web 搜索(/api/v1/web-search 与 /api/v1/web-search-providers)
### GET /api/v1/web-search/providers
用途:内置搜索提供方目录(只读)。权限:Viewer+,仅 JWT(未声明 API key 策略)。Handler: `internal/handler/web_search.go`
响应:200 `{"success":true,"data":[...]}`
```bash
curl $BASE/api/v1/web-search/providers -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/web-search-providers/types
用途:提供方类型与参数 schema。权限:Viewer+。Handler: `internal/handler/web_search_provider.go`
响应:200 `{"success":true,"data":[...]}`
```bash
curl $BASE/api/v1/web-search-providers/types -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/web-search-providers/test
用途:原始凭证测试(不落库)。权限:Admin+。请求体:`provider`(`binding:"required"`)、`parameters`(可选)。
响应:200 `{"success":bool,"error"}`
```bash
curl -X POST $BASE/api/v1/web-search-providers/test -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"provider":"tavily","parameters":{"api_key":"tvly-..."}}'
```
### POST /api/v1/web-search-providers
用途:创建提供方配置。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是(`binding:"required"`) | 名称 |
| `provider` | string | 是(`binding:"required"`) | 类型(bing/tavily/google…) |
| `description` | string | 否 | 描述 |
| `parameters` | object | 否 | 参数(api_key 建议走 credentials 子资源) |
| `is_default` | bool | 否 | 默认提供方 |
响应:201 `{"success":true,"data":{WebSearchProviderResponse}}`
```bash
curl -X POST $BASE/api/v1/web-search-providers -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"tavily-main","provider":"tavily"}'
```
### GET /api/v1/web-search-providers
用途:提供方列表。权限:Viewer+。响应:200 `{"success":true,"data":[...]}`
```bash
curl $BASE/api/v1/web-search-providers -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/web-search-providers/:id
用途:详情。权限:Viewer+。响应:200 `{"success":true,"data":{...}}`
```bash
curl $BASE/api/v1/web-search-providers/wsp-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/web-search-providers/:id
用途:更新(空字段保留原值;APIKey 保留)。权限:Admin+。请求体:`name/description/parameters/is_default`(均可选)。
响应:200 `{"success":true,"data":{...}}`
```bash
curl -X PUT $BASE/api/v1/web-search-providers/wsp-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"is_default":true}'
```
### DELETE /api/v1/web-search-providers/:id
用途:删除。权限:Admin+。响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/web-search-providers/wsp-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/web-search-providers/:id/credentials
用途:设置 API key(`{"api_key":"..."}`,省略时返回状态)。权限:Admin+。Handler: `internal/handler/web_search_provider_credentials.go`
响应:200 `{"success":true,"data":{"fields":{"api_key":{"configured":bool}}}}`
```bash
curl -X PUT $BASE/api/v1/web-search-providers/wsp-1/credentials -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"api_key":"tvly-..."}'
```
### DELETE /api/v1/web-search-providers/:id/credentials/:field
用途:删除凭证字段(`field` 仅 `api_key`)。权限:Admin+。响应:204。
```bash
curl -X DELETE $BASE/api/v1/web-search-providers/wsp-1/credentials/api_key -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/web-search-providers/:id/test
用途:测试已保存提供方。权限:Admin+。响应:200 `{"success":bool,"error"}`
```bash
curl -X POST $BASE/api/v1/web-search-providers/wsp-1/test -H "Authorization: Bearer $TOKEN"
```
## 数据源(/api/v1/datasource)
外部内容连接器(Feishu/Notion/语雀等),同步任务会写入 KB。Handler: `internal/handler/datasource.go`。本组多数响应为原始对象/数组(无 `success` 包装)。
### GET /api/v1/datasource/types
用途:可用连接器目录。权限:Viewer+。
响应:200 `[{type,name,description,icon,priority,auth_type,capabilities}]`
```bash
curl $BASE/api/v1/datasource/types -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/datasource/validate-credentials
用途:校验原始凭证(“测试连接”按钮,不落库)。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `type` | string | 是(`binding:"required"`) | 连接器类型 |
| `credentials` | map | 是(`binding:"required"`) | 凭证 |
响应:200 `{"status":"connected"}`;失败 400 `{"error":"..."}`
```bash
curl -X POST $BASE/api/v1/datasource/validate-credentials -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"type":"notion","credentials":{"token":"secret"}}'
```
### POST /api/v1/datasource
用途:创建数据源。权限:Admin+。请求体(`types.DataSource`):
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `knowledge_base_id` | string | 是 | 目标 KB(须归属本空间) |
| `name` | string | 是 | 名称 |
| `type` | string | 是 | 连接器类型 |
| `config` | object | 是 | 凭证(加密存储)+资源选择+设置 |
| `sync_schedule` | string | 否 | cron 表达式 |
| `sync_mode` | string | 否 | `incremental`(默认)/`full` |
| `conflict_strategy` | string | 否 | `overwrite`(默认)/`skip` |
| `sync_deletions` | bool | 否 | 默认 true |
| `sync_log_retention_days` | int | 否 | 默认 30 |
响应:201 `DataSourceResponse`(凭证剥离,见 `internal/handler/dto/datasource.go`)。
```bash
curl -X POST $BASE/api/v1/datasource -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"knowledge_base_id":"kb-1","name":"notion 同步","type":"notion","config":{}}'
```
### GET /api/v1/datasource
用途:数据源列表。权限:Viewer+。查询参数:`kb_id`(必填)。
响应:200 `[DataSourceResponse]`
```bash
curl "$BASE/api/v1/datasource?kb_id=kb-1" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/datasource/:id
用途:详情。权限:Viewer+。响应:200 `DataSourceResponse`;404 `{"error":"data source not found"}`
```bash
curl $BASE/api/v1/datasource/ds-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/datasource/:id
用途:更新(`id/tenant_id/knowledge_base_id` 锁定为原值)。权限:Admin+。请求体同创建。
响应:200 `DataSourceResponse`
```bash
curl -X PUT $BASE/api/v1/datasource/ds-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"notion 同步 v2","type":"notion","knowledge_base_id":"kb-1","config":{}}'
```
### DELETE /api/v1/datasource/:id
用途:删除。权限:Admin+。响应:204。
```bash
curl -X DELETE $BASE/api/v1/datasource/ds-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/datasource/:id/credentials
用途:整体替换凭证(数据源凭证为“单一逻辑字段 `credentials`”的原子 map)。权限:Admin+。请求体:`{"credentials":{...}}`(非空 map 必填)。Handler: `internal/handler/datasource_credentials.go`
响应:200 `{"success":true,"data":{"fields":{"credentials":{"configured":bool}}}}`
```bash
curl -X PUT $BASE/api/v1/datasource/ds-1/credentials -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"credentials":{"token":"secret"}}'
```
### DELETE /api/v1/datasource/:id/credentials/:field
用途:清空凭证(`field` 必须为 `credentials`)。权限:Admin+。响应:204。
```bash
curl -X DELETE $BASE/api/v1/datasource/ds-1/credentials/credentials -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/datasource/:id/validate
用途:校验已保存数据源连接。权限:Admin+。响应:200 `{"status":"connected"}`
```bash
curl -X POST $BASE/api/v1/datasource/ds-1/validate -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/datasource/:id/resources
用途:浏览外部资源树(懒加载)。权限:Admin+。查询参数:`parent_id`(可选,空=顶层)。
响应:200 `[{external_id,name,type,description,url,modified_at,parent_id,has_children,metadata}]`
```bash
curl "$BASE/api/v1/datasource/ds-1/resources?parent_id=" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/datasource/:id/resource-ancestors
用途:解析资源祖先链(选择器展开)。权限:Admin+。请求体:`{"resource_ids":["..."]}`(必填)。
响应:200 `{"ancestors":[...]}`
```bash
curl -X POST $BASE/api/v1/datasource/ds-1/resource-ancestors -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"resource_ids":["page-1"]}'
```
### POST /api/v1/datasource/:id/sync
用途:手动触发同步。权限:Admin+。响应:200 `SyncLog`(`id,status,started_at,items_total,items_created,items_updated,items_deleted,items_failed,...`)
```bash
curl -X POST $BASE/api/v1/datasource/ds-1/sync -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/datasource/:id/pause 与 POST /api/v1/datasource/:id/resume
用途:暂停 / 恢复定时同步。权限:Admin+。
响应:200 `{"status":"paused"}` / `{"status":"active"}`
```bash
curl -X POST $BASE/api/v1/datasource/ds-1/pause -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/datasource/:id/logs
用途:同步日志列表。权限:Viewer+。查询参数:`limit`(默认 10,上限 100)、`offset`(默认 0)。
响应:200 `[SyncLog]`
```bash
curl "$BASE/api/v1/datasource/ds-1/logs?limit=10" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/datasource/logs/:log_id
用途:单条同步日志。权限:Viewer+。响应:200 `SyncLog`;404 `{"error":"sync log not found"}`
```bash
curl $BASE/api/v1/datasource/logs/log-1 -H "Authorization: Bearer $TOKEN"
```
+566
View File
@@ -0,0 +1,566 @@
# API 参考:知识库与知识
路由注册:`internal/router/routes_knowledge.go` 的 `RegisterKnowledgeBaseRoutes`、`RegisterKnowledgeRoutes`。Handler:`internal/handler/knowledgebase.go`、`internal/handler/knowledge.go`。
权限速记:读路由为 Viewer+ 且需对 KB 有 read 权限(自有/组织共享/共享 Agent 可见);写路由为“KB 创建者 OR Admin+”且需 write 权限。API key:读需 `retrieve`,内容写需 `ingest`,KB 生命周期需 `manage_kbs`(均可被 full-access 覆盖),并受 KB 白名单约束。
分块、标签与分块预览接口(`/chunks`、`/knowledge-bases/:id/tags`、`/chunker/preview`)在[分块与标签](./02-api-chunks.md)。
## 知识库(/api/v1/knowledge-bases)
### POST /api/v1/knowledge-bases
用途:创建知识库。权限:Contributor+;API key `manage_kbs`/full。Handler: `internal/handler/knowledgebase.go`
请求体(`types.KnowledgeBase`):
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是 | 名称 |
| `description` | string | 否 | 描述 |
| `type` | string | 否 | `document`(默认)/`faq`/`wiki` |
| `embedding_model_id` | string | 否 | Embedding 模型 ID |
| `chunking_config` | object | 否 | 分块配置(chunk_size/overlap/separators/strategy…) |
| `image_processing_config` | object | 否 | 图像处理(多模态)配置 |
| `storage_provider_config` | object | 否 | 存储配置 |
| `vector_store_id` | string | 否 | 向量库绑定(非法返回 code 2200/2201) |
| `faq_config` / `wiki_config` / `extract_config` / `indexing_strategy` | object | 否 | 类型相关配置 |
响应:201 `{"success":true,"data":{KnowledgeBase}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"产品文档","type":"document"}'
```
### GET /api/v1/knowledge-bases
用途:知识库列表。权限:Viewer+;API key `retrieve`/full。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `agent_id` | string | 否 | 过滤某共享 Agent 可见的 KB |
| `agent_source_tenant_id` | uint64 | 否 | 同名 Agent 被多个空间共享时,指定来源空间;取值会与共享关系校验,非法值直接 400 |
| `creator` | string | 否 | `mine` / `others` |
响应:200 `{"success":true,"data":[KnowledgeBase],"total","page","page_size"}`
```bash
curl $BASE/api/v1/knowledge-bases -H "X-API-Key: $API_KEY"
```
### GET /api/v1/knowledge-bases/:id
用途:知识库详情(共享 KB 携带 `my_permission`)。权限:Viewer+,KB read。查询参数:`agent_id`(可选)。
响应:200 `{"success":true,"data":{KnowledgeBase}}`
```bash
curl $BASE/api/v1/knowledge-bases/kb-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledge-bases/:id
用途:更新知识库。权限:创建者 OR Admin+,KB write;API key `manage_kbs`/full。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是(`binding:"required"`) | 名称 |
| `description` | string | 否 | 描述 |
| `config` | object | 否 | 局部配置更新(分块/图像/wiki/索引策略) |
响应:200 `{"success":true,"data":{KnowledgeBase}}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"产品文档 v2"}'
```
### DELETE /api/v1/knowledge-bases/:id
用途:删除知识库(锁定为属主空间 + Admin;共享 editor 不可删)。权限:创建者 OR Admin+,KB write;API key `manage_kbs`/full。
响应:200 `{"success":true,"message":"Knowledge base deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/knowledge-bases/kb-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledge-bases/:id/pin
用途:置顶/取消置顶(按用户维度存储)。权限:Viewer+,KB read。无请求体。
响应:200 `{"success":true,"data":{KnowledgeBase(is_pinned 已切换)}}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/pin -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/knowledge-bases/:id/hybrid-search(兼容 GET)
用途:KB 内混合检索(向量+关键词)。权限:Viewer+,KB read;API key `retrieve`/full。GET 携带 JSON body 仅为向后兼容(#1727),推荐 POST。
查询参数:`resource_urls=handle|public`(`public` 把结果 `content` / `image_info` 里的 `resource://` 换成可加载直链,详见 [API 总览](./01-api-overview.md))。
请求体(`types.SearchParams`):
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query_text` | string | 条件必填 | 查询文本(除非提供 `query_embedding`) |
| `query_embedding` | []float32 | 否 | 预计算向量 |
| `vector_threshold` / `keyword_threshold` | float64 | 否 | 匹配阈值 |
| `match_count` | int | 否 | 返回条数上限 |
| `disable_keywords_match` / `disable_vector_match` | bool | 否 | 关闭某一路召回 |
| `knowledge_ids` | []string | 否 | 限定知识条目 |
| `tag_ids` | []string | 否 | 标签过滤(OR) |
| `only_recommended` | bool | 否 | FAQ 仅推荐条目 |
| `skip_context_enrichment` | bool | 否 | 跳过父块/上下文补齐 |
响应:200 `{"success":true,"data":[SearchResult]}`
```bash
curl -X POST "$BASE/api/v1/knowledge-bases/kb-1/hybrid-search?resource_urls=public" -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' -d '{"query_text":"退款流程","match_count":5}'
```
### POST /api/v1/knowledge-bases/copy
用途:跨 KB 拷贝内容(异步任务)。权限:Contributor+;API key `manage_kbs`/full(源/目标 KB 白名单在 handler 校验)。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `source_id` | string | 是(`binding:"required"`) | 源 KB |
| `target_id` | string | 否 | 目标 KB(为空则自动创建) |
| `task_id` | string | 否 | 自定义任务 ID |
响应:200 `{"success":true,"data":{"task_id","source_id","target_id","message"}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/copy -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"source_id":"kb-1"}'
```
### POST /api/v1/knowledge-bases/:id/duplicate
用途:创建 KB 副本(仅复制设置,不复制内容/索引/分享)。权限:Contributor+,源 KB read;API key `manage_kbs`/full。无请求体。
响应:201 `{"success":true,"data":{"source_id","target_id","message","knowledge_base":{...}}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/duplicate -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge-bases/copy/progress/:task_id
用途:查询拷贝进度(任务按空间隔离)。权限:Viewer+;API key `retrieve`/`manage_kbs`/full。
响应:200 `{"success":true,"data":{status,progress,message,...}}`
```bash
curl $BASE/api/v1/knowledge-bases/copy/progress/task-1 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge-bases/:id/move-targets
用途:列出可作为移动目标的 KB(同类型/同 embedding)。权限:Viewer+,KB read。
响应:200 `{"success":true,"data":[KnowledgeBase]}`
```bash
curl $BASE/api/v1/knowledge-bases/kb-1/move-targets -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge-bases/:id/files
用途:KB 范围文件代理(渲染共享 KB 内容中的图片;上下文 tenant 已被重写为 KB 属主)。权限:Viewer+,KB read;KB 受限 key 拒绝,全空间 `retrieve`/full key 放行。注册于 `serveKBScopedFiles`(`internal/router/router.go`)。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `file_path` | string | 是 | `provider://...` 存储路径(禁止 `..`) |
响应:200 文件流(`Content-Type` 按扩展名推断;`Cache-Control: private`)。
```bash
curl "$BASE/api/v1/knowledge-bases/kb-1/files?file_path=local://1/exports/chart.png" \
-H "Authorization: Bearer $TOKEN" -o chart.png
```
## 知识(KB 内容,/api/v1/knowledge-bases/:id/knowledge 与 /api/v1/knowledge)
### POST /api/v1/knowledge-bases/:id/knowledge/file
用途:上传文件创建知识。权限:KB 创建者 OR Admin+,KB write;API key `ingest`/full。Handler: `internal/handler/knowledge.go`
multipart/form-data 字段:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `file` | file | 是 | 上传文件 |
| `fileName` | string | 否 | 覆盖显示名 |
| `metadata` | JSON 字符串 | 否 | 自定义元数据 |
| `enable_multimodel` | bool | 否 | 多模态处理开关 |
| `tag_ids` | string | 否 | 逗号分隔标签 ID |
| `channel` | string | 否 | 摄取渠道 |
| `process_config` | JSON 字符串 | 否 | 解析配置覆盖(KnowledgeProcessOverrides) |
响应:200 `{"success":true,"data":{Knowledge}}`;重复文件返回 409 且 `data` 为已存在的 Knowledge。
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/knowledge/file \
-H "X-API-Key: $API_KEY" -F 'file=@./manual.pdf' -F 'enable_multimodel=true'
```
### POST /api/v1/knowledge-bases/:id/knowledge/url
用途:从 URL 抓取创建知识。权限/API key 同上。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `url` | string | 是(`binding:"required"`) | 抓取地址 |
| `file_name` / `file_type` / `title` | string | 否 | 覆盖信息 |
| `enable_multimodel` | *bool | 否 | 多模态开关 |
| `tag_ids` | []string | 否 | 标签 |
| `channel` | string | 否 | 渠道 |
| `process_config` | object | 否 | 解析覆盖 |
响应:201 `{"success":true,"data":{Knowledge}}`;重复 URL 返回 409。
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/knowledge/url -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' -d '{"url":"https://example.com/doc"}'
```
### POST /api/v1/knowledge-bases/:id/knowledge/manual
用途:创建手工(Markdown)知识。权限/API key 同上。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `title` | string | 否 | 标题 |
| `content` | string | 否 | Markdown 内容 |
| `status` | string | 否 | `draft` / `publish` |
| `tag_ids` | []string | 否 | 标签 |
| `channel` | string | 否 | 渠道 |
| `process_config` | object | 否 | 解析覆盖 |
响应:200 `{"success":true,"data":{Knowledge}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/knowledge/manual -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"title":"FAQ 汇总","content":"# 内容","status":"publish"}'
```
### GET /api/v1/knowledge-bases/:id/knowledge
用途:KB 下知识列表。权限:Viewer+,KB read;API key `retrieve`/full。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `page` / `page_size` | int | 否 | 分页(默认 1/20) |
| `tag_ids` | string | 否 | 逗号分隔标签(OR) |
| `keyword` | string | 否 | 关键字 |
| `file_type` | string | 否 | 文件类型过滤 |
| `parse_status` | string | 否 | `pending/processing/completed/failed` |
| `source` | string | 否 | 渠道或 `manual`/`url` |
| `start_time` / `end_time` | string | 否 | RFC3339,按 `updated_at` 过滤 |
响应:200 `{"success":true,"data":[Knowledge],"total","page","page_size"}`
```bash
curl "$BASE/api/v1/knowledge-bases/kb-1/knowledge?page=1&parse_status=completed" -H "X-API-Key: $API_KEY"
```
### GET /api/v1/knowledge-bases/:id/knowledge/folders
用途:获取知识库的文件夹目录树。整目录上传时目录结构会被保留(migration `000079` 起存在 `knowledges.folder_path` 列,早期把路径塞在 `file_name` 里的数据已回填)。权限:Viewer+ + KBAccessRead。
响应:200 `{"success":true,"data":[{FolderNode}]}`
```bash
curl $BASE/api/v1/knowledge-bases/kb-1/knowledge/folders -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledge-bases/:id/knowledge/folders
用途:重命名或移动文件夹,连同其所有子目录一起改路径。目标路径已存在时两个文件夹合并;不允许移动到自己的子目录下。权限:KB owner 或 Admin+ + KBAccessWrite。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `from` | string | 是 | 原路径 |
| `to` | string | 是 | 新路径 |
响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/knowledge/folders -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"from":"设计文档/旧版","to":"归档/设计文档"}'
```
### DELETE /api/v1/knowledge-bases/:id/knowledge
用途:清空 KB 全部内容(破坏性)。权限:Admin+,KB write;API key 仅 full-access。
响应:200 `{"success":true,"message":"Knowledge base contents clear task submitted","data":{"deleted_count":N}}`
```bash
curl -X DELETE $BASE/api/v1/knowledge-bases/kb-1/knowledge -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge/batch
用途:按 ID 批量获取知识(跨 KB,handler 自行校验访问)。权限:Viewer+;API key `retrieve`/full。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `ids` | []string | 是 | 知识 ID(可重复传参或逗号分隔) |
| `kb_id` | string | 否 | 限定 KB |
| `agent_id` | string | 否 | 共享 Agent 范围 |
| `agent_source_tenant_id` | uint64 | 否 | 共享 Agent 的来源空间选择器,与共享关系校验 |
响应:200 `{"success":true,"data":[Knowledge]}`
```bash
curl "$BASE/api/v1/knowledge/batch?ids=k-1&ids=k-2" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge/:id
用途:知识详情。权限:Viewer+,父 KB read。
响应:200 `{"success":true,"data":{Knowledge}}`
```bash
curl $BASE/api/v1/knowledge/k-1 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge/:id/stages 与 GET /api/v1/knowledge/:id/spans
用途:解析阶段/trace(两条路径同一 handler `GetKnowledgeSpans`)。权限:Viewer+,父 KB read。查询参数:`attempt`(int,0=最新一次)。
响应:200 `{"success":true,"data":{"knowledge_id","attempt","latest_attempt","parse_status","current_stage","trace":{...},"last_error":{...}}}`
```bash
curl $BASE/api/v1/knowledge/k-1/spans -H "Authorization: Bearer $TOKEN"
```
### DELETE /api/v1/knowledge/:id
用途:删除知识(异步)。权限:KB 创建者 OR Admin+,KB write;API key `ingest`/full。
响应:200 `{"success":true,"message":"Delete task submitted","data":{"task_id"}}`
```bash
curl -X DELETE $BASE/api/v1/knowledge/k-1 -H "X-API-Key: $API_KEY"
```
### PUT /api/v1/knowledge/:id
用途:更新知识元信息。权限同上。请求体(`types.Knowledge` 子集):`title`、`description`、`tags`、`custom_metadata`(均可选)。
`custom_metadata` 是用户自填的描述性元数据(与系统内部使用的 `metadata` 分开存放,migration `000078`),校验规则见 `internal/application/service/knowledge.go`:
| 约束 | 值 |
| --- | --- |
| 字段数 | ≤ 20 |
| 键长度 | 1-64 字符,不能为空白 |
| 值类型 | string / number / boolean / null |
| 值长度 | ≤ 1000 字符 |
整体覆盖式更新(传入的对象替换原有对象)。元数据发生变化且该文档已有摘要时,会自动入队一次摘要刷新(`summary_status` 转为 `pending`)。元数据文本会参与摘要生成与文档级模型上下文(`Knowledge.CustomMetadataText()`)。
响应:200 `{"success":true,"message":"Knowledge updated successfully","data":{Knowledge}}`
```bash
curl -X PUT $BASE/api/v1/knowledge/k-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"新标题","custom_metadata":{"部门":"研发中心","密级":"内部","版本":3}}'
```
### POST /api/v1/knowledge/:id/regenerate-summary
用途:在分块内容或自定义元数据被编辑后,重新生成该文档的摘要。权限:KB owner 或 Admin+,且对父 KB 有 write 权限。
行为分两种:文档此前没有摘要(`summary_status` 为空或 `none`)时同步触发一次生成;已有摘要时改为入队刷新任务,`summary_status` 转为 `pending`,由 `knowledge_summary_refresh.go` 异步执行。
响应:200 `{"success":true,"data":{Knowledge}}`
```bash
curl -X POST $BASE/api/v1/knowledge/k-1/regenerate-summary -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledge/manual/:id
用途:更新手工知识内容(`ManualKnowledgePayload` 子集:`title/content/status/...`)。权限同上。
响应:200 `{"success":true,"data":{Knowledge}}`
```bash
curl -X PUT $BASE/api/v1/knowledge/manual/k-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"content":"# 更新内容","status":"publish"}'
```
### POST /api/v1/knowledge/:id/reparse
用途:重新解析知识。权限同上。请求体(可选):`{"process_config":{...}}`。
响应:200 `{"success":true,"message":"Reparse task submitted","data":{Knowledge}}`
```bash
curl -X POST $BASE/api/v1/knowledge/k-1/reparse -H "X-API-Key: $API_KEY"
```
### POST /api/v1/knowledge/:id/cancel-parse
用途:取消解析。权限同上。无请求体。
响应:200 `{"success":true,"message":"Knowledge parse cancelled","data":{Knowledge}}`
```bash
curl -X POST $BASE/api/v1/knowledge/k-1/cancel-parse -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge/:id/download
用途:下载原始源文件(比预览更严格:Contributor+ 且 KB write;组织共享 Viewer 不可下载源文件)。API key `retrieve`/full。
响应:200 二进制流(`application/octet-stream`)。
```bash
curl -OJ $BASE/api/v1/knowledge/k-1/download -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge/:id/preview
用途:预览解析后的文件内容。权限:Viewer+,KB read。
响应:200 预览流(文本/HTML)。
```bash
curl $BASE/api/v1/knowledge/k-1/preview -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledge/image/:id/:chunk_id
用途:更新某分块的图片信息(caption/OCR 等)。权限:KB 创建者 OR Admin+,KB write。路径参数:`id` 知识 ID、`chunk_id` 分块 ID。请求体为图片信息 JSON。
响应:200 `{"success":true,...}`
```bash
curl -X PUT $BASE/api/v1/knowledge/image/k-1/c-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"caption":"架构图"}'
```
### GET /api/v1/knowledge/search
用途:跨 KB 文件搜索(会话 @文件 选择器)。权限:Viewer+;API key `retrieve`/full。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `q` | string | 否 | 关键字(为空且 `recent=true` 返回最近文件) |
| `file_type` / `file_types` | string | 否 | 类型过滤(后者逗号分隔) |
| `page` / `page_size` | int | 否 | 分页 |
| `recent` | bool | 否 | 最近文件模式 |
| `agent_id` | string | 否 | 共享 Agent 范围 |
| `agent_source_tenant_id` | uint64 | 否 | 共享 Agent 的来源空间选择器,与共享关系校验 |
响应:200 `{"success":true,"data":[Knowledge]}`
```bash
curl "$BASE/api/v1/knowledge/search?q=报告&recent=false" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge/move/progress/:task_id
用途:查询移动任务进度。权限:Viewer+;API key `retrieve`/full。
响应:200 `{"success":true,"data":{MoveProgress}}`
```bash
curl $BASE/api/v1/knowledge/move/progress/task-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledge/tags
用途:批量更新知识标签。权限:Contributor+;API key `ingest`/full(KB 白名单在 handler 校验)。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `updates` | map[string][]string | 是(`binding:"required,min=1"`) | knowledge_id → tag_ids |
| `kb_id` | string | 否 | 限定 KB |
响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/knowledge/tags -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"updates":{"k-1":["t-1"]},"kb_id":"kb-1"}'
```
### POST /api/v1/knowledge/batch-reparse
用途:批量重解析。权限:Contributor+;API key `ingest`/full。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `kb_id` | string | 是(`binding:"required"`) | KB ID |
| `ids` | []string | 是(`binding:"required"`) | 知识 ID 列表 |
| `process_config` | object | 否 | 解析覆盖 |
响应:200 `{"success":true,"message":"Batch reparse task submitted","data":{"task_id"}}`
```bash
curl -X POST $BASE/api/v1/knowledge/batch-reparse -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' -d '{"kb_id":"kb-1","ids":["k-1","k-2"]}'
```
### POST /api/v1/knowledge/batch-delete
用途:批量删除(≤200 条)。权限:Contributor+;API key `ingest`/full。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `kb_id` | string | 是(`binding:"required"`) | KB ID |
| `ids` | []string | 是(`binding:"required"`) | 知识 ID 列表(≤200) |
响应:200 `{"success":true,"message":"Batch delete task submitted","data":{"task_id","deleted_count"}}`
```bash
curl -X POST $BASE/api/v1/knowledge/batch-delete -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"kb_id":"kb-1","ids":["k-1"]}'
```
### POST /api/v1/knowledge/folder
用途:把若干文档归类到指定文件夹(只改归类,不动知识库归属,也不重新解析)。权限:Contributor+ / API key `ingest`。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `kb_id` | string | 是 | 知识库 ID |
| `knowledge_ids` | []string | 是 | 待移动的文档 |
| `folder_path` | string | 否 | 目标文件夹;空字符串表示移回知识库根目录 |
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/knowledge/folder -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"kb_id":"kb-1","knowledge_ids":["k-1","k-2"],"folder_path":"设计文档"}'
```
### POST /api/v1/knowledge/move
用途:跨 KB 移动知识(异步)。权限:Contributor+;API key `ingest`/full(源+目标 KB 均需在白名单)。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `knowledge_ids` | []string | 是(`binding:"required,min=1"`) | 待移动知识 |
| `source_kb_id` | string | 是(`binding:"required"`) | 源 KB |
| `target_kb_id` | string | 是(`binding:"required"`) | 目标 KB |
| `mode` | string | 是(`binding:"required,oneof=reuse_vectors reparse"`) | 复用向量或重解析 |
响应:200 `{"success":true,"data":{"task_id","source_kb_id","target_kb_id","knowledge_count","message"}}`
```bash
curl -X POST $BASE/api/v1/knowledge/move -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"knowledge_ids":["k-1"],"source_kb_id":"kb-1","target_kb_id":"kb-2","mode":"reuse_vectors"}'
```
+380
View File
@@ -0,0 +1,380 @@
# API 参考:模型与初始化
路由注册:`internal/router/router.go` 的 `RegisterModelRoutes`、`RegisterInitializationRoutes`、`RegisterEvaluationRoutes`、`RegisterWeKnoraCloudRoutes`。Handler:`internal/handler/model.go`、`internal/handler/model_credentials.go`、`internal/handler/initialization.go`、`internal/handler/evaluation.go`、`internal/handler/weknoracloud.go`。
系统信息与系统管理(`/system`、`/system/admin`)接口见[系统与平台管理](./02-api-system.md)。
## 模型(/api/v1/models)
API key:`manage_models` 或 full-access。
### GET /api/v1/models/providers
用途:模型厂商列表。权限:Viewer+。查询参数:`model_type`(可选:`chat/embedding/rerank/vllm/asr`)。Handler: `internal/handler/model.go`
响应:200 `{"success":true,"data":[{value,label,description,defaultUrls,modelTypes}]}`
```bash
curl "$BASE/api/v1/models/providers?model_type=chat" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/models
用途:创建模型。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是(`binding:"required"`) | 模型名 |
| `display_name` | string | 否 | 显示名 |
| `type` | string | 是(`binding:"required"`) | 模型类型 |
| `source` | string | 是(`binding:"required"`) | 来源(local/remote…) |
| `description` | string | 否 | 描述 |
| `parameters` | object | 是(`binding:"required"`) | 连接参数(base_url 等;密钥经 credentials 子资源管理) |
响应:201 `{"success":true,"data":{ModelResponse}}`(`id,name,type,source,parameters,is_default,is_builtin,status,credentials,...`)
```bash
curl -X POST $BASE/api/v1/models -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"gpt-4o-mini","type":"chat","source":"remote","parameters":{"base_url":"https://api.openai.com/v1"}}'
```
### GET /api/v1/models
用途:模型列表。权限:Viewer+。
响应:200 `{"success":true,"data":[ModelResponse]}`
```bash
curl $BASE/api/v1/models -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/models/:id
用途:模型详情。权限:Viewer+。
响应:200 `{"success":true,"data":{ModelResponse}}`
```bash
curl $BASE/api/v1/models/m-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/models/:id/debug
用途:调试已保存模型(发起真实上游调用,产生费用)。权限:Admin+。form-data 字段:`input`(≤64KB)、`options`(JSON 编码调试选项)、`documents`(JSON 数组,≤100 条)、`file`(可选)。
响应:200 `{"success":true,"data":{"ok",elapsed_ms,request,raw_response,observations,error}}`
```bash
curl -X POST $BASE/api/v1/models/m-1/debug -H "Authorization: Bearer $TOKEN" -F 'input=你好'
```
### PUT /api/v1/models/:id
用途:更新模型(内置模型由服务层限定 SystemAdmin)。权限:Admin+ 或 SystemAdmin(`AdminOrSystemAdmin`)。请求体:`name`、`display_name`(指针)、`description`、`parameters`(保留已存密钥)、`source`、`type`(均可选)。
响应:200 `{"success":true,"data":{ModelResponse}}`
```bash
curl -X PUT $BASE/api/v1/models/m-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"display_name":"GPT-4o mini"}'
```
### DELETE /api/v1/models/:id
用途:删除模型。权限:Admin+。
响应:200 `{"success":true,"message":"Model deleted"}`
仍被当前空间的知识库、智能体或长期记忆引用时,响应为 HTTP 400;兼容 message 保留,同时 `error.code=2300`,`error.details` 给出具体对象和引用位置:
```json
{
"success": false,
"error": {
"code": 2300,
"message": "model is used by 2 knowledge base(s); reconfigure or remove those references before deleting",
"details": {
"knowledge_bases": [
{"id": "kb-1", "name": "Product docs", "bindings": ["vlm_model"]},
{"id": "kb-2", "name": "Engineering", "bindings": ["vlm_model"]}
],
"agents": [],
"long_term_memory": {"bindings": []},
"knowledge_base_total": 2,
"agent_total": 0
}
}
}
```
知识库绑定值:`embedding_model`、`summary_model`、`image_processing_model`、`vlm_model`、`asr_model`、`wiki_synthesis_model`;智能体绑定值:`chat_model`、`rerank_model`、`vlm_model`、`asr_model`、`query_understand_model`、`follow_up_model`;长期记忆绑定值:`embedding_model`、`extract_model`。详情包含对象 `id`、`name`、合并后的 `bindings`,以及 `knowledge_base_total` / `agent_total`。列表最多各 50 条,删除守卫以总数为准。
```bash
curl -X DELETE $BASE/api/v1/models/m-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/models/:id/credentials
用途:设置模型密钥(密钥不经主 PUT 传输)。权限:Admin+ 或 SystemAdmin。Handler: `internal/handler/model_credentials.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `api_key` | *string | 否 | 新 API Key |
| `app_secret` | *string | 否 | 新 App Secret(两者均省略时仅返回状态) |
响应:200 `{"success":true,"data":{"fields":{"api_key":{"configured":bool},"app_secret":{"configured":bool}}}}`
```bash
curl -X PUT $BASE/api/v1/models/m-1/credentials -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"api_key":"sk-..."}'
```
### DELETE /api/v1/models/:id/credentials/:field
用途:删除某个密钥字段(`api_key` 或 `app_secret`)。权限:Admin+ 或 SystemAdmin。
响应:204 No Content
```bash
curl -X DELETE $BASE/api/v1/models/m-1/credentials/api_key -H "Authorization: Bearer $TOKEN"
```
## WeKnoraCloud
Handler: `internal/handler/weknoracloud.go`。API key:`manage_models`/full。
### POST /api/v1/weknoracloud/credentials
用途:保存 WeKnoraCloud SaaS 凭证。权限:Admin+。请求体:`{"app_id":"...","app_secret":"..."}`(均 `binding:"required"`)。
响应:200 `{"success":true,"message":"凭证保存成功"}`
```bash
curl -X POST $BASE/api/v1/weknoracloud/credentials -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"app_id":"app","app_secret":"secret"}'
```
### GET /api/v1/models/weknoracloud/status
用途:WeKnoraCloud 就绪状态探测。权限:Viewer+。
响应:200 服务状态对象。
```bash
curl $BASE/api/v1/models/weknoracloud/status -H "Authorization: Bearer $TOKEN"
```
## 初始化(/api/v1/initialization)
Handler: `internal/handler/initialization.go`。KB 配置类:API key `manage_kbs`(写)/`retrieve`(读);模型检测类:`manage_models`(均可 full-access)。
### GET /api/v1/initialization/config/:kbId
用途:读取 KB 当前模型/解析配置。权限:Viewer+,KB read。
响应:200 `{"success":true,"data":{"hasFiles",llm,embedding,rerank,multimodal,documentSplitting,nodeExtract,questionGeneration}}`
```bash
curl $BASE/api/v1/initialization/config/kb-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/initialization/initialize/:kbId
用途:初始化 KB 的模型与解析配置(首次配置向导)。权限:KB 创建者 OR Admin+,KB write。
主要字段(`InitializationRequest`):
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `llm.source` / `llm.modelName` | string | 是 | LLM 来源与模型名 |
| `llm.baseUrl` / `llm.apiKey` | string | 否 | 连接参数 |
| `embedding.source` / `embedding.modelName` | string | 是 | Embedding 模型 |
| `embedding.baseUrl` / `embedding.apiKey` / `embedding.dimension` | — | 否 | 连接与维度 |
| `rerank.enabled` + `rerank.modelName/baseUrl/apiKey` | — | 否 | Rerank 配置 |
| `multimodal.enabled` + `multimodal.vlm.*` + `multimodal.storageType` + `multimodal.cos.*|minio.*` | — | 否 | 多模态与图床 |
| `documentSplitting.chunkSize` / `separators` | int / []string | 是 | 分块配置 |
| `documentSplitting.chunkOverlap` | int | 否 | 重叠 |
| `nodeExtract.*` | — | 否 | 图谱抽取(enabled/text/tags/nodes/relations) |
| `questionGeneration.*` | — | 否 | 问题生成(enabled/questionCount) |
响应:200 `{"success":true,"message":"知识库配置更新成功","data":{"models":[Model],"knowledge_base":{KnowledgeBase}}}`
```bash
curl -X POST $BASE/api/v1/initialization/initialize/kb-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"llm":{"source":"remote","modelName":"gpt-4o-mini"},"embedding":{"source":"remote","modelName":"text-embedding-3-small"},"documentSplitting":{"chunkSize":512,"separators":["\n\n"]}}'
```
### PUT /api/v1/initialization/config/:kbId
用途:更新 KB 模型/分块配置(`KBModelConfigRequest`:`llmModelId` 必填,`embeddingModelId`、`vlm_config`、`asr_config`、`documentSplitting.*`、`multimodal.enabled`、`storageProvider`、`storageBackendId`、`nodeExtract.*`、`questionGeneration.*` 可选)。权限:KB 创建者 OR Admin+,KB write。
响应:200 `{"success":true,"message":"配置更新成功"}`
```bash
curl -X PUT $BASE/api/v1/initialization/config/kb-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"llmModelId":"m-1","embeddingModelId":"m-2"}'
```
### GET /api/v1/initialization/ollama/status
用途:Ollama 可用性探测。权限:Viewer+。
响应:200 `{"success":true,"data":{"available","version","baseUrl","error"}}`
```bash
curl $BASE/api/v1/initialization/ollama/status -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/initialization/ollama/models
用途:列出本地 Ollama 模型。权限:Viewer+。
响应:200 `{"success":true,"data":{"models":[...]}}`
```bash
curl $BASE/api/v1/initialization/ollama/models -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/initialization/ollama/models/check
用途:批量检查模型是否已存在。权限:Admin+。请求体:`{"models":["llama3"]}`(`binding:"required"`)。
响应:200 `{"success":true,"data":{"models":{"llama3":true}}}`
```bash
curl -X POST $BASE/api/v1/initialization/ollama/models/check -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"models":["llama3"]}'
```
### POST /api/v1/initialization/ollama/models/download
用途:拉取 Ollama 模型(异步任务)。权限:Admin+。请求体:`{"modelName":"llama3"}`(`binding:"required"`)。
响应:200 `{"success":true,"data":{"taskId","modelName","status","progress"}}`
```bash
curl -X POST $BASE/api/v1/initialization/ollama/models/download -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"modelName":"llama3"}'
```
### GET /api/v1/initialization/ollama/download/progress/:taskId
用途:下载任务进度。权限:Viewer+。
响应:200 `{"success":true,"data":{id,modelName,status,progress,message,startTime,endTime}}`
```bash
curl $BASE/api/v1/initialization/ollama/download/progress/task-1 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/initialization/ollama/download/tasks
用途:全部下载任务列表。权限:Viewer+。
响应:200 `{"success":true,"data":[DownloadTask]}`
```bash
curl $BASE/api/v1/initialization/ollama/download/tasks -H "Authorization: Bearer $TOKEN"
```
### 模型连通性检测(均 POST,权限 Admin+)
请求体统一为 `ModelTestRequest`:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `source` | string | 否 | 默认 `remote` |
| `modelName` | string | 是 | 模型名 |
| `baseUrl` / `apiKey` / `appSecret` | string | 否 | 连接参数 |
| `provider` / `interfaceType` | string | 否 | 厂商/接口类型 |
| `dimension` | int | 否 | embedding 维度 |
| `customHeaders` / `extraConfig` | map | 否 | 扩展 |
| `modelId` | string | 否 | 从已存模型取密钥 |
| 端点 | 用途 | 响应 data |
| --- | --- | --- |
| `POST /api/v1/initialization/remote/check` | LLM 远程连通性 | `{available,message}` |
| `POST /api/v1/initialization/embedding/test` | Embedding 测试 | `{available,message,dimension}` |
| `POST /api/v1/initialization/rerank/check` | Rerank 测试 | `{available,message}` |
| `POST /api/v1/initialization/asr/check` | ASR 测试 | `{available,message}` |
```bash
curl -X POST $BASE/api/v1/initialization/remote/check -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"modelName":"gpt-4o-mini","baseUrl":"https://api.openai.com/v1","apiKey":"sk-..."}'
```
### POST /api/v1/initialization/multimodal/test
用途:多模态(VLM+图床)端到端测试。权限:Admin+。multipart 字段:`image`(必填)、`vlm_model`、`vlm_base_url`(必填)、`vlm_api_key`、`vlm_interface_type`、`storage_type`(`cos|minio`,必填)及对应 `cos_*`/`minio_*` 字段、`chunk_size`、`chunk_overlap`、`separators`。
响应:200 `{"success":true,"data":{"success","caption","ocr","processing_time"}}`
```bash
curl -X POST $BASE/api/v1/initialization/multimodal/test -H "Authorization: Bearer $TOKEN" \
-F 'image=@demo.png' -F 'vlm_model=qwen-vl' -F 'vlm_base_url=http://x' -F 'storage_type=minio'
```
### POST /api/v1/initialization/extract/text-relation
用途:文本图谱抽取测试。权限:Admin+。请求体:`text`(必填,≤5000 字符)、`tags`(必填,至少一个)、`model_id`(必填)。
响应:200 `{"success":true,"data":{"nodes":[GraphNode],"relations":[GraphRelation]}}`
```bash
curl -X POST $BASE/api/v1/initialization/extract/text-relation -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"text":"小明在腾讯工作","tags":["人物","公司"],"model_id":"m-1"}'
```
### POST /api/v1/initialization/extract/fabri-tag
用途:生成示例标签。权限:Admin+。无请求体。
响应:200 `{"success":true,"data":{"tags":[...]}}`
```bash
curl -X POST $BASE/api/v1/initialization/extract/fabri-tag -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/initialization/extract/fabri-text
用途:按标签生成示例文本。权限:Admin+。请求体:`{"tags":[...],"model_id":"m-1"}`(model_id 必填)。
响应:200 `{"success":true,"data":{"text":"..."}}`
```bash
curl -X POST $BASE/api/v1/initialization/extract/fabri-text -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"model_id":"m-1","tags":["人物"]}'
```
## 评估(/api/v1/evaluation)
Handler: `internal/handler/evaluation.go`。API key:`run_evaluations`/full。
### POST /api/v1/evaluation
用途:发起评估任务(驱动 LLM 调用,产生费用)。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `dataset_id` | string | 否 | 数据集 ID |
| `knowledge_base_id` | string | 否 | 目标 KB |
| `chat_id` | string | 否 | 对话模型 ID |
| `rerank_id` | string | 否 | Rerank 模型 ID |
响应:200 `{"success":true,"data":{评估任务}}`
```bash
curl -X POST $BASE/api/v1/evaluation -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"knowledge_base_id":"kb-1","chat_id":"m-1"}'
```
### GET /api/v1/evaluation
用途:查询评估结果。权限:Viewer+。查询参数:`task_id`(必填)。
响应:200 `{"success":true,"data":{评估结果}}`
```bash
curl "$BASE/api/v1/evaluation?task_id=task-1" -H "Authorization: Bearer $TOKEN"
```
+440
View File
@@ -0,0 +1,440 @@
# API 参考:组织与共享
路由注册:`internal/router/router.go` 的 `RegisterOrganizationRoutes`。Handler:`internal/handler/organization.go`。
组织(Organization)以“空间(tenant)”为成员单位。组织组路由的 API key 策略为 `manage_spaces` 或 full-access;KB/Agent 分享管理仅 full-access key 可用。
## 组织管理(/api/v1/organizations)
### POST /api/v1/organizations
用途:创建组织。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是 | 组织名称 |
| `description` | string | 否 | 描述 |
| `avatar` | string | 否 | 头像 URL |
| `searchable` | bool | 否 | 是否可被搜索发现 |
| `require_approval` | bool | 否 | 加入是否需审批 |
| `member_limit` | int | 否 | 成员空间数上限 |
| `invite_code_validity_days` | int | 否 | 邀请码有效期(天) |
响应:201 `{"success":true,"data":{OrganizationResponse}}`
```bash
curl -X POST $BASE/api/v1/organizations -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"研发组织"}'
```
### GET /api/v1/organizations
用途:列出我所在的组织。权限:Viewer+。
响应:200 `{"success":true,"data":{"organizations":[...],"total":N,"resource_counts":{"knowledge_bases":{"by_organization":{}},"agents":{"by_organization":{}}}}}`
```bash
curl $BASE/api/v1/organizations -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/organizations/preview/:code
用途:按邀请码预览组织(不加入)。权限:Viewer+。路径参数:`code` 邀请码。
响应:200 `{"success":true,"data":{id,name,description,avatar,member_count,share_count,agent_share_count,is_already_member,require_approval,created_at}}`
```bash
curl $BASE/api/v1/organizations/preview/ABC123 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/organizations/join
用途:凭邀请码加入组织。权限:Admin+。请求体:`{"invite_code":"..."}`(必填)。
响应:200 `{"success":true,"data":{OrganizationResponse}}`
```bash
curl -X POST $BASE/api/v1/organizations/join -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"invite_code":"ABC123"}'
```
### POST /api/v1/organizations/join-request
用途:提交加入申请(需审批的组织)。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `invite_code` | string | 是 | 邀请码 |
| `message` | string | 否 | 申请附言 |
| `role` | string | 否 | 期望角色 |
响应:200 `{"success":true,"data":{JoinRequest}}`
```bash
curl -X POST $BASE/api/v1/organizations/join-request -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"invite_code":"ABC123","message":"申请加入"}'
```
### GET /api/v1/organizations/search
用途:搜索可发现(searchable)的组织。权限:Viewer+。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `q` | string | 否 | 关键字 |
| `limit` | int | 否 | 默认 20,上限 100 |
响应:200 `{"success":true,"data":[SearchableOrganization],"total":N}`
```bash
curl "$BASE/api/v1/organizations/search?q=研发" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/organizations/join-by-id
用途:按组织 ID 加入可发现组织(无需邀请码)。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `organization_id` | string | 是 | 目标组织 ID |
| `message` | string | 否 | 附言 |
| `role` | string | 否 | 期望角色 |
响应:200 `{"success":true,"data":{OrganizationResponse}}`
```bash
curl -X POST $BASE/api/v1/organizations/join-by-id -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"organization_id":"org-1"}'
```
### GET /api/v1/organizations/:id
用途:组织详情。权限:Viewer+。
响应:200 `{"success":true,"data":{OrganizationResponse}}`
```bash
curl $BASE/api/v1/organizations/org-1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/organizations/:id
用途:更新组织(服务层校验调用者空间为组织 owner)。权限:Admin+。请求体字段同创建(均可选)。
响应:200 `{"success":true,"data":{OrganizationResponse}}`
```bash
curl -X PUT $BASE/api/v1/organizations/org-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"description":"更新描述"}'
```
### DELETE /api/v1/organizations/:id
用途:删除组织。权限:Admin+(服务层要求组织 owner)。
响应:200 `{"success":true,"message":"Organization deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/organizations/org-1 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/organizations/:id/leave
用途:本空间退出组织。权限:Admin+。无请求体。
响应:200 `{"success":true,"message":"Left organization successfully"}`
```bash
curl -X POST $BASE/api/v1/organizations/org-1/leave -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/organizations/:id/request-upgrade
用途:申请提升本空间在组织内的角色。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `requested_role` | string | 是 | 期望的组织角色(`viewer/editor/admin`) |
| `message` | string | 否 | 附言 |
响应:200 `{"success":true,"data":{JoinRequest}}`
```bash
curl -X POST $BASE/api/v1/organizations/org-1/request-upgrade -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"requested_role":"editor"}'
```
### POST /api/v1/organizations/:id/invite-code
用途:生成组织邀请码。权限:Admin+(服务层要求组织 admin)。无请求体。
响应:200 `{"success":true,"data":{"invite_code":"..."}}`
```bash
curl -X POST $BASE/api/v1/organizations/org-1/invite-code -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/organizations/:id/search-tenants
用途:搜索可邀请的空间(返回按空间分组的候选)。权限:Admin+。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `q` | string | 是 | 空间名关键字 |
| `limit` | int | 否 | 默认 10,上限 50 |
响应:200 `{"success":true,"data":[{"tenant_id","tenant_name"}]}`
```bash
curl "$BASE/api/v1/organizations/org-1/search-tenants?q=demo" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/organizations/:id/search-users
用途:已废弃别名,行为同 `search-tenants`(返回空间分组结果)。权限:Admin+。参数同上。
```bash
curl "$BASE/api/v1/organizations/org-1/search-users?q=demo" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/organizations/:id/invite
用途:直接邀请空间加入组织。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `tenant_id` | uint64 | 二选一 | 目标空间 ID(推荐) |
| `user_id` | string | 二选一 | 兼容路径:用户 ID(解析为其空间) |
| `representative_user_id` | string | 否 | 该空间的代表用户 |
| `role` | string | 是 | 组织内角色 |
响应:200 `{"success":true,"message":"Member added successfully"}`
```bash
curl -X POST $BASE/api/v1/organizations/org-1/invite -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"tenant_id":2,"role":"viewer"}'
```
### GET /api/v1/organizations/:id/members
用途:组织成员(空间)列表。权限:Viewer+。
响应:200 `{"success":true,"data":{"members":[{id,user_id,representative_user_id,role,tenant_id,tenant_name,username,email,avatar,joined_at}],"total":N}}`
```bash
curl $BASE/api/v1/organizations/org-1/members -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/organizations/:id/members/:tenant_id
用途:修改成员空间的组织角色。权限:Admin+。路径参数 `tenant_id` 为成员空间 ID。请求体:`{"role":"editor"}`(必填,`viewer/editor/admin`)。
响应:200 `{"success":true,"message":"Member role updated successfully"}`
```bash
curl -X PUT $BASE/api/v1/organizations/org-1/members/2 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"role":"editor"}'
```
### DELETE /api/v1/organizations/:id/members/:tenant_id
用途:移除成员空间(含自移除)。权限:Admin+。
响应:200 `{"success":true,"message":"Member removed successfully"}`
```bash
curl -X DELETE $BASE/api/v1/organizations/org-1/members/2 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/organizations/:id/join-requests
用途:加入申请队列。权限:Admin+。
响应:200 `{"success":true,"data":{"requests":[{id,user_id,username,email,message,request_type,prev_role,requested_role,status,created_at,reviewed_at}],"total":N}}`
```bash
curl $BASE/api/v1/organizations/org-1/join-requests -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/organizations/:id/join-requests/:request_id/review
用途:审批加入/升级申请。权限:Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `approved` | bool | 是 | 通过/拒绝 |
| `message` | string | 否 | 审批意见 |
| `role` | string | 否 | 通过时授予的角色 |
响应:200 `{"success":true,"message":"Review completed"}`
```bash
curl -X PUT $BASE/api/v1/organizations/org-1/join-requests/req-1/review \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"approved":true}'
```
### GET /api/v1/organizations/:id/shares
用途:查看共享到该组织的 KB 列表。权限:Viewer+。
响应:200 `{"success":true,"data":{"shares":[KnowledgeBaseShareResponse],"total":N}}`
```bash
curl $BASE/api/v1/organizations/org-1/shares -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/organizations/:id/agent-shares
用途:查看共享到该组织的 Agent 列表。权限:Viewer+。
响应:200 `{"success":true,"data":{"shares":[AgentShareResponse],"total":N}}`
```bash
curl $BASE/api/v1/organizations/org-1/agent-shares -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/organizations/:id/shared-knowledge-bases
用途:组织空间视图:组织内全部共享 KB(含我自己的)。权限:Viewer+。
响应:200 `{"success":true,"data":[...含 is_mine、source_from_agent 标记...],"total":N}`
```bash
curl $BASE/api/v1/organizations/org-1/shared-knowledge-bases -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/organizations/:id/shared-agents
用途:组织空间视图:组织内全部共享 Agent。权限:Viewer+。
响应:200 `{"success":true,"data":[SharedAgentInfo],"total":N}`
```bash
curl $BASE/api/v1/organizations/org-1/shared-agents -H "Authorization: Bearer $TOKEN"
```
## KB 分享(/api/v1/knowledge-bases/:id/shares)
API key:仅 full-access。Handler: `internal/handler/organization.go`
### POST /api/v1/knowledge-bases/:id/shares
用途:把 KB 分享到组织。权限:KB 创建者 OR Admin+。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `organization_id` | string | 是 | 目标组织 |
| `permission` | string | 是 | 共享权限(组织角色语义,如 `viewer/editor`) |
响应:201 `{"success":true,"data":{KBShare}}`
```bash
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/shares -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"organization_id":"org-1","permission":"viewer"}'
```
### GET /api/v1/knowledge-bases/:id/shares
用途:查看该 KB 的分享列表。权限:Viewer+。
响应:200 `{"success":true,"data":{"shares":[KnowledgeBaseShareResponse],"total":N}}`
```bash
curl $BASE/api/v1/knowledge-bases/kb-1/shares -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/knowledge-bases/:id/shares/:share_id
用途:修改分享权限。权限:KB 创建者 OR Admin+。请求体:`{"permission":"editor"}`(必填)。
响应:200 `{"success":true,"message":"Share permission updated successfully"}`
```bash
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/shares/s-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"permission":"editor"}'
```
### DELETE /api/v1/knowledge-bases/:id/shares/:share_id
用途:取消分享。权限:KB 创建者 OR Admin+。
响应:200 `{"success":true,"message":"Share removed successfully"}`
```bash
curl -X DELETE $BASE/api/v1/knowledge-bases/kb-1/shares/s-1 -H "Authorization: Bearer $TOKEN"
```
## Agent 分享(/api/v1/agents/:id/shares)
API key:仅 full-access。Handler: `internal/handler/organization.go`
### POST /api/v1/agents/:id/shares
用途:把 Agent 分享到组织。权限:Agent 创建者 OR Admin+。请求体同 KB 分享(`organization_id` + `permission`,必填)。
响应:201 `{"success":true,"data":{AgentShare}}`
```bash
curl -X POST $BASE/api/v1/agents/agent-1/shares -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"organization_id":"org-1","permission":"viewer"}'
```
### GET /api/v1/agents/:id/shares
用途:查看该 Agent 的分享列表。权限:Agent 创建者 OR Admin+。
响应:200 `{"success":true,"data":{"shares":[AgentShareResponse],"total":N}}`
```bash
curl $BASE/api/v1/agents/agent-1/shares -H "Authorization: Bearer $TOKEN"
```
### DELETE /api/v1/agents/:id/shares/:share_id
用途:取消 Agent 分享。权限:Agent 创建者 OR Admin+。
响应:200 `{"success":true,"message":"Share removed successfully"}`
```bash
curl -X DELETE $BASE/api/v1/agents/agent-1/shares/s-1 -H "Authorization: Bearer $TOKEN"
```
## 共享资源聚合视图
### GET /api/v1/shared-knowledge-bases
用途:列出通过组织共享给我的 KB(去除属主侧向量库元数据)。权限:Viewer+;API key 需 `manage_spaces` 或 full-access。
响应:200 `{"success":true,"data":[...],"total":N}`
```bash
curl $BASE/api/v1/shared-knowledge-bases -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/shared-agents
用途:列出通过组织共享给我的 Agent。权限:Viewer+;API key 同上。
响应:200 `{"success":true,"data":[SharedAgentInfo],"total":N}`。`SharedAgentInfo` 含 `source_tenant_id`(来源空间)、`org_name`、`shared_by_username`、`permission`,以及 `web_search_ready`——只返回「来源空间的联网搜索是否可用」这一个布尔位,不下发来源空间的 provider 配置(会泄露配置),也不拿接收方空间的 provider ID 去比对(会误报不可用)。
使用共享 Agent 调用其它接口时,若同名 Agent 被多个空间共享,可带 `agent_source_tenant_id` 指明来源空间;该值会与共享关系逐一校验,非法或无权限时直接报错,不会静默回退到别的来源。
```bash
curl $BASE/api/v1/shared-agents -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/shared-agents/disabled
用途:设置“本空间禁用某共享 Agent”(影响整个空间的会话下拉)。权限:Admin+;API key 同上。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `agent_id` | string | 是(`binding:"required"`) | 共享 Agent ID |
| `disabled` | bool | 否 | 是否禁用(默认 false) |
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/shared-agents/disabled -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"agent_id":"agent-1","disabled":true}'
```
+244
View File
@@ -0,0 +1,244 @@
# API 参考:系统与平台管理
这一组是部署级接口:读系统信息,以及系统管理员专属的平台控制面(全局设置、运行时队列、平台 API Key、跨空间审计、重置密码)。功能说明见[平台管理与系统管理员](../03-features/20-platform-admin.md)。
路由注册:`internal/router/routes_auth_tenant.go` 的 `RegisterSystemAdminRoutes` 与 `RegisterSystemRoutes`。Handler:`internal/handler/system.go`、`internal/handler/audit_log.go`。
`/system/admin/*` 全组挂 `SystemAdmin()` 守卫;平台 API Key 按能力细分(`system_settings_read/manage`、`system_runtime_read/manage`、`system_tenants_read/manage`、`system_audit_read`)。
## 系统信息(/api/v1/system)
Handler: `internal/handler/system.go`。API key:`manage_vector_stores`/full。本组响应使用 `{"code":0,"msg":"success","data":...}` 包装。
### GET /api/v1/system/info
用途:系统版本与引擎信息。权限:Viewer+。
响应:200 `{"code":0,"msg":"success","data":{version,edition,commit_id,build_time,go_version,keyword_index_engine,vector_store_engine,graph_database_engine,minio_enabled,db_version,started_at,uptime_seconds}}`
```bash
curl $BASE/api/v1/system/info -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/system/parser-engines
用途:解析引擎列表与 DocReader 连接状态。权限:Viewer+。
响应:200 `{"code":0,"msg":"success","data":[...],"docreader_addr","docreader_transport","connected"}`
```bash
curl $BASE/api/v1/system/parser-engines -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/system/parser-engines/check
用途:用给定配置探测解析引擎(`types.ParserEngineConfig` 请求体)。权限:Admin+。
响应:200,同上。
```bash
curl -X POST $BASE/api/v1/system/parser-engines/check -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{}'
```
### POST /api/v1/system/docreader/reconnect
用途:重连 DocReader。权限:Admin+。请求体:`{"addr":"host:port"}`(`binding:"required"`)。
响应:200 `{"code":0,"msg":"连接成功",...,"connected":true}`
```bash
curl -X POST $BASE/api/v1/system/docreader/reconnect -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"addr":"docreader:50051"}'
```
### GET /api/v1/system/storage-engine-status
用途:对象存储引擎可用性。权限:Viewer+。
响应:200 `{"code":0,"msg":"success","data":{"engines":[{name,allowed,available,description}],"allowed_providers":[...],"minio_env_available":bool}}`
```bash
curl $BASE/api/v1/system/storage-engine-status -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/system/storage-engine-check
用途:校验存储配置(SSRF 防护后探测)。权限:Admin+。请求体:`provider`(必填,`minio/cos/tos/s3/oss/ks3/obs`)+ 对应 `minio|cos|tos|s3|oss|ks3|obs` 配置对象。
响应:200 `{"code":0,"data":{"ok","message","bucket_created"}}`
```bash
curl -X POST $BASE/api/v1/system/storage-engine-check -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"provider":"minio","minio":{"endpoint":"minio:9000"}}'
```
## 系统管理(/api/v1/system/admin,SystemAdmin 专属)
组级挂载 `SystemAdmin()` 守卫(始终强制,不受 EnableRBAC 影响);平台 API key 需对应 `system_*` capability。本组读取接口多返回原始行/数组(无包装)。Handler: `internal/handler/system.go`、`internal/handler/audit_log.go`。
### POST /api/v1/system/admin/promote
用途:授予 SystemAdmin。请求体:`user_id`(UUID,优先)或 `email`(二选一)。
响应:200 `UserInfo`(原始对象)。
```bash
curl -X POST $BASE/api/v1/system/admin/promote -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"email":"admin@ex.com"}'
```
### POST /api/v1/system/admin/revoke
用途:撤销 SystemAdmin。请求体:`{"user_id":"..."}`(`binding:"required"`)。
响应:200 `UserInfo`
```bash
curl -X POST $BASE/api/v1/system/admin/revoke -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"user_id":"u-1"}'
```
### GET /api/v1/system/admin/list
用途:SystemAdmin 列表。查询参数:`offset`(默认 0)、`limit`(默认 50,上限 200)。
响应:200 `{"total":N,"admins":[UserInfo]}`
```bash
curl $BASE/api/v1/system/admin/list -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/system/admin/users/reset-password
用途:重置用户密码。请求体:`email`(`binding:"required,email"`)、`new_password`(`binding:"required"`)。
响应:200 `{"message":"Password reset successfully"}`
```bash
curl -X POST $BASE/api/v1/system/admin/users/reset-password -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"email":"a@ex.com","new_password":"newpass1"}'
```
### GET /api/v1/system/admin/api-keys
用途:平台 API key 列表(掩码)。
响应:200 `{"success":true,"data":[{id,name,api_key,capabilities,expires_at_unix,...}]}`
```bash
curl $BASE/api/v1/system/admin/api-keys -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/system/admin/api-keys
用途:创建平台 API key(明文仅返回一次)。请求体:`name`(非空)、`capabilities`(`system_*` 列表,必填)、`expires_at_unix`(可选,须为未来时间)。
响应:201 `{"success":true,"data":{...,"api_key":"<明文>","token":"<明文>"}}`
```bash
curl -X POST $BASE/api/v1/system/admin/api-keys -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"ops","capabilities":["system_tenants_read"]}'
```
### DELETE /api/v1/system/admin/api-keys/:key_id
用途:删除平台 API key。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/system/admin/api-keys/3 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/system/admin/settings 与 GET /api/v1/system/admin/settings/:key
用途:平台运行时设置列表 / 单项(平台 key 需 `system_settings_read|manage`)。
响应:200 `[SystemSetting]` / `SystemSetting`(原始,无包装;字段:`key,value,value_type,description,last_modified_by,last_modified_at`)。
```bash
curl $BASE/api/v1/system/admin/settings -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/system/admin/settings/:key
用途:更新设置(平台 key 需 `system_settings_manage`)。请求体:`{"value":<任意 JSON,按注册表类型校验>}`(必填)。
响应:200 `SystemSetting`
```bash
curl -X PUT $BASE/api/v1/system/admin/settings/default_storage_quota -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"value":10737418240}'
```
### DELETE /api/v1/system/admin/settings/:key
用途:恢复设置默认值。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/system/admin/settings/default_storage_quota -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/system/admin/runtime/queues
用途:asynq 队列深度与并发状态(Lite 模式返回 `available:false`;平台 key 需 `system_runtime_read|manage`)。
响应:200 `{"available",upstream_concurrency,parse_concurrency,wiki_concurrency,pools,queues,model_limiter_available,models,timestamp}`
```bash
curl $BASE/api/v1/system/admin/runtime/queues -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/system/admin/runtime/queues/:queue/tasks
用途:队列任务列表。查询参数:`state`(`pending/active/scheduled/retry/archived/completed`)、`cursor`、`page_size`(默认 20,上限 100)。
响应:200 `{"available","tasks":[RuntimeTaskInfo],"page_size","has_more","next_cursor"}`
```bash
curl "$BASE/api/v1/system/admin/runtime/queues/default/tasks?state=pending" -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/system/admin/runtime/queues/:queue/tasks/:task_id/actions/:action
用途:任务操作(`action` ∈ `cancel/run_now/delete`;平台 key 需 `system_runtime_manage`)。
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/system/admin/runtime/queues/default/tasks/t-1/actions/cancel \
-H "Authorization: Bearer $TOKEN"
```
### DELETE /api/v1/system/admin/runtime/queues/:queue/archived
用途:清空归档任务。
响应:200 `{"success":true,"deleted":N}`
```bash
curl -X DELETE $BASE/api/v1/system/admin/runtime/queues/default/archived -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/system/admin/tenants/apply-default-storage-quota
用途:把当前默认存储配额批量写到全部空间(平台 key 需 `system_tenants_manage`)。无请求体。
响应:200 `{"affected":N,"quota_bytes":N,"quota_gb":N}`
```bash
curl -X POST $BASE/api/v1/system/admin/tenants/apply-default-storage-quota -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/system/admin/audit-log
用途:平台级审计日志(tenant_id=0 行;平台 key 需 `system_audit_read`)。查询参数同空间审计(`after_id/limit/action/outcome/actor`)。Handler: `internal/handler/audit_log.go`
响应:200 `{"success":true,"data":[AuditLog],"next_cursor":N}`
```bash
curl $BASE/api/v1/system/admin/audit-log -H "Authorization: Bearer $TOKEN"
```
+367
View File
@@ -0,0 +1,367 @@
# API 参考:租户(空间)与成员
路由注册:`internal/router/router.go` 的 `RegisterTenantRoutes`。Handler:`internal/handler/tenant.go`、`internal/handler/tenant_member.go`、`internal/handler/tenant_invitation.go`、`internal/handler/tenant_invite_link.go`、`internal/handler/audit_log.go`。
所有 `/tenants/:id/*` 路由在组级挂载 `PathTenantMatch()`(`internal/middleware/access.go`):URL 中的 `:id` 必须等于当前活跃空间(跨空间超管例外),防止越权操作他人空间。
## 空间生命周期
### POST /api/v1/tenants
用途:创建空间(自助开新工作区;调用者自动成为 Owner)。权限:任何已登录用户(可无空间);API key 仅平台 key 且具 `system_tenants_manage`。Handler: `internal/handler/tenant.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是(`binding:"required,min=1,max=128"`) | 空间名称 |
| `description` | string | 否(`binding:"max=512"`) | 描述 |
跨空间超管可提交完整 `types.Tenant`(含 `storage_quota`、`status` 等)。
响应:201 `{"success":true,"data":{Tenant}}`(配置允许时可能携带 `api_key`)。自助创建被禁用返回 403(code 2005),超配额返回 429。
```bash
curl -X POST $BASE/api/v1/tenants -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"我的空间"}'
```
### GET /api/v1/tenants
用途:列出我可访问的空间。权限:已登录;API key 需 `manage_tenant_settings` 或 full-access。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"data":{"items":[TenantResponse]}}`
```bash
curl $BASE/api/v1/tenants -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/tenants/all
用途:列出全部空间(跨空间超管)。权限:`CrossTenant()`(`CanAccessAllTenants` 且集群开启 `EnableCrossTenantAccess`);平台 key 需 `system_tenants_read|manage`。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"data":{"items":[TenantResponse]}}`
```bash
curl $BASE/api/v1/tenants/all -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/tenants/search
用途:按关键字搜索空间(跨空间超管)。权限:同上。Handler: `internal/handler/tenant.go`
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `keyword` | string | 否 | 关键字 |
| `tenant_id` | string | 否 | 精确空间 ID |
| `page` / `page_size` | int | 否 | 分页(默认 1/20,上限 100) |
响应:200 `{"success":true,"data":{"items":[...],"total","page","page_size"}}`
```bash
curl "$BASE/api/v1/tenants/search?keyword=demo&page=1" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/tenants/:id
用途:空间详情。权限:Viewer+;平台 key 需 `system_tenants_read|manage`。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"data":{TenantResponse}}`
```bash
curl $BASE/api/v1/tenants/1 -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/tenants/:id
用途:更新空间配置。权限:Owner;平台 key 需 `system_tenants_manage`。Handler: `internal/handler/tenant.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | *string | 否(`binding:"omitempty,min=1,max=128"`) | 新名称 |
| `description` | *string | 否(`binding:"omitempty,max=512"`) | 新描述 |
响应:200 `{"success":true,"data":{TenantResponse}}`
```bash
curl -X PUT $BASE/api/v1/tenants/1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"新名字"}'
```
### DELETE /api/v1/tenants/:id
用途:删除空间。权限:Owner;平台 key 需 `system_tenants_manage`。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"message":"Workspace deleted successfully"}`
```bash
curl -X DELETE $BASE/api/v1/tenants/1 -H "Authorization: Bearer $TOKEN"
```
## 空间 KV 配置
`:key` 为配置键而非空间 ID(空间取自认证上下文),可选值:`web-search-config`、`prompt-templates`、`parser-engine-config`、`storage-engine-config`、`chat-history-config`、`retrieval-config`。
### GET /api/v1/tenants/kv/:key
用途:读取空间级 KV 配置。权限:Viewer+;API key 需 `manage_tenant_settings` 或 full-access。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"data":{...对应配置对象...}}`
```bash
curl $BASE/api/v1/tenants/kv/retrieval-config -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/tenants/kv/:key
用途:更新空间级 KV 配置。权限:Admin+;API key 需 `manage_tenant_settings` 或 full-access。请求体:与 `:key` 对应的配置 JSON 对象。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"message":"Configuration updated"}`
```bash
curl -X PUT $BASE/api/v1/tenants/kv/web-search-config -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"enabled":true}'
```
## API Key 与 API 主体
### GET /api/v1/tenants/:id/api-keys
用途:列出空间 API key(掩码显示)。权限:Owner,仅 JWT(API key 默认拒绝)。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"data":[{id,scope_type,name,api_key(掩码),full_access,knowledge_base_ids,capabilities,last_used_at,expires_at,created_at}]}`
```bash
curl $BASE/api/v1/tenants/1/api-keys -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/tenants/:id/api-keys
用途:创建空间 API key(明文仅返回一次)。权限:Owner,仅 JWT。Handler: `internal/handler/tenant.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是 | key 名称 |
| `full_access` | bool | 否 | 空间全权 key(默认 false) |
| `knowledge_base_ids` | []string | 否 | KB 白名单(scoped key) |
| `capabilities` | []string | 否 | capability 列表(见总览) |
| `expires_at_unix` | *int64 | 否 | 过期时间戳 |
响应:201 `{"success":true,"data":{...,"api_key":"<明文>","token":"<明文>"}}`
```bash
curl -X POST $BASE/api/v1/tenants/1/api-keys -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"ingest-bot","capabilities":["ingest","retrieve"],"knowledge_base_ids":["kb-1"]}'
```
### DELETE /api/v1/tenants/:id/api-keys/:key_id
用途:删除 API key。权限:Owner,仅 JWT。路径参数:`key_id`。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/tenants/1/api-keys/5 -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/tenants/:id/api-principal-config
用途:读取 API 外部用户主体配置。权限:Owner,仅 JWT。Handler: `internal/handler/tenant.go`
响应:200 `{"success":true,"data":{"mode":"tenant|direct|signed_token","direct_header_name","signed_token_header_name","require_direct_header","has_hmac_secret"}}`
```bash
curl $BASE/api/v1/tenants/1/api-principal-config -H "Authorization: Bearer $TOKEN"
```
### PUT /api/v1/tenants/:id/api-principal-config
用途:更新 API 外部用户主体配置。权限:Owner,仅 JWT。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `mode` | string | 是 | `tenant` / `direct` / `signed_token` |
| `require_direct_header` | bool | 否 | direct 模式是否强制 Header |
| `hmac_secret` | *string | 否 | signed_token 模式密钥(传 `***` 保留原值) |
响应:200,同 GET。
```bash
curl -X PUT $BASE/api/v1/tenants/1/api-principal-config -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"mode":"signed_token","hmac_secret":"topsecret"}'
```
### POST /api/v1/tenants/:id/api-principal-test-token
用途:签发用于测试的外部用户 JWT。权限:Owner,仅 JWT。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `external_user_id` | string | 是 | 外部用户 ID(≤128 字符) |
| `expires_in_seconds` | int | 否 | 1-3600,默认 900 |
响应:200 `{"success":true,"data":{"token","header_name","expires_in_seconds","expires_at_unix","external_user_id"}}`
```bash
curl -X POST $BASE/api/v1/tenants/1/api-principal-test-token -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"external_user_id":"u-123"}'
```
## 成员管理(/tenants/:id/members)
Handler: `internal/handler/tenant_member.go`。API key 需 `manage_members` 或 full-access。
### GET /api/v1/tenants/:id/members
用途:成员列表。权限:Viewer+。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `q` | string | 否 | 邮箱/用户名过滤 |
| `page` / `page_size` | int | 否 | 分页 |
响应:200 `{"success":true,"data":{"members":[{user_id,email,username,avatar,role,status,invited_by,joined_at}],"total","page","page_size"}}`
```bash
curl $BASE/api/v1/tenants/1/members -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/tenants/:id/members
用途:直接添加成员。权限:Owner。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `email` | string | 是(`binding:"required,email"`) | 成员邮箱(须已注册) |
| `role` | string | 是(`binding:"required"`) | `owner/admin/contributor/viewer` |
响应:201 `{"success":true,"data":{成员对象}}`
```bash
curl -X POST $BASE/api/v1/tenants/1/members -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"email":"b@ex.com","role":"contributor"}'
```
### PUT /api/v1/tenants/:id/members/:user_id
用途:修改成员角色。权限:Owner。请求体:`{"role":"admin"}`(`binding:"required"`)。
响应:200 `{"success":true}`
```bash
curl -X PUT $BASE/api/v1/tenants/1/members/u-123 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"role":"admin"}'
```
### DELETE /api/v1/tenants/:id/members/:user_id
用途:移除成员。权限:Owner。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/tenants/1/members/u-123 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/tenants/:id/leave
用途:退出空间(任何成员可自行退出;服务层拒绝导致空间无 Owner 的退出)。权限:Viewer+,仅 JWT。
响应:200 `{"success":true}`
```bash
curl -X POST $BASE/api/v1/tenants/1/leave -H "Authorization: Bearer $TOKEN"
```
## 空间邀请(/tenants/:id/invitations 与 invite-links)
Handler: `internal/handler/tenant_invitation.go`、`internal/handler/tenant_invite_link.go`。API key 需 `manage_members` 或 full-access。
### GET /api/v1/tenants/:id/invitations
用途:空间邀请列表。权限:Viewer+。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `include_terminal` | bool | 否 | 包含已完结邀请 |
| `page` / `page_size` | int | 否 | 分页 |
响应:200 `{"success":true,"data":{"invitations":[{id,tenant_id,invitee_email,inviter_email,role,status,message,expires_at,is_share_link,accepted_count,...}],"total","page","page_size"}}`
```bash
curl $BASE/api/v1/tenants/1/invitations -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/tenants/:id/invitations
用途:邀请成员(被邀请人在 `/me/invitations` 确认后才入库)。权限:Owner。
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `email` | string | 是(`binding:"required,email"`) | 被邀请邮箱 |
| `role` | string | 是(`binding:"required"`) | 授予角色 |
| `message` | string | 否 | 附言 |
响应:201 `{"success":true,"data":{TenantInvitationResponse}}`
```bash
curl -X POST $BASE/api/v1/tenants/1/invitations -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"email":"c@ex.com","role":"viewer"}'
```
### DELETE /api/v1/tenants/:id/invitations/:inv_id
用途:撤销邀请。权限:Owner。
响应:200 `{"success":true}`
```bash
curl -X DELETE $BASE/api/v1/tenants/1/invitations/12 -H "Authorization: Bearer $TOKEN"
```
### POST /api/v1/tenants/:id/invite-links
用途:创建分享链接(多次可用的注册邀请链接)。权限:Owner。Handler: `internal/handler/tenant_invite_link.go`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `role` | string | 是(`binding:"required"`) | 链接授予的角色 |
| `message` | string | 否 | 附言 |
响应:201 `{"success":true,"data":{id,token,invite_url,role,status,expires_at,is_share_link:true,accepted_count}}`
```bash
curl -X POST $BASE/api/v1/tenants/1/invite-links -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"role":"viewer"}'
```
## 审计日志
Handler: `internal/handler/audit_log.go`。游标分页。
### GET /api/v1/tenants/:id/audit-log
用途:空间审计日志(含被拒绝操作记录)。权限:Admin+,仅 JWT。
| 查询参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `after_id` | int | 否 | 游标(上次响应 `next_cursor`) |
| `limit` | int | 否 | 1-100,默认 50 |
| `action` | string | 否 | 按动作过滤(如 `rbac.member_added`) |
| `outcome` | string | 否 | `success` / `denied` |
| `actor` | string | 否 | 按操作者 user_id 过滤 |
响应:200 `{"success":true,"data":[AuditLog],"next_cursor":N}`
```bash
curl "$BASE/api/v1/tenants/1/audit-log?limit=50" -H "Authorization: Bearer $TOKEN"
```
### GET /api/v1/knowledge-bases/:id/activity
用途:单个 KB 的活动流(只读审计)。权限:KB 创建者 OR Admin+,且对 KB 有 read 权限;仅 JWT。查询参数同上(`after_id/limit/action/outcome/actor`)。注册于 `RegisterKnowledgeBaseActivityRoutes`。
响应:200 `{"success":true,"data":[AuditLog],"next_cursor":N}`
```bash
curl $BASE/api/v1/knowledge-bases/kb-1/activity -H "Authorization: Bearer $TOKEN"
```