Files
Cyrene/docs/api/gateway-api.md
T
AskaEth 6ef9e082a6 feat: 语音流式输入管线 + VAD前端集成 + 插件-工具合并清理
- 前端: VAD语音检测(@ricky0123/vad-web) + useVoiceInput双模式(流式WS/REST)
- Gateway: VoiceStreamManager代理WS流式STT到voice-service
- Voice-service: DashScope REST → Realtime WS → Whisper三级引擎 + ffmpeg转码
- 共享模块: pkg/audio(音频转换) + pkg/dashscope(ASR REST客户端)
- 清理: 移除旧plugin-manager和pkg/plugins,完成插件→工具合并
- 文档: 完善gateway-api.md和voice-service.md语音API文档
- 工具: scripts/voice/ 语音转换脚本集

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 11:50:40 +08:00

34 KiB
Raw Blame History

Cyrene Gateway API 文档

版本: v1 | Base URL: http://<gateway-host>:<port>/api/v1

所有需要认证的接口在 HTTP Header 中携带 JWT

Authorization: Bearer <jwt_token>

WebSocket 通过 query 参数传 token/ws/chat?token=<jwt_token>


目录

  1. 认证
  2. WebSocket 实时通信
  3. 会话管理
  4. 消息搜索
  5. 语音 STT / TTS
  6. 文件管理
  7. 图片分析
  8. 知识库
  9. 记忆管理
  10. 自动化规则与场景
  11. 通知推送
  12. 提醒管理
  13. Webhook 第三方接入
  14. Admin 管理
  15. 健康检查

1. 认证

POST /auth/register — 注册

Auth: 无。IP 限流 ~5/min。仅 REGISTRATION_ENABLED=true 时可用(默认关闭)。

// 请求
{
  "username": "string (3-32 chars, ^[a-zA-Z0-9_]+$)",
  "password": "string (6-64 chars)",
  "email": "string (需含 @)",
  "nickname": "string (1-32 chars)",
  "verify_code": "string (6 chars, 开发阶段固定 000000)"
}

// 响应 201
{
  "user_id": "user_<username>",
  "token": "JWT",
  "refresh_token": "JWT (30天)",
  "expires": 1717000000,
  "nickname": "string"
}

错误: 400 用户名格式无效, 400 邮箱格式无效, 400 验证码错误, 403 当前不开放公开注册, 409 用户名已被注册


POST /auth/login — 登录

Auth: 无。IP 限流 ~5/min。

管理员始终通过 .env 中的 ADMIN_USERNAME / ADMIN_PASSWORD 验证,不依赖数据库状态。普通用户通过数据库 bcrypt 密码哈希验证。

// 请求
{
  "username": "string",
  "password": "string"
}

// 响应 200
{
  "user_id": "admin",          // admin 用户固定为 "admin",普通用户为 "user_<username>"
  "nickname": "string",
  "token": "JWT",
  "refresh_token": "JWT (30天)",
  "expires": 1717000000
}

错误: 400 用户名格式无效, 401 用户名或密码错误


POST /auth/refresh — 刷新 Token

Auth: JWT(可接受已过期的 token,或在 body 中提供 refresh_token)。

// 请求(可选)
{ "refresh_token": "string" }

// 响应 200
{
  "token": "新 JWT",
  "refresh_token": "新 JWT (30天)",
  "expires": 1717000000
}

错误: 401 刷新令牌无效或已过期, 401 未提供认证令牌


GET /profile — 查询当前用户

Auth: JWT。根据 token 返回当前登录用户的信息。

// 响应 200 (管理员)
{
  "user_id": "admin",
  "username": "admin",
  "nickname": "管理员",
  "is_admin": true,
  "created_at": "2026-01-01T00:00:00Z"
}

// 响应 200 (普通用户)
{
  "user_id": "user_alice",
  "username": "alice",
  "nickname": "Alice",
  "is_admin": false,
  "created_at": "2026-01-01T00:00:00Z"
}
字段 类型 说明
user_id string 用户 IDadmin 为 "admin",普通用户为 "user_<username>"
username string 用户名(管理员为 .env 中配置的 ADMIN_USERNAME
nickname string 显示昵称
is_admin bool 是否管理员
created_at string 注册时间 (RFC3339),数据库不可用时为 null

错误: 401 未提供认证令牌, 404 用户不存在


2. WebSocket 实时通信

GET /ws/chat — 建立连接

ws://<gateway>/ws/chat?token=<jwt>&session_id=<optional>&client_id=<optional>&device_name=<optional>
Query 参数 必填 说明
token 是* JWT(也可用 Authorization: Bearer header
session_id 不传自动生成 session_ + 12 随机字符
client_id 多端标识
device_name 设备名

注意:WebSocket 仅限 admin 用户;非 admin 收到 403


客户端 → 服务端 (ClientMessage)

{
  "type": "message|voice_input|voice_stream_start|voice_stream_chunk|voice_stream_end|ping|history",
  "session_id": "string (可选)",
  "mode": "text|voice_msg|voice_assistant",
  "content": "string (纯图片消息可留空,文字+图片时填写提问内容)",
  "audio_data": "string (voice_input / voice_stream_chunk 类型必填, base64)",
  "format": "string (voice_stream_start 可选, 音频格式: webm, wav, pcm, opus; 默认 webm)",
  "language": "string (voice_stream_start 可选, 识别语言: zh, en, ja, ko, auto; 默认 zh)",
  "sequence": 0,
  "attachments": [
    {
      "type": "image",
      "url": "string (base64 data URI, 旧格式, 向后兼容)",
      "file_id": "string (文件 UUID, 新格式推荐, 配合 POST /files/upload 使用)",
      "thumbnail_url": "string (缩略图 URL, 跨设备同步友好)",
      "filename": "string",
      "width": 0,
      "height": 0,
      "size": 0,
      "description": "string"
    }
  ],

图片附件两种格式

  • 旧格式 (url): base64 data URI,直接内嵌于 WebSocket 消息中,简单但不适合跨设备同步。
  • 新格式(推荐) (file_id): 先通过 POST /api/v1/files/upload 上传图片获取 file_idthumbnail_url,消息中只携带轻量引用。Gateway 自动解析为本地文件 URL 传给 AI-Core。
  "timestamp": 1717000000000,
  "client_id": "string",
  "device_name": "string",
  "user_agent": "string",
  "client_msg_id": "string"
}
type 说明
message 文字聊天,触发 AI 回复
voice_input 语音输入(完整音频),先转录再作为 message 处理
voice_stream_start 开启流式语音会话,Gateway 连接 Voice-Service 流式 STT
voice_stream_chunk 流式语音音频分片 (base64)Gateway 转发至 Voice-Service
voice_stream_end 结束流式语音,等待最终识别结果,自动触发 LLM 回复
ping 心跳,自动回复 pong
history 请求历史消息

服务端 → 客户端 (ServerMessage)

{
  "type": "string (见下表)",
  "message_id": "string",
  "text": "string (完整文本)",
  "content": "string (增量文本/完整内容)",
  "role": "user|assistant|action|system",
  "msg_type": "chat|action|thinking|tool_progress|system_info|markdown|code (后端始终填充,前端无需自行解析)",
  "session_id": "string",
  "error": "string (仅错误时)",
  "timestamp": 1717000000000,
  "segments": [ { "index": 0, "text": "string", "audio_url": "string", "duration_ms": 0 } ],
  "messages": [ Message ],
  "thinking_status": "string",
  "thinking_content": "string",
  "tool_progress": { "tool_name": "string", "status": "started|running|completed|failed", "progress": 0.5, "message": "string" },
  "system_info": { "level": "info|warning|error", "message": "string", "action": "string" },
  "notification": { "id": "string", "type": "info|warning|success|thinking|reminder", "title": "string", "body": "string", "timestamp": "string", "data": {} },
  "multi_message": { "messages": [ { "index": 0, "content": "string", "msg_type": "chat|action|system_info" } ] },
  "review_messages": [ { "type": "action|chat|markdown|code|search_result", "content": "string", "delay_ms": 0, "metadata": { "language": "string (code 类型时)", "url": "string (search_result 类型时)" } } ],
  "client_info": { "client_id": "string", "device_name": "string", "user_agent": "string" },
  "full_audio_url": "string",
  "response_mode": "string"
}

ServerMessage type 列表

type 说明
response 完整文本回复
stream_start AI 开始生成
stream_chunk 增量文本块
stream_end AI 生成结束(含完整 text
stream_segments 流式断句(语音)
voice_transcript 语音转录结果 (非流式, voice_input)
voice_interim 流式语音中间识别结果
voice_final 流式语音最终识别文本
error 错误
history_response 历史消息返回
notification 推送通知
multi_message 多条消息合并投递
review 审查后结构化消息
thinking 后台思考更新
tool_progress 工具执行进度
system_info 系统级通知
pong 响应 ping
device_update IoT 设备状态更新
background_thinking 后台思考状态变更
queued 消息已加入处理队列(会话繁忙时)

广播机制:服务端推送分为两类:

  • 用户消息回显type: "response", role: "user"):通过 SendToUserExcept 广播,排除发送者自身(发送者本地已渲染),仅同步到同用户的其他设备。
  • AI 回复消息stream_startstream_endresponse/reviewmulti_messagestream_segmentsrole: "assistant" 的消息):通过 SendToUser 广播给所有设备,包括发送者。

消息类型分类 (msg_type):所有 responsemulti_messagehistory_responsestream_chunkthinkingtool_progresssystem_info 类型的服务端消息中,msg_type 字段均由后端自动分类填充,前端只需直接读取 msg_type 并据此渲染,无需解析消息内容来猜测类型。

msg_type 可选值:

  • chat — 普通聊天消息
  • action — 动作/旁白消息(如 <action>昔涟轻轻推开窗户</action>),前端以斜体灰色样式渲染
  • markdown — Markdown 格式消息,前端使用安全渲染器转换后显示(支持标题、列表、表格、代码块、链接等)
  • code — 独立代码块消息,前端以深色背景 + 语言标签渲染,可包含 metadata.language 指明编程语言
  • thinking — 后台思考过程,前端显示为可折叠详情块
  • tool_progress — 工具执行进度,前端显示进度条
  • system_info — 系统通知,前端居中显示为 toast 样式

review 消息类型详情:

当 AI 回复包含多种格式内容(如工具调用结果中的 Markdown 文档或代码片段)时,后端解析器将回复拆分为多条 review_messages,每条独立指定 typecontent

  • action — 动作/旁白文本,由 <action>...</action> XML 标签标记(向后兼容旧括号 ()() 格式),不做 Markdown 渲染,禁止断句拆分
  • chat — 普通聊天文本,可按句长断句
  • markdown — Markdown 格式文本,禁止断句拆分,前端使用安全渲染器(先 HTML 转义再转换 Markdown 语法)
  • code — 代码块,禁止断句拆分,前端深色背景渲染,metadata.language 字段携带语言标识
  • search_result — 搜索工具调用结果摘要(后端内部使用,通常转为 markdownchat 类型展示)

Markdown 渲染器支持语法:标题 (h1-h6)、粗体/斜体、行内代码/围栏代码块、链接、图片、无序/有序列表、引用块、表格、水平线。


流式响应流程

Client                    Gateway                    AI-Core
  |                          |                          |
  |-- {type:"message"} -->   |                          |
  |                          |-- POST /api/v1/chat -->  |
  |                          |   (SSE streaming)        |
  |                          |<-- data: {delta:"..."}   |
  |<-- {type:"stream_start"} |                          |
  |<-- {type:"review"}       | (多条结构化消息)           |
  |<-- {type:"stream_segments"} | (断句事件)             |
  |<-- {type:"stream_end"}   | (含 full text)           |

消息排队机制

同一会话的消息处理为串行化队列。若上一轮 AI 回复尚未完成时用户发送新消息,新消息会加入等待队列,并在当前处理完成后自动消费。

Client                              Gateway
  |                                    |
  |-- msg1 (type:"message") -->        |
  |<-- {type:"stream_start"}          |  → AI-Core 处理中...
  |                                    |
  |-- msg2 (type:"message") -->        |
  |<-- {type:"queued"}                |  → 加入队列等待
  |                                    |
  |<-- {type:"stream_end"} (msg1)     |  → msg1 完成
  |<-- {type:"stream_start"} (msg2)   |  → 自动取出 msg2 处理
  |<-- ...                            |
  |<-- {type:"stream_end"} (msg2)     |

queued 消息表明用户消息已接收但尚未开始处理,客户端可据此显示"排队中"状态。


语音输入流程 (非流式)

Client                           Gateway                       Voice-Service
  |                                 |                               |
  |-- {type:"voice_input",         |                               |
  |    audio_data:"<base64>"} -->   |                               |
  |                                 |-- POST /transcribe -->        |
  |                                 |<-- {text:"..."}              |
  |<-- {type:"voice_transcript",   |                               |
  |     text:"转录结果"}            |                               |
  |                                 |                               |
  |   (Gateway 自动将转录文本       |                               |
  |    作为 message 发给 AI-Core)    |                               |
  |<-- {type:"stream_start"}       |                               |
  |<-- ... 正常流式回复 ...         |                               |

注意: voice_input 为非流式模式,客户端发送完整音频后一次性获取转录结果。适合 MediaRecorder 录音完成后使用。 推荐使用下方的流式语音输入,配合前端 VAD 实现边说边识别。


流式语音输入流程 (voice_stream_*)

配合前端 VAD (Voice Activity Detection) 实现自动语音检测和边说边识别。前端逐帧发送音频分片,Gateway 通过 WebSocket 代理到 Voice-Service 流式 STT,实时返回中间结果。

Client                                Gateway                          Voice-Service
  |                                      |                                   |
  |-- {type:"voice_stream_start",       |                                   |
  |    format:"webm", language:"zh"} --> |                                   |
  |                                      |-- WS /api/v1/stt/stream --------> |
  |                                      |<-- session ready                  |
  |<-- {type:"voice_interim", text:""}  |                                   |
  |                                      |                                   |
  |-- {type:"voice_stream_chunk",       |                                   |
  |    audio_data:"<base64>",           |                                   |
  |    sequence:0} ------------------>   |                                   |
  |                                      |-- binary audio frame ---------->  |
  |                                      |<-- {type:"result",                |
  |                                      |     text:"你好", isFinal:false}   |
  |<-- {type:"voice_interim",           |                                   |
  |     text:"你好"}                     |                                   |
  |                                      |                                   |
  |-- ... more chunks ...               |                                   |
  |                                      |                                   |
  |-- {type:"voice_stream_end"} ----->   |                                   |
  |                                      |-- {action:"stop"} --------------> |
  |                                      |<-- {type:"result",                |
  |                                      |     text:"你好世界", isFinal:true}|
  |<-- {type:"voice_final",             |                                   |
  |     text:"你好世界"}                 |                                   |
  |                                      |                                   |
  |   (Gateway 自动将最终文本           |                                   |
  |    作为 message 发给 AI-Core)        |                                   |
  |<-- {type:"stream_start"}            |                                   |
  |<-- ... 正常流式 LLM 回复 ...         |                                   |

消息详情:

voice_stream_start — 开启流式语音会话

{
  "type": "voice_stream_start",
  "format": "webm",
  "language": "zh"
}
字段 类型 必填 说明
format string 音频格式,默认 "webm"。支持: webm, wav, pcm, opus
language string 识别语言,默认 "zh"。支持: zh, en, ja, ko, auto

Gateway 收到后连接 Voice-Service 流式 STT WebSocket。成功时返回空 voice_interim 确认会话建立;失败返回 error

voice_stream_chunk — 发送音频分片

{
  "type": "voice_stream_chunk",
  "audio_data": "<base64 encoded audio>",
  "sequence": 0
}
字段 类型 必填 说明
audio_data string Base64 编码的音频数据
sequence int 分片序号,从 0 递增,用于排序和去重

Gateway 将 audio_data 解码后以 binary 帧转发至 Voice-Service。无直接响应;识别结果通过 voice_interim 异步推送。

voice_stream_end — 结束流式语音

{
  "type": "voice_stream_end"
}

Gateway 向 Voice-Service 发送 stop 信号,等待最终识别结果。最终文本通过 voice_final 返回,并自动触发 LLM 回复流程。

voice_interim — 中间识别结果 (Server → Client)

{
  "type": "voice_interim",
  "message_id": "voice_<random>",
  "text": "中间识别文本",
  "timestamp": 1717000000000
}
字段 说明
text 当前累积的识别文本,非最终结果,会随更多音频输入而更新

前端处理: 收到 voice_interim 后应在 UI 中展示实时识别文本(如灰色斜体),收到 voice_final 后替换为最终文本。

voice_final — 最终识别结果 (Server → Client)

{
  "type": "voice_final",
  "message_id": "voice_<random>",
  "text": "最终识别文本",
  "timestamp": 1717000000000
}
字段 说明
text 最终的完整识别文本。空字符串表示未识别到语音

收到 voice_final 后,Gateway 自动将 text 作为 message 类型转发至 AI-Core 触发 LLM 流式回复。随后的 stream_start / review / stream_end 流程与普通文字消息相同。


3. 会话管理

所有接口需要 JWT。Admin 可操作所有用户;非 admin 仅限自己的数据。

POST /sessions — 创建会话

// 请求 (全部可选,空 body 也可)
{
  "session_id": "string (可选,不传自动生成)",
  "title": "string (默认 '新的对话')",
  "is_main": false
}

// 响应 201
{
  "id": "string",
  "user_id": "string",
  "title": "string",
  "is_main": false,
  "created_at": 1717000000000,
  "updated_at": 1717000000000
}

GET /sessions — 列表

?user_id=xxx — admin 可查任意用户;非 admin 只能查自己。

// 响应 200
{ "sessions": [ Session, ... ] }

GET /sessions/:id — 详情

同 Session 结构。

错误: 404 {"error":"会话不存在","errorType":"session_not_found","hint":"该会话可能已被删除或尚未创建"}

DELETE /sessions/:id — 删除

{"status":"deleted"}

DELETE /sessions — 清空全部

?user_id=xxx{"status":"deleted"}

GET /sessions/:id/messages — 消息

?limit=50&offset=0

// 响应 200
{
  "messages": [
    {
      "id": 1,
      "session_id": "string",
      "role": "user|assistant|system|action",
      "msg_type": "chat|action|markdown|code",
      "content": "string",
      "created_at": 1717000000000
    }
  ]
}

DELETE /sessions/:id/messages — 清空服务器本地所有消息

{"status":"cleared"}

GET /sessions/:id/export — 导出

?format=json|markdown|txt(默认 json

返回文件下载。JSON 导出格式:

{
  "session": { "id", "title", "created_at", "updated_at" },
  "messages": [ { "role", "content", "created_at" } ]
}

4. 消息搜索

GET /messages/search — 全文搜索

?q=<keyword>&user_id=xxx&limit=50&offset=0

// 响应 200
{
  "results": [
    {
      "message_id": "string",
      "session_id": "string",
      "session_title": "string",
      "role": "string",
      "content": "string",
      "created_at": 1717000000000
    }
  ],
  "total": 10,
  "query": "keyword",
  "limit": 50,
  "offset": 0
}

5. 语音 STT / TTS

POST /voice/transcribe — 语音转文字

Content-Type: multipart/form-data。字段 audio (file)。最大 10MB。接受 PCM/WAV/MP3/OGG/FLAC/WebM 等格式。

// 响应 200
{ "success": true, "text": "识别结果文本" }

// 错误
{ "success": false, "error": "语音识别失败: ..." }

POST /voice/tts — 文字转语音

Content-Type: application/json

代理到 Voice-Service POST /api/v1/tts/synthesize

GET /voice/tts/voices — 发音人列表

代理到 Voice-Service GET /api/v1/tts/voices

GET /voice/tts/status — TTS 状态

GET /voice/status — 语音服务完整状态 (STT + TTS)

Voice-Service 不可达时返回 502

{"error":"Voice-Service 不可达: ...","errorType":"voice_service_unreachable"}

6. 文件管理

POST /files/upload — 上传

Content-Type: multipart/form-data。字段 file。最大 20MB。

允许 MIME 类型:image/jpeg,png,gif,webp,svg+xml | application/pdf,msword,vnd.openxmlformats-officedocument.wordprocessingml.document | text/plain,markdown | audio/mpeg,wav,ogg,webm | video/mp4,webm

// 响应 201
{
  "id": "uuid",
  "filename": "string (脱敏后)",
  "mime_type": "string",
  "size": 1024,
  "url": "/api/v1/files/<id>/download"
}

错误: 400 {"error":"文件大小超过限制 (最大 20MB)","errorType":"file_too_large"}, 400 {"error":"不支持的文件类型: ...","errorType":"unsupported_type"}

文件在 AI 对话中的传递链路(推荐新流程)

  1. 客户端先调用 POST /api/v1/files/upload 上传图片,获得 file_idthumbnail_url
  2. 客户端发送消息时,attachments 中携带 file_id(轻量引用,不再内嵌 base64
  3. Gateway 收到 file_id 后,从 FileStore 解析为本地下载 URLhttp://127.0.0.1:{port}/api/v1/files/{id}/download
  4. AI-Core 下载该 URL 并转为 base64 data URL,以多模态格式传给外部 LLM API

向后兼容attachments[].url 仍支持 base64 data URI或相对路径,Gateway 会将相对路径补全为绝对 URL。

GET /files — 列表

?page=1&limit=20

// 响应 200
{
  "files": [
    {
      "id": "uuid", "user_id": "string", "filename": "string",
      "mime_type": "string", "size": 1024, "hash": "sha256hex",
      "is_public": false, "created_at": 1717000000000,
      "url": "string", "thumbnail_url": "string (仅图片)"
    }
  ],
  "total": 100, "page": 1, "limit": 20
}

GET /files/:id — 元数据

返回单个 File 对象。

GET /files/:id/download — 下载

文件流下载。404 → {"error":"文件实体不存在(可能已被清理)","errorType":"file_missing"}

GET /files/:id/thumbnail — 缩略图

图片:JPEG 缩略图 (max 300x300)。非图片:SVG 占位图标。Cache-Control: public, max-age=86400

DELETE /files/:id — 删除

{"status":"deleted"}


7. 图片分析

POST /images/analyze — 分析

两种方式:

  • JSON: {"file_id": "uuid"} — 分析已上传文件
  • Multipart: 字段 fileimage — 直接上传分析 (max 10MB),支持 JPEG/PNG/GIF
// 响应 200
{
  "format": "jpeg",
  "width": 1920,
  "height": 1080,
  "file_size": 204800,
  "description": "AI 生成的图片描述",
  "top_colors": [ { "hex": "#4A90D9", "percent": 35.2 } ],
  "exif": { "Make": "Canon" },
  "analyzed_by": "openai_vision|local"
}

GET /images/analyze/:file_id — 按已上传文件分析

同上。


8. 知识库

POST /knowledge/bases — 创建知识库

// 请求
{
  "name": "string (必填)",
  "description": "string"
}

// 响应 201
{
  "id": "uuid", "user_id": "string", "name": "string",
  "description": "string", "created_at": "...", "updated_at": "...", "doc_count": 0
}

GET /knowledge/bases — 列表

{ "knowledge_bases": [ KnowledgeBase ], "total": 10 }

GET /knowledge/bases/:id — 详情(含文档列表)

{ "knowledge_base": KnowledgeBase, "documents": [ KnowledgeDocument ] }

PUT /knowledge/bases/:id — 更新

{ "name": "string (必填)", "description": "string" }
 { "status": "updated" }

DELETE /knowledge/bases/:id — 删除

{"status":"deleted"}


POST /knowledge/bases/:id/documents — 添加文档

// 请求
{
  "title": "string (必填)",
  "content": "string (text 类型时)",
  "source_type": "text|file|url (默认 text)",
  "file_id": "string (file 类型必填)"
}

// 响应 201
{
  "id": "uuid", "kb_id": "string", "user_id": "string",
  "title": "string", "source_type": "string", "source_ref": "string",
  "content_type": "string", "raw_content": "string",
  "chunk_count": 5, "created_at": "...", "updated_at": "..."
}

注意:source_type=file 时 gateway 读取文件内容(仅支持文本类型和 application/json)。

GET /knowledge/bases/:id/documents — 文档列表

{"documents": [ KnowledgeDocument ], "total": 10}

GET /knowledge/documents/:id — 文档详情(含分块)

{
  "document": KnowledgeDocument,
  "chunks": [ KnowledgeChunk ]
}

DELETE /knowledge/documents/:id — 删除

{"status":"deleted"}


POST /knowledge/search — 语义搜索

// 请求
{
  "query": "string (必填)",
  "kb_ids": ["uuid"],  // 可选,空=搜索全部
  "limit": 5           // 1-50
}

// 响应 200
{
  "chunks": [ SearchChunkResult ],
  "total": 5,
  "query": "string"
}

9. 记忆管理

代理到 Memory-Service。

GET /memory/search — 搜索

?q=<keyword>&user_id=xxx → 代理到 Memory-Service POST /memories/query

GET /memory — 列表

?user_id=xxx → 代理到 Memory-Service GET /memories

POST /memory — 添加

{
  "content": "string (必填)",
  "category": "string (默认 other)",
  "priority": 1
}

DELETE /memory — 删除

?id=<memory_id>

Memory-Service 不可达时返回 502

{"error":"Memory-Service 不可达: ...","errorType":"memory_service_unreachable"}

10. 自动化规则与场景

规则

GET /automation/rules — 列表

{
  "rules": [
    {
      "id": "32位hex", "user_id": "string", "name": "string",
      "description": "string", "trigger_type": "string",
      "trigger_config": {}, "conditions": {}, "actions": {},
      "enabled": true, "created_at": "..."
    }
  ],
  "count": 5
}

POST /automation/rules — 创建

// 请求
{
  "name": "string (必填)",
  "description": "string",
  "trigger_type": "string (必填)",
  "trigger_config": {},
  "conditions": {},
  "actions": {} (必填),
  "enabled": true
}

// 响应 201 → {"success": true, "rule": Rule}

GET /automation/rules/:id — 详情

{"rule": Rule} | 404 → {"error":"规则不存在"}

PUT /automation/rules/:id — 更新

所有字段可选(partial update)。{"success": true, "rule": Rule}

DELETE /automation/rules/:id — 删除

{"success": true}

POST /automation/rules/:id/trigger — 手动触发

{"success": true, "message": "规则已触发"}


场景

GET /automation/scenes — 列表

{"scenes": [ Scene ], "count": 5}

POST /automation/scenes — 创建

{
  "name": "string (必填)",
  "icon": "string",
  "rule_ids": ["rule_id_1", "rule_id_2"]
}
 {"success": true, "scene": Scene}

GET /automation/scenes/:id — 详情

{"scene": Scene}

PUT /automation/scenes/:id — 更新

所有字段可选。{"success": true, "scene": Scene}

DELETE /automation/scenes/:id — 删除

{"success": true}

POST /automation/scenes/:id/execute — 执行

{"success": true, "message": "场景已执行"}


11. 通知推送

POST /notifications/push — 推送通知

// 请求
{
  "user_id": "string (必填)",
  "type": "info|warning|success|thinking|reminder (必填)",
  "title": "string (必填)",
  "body": "string (必填)",
  "data": {}
}

// 响应 200
{
  "success": true,
  "notification": {
    "id": "uuid",
    "type": "info",
    "title": "...",
    "user_id": "...",
    "timestamp": "2024-01-01T12:00:00Z",
    "delivered": true
  }
}

delivered = true 表示目标用户有活跃 WebSocket 连接。


12. 提醒管理

GET /reminders — 列表

?user_id=xxx&status=pending|completed|cancelled&limit=50&offset=0

// 响应 200
{
  "reminders": [
    {
      "id": "string", "user_id": "string", "title": "string",
      "description": "string", "remind_at": "2024-01-01T15:00:00Z",
      "status": "pending",
      "repeat_type": "none|daily|weekly|monthly",
      "session_id": "string", "notified": false,
      "created_at": "...", "completed_at": null
    }
  ],
  "count": 5
}

POST /reminders — 创建

// 请求
{
  "title": "string (必填)",
  "description": "string",
  "remind_at": "2024-01-01T15:00:00Z (必填, ISO 8601)",
  "repeat_type": "none|daily|weekly|monthly (默认 none)",
  "session_id": "string"
}

// 响应 201
{ "success": true, "reminder": Reminder }

错误: 400 {"error":"时间格式无效,请使用 ISO 8601 格式 (例如 2024-01-01T15:00:00Z)"}

PUT /reminders/:id — 更新

所有字段可选 (partial update)。设置 status=completed|cancelled 会自动写入 completed_at

{"success":true, "reminder":Reminder} | 404 {"error":"提醒不存在"}

DELETE /reminders/:id — 删除

{"success":true}


13. Webhook 第三方接入

Auth: X-Webhook-Key header。

POST /webhook/generic — 通用 Webhook

// 请求
{
  "message": "string (必填)",
  "user_id": "string (默认 webhook_generic,自动加 ext_ 前缀)",
  "session_id": "string (默认 webhook_ + 12 随机字符)",
  "mode": "text|voice_msg (默认 text)",
  "platform": "string (默认 generic)"
}

// 响应 200
{
  "reply": "AI 回复文本",
  "session_id": "string",
  "message_id": "string",
  "finish_reason": "stop"
}

错误: 400 {"error":"消息不能为空"}, 502 {"error":"AI 服务暂不可用: ..."}

POST /webhook/discord — Discord 交互

接收标准 Discord Interaction

  • type=1 (PING) → {"type":1}
  • type=2 (APPLICATION_COMMAND) → 处理 /chat message: 命令
// 响应 200
{ "type": 4, "data": { "content": "AI 回复" } }

14. Admin 管理

需要 JWT + admin 权限(user_id == "admin")。非 admin 返回 403

会话管理

GET /admin/sessions — 活跃会话列表

{ "sessions": [ SessionState ], "total": 5 }

GET /admin/sessions/active — 按用户分组

{ "users": { "user_id": [ SessionState ] } }

GET /admin/sessions/:id — 指定会话详情

404 → {"error":"会话不存在","errorType":"session_not_found"}


客户端管理

GET /admin/clients — 已知客户端

?user_id=admin

{
  "clients": [
    {
      "client_id": "string", "device_name": "string",
      "user_agent": "string", "note": "string",
      "last_seen": 1717000000000, "online": true
    }
  ],
  "total": 3
}

PUT /admin/clients/:id/note — 设置备注

{ "note": "string" }
 { "status": "ok", "client_id": "string", "note": "string" }

404 → {"error":"客户端未找到"}


模型配置管理

GET /admin/models/providers — Provider 列表

{
  "providers": [
    { "name": "string", "base_url": "string", "api_key": "string" }
  ],
  "total": 2
}

POST /admin/models/providers/:name — 创建/更新 Provider

{ "name": "...", "base_url": "...", "api_key": "..." }
 { "status": "saved", "name": "string" }

DELETE /admin/models/providers/:name — 删除

{"status":"deleted","name":"string"}

GET /admin/models/models — Model 列表

{
  "models": [
    {
      "id": "string", "name": "string", "provider": "string",
      "description": "string", "priority": 1, "tags": [],
      "params": { "temperature": 0.7 }, "enabled": true,
      "updated_at": "..."
    }
  ],
  "total": 5
}

POST /admin/models/models/:id — 创建/更新 Model

{ "id": "...", "name": "...", "provider": "...", "params": {}, ... }
 { "status": "saved", "id": "string" }

DELETE /admin/models/models/:id — 删除

{"status":"deleted","id":"string"}

GET /admin/models/routing — 路由规则列表

POST /admin/models/routing/:purpose — 创建/更新路由规则

{ "purpose": "...", "fallback_chain": ["model1", "model2"], "required": true }
 { "status": "saved", "purpose": "string" }

DELETE /admin/models/routing/:purpose — 删除

POST /admin/models/health-check — 测试 Provider 连接

{ "provider": "string (必填)" }
 { "provider": "string", "message": "Provider 配置已保存,连接测试请通过实际 LLM 调用验证" }

GET /admin/models/fetch-models/:name — 代理获取远程模型列表

?url=<provider_models_api_url> → 返回该 Provider 支持的模型列表。


15. 健康检查

GET /health — 健康检查

Auth: 无。

{
  "status": "ok",
  "service": "cyrene-gateway",
  "ws_connections": 3
}

附录:错误格式

所有 API 错误统一为:

{
  "error": "错误描述",
  "errorType": "error_code (可选,客户端可据此判断)",
  "hint": "解决建议 (可选)"
}

errorType 列表

errorType 含义
session_not_found 会话不存在
file_too_large 文件超过大小限制
unsupported_type 不支持的 MIME 类型
file_missing 文件实体已清理
memory_service_unreachable Memory-Service 不可达
voice_service_unreachable Voice-Service 不可达
admin_only 仅限管理员操作

HTTP 状态码

状态码 场景
200 成功
201 创建成功
400 请求参数错误
401 未认证 / Token 无效
403 无权限
404 资源不存在
409 资源冲突 (如用户名已存在)
413 请求体过大
502 下游服务不可达