标准化OpenAPI接入指南
本文档介绍如何通过标准化 OpenAPI 将搭子的核心能力接入到硬件或软件应用中。通过 OpenAPI,可接入的搭子能力包括:
- 会话与消息:创建会话、发送消息、接收流式回复、管理历史会话
- 对话交互:处理搭子的澄清问答与权限申请弹窗
- 文件:上传文件、获取会话产出物(报告、文档、图片等)
- 积分:查询余额、发放与消费流水
- Skill 管理:初始化、查询 Skill 列表与详情
- 定时任务:查询定时任务列表
- 个性化配置:定制首页 Logo、slogan 与推荐问
1 快速开始
1.1 接入总览
接入遵循以下流程:
- 申请 API Key:按 1.2 API Key 申请步骤注册账号并获取沙盒 / 线上两套 Key。
- 获取访问凭证:调用
DescribeToken获取渠道用户 Token({dumateToken}),用于后续所有接口鉴权。 - 创建会话:调用
POST /session创建会话,获得 sessionID。 - 发送消息:调用
POST /session/:sessionID/prompt_async发送用户输入。 - 接收回复:通过
GET /event(SSE)订阅实时事件,接收搭子产生的文本、工具调用、任务进度等消息。 - 管理会话:按需调用停止消息、历史会话/消息查询、文件与积分等接口。
1.2 API Key 申请步骤
API Key 是账号级凭证,所有接口均通过 Authorization: Bearer {apiKey} 携带。申请流程如下:
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1. 注册账号 | 在百度智能云注册账号 | 需提供企业或个人实名信息,用于身份核验 |
| 2. 提交入驻申请 | 请在 硬件合作申请 中提交相关信息 | 说明接入用途(如"自研 App 内搭子"),便于审核 |
| 3. 审核 | 等待服务方审核 | "申请中 → 审核通过",通过后可进入控制台创建 Key;审核驳回会说明原因 |
| 4. 创建沙盒 Key | 在控制台创建一个"沙盒环境"API Key | 用于联调环境测试(见 1.3),额度与线上隔离 |
| 5. 创建线上 Key | 审核通过后创建"线上环境"API Key | 用于生产环境,涉及真实积分扣减 |
| 6. 环境绑定 | 将两把 Key 分别用于对应环境 | 沙盒与线上 Key 不可混用;线上请求必须使用线上 Key |
说明:
- Key 创建后在控制台仅展示一次,请立即保存到安全的密钥管理位置(环境变量 / 密钥服务),不要硬编码在代码或提交到仓库。
- Key 泄露可在控制台吊销后重新创建,吊销会使对应环境所有请求鉴权失败。
{route}路由段与沙盒域名会随入驻审核通过一并提供(见 1.3)。
1.3 环境与地址
所有接口提供联调(沙盒)与线上两套环境,接入阶段请先使用沙盒环境联调,通过后切换到线上环境。
| 环境 | 标准 OpenAPI 地址 | Dispatch 服务地址 |
|---|---|---|
| 沙盒 | https://www.dumate.cn/openapi-sandbox?Action=ActionName |
域名与路由前缀由服务方在入驻时提供 |
| 线上 | https://www.dumate.cn/openapi?Action=ActionName |
https://www.dumate.cn/dispatch/{route}/... |
说明:
ActionName为接口名称,下文各接口均以Action=接口名方式调用(除 dispatch 服务外默认走标准 OpenAPI)。- Dispatch 服务地址中的
{route}为服务方分配的接入路由段,非公开通用值,接入时向服务方获取。 - 沙盒环境的 dispatch 域名与路由段由服务方在入驻时提供,本文用
{sandbox-host}/{sandboxRoute}表示;线上统一为www.dumate.cn/{route}。 - 沙盒与线上环境使用不同的 API Key,请勿混用。
1.4 请求方式与鉴权
- 请求方式:如无特别说明,默认
POST,请求体为 JSON。 - 鉴权方式:Bearer Token,所有接口均需在请求 Header 中携带
Authorization(API Key)与X-Dumate-Token(用户 Token),详见 2 鉴权。
1.5 第一个请求示例(获取 Token)
1curl -X POST 'https://www.dumate.cn/openapi?Action=DescribeToken' \
2 -H 'Authorization: Bearer {apiKey}' \
3 -H 'X-Dumate-User-Id: {X-Dumate-User-Id}' \
4 -H 'X-Dumate-Token: {dumateToken}' \
5 -H 'Content-Type: application/json'
响应:
1{
2 "token": "{dumateToken}",
3 "expired_at": "2026-07-10T13:58:49.23978Z"
4}
1.6 端到端最小示例
以下 5 步串起一次完整对话(沙盒环境,全部使用沙盒 Key 与沙盒域名)。可直接复制调试,再按 1.7 切换线上。
Step 1 获取 Token(DescribeToken)
1curl -X POST 'https://www.dumate.cn/openapi-sandbox?Action=DescribeToken' \
2 -H 'Authorization: Bearer {sandboxApiKey}' \
3 -H 'X-Dumate-User-Id: {X-Dumate-User-Id}' \
4 -H 'Content-Type: application/json'
返回 token(即 {dumateToken})。
Step 2 创建会话(POST /session)
1curl -X POST 'https://{sandbox-host}/dispatch/{sandboxRoute}/session' \
2 -H 'Authorization: Bearer {dumateToken}' \
3 -H 'X-Dumate-Device-Id: 1|web.{raw-device-id}' \
4 -H 'Content-Type: application/json' \
5 -d '{"title": "首次对话"}'
返回会话对象中的 id 即 {sessionID}。
Step 3 发送消息(POST /session/:sessionID/prompt_async)
1curl -X POST 'https://{sandbox-host}/dispatch/{sandboxRoute}/session/{sessionID}/prompt_async' \
2 -H 'Authorization: Bearer {dumateToken}' \
3 -H 'X-Dumate-Device-Id: 1|web.{raw-device-id}' \
4 -H 'Content-Type: application/json' \
5 --data-raw '{"parts": [{"type": "text", "text": "你好,请介绍一下你自己"}]}'
返回 HTTP 204,无响应体。
Step 4 接收回复
- 方案 A(推荐,实时):通过
GET /event(SSE)订阅,等待"消息完成 / 会话空闲"类事件后结束本条消息的等待(事件协议见 3.3)。 - 方案 B(兜底,轮询):轮询
DescribeSessionStatus直到该会话不再是 busy(不再出现在结果中),再调用DescribeSessionMessages拉取最终文本:
1# 等待会话空闲
2curl -X POST 'https://www.dumate.cn/openapi-sandbox?Action=DescribeSessionStatus' \
3 -H 'Authorization: Bearer {sandboxApiKey}' \
4 -H 'X-Dumate-Token: {dumateToken}'
5
6# 拉取对话消息
7curl -X POST 'https://www.dumate.cn/openapi-sandbox?Action=DescribeSessionMessages&sessionID={sessionID}&limit=10' \
8 -H 'Authorization: Bearer {sandboxApiKey}' \
9 -H 'X-Dumate-Token: {dumateToken}'
Step 5 验证扣分(DescribePointsUsage)
1curl -X POST 'https://www.dumate.cn/openapi-sandbox?Action=DescribePointsUsage' \
2 -H 'Authorization: Bearer {sandboxApiKey}' \
3 -H 'X-Dumate-Token: {dumateToken}' \
4 -H 'Content-Type: application/json' \
5 -d '{"startAt": {startAt}, "endAt": {endAt}}'
list 中出现 pointsChange 为负值的记录即表示本次对话已计费(扣分规则见 6.5)。
说明:Step 4 方案 B 中 DescribeSessionStatus 仅返回非空闲会话,会话从结果中消失即可认为处理完成;如需要更精确的完成判定,以 Step 4 方案 A 的 SSE 事件为准。
1.7 沙盒迁移线上切换清单
联调通过后切换线上环境,逐项核对:
| 检查项 | 沙盒 | 线上 |
|---|---|---|
| 1. API Key | 沙盒 Key({sandboxApiKey}) |
线上 Key(控制台创建) |
| 2. 标准 OpenAPI 域名 | openapi-sandbox |
openapi |
| 3. Dispatch 域名/路由段 | {sandbox-host} / {sandboxRoute} |
www.dumate.cn / {route} |
| 4. 用户 Token | 沙盒环境获取 | 线上环境重新获取(建议线上使用线上环境签发的 Token,沙盒 Token 在线上可能失效) |
| 5. 数据/扣费 | 测试数据,不产生真实扣费 | 生产数据,真实扣减积分 |
| 6. 回归冒烟 | - | 用 1.6 的 5 步链路在线上完整跑一遍 |
2 鉴权
2.1 获取访问凭证 DescribeToken
获取(含刷新)渠道用户 Token,用于后续全部接口调用。首次获取时,Header 中传入 X-Dumate-User-Id,值为 App 跳转时带过去的 userId 字段值。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeToken |
| 是否鉴权 | 是(API Key) |
请求 Header
| Header | 必填 | 说明 |
|---|---|---|
Authorization |
是 | Bearer {apiKey} |
Content-Type |
是 | application/json |
X-Dumate-User-Id |
首次获取必填 | App 跳转时带过去的用户 ID 字段值 |
X-Dumate-Token |
刷新时必填 | 已持有的用户 Token |
请求体:无。
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
token |
string | 访问凭证(Token),后续接口以 X-Dumate-Token Header 携带 |
expired_at |
string | 过期时间,UTC 格式(例:2026-07-10T13:58:49.23978Z 表示北京时间 2026-07-10 21:58:49 过期) |
响应示例
1{
2 "token": "{dumateToken}",
3 "expired_at": "2026-07-10T13:58:49.23978Z"
4}
注意事项:
- Token 有过期时间,请关注
expired_at(UTC)并提前刷新,避免接口调用因 Token 过期失败。 - 首次获取与刷新均使用本接口,首次需额外携带
X-Dumate-User-Id。
Token 刷新标准流程(推荐实现):
- 主动预刷新:检测到
expired_at距今不足 10 分钟时,调用DescribeToken(携带旧 Token 的X-Dumate-TokenHeader)刷新后继续使用新 Token。 - 401 被动刷新:任意接口返回
code=401/PermissionDenied时,先调用DescribeToken刷新 Token,再重试原请求一次(最多一次,避免死循环)。 - 保存与同步:刷新成功后立即替换本地 Token 并持久化;多端场景可通过账号体系广播新 Token。
注意:DescribeToken 不带 X-Dumate-Token 时视为首次获取(需 X-Dumate-User-Id);带旧 Token 时视为刷新。两者响应结构一致。
2.2 请求 Header
以下 Header 为全部标准 OpenAPI 接口通用。
| Header | 值 | 必填 | 备注 |
|---|---|---|---|
Authorization |
Bearer {apiKey} |
是 | API Key 来源于开放平台控制台;注意区分沙盒与线上环境的 Key |
X-Dumate-Token |
{dumateToken} |
是 | 由 DescribeToken 获取 |
Content-Type |
application/json |
是 | 如接口有特殊说明(如文件上传),按具体接口执行 |
2.3 响应结构
所有接口响应统一包含以下字段:
| 名称 | 类型 | 说明 |
|---|---|---|
requestId |
string | 请求 ID,用于问题定位 |
code |
string | 错误码(仅异常时返回) |
message |
string | 错误信息(仅异常时返回) |
成功场景:
1HTTP/1.1 200 OK
2{
3 "requestId": "{requestId}",
4 "otherField": any
5}
失败场景(HTTP 状态码仍为 200,业务错误以 code / message 标识):
1{
2 "code": "401",
3 "message": "PermissionDenied",
4 "requestId": "{requestId}"
5}
3 会话与消息
3.1 创建会话 POST /session
用户发起新对话时调用,创建会话并启动运行环境。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /dispatch/{route}/session |
| 是否鉴权 | 是(用户 Token + 设备 ID) |
请求 Header
| Header | 必填 | 说明 |
|---|---|---|
Authorization |
是 | Bearer {dumateToken} |
X-Dumate-Device-Id |
是 | 格式为 {device-id-ver}|{os}.{raw-device-id},其中:· device-id-version = 1· os:darwin / windows / ios / android / harmony / xiaodu 等,其他平台标识以服务方发布为准· raw-device-id:各端自行确定的设备标识,[a-zA-Z0-9_.-]{16,128} |
Content-Type |
是 | application/json |
X-Dumate-Account-Id |
否 | 服务方云账号 ID |
User-Agent |
否 | UA 中加上链路上各种版本信息,其中最开始的发起端加上: · PC: DumateApp/{版本号}· Mobile: DumateMobile/{版本号}样例: [DumateApp/1.0.34.1 go/1.0.0 Chrome/1.23.4] |
X-Dumate-Client-Source |
否 | 来源方:dumate-web(dumate 网页端)、dumate-app(dumate 移动端)、partner-channel(合作渠道) |
Refer |
否 | 网页端调用时注明来源。样例:https://www.dumate.cn/app |
请求体参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
parentID |
string | 否 | 父会话 ID(ses_ 前缀)。传入时创建子会话 |
title |
string | 否 | 会话标题。缺省自动生成(格式 New session - 2026-04-23 14:30:00,UTC+8) |
permission |
PermissionRule[] | 否 | 会话级权限规则集,覆盖默认权限 |
PermissionRule 结构
1{
2 "permission": "bash",
3 "pattern": "rm *",
4 "action": "ask"
5}
| 字段 | 类型 | 说明 |
|---|---|---|
permission |
string | 权限类型,如 bash、read、mount_directory、* |
pattern |
string | 匹配模式,支持通配符,如 *、rm *、*.env |
action |
string | 动作:allow 允许 / deny 拒绝 / ask 询问用户 |
请求示例
1curl -X POST 'https://www.dumate.cn/dispatch/{route}/session' \
2 -H 'Authorization: Bearer {dumateToken}' \
3 -H 'X-Dumate-Device-Id: 1|web.{raw-device-id}' \
4 -H 'Content-Type: application/json' \
5 -d '{"title": "新任务"}'
响应示例(会话对象,字段结构见 3.6 会话对象数据结构)
1{
2 "id": "ses_{sessionID}",
3 "slug": "glowing-panda",
4 "version": "0.0.0-dumate_server-202605210956",
5 "projectID": "global",
6 "directory": "/home/work/dumate/{accountId}/workspace",
7 "is_subagent": false,
8 "title": "新任务",
9 "time": {
10 "created": 1779418858625,
11 "updated": 1779418858625
12 }
13}
3.2 发送消息 POST /session/:sessionID/prompt_async
向指定会话发送用户消息并触发搭子处理。采用异步非阻塞模式:服务端触发处理并立即返回 HTTP 204,搭子处理进度与结果通过 SSE 事件推送(见 3.3 接收消息)。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /dispatch/{route}/session/{sessionID}/prompt_async |
| 是否鉴权 | 是 |
请求 Header
| Header | 必填 | 说明 |
|---|---|---|
Authorization |
是 | Bearer {dumateToken} |
X-Dumate-Device-Id |
是 | 设备标识 |
X-Dumate-Request-Id |
否 | 请求追踪 ID |
X-Dumate-Location-Coarse |
否 | 用户 IP 粗定位。值为 location 序列化为 UTF-8 JSON 后做 percent-encoding 的结果(至少含 province / city / district / town / street 中一个非空字段),放在 Header 而非 Body |
请求体参数
| 参数 | 必填与否 | 说明 |
|---|---|---|
requestID (string) |
否 | 请求追踪 ID。dumate_server 的 Body Schema 接受该字段,但 prompt_async 路由以 X-Dumate-Request-Id Header 为准 |
deviceId (string) |
否 | 设备 ID。Body Schema 接受该字段,但 prompt_async 路由以 X-Dumate-Device-Id Header 为准 |
messageID (string) |
否 | 用户消息 ID,格式通常以 msg_ 开头;不传时由服务端生成 |
sandboxId (string) |
否 | Sandbox ID。Body Schema 接受该字段,但 prompt_async 路由以 X-Sandbox-ID Header 为准 |
dtoken (string) |
否 | 模型访问凭证。Body Schema 接受该字段,但 prompt_async 路由以 X-Dumate-Token Header 为准;云端模式下该 Header 必填 |
sandboxDomain (string) |
否 | Sandbox 域名。Body Schema 接受该字段,但 prompt_async 路由以 X-Sandbox-Domain Header 为准 |
accessToken (string) |
否 | Envd 访问凭证。Body Schema 接受该字段,但 prompt_async 路由以 X-Envd-Access-Token Header 为准 |
userAgent (string) |
否 | 调用端信息。Body Schema 接受该字段,但 prompt_async 路由以 User-Agent Header 为准 |
triggerType (string) |
否 | 请求触发方式。Body Schema 接受该字段,但 prompt_async 路由以 X-Dumate-Trigger-Type Header 为准;cron 表示定时任务 |
expConfig (object) |
否 | 实验配置。Body Schema 接受该字段,但 prompt_async 路由以 X-Dumate-Exp-Config Header 中的 JSON 为准 |
expConfig.abExpIds (string[]) |
否 | AB 实验 ID 列表 |
expConfig.aiAssistant (object) |
否 | 搭子实验配置 |
expConfig.aiAssistant.enabled (boolean) |
否 | 是否启用搭子实验能力 |
model (object) |
否 | 指定本轮使用的模型;不传时使用服务端默认模型 |
model.providerID (string) |
model 存在时必填 | Provider ID,例如 default |
model.modelID (string) |
model 存在时必填 | Model ID,例如 default |
agent (string) |
否 | 指定处理本轮消息的 Agent |
noReply (boolean) |
否 | 是否不生成搭子回复 |
tools (Record<string, boolean>) |
否 | 工具开关映射。该字段已废弃,工具与权限应通过 Session permission 配置 |
format (object) |
否 | 输出格式配置 |
format.type (string) |
format 存在时必填 | text 或 json_schema。使用 json_schema 时还需传 format.schema |
system (string) |
否 | 本轮自定义 System Prompt |
variant (string) |
否 | 消息变体标识 |
parts (array) |
是 | 本轮消息内容列表,可包含文本、文件等 Part |
说明:requestID、deviceId、dtoken、userAgent、triggerType、accessToken 等字段在 Body 中可接受,但本接口以对应 Header 传参为准。
Text Part
| 参数 | 必填与否 | 说明 |
|---|---|---|
parts[].id (string) |
否 | Part ID;不传时由服务端生成 |
parts[].visibility (string) |
否 | 可选值:frontend、model、both。不传时按默认规则处理 |
parts[].type (string) |
是 | 文本 Part 固定为 text |
parts[].text (string) |
是 | 用户输入的文本内容 |
parts[].synthetic (boolean) |
否 | 是否为系统合成的文本。普通用户输入通常不传 |
parts[].ignored (boolean) |
否 | 是否忽略该 Part。普通用户输入通常不传 |
parts[].time (object) |
否 | Part 的时间信息 |
parts[].time.start (number) |
time 存在时必填 | 开始时间戳,单位为毫秒 |
parts[].time.end (number) |
否 | 结束时间戳,单位为毫秒 |
parts[].metadata (object) |
否 | 自定义扩展元数据 |
File Part
文件二进制通过上传接口(见 5 文件)先上传,本条消息只传文件引用。上传文件后,不需要再次向本接口上传文件二进制,而是在 parts 中传入文件引用。
| 参数 | 必填与否 | 说明 |
|---|---|---|
parts[].id (string) |
否 | Part ID;不传时由服务端生成 |
parts[].visibility (string) |
否 | 可选值:frontend、model、both |
parts[].type (string) |
是 | 文件 Part 固定为 file |
parts[].mime (string) |
否,建议传 | 文件 MIME 类型,例如 video/mp4、image/png;不传时服务端尝试根据路径推断 |
parts[].filename (string) |
否;url 为 blob: 时必填 | 普通文件可表示文件名;线上云端上传链路中承载 CreatePreSessionFile.filePath,例如 /dumate/{userID}/workspace/uploads/{uploadID}/文件名 |
parts[].url (string) |
是 | 文件引用。必须是带协议的 URL,不能填写 /dumate/... 裸路径 |
parts[].mediaType (string) |
否 | 上游兼容字段,通常与 mime 相同;当前 dumate_server 的 FilePart Schema 未声明该字段,服务端以 mime 为准 |
parts[].preview (string) |
否 | 线上请求携带的上传对象相对标识。当前 dumate_server 的文件路径归一化不读取该字段 |
parts[].source (object) |
否 | 文件来源信息 |
请求示例(文本 + 文件)
1curl -X POST 'https://www.dumate.cn/dispatch/{route}/session/{sessionID}/prompt_async' \
2 -H 'Authorization: Bearer {dumateToken}' \
3 -H 'X-Dumate-Device-Id: 1|web.{raw-device-id}' \
4 -H 'Content-Type: application/json' \
5 --data-raw '{
6 "model": {"providerID": "default", "modelID": "default"},
7 "parts": [
8 {"type": "text", "text": "请帮我分析这张图"},
9 {"type": "file", "url": "file:///dumate/{userID}/workspace/uploads/{uploadID}/图片.png", "mime": "image/png"}
10 ]
11 }'
3.3 接收消息 GET /event
订阅当前会话运行环境的实时事件流(SSE,Content-Type: text/event-stream)。接入方在进入会话页后建立一次长连接,此后 UI 的所有状态更新(搭子文本、工具调用、任务进度、权限请求等)均由该事件流驱动。
| 项目 | 内容 |
|---|---|
| 请求方式 | GET |
| 请求路径 | /dispatch/{route}/event |
| 是否鉴权 | 是 |
请求 Header
| Header | 必填 | 说明 |
|---|---|---|
Authorization |
是 | Bearer {dumateToken} |
X-Dumate-Device-Id |
是 | 设备标识(格式见 3.1) |
Content-Type |
是 | application/json |
X-Dumate-Account-Id |
否 | 服务方云账号 ID |
User-Agent |
否 | UA 中加上链路上各种版本信息,其中最开始的发起端加上: · PC: DumateApp/{版本号}· Mobile: DumateMobile/{版本号}样例: [DumateApp/1.0.34.1 go/1.0.0 Chrome/1.23.4] |
X-Dumate-Client-Source |
否 | 来源方:dumate-web(dumate 网页端)、dumate-app(dumate 移动端)、partner-channel(合作渠道) |
Refer |
建议 | 网页端调用时注明来源。样例:https://www.dumate.cn/app |
请求示例
1curl 'https://www.dumate.cn/dispatch/{route}/event' \
2 -H 'Authorization: Bearer {dumateToken}' \
3 -H 'X-Dumate-Device-Id: 1|web.{raw-device-id}' \
4 -H 'Referer: https://www.dumate.cn/app/session/{sessionID}'
3.3.1 事件流协议
事件流采用 SSE 规范:每个事件由 event: 事件名与 data: 负载(JSON)组成,空行分隔。事件负载为 JSON,事件名区分事件类型。具体事件名与字段结构请以服务方提供的《SSE 事件说明》为准(接入时向服务方索取),本节给出事件类别的行为清单,供接入方规划 UI 与状态机:
| 事件类别 | 触发时机 | 推荐客户端动作 |
|---|---|---|
| 文本增量 | 搭子生成回复过程中,文本逐段产出 | 追加渲染到当前消息,保持 loading |
| 推理过程 | 模型推理/思考过程产出 | 可选展示,收起/展开 |
| 工具调用更新 | 搭子调用工具(命令执行、文件读写、Skill 等)时 | 展示工具名、状态(进行中/完成/失败) |
| 任务进度更新 | 搭子更新 Todo 任务列表时 | 刷新任务进度 UI(见 3.5) |
| 权限请求出现 | 搭子需要用户授权(bash/read/write/location 等)时 | 弹权限框(见 4.5),等待用户回复 |
| 澄清问题出现 | 搭子需要补充信息时 | 弹澄清框(见 4.1) |
| 消息完成 | 单条搭子消息产出完成 | 结束 loading,标记消息完成 |
| 会话空闲 | 整轮处理结束、无待办 | 结束本轮 loading,刷新会话/文件/任务状态 |
3.3.2 连接建立时机
- 用户进入会话页即可建立连接(未发送消息也可空连接)。
- 建议每会话一条连接;若实现为全局单连接,需按会话过滤事件(事件负载含 sessionID 标识,以《SSE 事件说明》字段为准)。
- 连接鉴权失败(如 Token 过期)返回错误后,按 2.1 刷新 Token 重连。
3.3.3 断线重连与对账
SSE 连接可能因网络切换、网关空窗等原因断开,接入方需处理重连与状态对账:
- 自动重连:检测到连接断开后按退避策略重连(如 1s → 2s → 5s → 10s,封顶 30s,最多重试 N 次)。
- 权限对账:重连后调用
GET /permission(见 4.5),补齐断线期间可能遗漏的 pending 权限请求,避免权限弹窗漏显。 - 消息对账:重连后调用
DescribeSessionMessages(3.10)拉取最近消息,用于补齐断线期间未接收的增量;有权限请求时先处理权限。 - 任务对账:重连后调用
GET /session/:sessionID/todo(3.5)刷新任务进度,避免进度 UI 与真实状态不一致。 - 完成判定兜底:若长时间未收到“会话空闲”类事件但会话已无产出,可轮询
DescribeSessionStatus(3.9)确认会话是否仍 busy,作为完成判定的兜底手段。
注意事项:
- 事件类型、数据结构与响应示例详见服务方提供的《SSE 事件说明》。
- 同一账号的
/event、权限查询与回复请求需路由到同一服务实例(接入网关按账号做粘性路由)。 - SSE 是事件推送通道,UI 的权威数据源仍以各查询接口(会话、消息、文件、任务)为准;重连后以查询接口对账补齐。
3.4 停止消息 POST /session/:sessionID/abort
强制中止当前正在进行的搭子任务(模型推理与工具调用循环)。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /dispatch/{route}/session/{sessionID}/abort |
| 是否鉴权 | 是 |
请求体:无。
请求示例
1curl -X POST 'https://www.dumate.cn/dispatch/{route}/session/{sessionID}/abort' \
2 -H 'Authorization: Bearer {dumateToken}' \
3 -H 'X-Dumate-Device-Id: 1|web.{raw-device-id}'
响应:HTTP 200,true 表示中止成功。
3.5 查询任务进度 GET /session/:sessionID/todo
获取搭子记录的任务列表,用于展示多步骤任务的进度。
| 项目 | 内容 |
|---|---|
| 请求方式 | GET |
| 请求路径 | /dispatch/{route}/session/{sessionID}/todo |
| 是否鉴权 | 是 |
响应参数(JSON 数组)
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 任务唯一 ID |
content |
string | 任务描述(如“实现功能X”) |
status |
string | pending / in_progress / completed |
activeForm |
string | 进行中时的展示文案(如“正在实现功能X”) |
3.6 会话对象数据结构
创建会话、会话列表与详情接口均返回会话对象,字段如下:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | Session ID(ses_ 前缀) |
slug |
string | 是 | URL 友好短标识 |
projectID |
string | 是 | 所属项目 ID |
workspaceID |
string | 否 | 所属工作区 ID |
directory |
string | 是 | 会话工作目录(绝对路径) |
parentID |
string | 否 | 父 Session ID(Fork 场景) |
is_subagent |
boolean | 是 | 是否为子 Agent 创建的 Session |
title |
string | 是 | 会话标题 |
version |
string | 是 | 创建时的服务端版本号 |
time.created |
number | 是 | 创建时间戳(ms) |
time.updated |
number | 是 | 最后更新时间戳(ms) |
time.compacting |
number | 否 | 最后压缩时间戳(ms) |
time.archived |
number | 否 | 归档时间戳(ms) |
summary.additions |
number | 否 | 文件变更新增行数 |
summary.deletions |
number | 否 | 文件变更删除行数 |
summary.files |
number | 否 | 变更文件数 |
share.url |
string | 否 | 分享链接(已分享时存在) |
permission |
object | 否 | 会话级权限规则集 |
revert.messageID |
string | 否 | 回退到的消息 ID |
revert.partID |
string | 否 | 回退到的 Part ID |
revert.snapshot |
string | 否 | 快照标识 |
revert.diff |
string | 否 | 变更 diff |
isPinned |
boolean | 是 | 是否置顶该会话 |
source |
string | 否 | 会话来源 |
3.7 历史会话列表 DescribeSessions
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeSessions |
| 是否鉴权 | 是 |
请求体参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
roots |
boolean | 否 | 只返回根会话(无 parentID) |
search |
string | 否 | 按标题模糊搜索 |
limit |
int | 否 | 返回最大条数 |
source |
string | 否 | 来源过滤,可选 manual、scheduled |
响应参数:result —— 会话对象数组(结构见 3.6)。
响应示例
1{
2 "result": [
3 {
4 "deviceId": "{deviceId}",
5 "directory": "/home/work/dumate/workspace",
6 "id": "ses_{sessionID}",
7 "title": "搜索狗狗图片",
8 "source": "manual",
9 "isPinned": false,
10 "time": {"created": 1782203832706, "updated": 1782203857358}
11 }
12 ]
13}
3.8 历史会话详情 DescribeSession
| 项目 | 内容 |
|---|---|
| 请求方式 | POST(参数为 Query 参数,拼接在请求 URL 上) |
| 请求路径 | /openapi?Action=DescribeSession&sessionID={sessionID} |
| 是否鉴权 | 是 |
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
sessionID |
Query | string | 是 | 会话 ID |
响应参数:会话对象(结构见 3.6),另含 permission(会话级权限规则)与 requestId。
响应示例
1{
2 "requestId": "{requestId}",
3 "id": "ses_{sessionID}",
4 "title": "每日任务-123",
5 "source": "scheduled",
6 "permission": [
7 {"permission": "question", "pattern": "*", "action": "deny"},
8 {"permission": "scheduler_create_job", "pattern": "*", "action": "deny"}
9 ],
10 "readStatus": "unread",
11 "time": {"created": 1783558803151, "updated": 1783558806920}
12}
3.9 查询会话状态 DescribeSessionStatus
返回当前账号下所有非空闲(非 idle)会话的状态,空闲会话不在结果中。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeSessionStatus |
| 是否鉴权 | 是 |
请求体:无。
响应参数:JSON 对象,key 为会话 ID。
| 字段 | 类型 | 说明 |
|---|---|---|
{sessionID}.type |
string | busy 或 retry |
{sessionID}.attempt |
number | 重试次数(仅 retry 状态) |
{sessionID}.message |
string | 重试原因(仅 retry 状态) |
{sessionID}.next |
number | 下次重试时间戳 ms(仅 retry 状态) |
响应示例
1{
2 "ses_{sessionID}": {
3 "type": "busy"
4 }
5}
3.10 历史会话消息 DescribeSessionMessages
| 项目 | 内容 |
|---|---|
| 请求方式 | POST(参数为 Query 参数) |
| 请求路径 | /openapi?Action=DescribeSessionMessages&sessionID={sessionID}&limit={limit} |
| 是否鉴权 | 是 |
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
sessionID |
Query | string | 是 | 会话 ID |
limit |
Query | number | 否 | 返回消息条数上限。从最新消息开始截取,翻转时间升序返回(如 limit=140 返回最近 140 条);不传返回全部。不支持 offset 分页 |
响应参数:result —— 消息数组。role=user 的消息字段见下方 User 消息,role=assistant 见 Assistant 消息;每条消息均含 parts 数组(见 Part 类型)。
User 消息字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 消息 ID(msg_ 前缀) |
sessionID |
string | 是 | 所属 Session ID |
role |
string | 是 | 固定为 "user" |
time.created |
number | 是 | 创建时间戳(ms) |
parts |
array | 是 | 消息内容片段,见 Part 类型 |
format |
string | 否 | 消息格式 |
summary |
string | 否 | 摘要(压缩后) |
agent |
string | 否 | 指定 Agent 名称 |
model.providerID |
string | 否 | 使用的 Provider ID |
model.modelID |
string | 否 | 使用的模型 ID |
system |
string | 否 | 自定义 system prompt |
variant |
string | 否 | 消息变体标识 |
Assistant 消息字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 消息 ID(msg_ 前缀) |
sessionID |
string | 是 | 所属 Session ID |
role |
string | 是 | 固定为 "assistant" |
time.created |
number | 是 | 创建时间戳(ms) |
time.completed |
number | 否 | 完成时间戳(ms) |
parts |
array | 是 | 消息内容片段,见 Part 类型 |
error |
string | 否 | 出错时的错误信息 |
parentID |
string | 否 | 父消息 ID(Fork 场景) |
modelID |
string | 否 | 使用的模型 ID |
providerID |
string | 否 | 使用的 Provider ID |
mode |
string | 否 | 执行模式 |
agent |
string | 否 | 使用的 Agent 名称 |
path.cwd |
string | 否 | 执行时的工作目录 |
path.root |
string | 否 | 执行时的项目根目录 |
summary |
string | 否 | 摘要(压缩后) |
cost |
number | 否 | 本次消费费用 |
tokens.total |
number | 否 | 总 token 数 |
tokens.input |
number | 否 | 输入 token 数 |
tokens.output |
number | 否 | 输出 token 数 |
tokens.reasoning |
number | 否 | 推理 token 数 |
tokens.cache.read |
number | 否 | 缓存命中 token 数 |
tokens.cache.write |
number | 否 | 缓存写入 token 数 |
finish |
string | 否 | 完成原因(stop / length / tool_calls 等) |
variant |
string | 否 | 消息变体标识 |
Part 类型
所有 Part 均含公共字段:id(prt_ 前缀)、messageID、sessionID、type,类型为 String。各 type 特有字段:
| Type | 说明 | 特有字段 |
|---|---|---|
text |
文本内容 | text: string |
file |
文件引用 | url: string;可选 filename: string、mediaType: string |
tool |
工具调用 | callID: string、tool: string(工具名)、state: object(见 ToolState)、metadata: object |
reasoning |
模型推理过程 | text: string;可选 summary: string |
step-start |
推理步骤开始 | 无额外字段 |
step-finish |
推理步骤结束 | 无额外字段 |
subtask |
子任务调用 | description: string、sessionID: string |
agent |
Agent 调用 | agent: string、description: string、sessionID: string |
file-import |
文件导入块 | files: array(文件块列表) |
file-export |
文件导出块 | files: array(文件块列表) |
compaction |
上下文压缩记录 | summary: string |
retry |
重试记录 | error: string、attempt: number |
snapshot |
文件快照 | snapshot: string |
patch |
文件 diff | patch: string |
ToolState(以 type 字段区分状态)
pending(待执行):
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string | "pending" |
input |
any | 工具调用入参 |
raw |
string | 原始输入字符串(可选) |
running(执行中):
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string | "running" |
input |
any | 工具调用入参 |
title |
string | UI 展示标题(可选) |
metadata |
object | 附加上下文 |
time.start |
number | 开始时间戳(ms) |
completed(已完成):
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string | "completed" |
input |
any | 工具调用入参 |
output |
any | 工具调用输出 |
title |
string | UI 展示标题(可选) |
metadata |
object | 附加上下文 |
time.start |
number | 开始时间戳(ms) |
time.end |
number | 结束时间戳(ms) |
time.compacted |
boolean | 是否已被压缩(可选) |
attachments |
string[] | 附件列表(可选) |
error(执行失败):
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string | "error" |
input |
any | 工具调用入参 |
error |
string | 错误信息 |
metadata |
object | 附加上下文 |
time.start |
number | 开始时间戳(ms) |
time.end |
number | 结束时间戳(ms) |
响应示例
1{
2 "requestId": "{requestId}",
3 "result": [
4 {
5 "info": {
6 "id": "msg_{messageID}",
7 "role": "assistant",
8 "sessionID": "ses_{sessionID}",
9 "finish": "stop",
10 "time": {"created": 1781672921612, "completed": 1781672923336}
11 },
12 "parts": [
13 {"id": "prt_{partId}", "type": "step-start"},
14 {"id": "prt_{partId}", "type": "text", "text": "已完成。", "time": {"start": 1781672923007, "end": 1781672923007}},
15 {"id": "prt_{partId}", "type": "step-finish"}
16 ]
17 }
18 ]
19}
3.11 首页推荐问 DescribeRecommendQueries
获取首页推荐问列表,用于在首页展示引导用户提问的推荐内容。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST(参数为 Query 参数) |
| 请求路径 | /openapi?Action=DescribeRecommendQueries&clientType={clientType} |
| 是否鉴权 | 是 |
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
clientType |
Query | string | 是 | mobile / desktop / web |
响应参数:result —— 推荐问数组。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
int64 | 是 | 推荐问 ID |
tag |
string | 是 | 分类标签 |
query |
string | 是 | 实际发送给对话服务的 Query |
display |
string | 是 | 当前 clientType 的展示文案 |
execScope |
string | 否 | 可执行端,逗号分隔(如 desktop,web,mobile) |
displayScope |
string | 否 | 可展示端,逗号分隔 |
attachment |
object | 否 | 推荐问附件(见 Attachment.Info) |
skills |
array | 是 | 关联 Skill(见 Resource.Info),无数据时返回 [] |
plugins |
array | 是 | 关联 Plugin(见 Resource.Info),无数据时返回 [] |
icon |
string | 否 | 分类标签图标的签名地址 |
Attachment.Info
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
bosPath |
string | 是 | 签名下载地址 |
fileName |
string | 是 | 文件名 |
fileType |
string | 是 | 文件 MIME 类型 |
fileSize |
string | 是 | 格式化文件大小(如 128.5KB) |
cfsPath |
string | 否 | 用户文件路径,可在发起会话时直接引用 |
Resource.Info(skills / plugins 元素)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
string | 是 | skill / plugin |
displayName |
string | 是 | 展示名称 |
name |
string | 是 | Skill 名称或 Plugin Code |
注意事项(分屏规则):
- 接口不返回分页字段,
result为扁平数组,客户端每 4 条切分一屏(第 1 屏result[0:4],第 2 屏result[4:8],依此类推;候选不足时最后一屏可少于 4 条)。 - 同一屏不出现重复 id,同屏内优先不同 tag。
- 服务端会做个性化编排,同一用户多次请求返回的内容和顺序可能变化,请按返回顺序展示。
4 对话交互
搭子在任务执行过程中可能向用户发起两类交互:澄清问答(信息不足时提问)与权限申请(需要访问本地资源或执行敏感操作时请求授权)。
4.1 澄清问答 DescribeConversationQuestions
获取当前所有待回答的澄清问题(搭子主动发起,通常 1-4 个问题)。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeConversationQuestions |
| 是否鉴权 | 是 |
请求体:无。
响应参数:result —— 问题请求数组。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 问题请求 ID(que_ 前缀),回复时使用 |
sessionID |
string | 是 | 所属会话 ID |
questions |
array | 是 | 问题列表(1-4 个) |
tool.messageID |
string | 否 | 触发该问题的工具调用所在消息 ID |
tool.callID |
string | 否 | 触发该问题的工具调用 ID |
questions 数组元素
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
question |
string | 是 | 完整问题文本,以问号结尾 |
header |
string | 是 | 短标签,最多 30 字符,用于 UI 展示 |
options |
array | 是 | 选项列表(2-4 个),每项含 label: string(选项文字)与 description: string(选项说明) |
custom |
boolean | 否 | 是否允许用户自定义输入 |
响应示例
1{
2 "requestId": "{requestId}",
3 "result": [
4 {
5 "id": "que_{requestID}",
6 "sessionID": "ses_{sessionID}",
7 "questions": [
8 {
9 "question": "这份 PPT 是关于什么主题的?用途是什么?",
10 "header": "PPT 主题与用途",
11 "options": [
12 {"label": "工作汇报", "description": "面向团队或管理层的工作总结"},
13 {"label": "学术讲座", "description": "研究进展或学术内容分享"}
14 ]
15 }
16 ]
17 }
18 ]
19}
4.2 回复澄清问题 ReplyConversationQuestion
用户在澄清弹窗中回答后调用,把答案回传给搭子继续执行。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=ReplyConversationQuestion |
| 是否鉴权 | 是 |
请求体参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
requestID |
string | 是 | 问题请求 ID,来自 DescribeConversationQuestions 返回的 result[].id,前缀一般是 que_ |
answers |
string[][] | 是 | 按 questions 顺序填写,每个元素是该题选中的 label 列表,支持多选;custom=true 时可直接传用户输入内容 |
请求示例
1{
2 "requestID": "que_{requestID}",
3 "answers": [
4 ["自动驾驶产品竞品分析"],
5 ["10-20页"]
6 ]
7}
响应示例
1{
2 "requestId": "{requestId}",
3 "result": true
4}
4.3 权限申请 DescribeConversationPermissions
获取当前所有待审批的权限请求(已处理的不在列表中),用于展示权限弹窗。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeConversationPermissions |
| 是否鉴权 | 是 |
请求体:无。
响应参数:result —— 权限请求数组(PermissionRequest)。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 权限请求 ID(per_ 前缀) |
sessionID |
string | 是 | 所属 Session ID |
permission |
string | 是 | 权限类型,如 bash、read、write |
patterns |
string[] | 是 | 匹配的操作模式,如 ["rm -rf dist"] |
metadata |
object | 是 | 附加上下文(如具体命令参数) |
always |
string[] | 是 | 已被标记为始终允许的 patterns |
tool.messageID |
string | 否 | 触发该权限的工具调用所在消息 ID |
tool.callID |
string | 否 | 触发该权限的工具调用 ID |
4.4 回复权限申请 ReplyConversationPermission
用户在权限弹窗中选择允许或拒绝后调用,把审批结果回传给搭子,搭子收到后继续执行或中止。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=ReplyConversationPermission |
| 是否鉴权 | 是 |
请求体参数
| 字段 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
requestID |
body | string | 是 | 权限请求 ID,来自 DescribeConversationPermissions 返回的 result[].id |
reply |
body | string | 是 | 审批结果:once / always / reject |
message |
body | string | 否 | 可选备注 |
请求示例
1{
2 "requestID": "per_{requestID}",
3 "reply": "once",
4 "message": "approve"
5}
响应示例
1{
2 "requestId": "{requestId}",
3 "result": true
4}
4.5 查询待处理权限(实时通道) GET /permission
获取当前会话运行环境中所有尚未回复的权限请求,用于权限弹窗展示,以及页面刷新、SSE 重连或 App 回到前台后的状态对账。只返回 pending 请求,不返回历史或已批准的规则。
| 项目 | 内容 |
|---|---|
| 请求方式 | GET |
| 请求路径 | /dispatch/{route}/permission |
| 是否鉴权 | 是 |
请求参数
| 字段 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
directory |
Query | string | 否 | 工作区目录(通常由接入层补齐或透传) |
Console、Agent-Hub 与 qianfan-desk 的路径映射如下:
| 调用层 | HTTP 路径 |
|---|---|
| Console / Web | GET /dispatch/clawguard/permission |
| Agent-Hub | GET /v2/dumate/permission |
| qianfan-desk | GET /permission |
响应参数:PermissionRequest[],除 4.3 的字段外,还包含服务端生成的展示信息:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 权限请求 ID,以 per_ 开头;回复接口必须原样使用该值 |
sessionID |
string | 是 | 所属会话 ID,以 ses_ 开头 |
permission |
string | 是 | 权限类型,例如 location、bash、read、write |
patterns |
string[] | 是 | 本次申请覆盖的操作模式;location 通常为 ["*"] |
metadata |
object | 是 | 附加上下文 |
always |
string[] | 是 | 允许持久批准的 pattern;空数组表示不支持持久批准 |
tool.messageID |
string | 否 | 触发该权限请求的消息 ID |
tool.callID |
string | 否 | 触发该权限请求的 Tool Call ID |
display |
object | 否 | 服务端生成的展示信息 |
display.title |
string | 是 | 弹窗标题 |
display.riskLevel |
string | 是 | 风险等级:high、medium 或 low |
display.riskLabel |
string | 是 | 风险标签 |
display.description |
string | 是 | 面向用户的权限说明 |
display.resolvedPaths |
string[] | 是 | 解析后的相关路径;location 场景为空数组 |
响应示例(定位权限)
1[
2 {
3 "id": "per_{requestID}",
4 "sessionID": "ses_{sessionID}",
5 "permission": "location",
6 "patterns": ["*"],
7 "metadata": {},
8 "always": [],
9 "tool": {"messageID": "msg_{messageID}", "callID": "{callID}"},
10 "display": {
11 "title": "获取您的地理位置",
12 "riskLevel": "medium",
13 "riskLabel": "请确认",
14 "description": "请求使用您的当前位置以提供更精准的回答,同意后将仅在本次对话中使用。",
15 "resolvedPaths": []
16 }
17 }
18]
4.6 回复权限请求(实时通道) POST /permission/:requestID/reply
用户允许或拒绝权限请求后调用。服务端使用 requestID 找到对应 pending 请求,并唤醒正在等待结果的搭子流程。
Console、Agent-Hub 与 qianfan-desk 的路径映射如下:
| 调用层 | HTTP 路径 |
|---|---|
| Console / Web | POST /dispatch/clawguard/permission/:requestID/reply |
| Agent-Hub | POST /v2/dumate/permission/:requestID/reply |
| qianfan-desk | POST /permission/:requestID/reply |
Path 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
requestID |
string | 是 | 权限请求 ID,必须取自 GET /permission 返回项的 id 或 permission.asked.properties.id |
请求体参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
reply |
string | 是 | once、always 或 reject |
message |
string | 否 | 拒绝时可携带用户补充说明 |
data |
any | 否 | 权限相关业务数据;仅 askWithData 类型的权限请求会消费。location 权限通过该字段回传位置 |
location 的 data 结构
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
province |
string | 否 | 省或直辖市 |
city |
string | 否 | 城市 |
district |
string | 否 | 区或县 |
town |
string | 否 | 街道或镇 |
street |
string | 否 | 门牌或街道地址 |
请求示例(定位授权)
1{
2 "reply": "once",
3 "data": {
4 "province": "北京市",
5 "city": "北京市",
6 "district": "海淀区",
7 "town": "上地街道",
8 "street": "信息路"
9 }
10}
请求示例(拒绝)
1{
2 "reply": "reject",
3 "message": "本次不允许获取位置"
4}
响应:HTTP 200 true。
注意事项(可靠性):
- 权限等待没有内置超时。若回复在到达服务端前丢失,pending 会继续存在、搭子继续等待,客户端应在回复后重新调用
GET /permission对账并重试。 - 服务端已处理但响应丢失时,重新查询该 ID 会从列表消失。
- 请求 ID 不存在时回复会静默返回(HTTP 仍为 200 true),因此 200 true 只表示调用成功,需结合
GET /permission结果与会话状态确认处理成功。
5 文件
5.1 上传文件 CreatePreSessionFile
将会话输入框中的文件上传至服务端,供会话使用。具体传参字段和值的形状请以接口实际要求为准。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=CreatePreSessionFile |
| Content-Type | multipart/form-data; boundary=xxx(boundary 部分一般由代码或浏览器自动生成) |
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
sessionId |
string | 否 | 会话 ID;当前会话还未生成会话 ID 时传空字符串 |
file |
string | 是 | 本地文件(file=@/path/to/your/file.ext),单个文件不超过 10MB |
请求示例
1curl -X POST 'https://www.dumate.cn/openapi?Action=CreatePreSessionFile' \
2 -H 'Authorization: Bearer {apiKey}' \
3 -H 'X-Dumate-Token: {dumateToken}' \
4 -F 'sessionId=' \
5 -F 'file=@/path/to/your/file.ext'
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
filePath |
string | 上传后的文件路径(形如 /dumate/{accountId}/workspace/uploads/{accountId}/{uploadId}.mp4),发起会话时作为文件 Part 的引用使用 |
响应示例
1{
2 "filePath": "/dumate/{accountId}/workspace/uploads/{uploadId}/example.mp4"
3}
5.2 获取预上传文件访问地址 DescribePreSessionFile
获取已上传文件的签名下载地址。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST(参数为 Query 参数) |
| 请求路径 | /openapi?Action=DescribePreSessionFile&path={path}(path 需 URL 编码) |
| 是否鉴权 | 是 |
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
path |
Query | string | 是 | CreatePreSessionFile 返回的 filePath。作为 Query 参数传递时请对 path 做 URL 编码 |
响应参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | 是 | 归一化后路径(形如 /dumate/{accountId}/workspace/uploads/xxx.png) |
fileName |
string | 是 | 文件存储名 |
mimeType |
string | 否 | MIME 类型,无法根据扩展名判断时不返回 |
size |
int64 | 是 | 文件大小(字节) |
downloadUrl |
string | 是 | 签名下载地址 |
expireSeconds |
int | 是 | downloadUrl 有效期(秒) |
响应示例
1{
2 "requestId": "{requestId}",
3 "path": "/dumate/{accountId}/workspace/uploads/{uploadId}.png",
4 "fileName": "{uploadId}.png",
5 "mimeType": "image/png",
6 "size": 656471,
7 "downloadUrl": "http://{bos-host}/{bucket}/{accountId}/workspace/uploads/{uploadId}.png?authorization={signature}",
8 "expireSeconds": 3600
9}
注意:仅支持通过 CreatePreSessionFile 上传的文件。
5.3 单个历史会话的文件产出物 DescribeSessionFiles
获取指定会话生成的文件产出物清单(报告、文档、图片等)。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST(参数为 Query 参数) |
| 请求路径 | /openapi?Action=DescribeSessionFiles&sessionID={sessionID} |
| 是否鉴权 | 是 |
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
sessionID |
Query | string | 是 | 会话 ID |
响应参数:result —— 文件视图数组
响应示例
1{
2 "result": [
3 {
4 "artifactID": "art_{artifactId}",
5 "downloadUrl": "https://{bos-host}/{bucket}/artifact/global/ses_{sessionID}/art_{artifactId}/报告.docx?authorization={signature}",
6 "errorCode": null,
7 "errorMessage": null,
8 "fileType": "document",
9 "filename": "报告.docx",
10 "mimeType": "xxx",
11 "path": "/home/work/dumate/{accountId}/workspace/ses_{sessionID}/报告.docx",
12 "pdfUrl": "{pdfUrl}",
13 "previewMode": "pdf",
14 "previewStatus": "ready",
15 "previewUrl": "https://{bos-host}/docs/convert/{convertId}.pdf?authorization={signature}",
16 "relativePath": "报告.docx",
17 "timeUpdated": 1784284822612,
18 "uploadStatus": "ready"
19 }
20 ]
21}
5.4 单个文件详情 DescribeSessionFile
| 项目 | 内容 |
|---|---|
| 请求方式 | POST(参数为 Query 参数) |
| 请求路径 | /openapi?Action=DescribeSessionFile&sessionID={sessionID}&path={path}(path 需 URL 编码) |
| 是否鉴权 | 是 |
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
sessionID |
Query | string | 是 | 会话 ID |
path |
Query | string | 是 | 文件绝对路径(对齐会话文件清单的 path 字段) |
响应参数:单个文件视图
响应示例
1{
2 "artifactID": "art_{artifactId}",
3 "downloadUrl": "https://{bos-host}/{bucket}/artifact/global/ses_{sessionID}/art_{artifactId}/报告.docx?authorization={signature}",
4 "errorCode": null,
5 "errorMessage": null,
6 "fileType": "document",
7 "filename": "报告.docx",
8 "mimeType": "xxx",
9 "path": "/home/work/dumate/{accountId}/workspace/ses_{sessionID}/报告.docx",
10 "pdfUrl": "{pdfUrl}",
11 "previewMode": "pdf",
12 "previewStatus": "ready",
13 "previewUrl": "https://{bos-host}/docs/convert/{convertId}.pdf?authorization={signature}",
14 "relativePath": "报告.docx",
15 "timeUpdated": 1784284822612,
16 "uploadStatus": "ready"
17}
5.5 文件预览与下载 FilePreviewView
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
filename |
string | 是 | 文件名 |
path |
string | 是 | 文件绝对路径 |
relativePath |
string | 是 | 相对工作区路径 |
artifactID |
string | 是 | 当前路径对应的最新 artifact ID |
uploadStatus |
string | 是 | 上传状态(见下表) |
pdfPreviewStatus |
string | 是 | 预览状态(见下表) |
previewMode |
string | 是 | pdf / download / none |
previewUrl |
string/null | 是 | 前端推荐直接打开的统一地址 |
downloadUrl |
string/null | 是 | 原始文件下载地址(仅 uploadStatus=ready 时保证可用) |
pdfUrl |
string/null | 是 | PDF 专用预览地址(仅 pdfPreviewStatus=ready 时保证可用) |
errorCode |
string/null | 是 | 失败错误码 |
errorMessage |
string/null | 是 | 失败错误信息 |
timeUpdated |
number | 是 | 最后更新时间戳(ms) |
5.5.1 文件状态字段
uploadStatus
| 值 | 说明 |
|---|---|
pending |
文件已注册,尚未开始上传 |
uploading |
文件上传中 |
ready |
上传完成,downloadUrl 可用 |
failed |
上传失败,结合 errorCode / errorMessage 处理 |
pdfPreviewStatus
| 值 | 说明 |
|---|---|
none |
不走 PDF 预览链路 |
pending |
已进入预览流程 |
converting |
PDF 转换中 |
ready |
预览生成完成,pdfUrl 可用 |
failed |
预览生成失败 |
5.5.2 预览相关字段
previewMode
| 值 | 说明 |
|---|---|
pdf |
优先打开 PDF 预览 |
download |
无 PDF 预览,直接消费原始下载地址 |
none |
当前无可用预览入口 |
previewUrl 与 pdfUrl 的区别
这两个字段语义不同,必须区分:
| 字段 | 说明 |
|---|---|
pdfUrl |
PDF 专用预览地址;只有文档类文件转码成功后才会有值 |
previewUrl |
前端推荐直接打开的统一地址;前端点击“预览/打开”时优先使用它 |
计算规则:
- 当
previewMode = "pdf":previewUrl = pdfUrl - 当
previewMode = "download":previewUrl = downloadUrl - 当
previewMode = "none":previewUrl = null
注意事项:
pdfUrl是 PDF 能力字段,previewUrl是前端统一消费字段,语义不同,请勿混淆。pdfPreviewStatus=ready且pdfUrl非空时previewMode=pdf;pdfPreviewStatus=none且downloadUrl非空时previewMode=download;failed/无可消费 URL 时previewMode=none。
6 积分
6.1 获取积分详情 DescribePointsOverview
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribePointsOverview |
| 是否鉴权 | 是 |
请求体:无。
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
remainingPoints |
float64 | 当前用户剩余积分 |
currentPackage |
string | 当前会员身份,普通用户为空字符串;枚举 plan_pro、plan_max |
packageExpireAt |
int | 当前用户会员到期时间(UTC 秒数);普通用户或已过期用户为 0 |
响应示例
1{
2 "remainingPoints": 1000.0,
3 "currentPackage": "plan_pro",
4 "packageExpireAt": 1780416000
5}
6.2 发放每日登录积分 IssueLoginBonus
每日发放登录积分,幂等(一天仅发放一次)。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=IssueLoginBonus |
| 是否鉴权 | 是 |
请求体:无。
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
result |
bool | 是否发放成功 |
响应示例
1{
2 "result": true
3}
6.3 获取积分发放记录 DescribePointsCharge
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribePointsCharge |
| 是否鉴权 | 是 |
请求体参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
startAt |
int | 是 | 开始日期当天 0 点的 UTC Unix 秒数 |
endAt |
int | 是 | 结束日期当天 24 点的 UTC Unix 秒数 |
page |
int | 否 | 页码,不传默认 1 |
limit |
int | 否 | 每页条数,不传默认 10 |
changeType |
string | 否 | 发放类型,不传默认返回全部类型数据 |
changeType 枚举值
1const (
2 ChangeTypeOrderPlanPro string = "order_plan_pro" // 订阅个人版 Pro
3 ChangeTypeOrderPlanMax string = "order_plan_max" // 订阅个人版 Max
4 ChangeTypeOrderPlanPoint string = "order_plan_point" // 订阅积分增量包
5 ChangeTypeOrderPlanTeam string = "order_plan_team" // 订阅企业 Team 版
6 ChangeTypeRedeemPlan string = "redeem_plan" // 会员兑换,使用会员兑换码进行兑换时使用
7 ChangeTypeFreeGrant string = "free_grant" // 免费赠送
8 ChangeTypePointClear string = "point_clear" // 积分清零
9 ChangeTypeInviteBonus string = "invite_bonus" // 邀请奖励
10 ChangeTypeNewbieTask string = "newbie_task" // 新手任务
11)
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
totalCount |
int | 总记录数 |
list |
array | 本页数据(积分流水,见下),每个元素结构见 PointRecord 结构体 |
响应示例
1{
2 "totalCount": 2,
3 "list": [
4 {
5 "packageId": "{packageId}",
6 "createdAt": 1780416000,
7 "changeType": "order_plan_point",
8 "pointsChange": "1000.00"
9 },
10 {
11 "packageId": "{packageId}",
12 "createdAt": 1780329600,
13 "changeType": "order_plan_pro",
14 "pointsChange": "10000.00"
15 }
16 ]
17}
积分流水(PointRecord)
| 字段 | 类型 | 说明 |
|---|---|---|
packageId |
string | 资源包 ID |
createdAt |
int | 发生时间(UTC Unix 秒数) |
changeType |
string | 计费类型 |
pointsChange |
string | 积分变动值(正/负),保留两位小数 |
6.4 获取积分消耗记录 DescribePointsUsage
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribePointsUsage |
| 是否鉴权 | 是 |
请求体参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
startAt |
int | 是 | 开始日期当天 0 点的 UTC Unix 秒数 |
endAt |
int | 是 | 结束日期当天 24 点的 UTC Unix 秒数 |
page |
int | 否 | 页码,默认 1 |
limit |
int | 否 | 每页条数,默认 10 |
请求示例
1{
2 "startAt": 1780243200,
3 "endAt": 1780416000,
4 "page": 1,
5 "limit": 10
6}
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
totalCount |
int | 总记录数 |
list |
array | 本页数据(积分使用,见下) |
积分使用(PointUsage)
| 字段 | 类型 | 说明 |
|---|---|---|
conversationId |
string | 关联会话 ID |
conversationTitle |
string | 关联会话名称 |
createdAt |
int | 发生时间(UTC Unix 秒数) |
packageId |
string | 消耗资源包 ID |
pointsChange |
string | 积分变动值(正/负),保留两位小数 |
响应示例
1{
2 "totalCount": 2,
3 "list": [
4 {
5 "conversationId": "{conversationId}",
6 "conversationTitle": "我的机器人Chat01",
7 "packageId": "{packageId}",
8 "createdAt": 1780416000,
9 "pointsChange": "-227.08"
10 },
11 {
12 "conversationId": "{conversationId}",
13 "conversationTitle": "我的机器人Chat02",
14 "packageId": "{packageId}",
15 "createdAt": 1780329600,
16 "pointsChange": "-1330.20"
17 }
18 ]
19}
6.5 计费与限流说明
6.5.1 计费机制
- 计费主体:搭子对话按消息消耗积分。单条回复的消耗通过
DescribeSessionMessages消息中的cost字段(见 3.10)查看,与DescribePointsUsage的pointsChange(负值)相互印证。 - 余额口径:
DescribePointsOverview.remainingPoints 为当前可用积分;currentPackage标识会员身份(plan_pro/plan_max),会员用户按会员权益计费。 - 流水对账:
DescribePointsCharge(发放)与DescribePointsUsage(消耗)均为按日期的分页流水(UTC 秒),可据此实现积分账单。 - 余额不足:余额不足以支付本次消耗时如何处理(按余额扣至 0 / 拒绝本次请求),以接口实际返回为准;建议接入方在
remainingPoints低于阈值时提前引导用户充值/订阅。
6.5.2 限流与并发
接口存在请求频率与并发限制,超限时返回限流错误码(见 10.1,以实际 message 为准)。接入方应在客户端实现退避重试,并向用户提示“请求过于频繁”。
7 Skill 管理
Skill 是搭子可调用的能力单元(如地图查询、百科知识、数据分析等)。
7.1 初始化 Skill InitSkills
初始化/更新用户 Skill 沙箱文件。单个用户多次调用只会触发一次初始化,后续调用会对比用户云上沙箱中的 Skill 版本做自动更新(用户无感)。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=InitSkills |
| 是否鉴权 | 是 |
请求体:无。
请求示例
1curl -X POST 'https://www.dumate.cn/openapi?Action=InitSkills' \
2 -H 'Authorization: Bearer {apiKey}' \
3 -H 'X-Dumate-Token: {dumateToken}'
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
success |
bool | 是否初始化成功 |
响应示例
1{
2 "requestId": "{requestId}",
3 "success": true
4}
7.2 获取用户 Skill 列表 DescribeSkills
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeSkills |
| 是否鉴权 | 是 |
请求体参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
nameFilter |
string | 否 | 按名称过滤 |
enable |
string | 否 | 启用状态过滤 |
sortBy |
string | 否 | 排序字段,默认 name |
appVersion |
string | 否 | 应用版本,默认空字符串 |
请求示例
1curl -X POST 'https://www.dumate.cn/openapi?Action=DescribeSkills' \
2 -H 'Authorization: Bearer {apiKey}' \
3 -H 'X-Dumate-Token: {dumateToken}' \
4 -H 'Content-Type: application/json' \
5 --data '{"nameFilter": "demo"}'
响应参数:skillList —— Skill 元素数组。
Skill 元素字段
| 字段 | 类型 | 说明 |
|---|---|---|
name |
string | Skill 唯一标识(code) |
description |
string | Skill 描述(英文) |
scope |
string | 作用域:project(用户级)/ global(全局) |
source |
string | 来源:official(官方)/ user(用户自定义) |
version |
string | 当前安装版本(云端广场版本) |
labels |
array | 标签列表(见 Label) |
authorInfo |
object | 作者信息(见 AuthorInfo) |
displayName |
string | Skill 中文显示名称 |
icon |
string | Skill 图标 URL(可选) |
remark |
string | Skill 中文描述 |
Label
| 字段 | 类型 | 说明 |
|---|---|---|
labelCode |
string | 标签代码 |
labelName |
string | 标签名称 |
labelIcon |
string | 标签图标(可选) |
AuthorInfo
| 字段 | 类型 | 说明 |
|---|---|---|
authorId |
string | 作者 ID(可选) |
authorName |
string | 作者名称(可选) |
authorAvatar |
string | 作者头像(可选) |
fromThirdParty |
string | 第三方来源平台标识(可选) |
响应示例
1{
2 "requestId": "{requestId}",
3 "skillList": [
4 {
5 "authorInfo": {
6 "authorName": "百度千帆官方"
7 },
8 "description": "The Baidu Baike Component is a knowledge service tool designed to query authoritative encyclopedia explanations for various nouns. Its core function is given a specific \"noun\" (object, person, location, concept, event, etc.) provided by the user, it returns a standardized, detailed entry explanation sourced from Baidu Baike.",
9 "displayName": "百度百科",
10 "icon": "https://{cdn-host}/icons/{iconId}.png",
11 "labels": [
12 {
13 "labelCode": "dumate_skill_official",
14 "labelName": "官方"
15 },
16 {
17 "labelCode": "dumate_skill_noauth",
18 "labelName": "免鉴权"
19 },
20 {
21 "labelCode": "tool_square_industry_service",
22 "labelIcon": "https://{cdn-host}/icons/{iconId}.svg",
23 "labelName": "行业服务"
24 }
25 ],
26 "name": "baidu-baike-data",
27 "remark": "百度百科组件是一个知识服务工具,用于查询各类名词的权威百科解释。其核心功能是:给定用户提供的特定名词(事物、人物、地点、概念、事件等),从百度百科返回标准化、详细的词条说明。",
28 "scope": "global",
29 "source": "official",
30 "version": "1.1.3"
31 }
32 ]
33}
7.3 获取用户 Skill 详情 DescribeSkill
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeSkill |
| 是否鉴权 | 是 |
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
string | 是 | Skill 名称 |
请求示例
1curl -X POST 'https://www.dumate.cn/openapi?Action=DescribeSkill' \
2 -H 'Authorization: Bearer {apiKey}' \
3 -H 'X-Dumate-Token: {dumateToken}' \
4 -H 'Content-Type: application/json' \
5 --data '{"name":"baidu-ai-map"}'
响应参数
result 数据结构(UserSkillDetailResponse):内嵌 SkillUserItem 全部字段,并附加 files、updatedAt。
| 字段名 | 类型 | 说明 |
|---|---|---|
name |
string | Skill 唯一标识(code) |
description |
string | Skill 描述(英文) |
scope |
string | 作用域:project(用户级)/ global(全局) |
source |
string | 来源:official(官方)/ user(用户自定义) |
version |
string | 当前安装版本(云端广场版本) |
labels |
array | 标签列表,结构见 Label(可选) |
authorInfo |
object | 作者信息,结构见 AuthorInfo(可选) |
displayName |
string | Skill 中文显示名称 |
icon |
string | Skill 图标 URL(可选) |
remark |
string | Skill 中文描述 |
响应示例
1{
2 "requestId": "{requestId}",
3 "authorInfo": {
4 "authorName": "百度地图"
5 },
6 "description": "百度地图 API 调用工具,用于获取结构化地图数据。支持:地点检索(POI搜索)、路线规划(驾车/步行/骑行/公交)、地理编码(地址转坐标)、逆地理编码(坐标转地址)。需要 BAIDU_MAP_AUTH_TOKEN 环境变量。",
7 "displayName": "百度地图",
8 "icon": "https://{cdn-host}/icons/{iconId}.svg",
9 "labels": [
10 {
11 "labelCode": "dumate_skill_official",
12 "labelName": "官方"
13 },
14 {
15 "labelCode": "tool_square_industry_service",
16 "labelIcon": "https://{cdn-host}/icons/{iconId}.svg",
17 "labelName": "行业服务"
18 }
19 ],
20 "name": "baidu-ai-map",
21 "remark": "百度地图 API 调用工具,用于获取结构化地图数据。支持:地点检索(POI搜索)、路线规划(驾车/步行/骑行/公交)、地理编码(地址转坐标)、逆地理编码(坐标转地址)。需要 BAIDU_MAP_AUTH_TOKEN 环境变量。适用场景:需要精确坐标、结构化路线数据、地址解析等 API 级能力。不适用:一般性路线查询、地点介绍、旅游攻略等搜索类需求。",
22 "scope": "global",
23 "source": "official",
24 "version": ""
25}
8 定时任务
8.1 任务列表 DescribeSessionJobs
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeSessionJobs |
| 是否鉴权 | 是 |
请求体参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
workspaceId |
string | 否 | 按工作区过滤 |
sort |
string | 否 | latestTriggeredAtDesc(按最近触发倒序);默认 created_at DESC |
page |
int | 否 | 页码,1-based,默认 1 |
size |
int | 否 | 每页条数,默认 20,上限 100 |
响应参数:result —— Job 数组(注:返回的是数组而不是 {items, totalCount} 包裹层;满 size 视为可能还有下一页)。
Job 字段
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 任务 ID(job_ 前缀) |
workspaceId |
string | 所属工作区 ID |
name |
string | 任务名称 |
enabled |
boolean | 是否启用 |
cronExpr |
string | 调度表达式(5 段格式:分 时 日 月 周) |
timezone |
string | 时区 |
executor.message |
string | 任务执行的指令消息 |
executor.model |
string | 任务执行模型(实际以服务端返回为准) |
concurrency |
string | 并发策略:forbid / allow |
retry.maxRetries |
int | 最大重试次数 |
retry.maxDelayMs |
int | 最大重试延迟(ms) |
timeoutSecs |
int | 超时时间(秒) |
createdAt / updatedAt |
int | 创建 / 更新时间戳(ms) |
version |
int | 版本号 |
accountId |
string | 所属账号 |
agent |
string | 执行 Agent 名称 |
bindDeviceId |
string | 绑定设备 ID(本地调度模式) |
deviceName |
string | 设备名称(本地调度模式) |
schedulerMode |
string | 调度模式:cloud / local |
taskType |
string | 任务类型 |
createdVia |
string | 创建方式:manual 等 |
source |
string | 来源:desktop / cloud 等 |
syncStatus |
string | 同步状态 |
runStartTimeMs |
int | 最近开始运行时间(ms) |
template |
int | 是否为预置模板任务:1 模板任务 / 0 普通任务 |
state.nextRunAtMs |
int | 下次运行时间(ms) |
state.lastRunAtMs |
int | 上次运行时间(ms) |
state.lastStatus |
string | 上次运行状态 |
state.consecutiveErrors |
int | 连续错误次数 |
state.retryAfterMs |
int | 重试等待时间(ms) |
state.readStatus |
string | 阅读状态 |
响应示例
1{
2 "result": [
3 {
4 "id": "job_{jobId}",
5 "workspaceId": "ws_{workspaceId}",
6 "name": "每日记忆总结",
7 "enabled": false,
8 "cronExpr": "0 9 * * *",
9 "timezone": "Local",
10 "executor": {"message": "总结记忆文件,生成结构化的每日总结报告"},
11 "concurrency": "forbid",
12 "retry": {"maxRetries": 0, "maxDelayMs": 3600000},
13 "timeoutSecs": 1800,
14 "createdAt": 1784272894199,
15 "updatedAt": 1784272894199,
16 "version": 1,
17 "accountId": "{accountId}",
18 "agent": "daily-summary",
19 "schedulerMode": "local",
20 "source": "desktop",
21 "taskType": "unknown",
22 "createdVia": "manual",
23 "syncStatus": "ok",
24 "template": 0,
25 "state": {"nextRunAtMs": 0, "lastRunAtMs": 0, "lastStatus": "", "consecutiveErrors": 0, "retryAfterMs": 0, "readStatus": "read"}
26 }
27 ]
28}
9 个性化配置
9.1 首页定制 DescribeHomepageConfig
下发定制 Logo、slogan 等首页配置,用于渠道/应用首页品牌化展示。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求路径 | /openapi?Action=DescribeHomepageConfig |
| 是否鉴权 | 是 |
请求体参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
version |
string | 是 | 客户端版本号 |
clientType |
string | 否 | desktop / mobile,默认 desktop |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
query |
String | 首页预置 query 文案 |
logo |
Object | 首页 Logo 配置(静态/动画图、slogan、尺寸) |
prompt |
String | 首页引导文案 |
startTime |
String | 配置生效时间 |
expirationTime |
String | 配置过期时间 |
ext |
Object | 扩展配置 |
响应示例
1{
2 "expirationTime": "2026-07-26T18:00:00+08:00",
3 "ext": {"skill": []},
4 "logo": {
5 "width": 228,
6 "height": 74,
7 "icon": "https://{cdn-host}/homepage_config/{customId}/icon.png?md5hash={md5}×tamp={ts}",
8 "slogan": "{定制slogan占位}",
9 "primary": {"duration": 3.276, "hold": 10, "image": "https://{cdn-host}/homepage_config/1.0.44/active.png?md5hash={md5}×tamp={ts}"},
10 "hover": {"duration": 0.1, "image": "https://{cdn-host}/homepage_config/1.0.44/hover.png?md5hash={md5}×tamp={ts}"}
11 },
12 "prompt": "首页引导文案",
13 "query": "[\"欢迎使用搭子\"]",
14 "requestId": "{requestId}",
15 "startTime": "2026-07-01T17:45:00+08:00"
16}
10 返回码与错误处理
10.1 错误码
接口异常时(HTTP 状态码仍为 200)统一返回 code + message 字段:
| code | 示例 message | 说明 |
|---|---|---|
| 401 | PermissionDenied | 鉴权失败:API Key 或 Token 无效 / 过期 |
| 400 | 参数错误:FieldName | 请求参数错误,message 指明出错字段 |
| 400 | 业务异常信息 | 业务规则校验失败,以 message 描述 |
通用处理建议:
- 所有接口先校验
requestId是否返回;异常时读取code/message定位问题。 - 收到 401:检查沙盒/线上环境是否匹配、API Key 与 Token 是否有效,必要时刷新 Token 后重试。
- 收到 400:按 message 提示修正参数(必填缺失、格式错误、枚举越界等)。
10.2 注意事项与 FAQ
| 主题 | 说明 |
|---|---|
| Token 过期时间 | DescribeToken 返回的 expired_at 为 UTC 格式,需转换为本地时间判断,提前刷新 |
| Token 过期处理 | 收到 401 后按 2.1 标准流程刷新 Token 并重试一次 |
| API Key 安全 | Key 仅控制台展示一次,妥善保管勿入仓库;泄露后在控制台吊销重建 |
| 环境区分 | 沙盒与线上使用不同的 API Key(且 Token 与 Key 环境强绑定),请勿混用;切换按 1.7 清单 |
| 接入前置条件 | 未申请 API Key 前无法调用任何接口,见 1.2 申请步骤 |
| Query 参数 | 标注“Query 参数”的接口(如会话详情、文件详情、推荐问、预上传文件地址)需将参数拼接在 URL 上,且 path 类参数需 URL 编码 |
| 分屏规则 | 推荐问接口不分页返回,客户端按每 4 条切分一屏 |
| 文件大小 | CreatePreSessionFile 单个文件不超过 10MB |
| 文件生命周期 | 上传文件保留时长由服务端策略决定,生产环境请勿长期依赖缓存文件 |
| 文件预览 | previewUrl 是前端统一消费字段(点击打开优先用它);pdfUrl 仅为 PDF 能力字段;两者语义不同 |
| 权限回复对账 | POST /permission/:requestID/reply 返回 200 true 只代表调用成功;需重新 GET /permission 确认 pending 已清除 |
| SSE 粘性路由 | 同一账号的 /event、权限查询与回复请求需路由到同一服务实例(通常由网关按账号粘性处理) |
| SSE 断线处理 | 按 3.3.3 自动重连,重连后用权限/消息/任务三连对账补齐状态 |
| 消息完成判定 | 以 SSE“会话空闲”类事件为准,兜底轮询 DescribeSessionStatus(见 3.3.3 / 1.6 Step 4) |
| 消息 limit | 历史消息接口不支持 offset 分页,limit 仅为数量截断 |
| 定时任务返回结构 | DescribeSessionJobs 返回裸 Job 数组(非分页包裹层),满 size 视为可能还有下一页 |
评价此篇文章
