- 添加会话归档接口及相关服务逻辑,并确保幂等性 - 实现单条消息获取接口,校验消息所属会话 - 增加 SSE 增量推送与实时消息订阅功能 - 提供相关的测试用例覆盖新功能 - 更新接口文档,完善 OpenAPI 规范,新增多项示例
7.2 KiB
7.2 KiB
ChatSession & Message API(MVP-1)
基地址:http://localhost:8000/api(FrankenPHP 容器 8000 端口)
认证方式:JWT,Authorization: Bearer {token}
自然语言:中文
变更记录
- 2025-02-14:新增 ChatSession 创建、消息追加、增量查询接口;支持状态门禁与 dedupe 幂等。
- 2025-02-14:MVP-1.1 增加会话列表、会话更新(重命名/状态变更),列表附带最后一条消息摘要。
领域模型
ChatSession:session_id(UUID)、session_name、status(OPEN/LOCKED/CLOSED)、last_seqMessage:message_id(UUID)、session_id、role(USER/AGENT/TOOL/SYSTEM)、type(字符串)、content、payload(json)、seq(会话内递增)、reply_to(UUID)、dedupe_key- 幂等:
UNIQUE (session_id, dedupe_key);同一 dedupe_key 返回已有消息。 - 状态门禁:
CLOSED禁止追加,例外role=SYSTEM && type in [run.status, error];LOCKED禁止role=USER && type=user.prompt。 - 会话缓存:
chat_sessions.last_message_id记录最后一条消息;appendMessage事务内同步更新last_seq、last_message_id、updated_at。
接口
创建会话
POST /sessions- 请求体字段
字段 必填 类型 说明 session_name 否 string(≤255) 会话名称 - 响应 201(JSON)
字段 类型 说明 session_id uuid 主键 session_name string null status enum `OPEN last_seq int 当前最大 seq last_message_id uuid null created_at, updated_at datetime 时间戳 - 错误:401 未授权
追加消息
POST /sessions/{session_id}/messages- 请求体字段
字段 必填 类型 说明 role 是 enum `USER type 是 string(≤64) 如 user.prompt/agent.message等content 否 string 文本内容 payload 否 object jsonb 结构 reply_to 否 uuid 引用消息 dedupe_key 否 string(≤128) 幂等键 - 响应 201(JSON)
字段:message_id, session_id, seq, role, type, content, payload, reply_to, dedupe_key, created_at - 幂等:同 session + dedupe_key 返回已存在的消息(同
message_id/seq)。 - 错误:401 未授权;403 违反状态门禁(CLOSED 禁止,LOCKED 禁止 user.prompt);404 session 不存在;422 校验失败。
按序增量查询
GET /sessions/{session_id}/messages?after_seq=0&limit=50- 查询参数
参数 默认 类型 说明 after_seq 0 int 仅返回 seq 大于该值 limit 50 int(≤200) 返回数量上限 - 响应 200:
data数组,元素字段同“追加消息”响应。 - 错误:401/404/422
会话列表
GET /sessions?page=1&per_page=15&status=OPEN&q=keyword- 查询参数
参数 默认 类型 说明 page 1 int 分页页码 per_page 15 int(≤100) 分页大小 status - enum 过滤 `OPEN q - string ILIKE 模糊匹配 session_name - 响应 200:分页结构(
data/links/meta),data每项字段:字段 类型 说明 session_id uuid 会话主键 session_name string null status enum `OPEN last_seq int 当前最大 seq last_message_id uuid null last_message_at datetime null last_message_preview string content 截断 120,空内容返回空字符串 last_message_role string null last_message_type string null created_at, updated_at datetime 时间戳 - 排序:
updated_atDESC - 错误:401/422
会话更新
PATCH /sessions/{session_id}- 请求体(至少一项,否则 422)
字段 必填 类型 说明 session_name 否 string 1..255 自动 trim status 否 enum `OPEN - 规则:
CLOSED不可改回OPEN(返回 403)。- 任意更新都会刷新
updated_at。
- 响应 200:字段同“会话列表”项。
- 错误:401 未授权;403 状态门禁;404 session 不存在;422 校验失败。
获取会话详情
GET /sessions/{session_id}- 响应 200:字段同“会话列表”项。
- 错误:401 未授权;404 session 不存在。
归档会话(Archive)
POST /sessions/{session_id}/archive- 行为:将
status置为CLOSED,更新updated_at,幂等(重复归档返回当前状态)。 - 响应 200:字段同“会话列表”项(status=CLOSED)。
- 错误:401 未授权;404 session 不存在。
获取单条消息(带会话校验)
GET /sessions/{session_id}/messages/{message_id}- 行为:校验
message.session_id与路径参数一致,否则 404。 - 响应 200:字段同“追加消息”响应。
- 错误:401 未授权;404 不存在或不属于该会话。
SSE 实时增量
GET /sessions/{session_id}/sse?after_seq=123- 头部:
Accept: text/event-stream,可带Last-Event-ID(优先于 query)用于断线续传。 - 查询参数
参数 默认 类型 说明 after_seq 0 int backlog 起始 seq(若有 Last-Event-ID 则覆盖) limit 200 int(≤500) backlog 最多条数 - SSE 输出格式:
id: {seq} event: message data: {...message json...}id为消息seq,便于续传;data为消息 JSON(同追加消息响应字段)。
- Backlog:建立连接后先补发
seq > after_seq的消息(order asc,最多limit条),再进入实时订阅。 - 实时:Redis channel
session:{session_id}:messages发布消息 ID,SSE 侧读取后按 seq 去重、推送。 - 心跳:周期输出
: ping保活(生产环境)。 - 错误:401 未授权;404 session 不存在。
cURL 示例
# 创建会话
SESSION_ID=$(curl -s -X POST http://localhost:8000/api/sessions \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"session_name":"Demo"}' | jq -r '.data.session_id')
# 追加消息(支持 dedupe_key 幂等)
curl -s -X POST http://localhost:8000/api/sessions/$SESSION_ID/messages \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"role":"USER","type":"user.prompt","content":"hello","dedupe_key":"k1"}'
# 增量查询
curl -s "http://localhost:8000/api/sessions/$SESSION_ID/messages?after_seq=0&limit=50" \
-H "Authorization: Bearer $TOKEN"
# 归档
curl -X POST http://localhost:8000/api/sessions/$SESSION_ID/archive \
-H "Authorization: Bearer $TOKEN"
# 获取单条消息
curl -s http://localhost:8000/api/sessions/$SESSION_ID/messages/{message_id} \
-H "Authorization: Bearer $TOKEN"
# SSE(断线续传:可带 Last-Event-ID)
curl -N http://localhost:8000/api/sessions/$SESSION_ID/sse?after_seq=10 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/event-stream"