← 全部文档

平台插件 REST API 契约

插件应用与 Cadau 之间的接口约定,给对接团队查阅。

来源 sdk/platform-plugin/contracts/API.md

Base URL:{Cadau 站点}/api/v1 版本:0.1(与 Cadau 后端 platform_plugin_*.go 一致)

适用范围:下文 REST 与 platform_plugins[] 注册仅用于 应用桌面 iframe 型插件。对话里让工作智能体调业务 API(识脸、画图等)请用 技能 + 联网能力包,见 [../../agent-capability/README.md](/docs/sdk-agent-capability) 与 [../README.md](/docs/sdk-platform-plugin)。


0. 注册与插件网关

在 Cadau mindlink.json → platform_plugins[] 注册(示例 registration.example.json):

{
  "module_id": "my-plugin",
  "display_name": "我的插件 (My plugin)",
  "entry_base_url": "/p/my-plugin/",
  "upstream_url": "http://127.0.0.1:3010",
  "enabled": true
}
字段说明
module_id唯一标识;网关路径为 /p/{module_id}/
entry_base_urlLaunch 拼 launch_token 后给 iframe;推荐同源 /p/{module_id}/
upstream_url可选;Cadau 将 /p/{module_id}/* 反代到此内网地址
enabled为 false 时桌面不展示

网关请求路径(浏览器 → Cadau Web → 后端 → upstream):

GET /p/my-plugin/api/health

→ 反代到 {upstream_url}/api/health(路径前缀 /p/my-plugin 会被剥掉)。

无 upstream 时:仅 entry_base_url 指向你的公网/独立 URL,Cadau 不代理静态页与插件 API。

实现对照:backend/internal/platformplugin/proxy.go;Web Nginx location /p/ → 后端。


1. Cadau 侧(用户已登录)

1.1 列出已注册插件

GET /platform-plugins
Authorization: Bearer {用户 access_token}

响应 items[]:module_id, display_name, suite, icon, entry_base_url, enabled(内网 upstream_url 不返回给客户端)

1.2 启动插件

POST /workspaces/{workspace_id}/platform-plugins/{module_id}/launch
Authorization: Bearer {用户 access_token}

响应:

字段说明
module_id插件标识
display_name给人看的应用名。中文后加英文括号,如「邮件 (Email)」,避免看不懂中文的人无法辨认
launch_token插件用 JWT,约 15 分钟有效;Cadau 壳在过期前静默续签并向 iframe 推送
entry_urliframe 入口,已附带 launch_token、workspace_id 查询参数
expires_atISO 8601
api_base_url相对站点的 API 前缀,通常为 /api/v1
workspace_id当前工作区
member_roleowner / admin / member
data_namespace工作区插件数据隔离(与 session 同结构)

1.3 插件随发技能(安装到工作区技能中心)

应用型插件可在仓库携带 skills/{slug}/(见 platform-plugin §7.5)。安装进 工作区技能中心 使用 用户登录 鉴权,不是 launch_token。

产品口径:按 slug 幂等写入技能中心;区内智能体默认可召回;不要在 seed 时改写各智能体的可用技能收窄配置。

GET /workspaces/{workspace_id}/platform-plugins/{module_id}/skills
Authorization: Bearer {用户 access_token}

响应:

字段说明
module_id插件标识
skills[]slug、installed、up_to_date、needs_update、skill_id、name、bundle_fingerprint、installed_fingerprint
any_missing是否存在未安装项
any_needs_update是否存在已装但指纹落后项
can_manage_members当前用户是否可 seed

无已注册随发技能时返回 skills: [](仍 200)。

POST /workspaces/{workspace_id}/platform-plugins/{module_id}/skills/seed
Authorization: Bearer {用户 access_token}
Content-Type: application/json

{ "slug": "practice-checklist-to-pack" }
  • 须 可管理成员。
  • slug 可选;省略则安装/升级该模块全部已注册随发技能。
  • 响应:{ "ok": true, "module_id", "results": [ { slug, created, upgraded, skipped, skill_id, name, fingerprint } ] }。
  • 未知 module_id/slug(无注册包)→ 404。

实现:backend/internal/skillfromchat/plugin_skill_seed.go(RegisterPluginSkillBundle);合规注册见同包 compliance_practice_seed.go;作者镜像:plugins/compliance/skills/。


2. 插件侧(Bearer launch_token)

以下接口 无需 Cadau 用户 Cookie,仅需:

Authorization: Bearer {launch_token}

2.1 校验会话

GET /platform-plugins/session

响应:

{
  "module_id": "my-plugin",
  "module_display_name": "我的插件 (My plugin)",
  "user_id": "uuid",
  "user_display_name": "张三",
  "workspace_id": "uuid",
  "workspace_name": "研发团队",
  "member_role": "admin",
  "expires_at": "2026-07-02T10:00:00Z",
  "data_namespace": {
    "kind": "postgres_schema",
    "location": "ws_…",
    "schema": "ws_…"
  }
}

data_namespace:工作区插件数据隔离(Postgres schema 或 SQLite 文件路径/DSN)。Launch 响应同样包含该字段。

智能体调用插件:工具 plugin_invoke → Cadau 签发短时 JWT(knd=plugin_invoke)→ 插件 POST /api/agent/invoke。操作清单见插件 operations.json(或配置 operations_url)。

错误码:plugin_launch_invalid(过期或无效)、plugin_disabled、forbidden

2.1.1 工作区成员(绑定账号用)

GET /platform-plugins/workspace-members

Bearer launch_token。返回当前工作区成员简表(user_id、display_name、email、phone、member_role),供插件绑定员工档案、任命插件内角色。任意工作区成员可读。

2.1.2 代发短信 / 邮件

GET /platform-plugins/notify
POST /platform-plugins/notify

Bearer 为 launch_token,或插件用与 Cadau 相同 jwt_secret 签发的短时 JWT(knd=plugin_notify,wid / mod)。用于摄像机回传等没有用户会话时的告警。

查询通道 GET:与代发同一套判断(本机通道或路由端已开通)。不要在插件里自己猜。

{ "sms": { "configured": true }, "email": { "configured": false }, "wecom": { "configured": false, "note": "微信消息尚未开通" } }

代发 POST:

{ "channel": "sms", "to": "13800138000", "text": "201811" }
{ "channel": "email", "to": "ops@example.com", "subject": "安防提醒", "text": "正文", "html": "<p>正文</p><p><img src=\"cid:snap1\" alt=\"抓拍\"></p>", "images": [{ "cid": "snap1", "content_type": "image/jpeg", "filename": "capture.jpg", "data_base64": "…" }] }
  • channel:sms 或 email(微信消息尚未开通)
  • 短信走站点短信通道(模板第一项为告警摘要,建议不超过 60 字)
  • 邮件走站点邮件通道,可自定义主题与正文;安防提醒可带 html 与最多两张 images(JPEG,cid 内嵌并作为附件,便于网页邮箱查看抓拍)
  • 同一工作区每分钟最多 40 条

错误码:sms_not_configured、smtp_not_configured、invalid_phone、invalid_email、rate_limited

2.2 知识文档

路径均相对于插件主题目录 plugin-{module_id}/(Cadau 自动维护索引)。

列出

GET /platform-plugins/knowledge/items

读取

GET /platform-plugins/knowledge/content?path=guide.md

写入(需 member_role 为 owner/admin)

PUT /platform-plugins/knowledge/content
Content-Type: application/json

{
  "path": "guide.md",
  "content": "# 标题\n\n正文…",
  "title": "入门指南",
  "summary": "一句话摘要,供检索匹配",
  "tags": ["标签1", "标签2"]
}

删除(需 owner/admin)

DELETE /platform-plugins/knowledge/content?path=guide.md

批量同步(需 owner/admin)

POST /platform-plugins/knowledge/sync
Content-Type: application/json

{
  "documents": [
    { "path": "a.md", "content": "…", "title": "A" },
    { "path": "b.md", "content": "…", "title": "B" }
  ]
}

响应:{ "ok": true, "synced": ["a.md","b.md"], "count": 2, "theme_dir": "plugin-my-plugin" }

范围:插件知识同步为 Markdown 正文(path + content)。工作区知识里的图片/短视频等富媒体由 Cadau 产品侧管理,不经本 sync API 上传。

2.2.1 规范库只读(工作区法规与管理标准)

真源与发布流见产品 §3.2.2 / docs/core-mechanisms/规范库.md。插件仅可读 已发布且生效中 的条目。

GET /platform-plugins/standards
GET /platform-plugins/standards?tag=hr
GET /platform-plugins/standards/{standardId}
GET /platform-plugins/standards/{standardId}/content

鉴权:Authorization: Bearer <launch_token>(与知识 API 相同)。

2.2.2 资料库只读(工作区模板与表格)

真源与发布流见产品 §3.2.3 / docs/core-mechanisms/资料库.md。插件仅可读 已发布 条目;/file 返回二进制文件流。

GET /platform-plugins/assets
GET /platform-plugins/assets?tag=hr
GET /platform-plugins/assets/{assetId}
GET /platform-plugins/assets/{assetId}/file

鉴权:Authorization: Bearer <launch_token>(与知识 API 相同)。

2.2.3 工作区大模型(结构化 JSON)

插件不要自带模型 API Key。需要「根据正文生成问卷 / 推荐编制」等短时结构化结果时,经本接口使用当前工作区已配置的大模型。

与「插件内嵌助手对话」(§2.3 embed)不同:本接口是服务端一次性 system+user → JSON 文本,无会话态。

POST /platform-plugins/ai/json
Authorization: Bearer <launch_token>
Content-Type: application/json

{
  "system": "你是……只输出一个 JSON 对象:{...}",
  "user": "{ \"context\": \"…\" }"
}

响应:

{ "text": "{ \"…\": \"模型返回的 JSON 字符串(可能仍带说明文字,调用方应解析/清洗)\" }" }
约束说明
鉴权launch_token(与知识 / 规范库相同)
system / user均必填;长度按 Unicode 字符计:system≤32000、user≤400000(适配大上下文模型;业务侧仍建议按任务拆分)
未配置模型HTTP 503,code≈llm_disabled,文案提示工作区尚未配置大模型
调用失败HTTP 502,code≈llm_error
SDKGo Client.AIJSON · JS client.aiJSON(system, user)
可选attachment_ids 附图/PDF;pdf_pages=true 时即使 PDF 有文本层也附带页面截图(用于抽证件照)

官方用法参考:plugins/hr 编制智能推荐、简历抽出照片与证书、plugins/compliance 按规范生成调查问卷。

2.2.4 插件上传抽图 / 裁切

简历分析等场景从已上传的 PDF / Word(.docx)/ 网页简历 / 图片抽出嵌入图,或按归一化框裁切证件照、证书扫描件。结果写入当前用户的上传库,返回新的 file_id。

POST /platform-plugins/uploads/{id}/extract-images
Authorization: Bearer <launch_token>
POST /platform-plugins/uploads/{id}/extract-text
Authorization: Bearer <launch_token>

响应 { "text": "可读正文" }。抽不出或乱码时 text 为空。

POST /platform-plugins/uploads/{id}/crop
Authorization: Bearer <launch_token>
Content-Type: application/json

{ "items": [{ "page": 1, "x": 0.7, "y": 0.05, "width": 0.25, "height": 0.28, "label": "求职者照片" }] }

x/y/width/height 为 0–1 相对页面(或相对整张图片)。响应均为 { "images": [{ "file_id", "filename", "mime_type", "width", "height", "page" }] }。

2.3 内嵌助手令牌

POST /platform-plugins/embed-token
Content-Type: application/json

{
  "user_agent_id": "uuid",
  "app_id": "my-plugin",
  "ttl_seconds": 3600
}

响应与 POST /user-agents/{id}/embed-token 类似:access_token、token_type、expires_in、expires_at、workspace_id、user_agent_id、app_id、permanent、record_id

随后前端加载 {Cadau}/embed/mindlink-widget.min.js 并 init(见嵌入 SDK 契约)。

2.4 发起工作流(审批须带单据快照)

业务单据走工作流审批时,发起时把要审的全文写入 variables.approval_doc。引擎会提到实例载荷,审批步直接渲染。引擎 不会回头去插件再拉单据。禁止只传 id / 标题再让审批人跳回应用。

GET /platform-plugins/workflows/definitions
POST /platform-plugins/workflows/start
Authorization: Bearer <launch_token>
Content-Type: application/json
{
  "definition_id": "uuid",
  "title": "提交用人需求 · YR-2026-0001",
  "variables": {
    "staffing_req_id": "uuid",
    "approval_doc": {
      "title": "用人需求 YR-2026-0001",
      "subtitle": "按编制缺口拟用人需求",
      "fields": [
        { "label": "申请人", "value": "陈晨" },
        { "label": "申请部门", "value": "职能支持" }
      ],
      "tables": [{
        "title": "明细",
        "columns": ["部门", "岗位", "人数"],
        "rows": [["职能支持", "财务专员", "1"]]
      }],
      "note": ""
    }
  }
}
字段说明
definition_id工作区流程定义 id(GET …/definitions)。须已发布;未发布会拒绝发起
title实例标题,给人看
variables.approval_doc审批类必填。对象或 JSON 字符串。形状见下表 ApprovalDoc
其它 variables写回用的业务 id 等扁平键(如 staffing_req_id),与快照分开

ApprovalDoc:

字段类型说明
titlestring单据标题(含单号)
subtitlestring可选副标题
fields[]{ label, value }单头:申请人、部门、事由、有效期等,不要只给 id
tables[]{ title?, columns[], rows[][] }明细行
notestring可选备注

SDK:Go Client.StartWorkflow + WithApprovalDoc / FieldListApprovalDoc;TS client.startWorkflow + withApprovalDoc / fieldListApprovalDoc。类型 ApprovalDoc。

自动节点 invoke 成功也可返回顶层 approval_doc(例如签署单在流程中创建后再挂快照)。提交即审批的主路径仍是发起时写入。

参考:plugins/hr 提交用人需求、入离调办结后发起;产品真值 workflow.json-v1.md「审批单据快照」。


3. 插件自有 HTTP 约定(推荐)

路径说明
POST /api/bootstrapbody { "launch_token" } → 验会话、可选同步知识、返回用户上下文(含 data_namespace)
GET /api/session用 Bearer 或 Cookie 中的启动令牌刷新会话
GET /api/health健康检查
GET /operations.json智能体可调用操作清单;有填写弹层时 必须 含 fill_open_form(见 §3.2);可同文件声明 workflow_steps;或在注册里配 operations_url
POST /api/agent/invoke(可选)智能体 plugin_invoke 与工作流自动节点;校验 JWT(knd=plugin_invoke),非 launch_token

iframe 会话:前端将 launch_token 存入 sessionStorage,后续请求带 Authorization: Bearer …。插件自有 API 路径请用相对路径或 resolvePluginAPI(),以兼容 Cadau 同源网关 /p/{module_id}/。

3.1 宿主 ↔ 插件 postMessage

方向type说明
宿主 → 插件mindlink:launch_token静默续签;须写入 sessionStorage(JS:listenHostLaunchToken)
宿主 → 插件mindlink:themetheme: light \dark(JS:listenHostTheme)
宿主 → 插件mindlink:localelocale: zh \en(JS:listenHostLocale)
宿主 → 插件mindlink:plugin_tab帮助深链等切换插件内 tab(JS:listenHostPluginTab)
宿主 → 插件mindlink:plugin_nav打开栏目抽屉(Cadau 小屏汉堡;JS:listenHostPluginNav)
宿主 → 插件mindlink:plugin_data_changed业务数据已变,建议刷新(JS:listenHostPluginDataChanged)
宿主 → 插件mindlink:plugin_form_fill把助手解析的字段写回当前草稿(§3.2;JS:listenHostPluginFormFill)
插件 → 宿主mindlink:request_launch_tokensource 须为 mindlink-plugin;热重载/401 时主动要令牌(JS:requestHostLaunchToken)
插件 → 宿主mindlink:request_localesource 须为 mindlink-plugin;首屏或热重载时主动要当前语言(JS:requestHostLocale)
插件 → 宿主mindlink:plugin_ui_changed上报当前打开的填写弹层(§3.2;JS:postPluginUiChanged)
插件 → 宿主mindlink:plugin_tab_changed当前栏目 id + 用户可见 title(Cadau 小屏顶栏;JS:postPluginTabChanged)

宿主消息 source 为 mindlink;插件消息 source 为 mindlink-plugin。

3.2 认正在填的单(宿主协议)

有可填弹层的插件 必须 实现。产品口径:[../README.md §6.1](/docs/sdk-platform-plugin);规格 §4.1.5。

用户打开填写弹层时,应用助手要认出这张单。无特殊说明时,自然语言操作默认针对当前界面(当前应用、页签、已打开的填写弹层),用户不必点名单据。把自然语言写回草稿、立刻显示;未说「保存 / 创建 / 提交 / 办结」前 不得落库。

#### 3.2.1 插件 → 宿主:mindlink:plugin_ui_changed

window.parent.postMessage,source 必须为 mindlink-plugin。JS:postPluginUiChanged。

{
  "source": "mindlink-plugin",
  "type": "mindlink:plugin_ui_changed",
  "module_id": "my-plugin",
  "tab": "home",
  "dialog": "draft",
  "dialog_title": "示例草稿",
  "form": { "name": "张三" },
  "field_hints": "名称,备注",
  "readonly": false
}
字段说明
module_id与注册一致
tab当前页签(可选)
dialog当前弹层 id;关闭时传空字符串,宿主会清掉「正在填的单」
dialog_title用户可见标题(问「当前界面」时用这个)
form已填非空字段(字符串);空草稿也可只报 dialog + field_hints。表格有多行时须上报每一行(如 line_count、line_1、line_2),禁止只报第一行
field_hints可写字段的用户说法,逗号分隔,如 名称,备注
readonlytrue:查看弹层,助手只点明标题、不调用 fill_open_form

Cadau 会把 dialog / dialog_title / form / field_hints / readonly 带进对话 client_context。

#### 3.2.2 操作 fill_open_form

operations.json 中 name 必须为 fill_open_form,mutates: false。Cadau POST /api/agent/invoke 请求体:

{
  "operation": "fill_open_form",
  "args": {
    "form": "draft",
    "fields": { "name": "张三", "备注": "加急" }
  }
}
args说明
form与当前 dialog 一致;可省略(宿主按当前打开的弹层回填)。也可接受 dialog / case_type
fields要写入的键值;中英文字段名均可;可嵌套,宿主/SDK 会拍平

插件成功响应(可包在 { "ok": true, "result": { … } } 里,宿主会向下找 ui_action):

{
  "ui_action": "fill_form",
  "form": "draft",
  "fields": { "name": "张三", "note": "加急" },
  "unresolved": [],
  "note": "已写入当前打开的表单,尚未保存到系统"
}
字段说明
ui_action必须 fill_form,否则宿主不会写回界面
form目标草稿 id
fields已规范化、可直接塞进输入框的字符串(名称已解析成 id 的放这里)
unresolved可选;{ "field", "value", "reason" }[],对不上现有记录时告知助手
note可选;助手可读的一句说明

禁止在本操作里 INSERT/UPDATE 业务表。需要解析「研发部」→ 部门 id 时只改 fields,仍不落库。

Go:FillOpenFormPassthrough(body.Args);TS:fillOpenFormPassthrough(args)。骨架:templates/starter/cmd/plugin/main.go。

#### 3.2.3 宿主 → 插件:mindlink:plugin_form_fill

Cadau 壳在解析到 ui_action=fill_form 后向 iframe postMessage(source=mindlink)。JS:listenHostPluginFormFill。

{
  "source": "mindlink",
  "type": "mindlink:plugin_form_fill",
  "module_id": "my-plugin",
  "form": "draft",
  "fields": { "name": "张三", "note": "加急" }
}

插件把 fields 合并进当前打开且 dialog 匹配的草稿,立刻刷新输入框。mutates: false,宿主 不会因此刷新列表。

3.3 扩展工作流节点与清单契约(workflow_steps / rubric)

插件可在同一份 operations.json 中声明 workflow_steps,把领域自动节点挂进流程设计器(仅当该插件已启用时出现在目录中)。引擎到达该步时调用 POST /api/agent/invoke(与 plugin_invoke 同一入口)。

{
  "module_id": "my-plugin",
  "operations": [
    { "name": "workflow_load_checklist", "mutates": false, "min_role": "member" }
  ],
  "workflow_steps": [
    {
      "type": "my-plugin.load_checklist",
      "label": "加载材料清单",
      "description": "写入实例 rubric,供上传证据 / 自动评分使用",
      "color": "#0891b2",
      "kind": "auto",
      "operation": "workflow_load_checklist",
      "config_hint": "可选 phases"
    }
  ]
}
workflow_steps[] 字段说明
type步骤 type(建议 {module_id}.{动作})
kindauto:到达后 Invoke,成功后按 always 前进。wait:到达后 Invoke;{ ok, pending: true } 则挂起,插件再 POST /api/v1/platform-plugins/workflows/plugin-wait/complete 按 pass/fail 推进;pending: false 且带 outcome 则立刻出线
operation对应 operations 中的操作名
label / description / color设计器展示

成功响应(加载类节点返回 rubric;写回类节点可只返回 variables;等待类节点可返回 pending):

{ "ok": true, "rubric": [ /* RubricItem[] */ ], "approval_doc": { }, "variables": { }, "pending": false }
  • pending: true(仅 kind: wait):实例停在本步,给发起人一张只读待办。完成须插件带 launch 会话调用 POST /api/v1/platform-plugins/workflows/plugin-wait/complete(instance_id、step_id、outcome:pass/fail,可选 variables)。
  • pending: false 且 outcome: pass|fail:已结束,立刻按出线走(例如到达时已经签完)。
  • rubric:写入实例,供核心节点 上传证据(human.upload)与 自动评分(llm.score)消费;必须符合下表 RubricItem。加载类节点必填。
  • approval_doc:可选。业务单据快照,审批步直接展示(对标检查项)。提交即审批应在发起时写入 variables.approval_doc(见 §2.4),不要只在自动节点补。形状见 §2.4 ApprovalDoc。
  • variables:合并进实例变量(扁平键)。写回类节点(如确认用人需求)用此回写 staffing_req_status 等。
  • 失败:{ "ok": false, "error": "用户可见说明", "rubric": [] }。
  • 响应须在 HTTP 体顶层带 ok(不要只包在 result 里)。参考:plugins/compliance 加载检查标准、plugins/hr 确认/退回用人需求。

#### RubricItem(清单条目 · 实现真值)

与后端 backend/internal/standards.RubricItem、SDK 类型 RubricItem(Go / TS)对齐。其它领域(入职材料、培训确认等)加载节点须输出同一形状,勿另起字段名。

字段类型必需说明
idstring是稳定主键;上传 item_photos、评价、评分结果均按此 id 挂接
requirement_textstring是办理页展示的要求说明
scoring_textstring上传可不严;接自动评分时建议有合格/打分依据
codestring否展示用编号
phasestring否阶段键(小写比较);供上传节点 config.phases 过滤
tierstring否red \baseline \excellence
photo_standard_textstring否拍照/取证提示
reference_photo_upload_idsstring[]否合格样例图 upload_id(最多 3 张);办理页对照展示
must_passbool否红线项;默认 false
iway_refstring否领域引用;非通用必需可省略

参考实现:plugins/compliance 的 workflow_load_check_items → toRubric。产品侧说明见 docs/core-mechanisms/workflow.json-v1.md §检查项清单契约;机制指南见 [../README.md](/docs/sdk-platform-plugin) §6.2。

3.4 Cookie / 存储命名(勿混用)

名称谁写用途
ml_plugin_gwCadau 网关Path=/p/{module_id}/,浏览器访问反代路径时的网关鉴权
ml_plugin_launch插件进程(Go bootstrap)插件 origin 上的辅助 Cookie(可选)
ml_plugin_launch_token插件前端 sessionStorageBearer 真源;续签后必须更新

4. 安全响应头(插件服务)

Content-Security-Policy: frame-ancestors 'self' http://localhost:8080 http://127.0.0.1:8080

生产环境替换为客户 Cadau Web 源。Go SDK:mindlinkplugin.FrameAncestorsCSP(...)。


5. 错误体

{
  "error": "用户可见说明",
  "code": "machine_code",
  "request_id": "…"
}

常见 code:unauthorized, plugin_launch_invalid, forbidden, validation_error, not_found