全部文档

Cadau 嵌入 SDK 契约(V1.5.13)

- 目标:让宿主系统以最低接入成本集成“我的智能体”对话能力,并支持有限、可审计的页面操作联动。

来源 sdk/host-embed/SDK契约.md

适用范围:外部系统通过一段 JS 嵌入「我的智能体」,在宿主页面实现 AI 对话与受控操作。

对齐来源:docs/产品规格.md §4.2.3、§7.5。

实现对照:嵌入前端见 sdk/host-embed/widget/;静态脚本由 GET /embed/mindlink-widget.min.js 提供(backend/internal/embedsdk);令牌 API 见 POST /api/v1/user-agents/{id}/embed-token。集成说明见同目录 网站集成说明.md


1. 目标与边界

  • 目标:让宿主系统以最低接入成本集成“我的智能体”对话能力,并支持有限、可审计的页面操作联动。
  • 边界:嵌入端不持有长期密钥;不允许任意脚本执行;所有对话能力统一走 Cadau 后端 REST。

2. 接入方式

2.1 Script + JS 初始化

官方部署由 Cadau 服务 提供静态脚本(与 API 同源),路径固定为 /embed/mindlink-widget.min.js。宿主升级 Cadau 后无需替换自托管的 JS 文件,只需继续引用该 URL。

A 路径(公开客服,推荐最小配置):

<script src="https://mindlink.example.com/embed/mindlink-widget.min.js"></script>
<script>
  window.MindLinkWidget.init({
    base_url: "https://mindlink.example.com",
    user_agent_id: "ua_123",
    auth: { token: "eyJ..." }
  });
</script>

也可在 script 标签上使用 data-base-url / data-agent-id / data-token 自动挂载(可选 data-app-iddata-themedata-positiondata-entrydata-titledata-greetingdata-welcome)。「网站嵌入」复制脚本时可勾选入口形态。静态对照:examples/cadau-embed-site/

B 路径(业务系统) 须传 host_actor(当前登录用户身份),并可传 api_base_urlapp_idworkspace_idauth.expires_at 等(见宿主增强文档)。

2.2 Web Component 初始化

HTML 属性可覆盖 app-idapi-base-urlbase-urluser-agent-idworkspace-idthemepositionlocaleauth / host_actor 须用 JS 赋值(无 HTML 属性)。未设置 auth 时不会挂载。

元素暴露与 WidgetHostApi 相同的方法:on / open / close / destroy / updateAuth / updateHostActor / sendMessagecontainer 固定为元素自身(行内挂载时把元素放进业务容器即可)。

<mindlink-widget
  base-url="https://mindlink.example.com"
  user-agent-id="ua_123"
  theme="auto"
  position="bottom-right"
></mindlink-widget>
<script>
  const el = document.querySelector("mindlink-widget");
  el.auth = { token: "eyJ..." };
  // el.host_actor = { external_user_id: "...", actor_kind: "employee", ... };
  el.on("action", (ev) => { /* 同 Script init */ });
</script>

Script 行内挂载可传 container(选择器或 HTMLElement),与 position: "inline" 配合使用(见 WidgetInitOptions)。


3. TypeScript 契约(建议)

export type WidgetTheme = "light" | "dark" | "auto";
export type WidgetPosition = "bottom-right" | "bottom-left" | "middle-right" | "center" | "inline";

export interface EmbedAuth {
  token: string;
  /** 可选;缺省时挂件不本地预判过期 */
  expires_at?: string; // ISO 8601
}

/**
 * 当前宿主登录用户(B 路径必传)。Cadau 不以此建账号。
 * 校验:`external_user_id` 必填;`actor_kind` 为 `employee` 时 `employee_id` 必填。
 * 未传 `actor_kind` 时:有 `employee_id` 则视为 `employee`,否则 `business`。
 */
export interface HostActor {
  external_user_id: string;
  actor_kind?: "business" | "employee";
  display_name?: string;
  tenant_external_id?: string;
  employee_id?: string;
  emp_no?: string;
  roles?: string[];
  managed_org_unit_ids?: string[];
  managed_employee_ids?: string[];
  org_unit_id?: string;
  org_unit_name?: string;
}

export interface WidgetInitOptions {
  /** Cadau 站点根;未传 api_base_url 时推导为 `{base_url}/api/v1` */
  base_url?: string;
  /** 可选;缺省 `mindlink-embed` */
  app_id?: string;
  /** 可选;可由 base_url 推导 */
  api_base_url?: string;
  user_agent_id: string;
  auth: EmbedAuth;
  /** 可选;缺省依赖 JWT wid */
  workspace_id?: string;
  theme?: WidgetTheme;
  position?: WidgetPosition;
  /**
   * 预留语言码(默认 `"zh-CN"`)。当前 UI 文案固定中文,设置后无切换效果。
   */
  locale?: string;
  entry?: {
    auto_open?: boolean;
    /** 用户明确请求打开界面时,自动执行回答里首条宿主可执行的 mindlink://action/(默认 true) */
    auto_execute_navigation?: boolean;
    /** 空态提示文案;空字符串时使用内置默认句 */
    welcome_text?: string;
    /** 面板标题;空则用「操作助手」 */
    title?: string;
    /** 标题下说明 */
    subtitle?: string;
    /** 首次来访在角落按钮旁出一句招呼(打开或关掉后不再出) */
    greeting?: boolean;
    greeting_text?: string;
  };
  /** 挂载父节点;默认 `document.body`。inline 模式建议传入页面内容器。 */
  container?: HTMLElement | string;
  /**
   * 当前登录用户身份(B 路径必传)。写入 chat 请求的 `client_context.host_actor` 与顶层 `host_actor`;
   * 历史会话 / 人工客服 / 工单按此人隔离;传软查数亦用。换用户时调用 `updateHostActor`。
   */
  host_actor?: HostActor;
}

export interface WidgetHostApi {
  open(): void;
  close(): void;
  destroy(): void;
  updateAuth(auth: EmbedAuth): void;
  /** 登录用户切换时更新身份(与 init.host_actor 同结构)。 */
  updateHostActor(hostActor: HostActor | null | undefined): void;
  sendMessage(message: string): Promise<void>;
  on(event: WidgetEventName, handler: (event: WidgetEvent) => void): () => void;
}

export type WidgetEventName = "ready" | "message" | "action" | "error" | "close";

export interface WidgetBaseEvent {
  type: WidgetEventName;
  request_id?: string;
  ts: string; // ISO 8601
}

export interface WidgetReadyEvent extends WidgetBaseEvent {
  type: "ready";
  app_id: string;
  user_agent_id: string;
}

export interface WidgetMessageEvent extends WidgetBaseEvent {
  type: "message";
  session_id: string;
  message_id: string;
  role: "user" | "assistant" | "system";
  content: string;
}

export type WidgetActionType = "open_url" | "open_module" | "emit_event";

export interface WidgetActionEvent extends WidgetBaseEvent {
  type: "action";
  action: {
    type: WidgetActionType;
    payload: Record<string, unknown>;
  };
}

export interface WidgetErrorEvent extends WidgetBaseEvent {
  type: "error";
  code: string;
  message: string;
}

export interface WidgetCloseEvent extends WidgetBaseEvent {
  type: "close";
  reason?: string;
}

export type WidgetEvent =
  | WidgetReadyEvent
  | WidgetMessageEvent
  | WidgetActionEvent
  | WidgetErrorEvent
  | WidgetCloseEvent;

4. 鉴权与安全要求

4.1 令牌签发(当前实现)

  • Cadau 主站登录用户 调用 POST /api/v1/user-agents/{id}/embed-token 签发(该助手「管理 → 网站嵌入」);请求体可选 app_id(默认 mindlink-embed)、ttl_secondspermanenthost_actor(B 路径代签时写入登记,对话与数据策略以登记为准,浏览器无法改成别人)。
  • 响应含 access_tokentoken_typeBearer)、expires_in(秒)、expires_atuser_agent_idworkspace_idapp_idpermanentrecord_id;登记写入 embed_access_tokens(含 app_id、吊销用 jwt_jti)。同一 user_agent_id 可被多个第三方 app_id 复用;宿主侧用户与权限由第三方系统自行维护。
  • 宿主后端代签为推荐生产形态,但须自行对接上述 API 或等价签发服务;契约不假定宿主自建 JWT。

4.2 JWT 与校验(当前实现)

  • 嵌入 JWT Claims(authx.Claims):sub(用户)、wid(工作区)、emb=1jti(= 登记行 jwt_jti)、expJWT 内不含 app_id / user_agent_id;二者由 init 参数与登记行约束,业务上须与签发时一致。
  • 受保护 API:Authorization: Beareremb=1 时 middleware 额外查 embed_access_tokens 未吊销且未过期,失败码 embed_token_revoked
  • 过期/签名错误:通用 unauthorized(文案「令牌无效或已过期」),尚未单独返回 embed_token_expired / embed_token_invalid
  • 可选请求头 X-Workspace-Id:与 init.workspace_id 一致时推荐携带(embed-sdk 已发)。
  • 请求头 X-Host-External-User-Id(embed-sdk 已发):B 路径为签发时绑定的 host_actor.external_user_id;A 路径为浏览器访客标识。用于历史会话按人/按访客隔离。未带此头且令牌未绑定身份时嵌入会话列表返回空(避免串话)。
  • 数据权限身份:仅采用签发时写入 embed_access_tokens.host_actor_json 的登记;请求体 host_actor 不能冒充他人。A 路径未绑定时不采信客户端身份做查数。
  • POST /api/v1/host/agent-runs 拒绝嵌入令牌(forbidden_embed_token),须用集成账号在服务端调用。

4.3 其他

  • 支持短期与长期有效令牌;长期仍可通过 DELETE /api/v1/embed-access-tokens/{id} 收回。
  • embed_origin_not_allowed / 来源白名单:配置 http.allowed_origins(或环境变量 HTTP_ALLOWED_ORIGINS)后生效;未配置时 CORS 仍反射请求 Origin(仅本地联调)。
  • 默认 Shadow DOM 隔离;宿主配置 CSP,禁止不可信脚本注入。

5. 对话与动作协议

5.1 Chat 请求(嵌入模式,当前实现)

嵌入挂件使用 POST /api/v1/chat/stream(SSE),非同步 POST /api/v1/chat

挂件已处理的 SSE 事件:start / token / done / error,以及工具轮次的 round_start / tool_call / tool_output(用于展示进度;宿主一般无需监听)。

{
  "message": "请给我今天的跟进建议",
  "session_id": "optional",
  "user_agent_id": "ua_123",
  "request_id": "req_embed_001",
  "workspace_id": "ws_001",
  "client_context": {
    "channel": "embed_widget",
    "app_id": "crm-prod",
    "page_url": "https://crm.example.com/home",
    "host_actor": { "external_user_id": "…", "actor_kind": "employee" }
  },
  "host_actor": { "external_user_id": "…", "actor_kind": "employee" },
  "attachment_ids": []
}
  • user_agent_id 必填;init 时为空会在前端抛错,无法发消息。
  • client_context客户端已发送,服务端已解析channel=embed_widget(或 JWT emb=1)时会话来源记为嵌入;app_id 写入会话的 embed_app_idhost_actor(或顶层同名字段)用于会话隔离与数据连接策略。B 路径下列表/历史/人工客服/工单按 host_actor.external_user_id 只返回该登录用户自己的内容。
  • 历史与会话:GET /api/v1/chat/sessions?kind=agent&user_agent_id=...(嵌入可带 host_external_user_id 或请求头 X-Host-External-User-Id)、GET /api/v1/chat/history?session_id=...(embed-sdk 已用)。
  • 可选附件:attachment_ids(先 POST /api/v1/uploads);编辑重发:POST /api/v1/chat/truncate;停止生成:GET /api/v1/chat/sessions/{id}/generationPOST …/generation/stop(挂件已接)。
  • 同时正在回复人数达上限时,本接口返回 HTTP 429、码 embed_generation_limit。上限优先读该智能体配置 max_embed_streams(Cadau:我的智能体 → 嵌入助手同时回复上限)。未设则用服务器默认(通常 20)。智能体配置不得高于服务器上限;服务器上限 > 0 时,智能体填 0 会回落到服务器默认,并不能突破成不限制。仅当服务器默认本身为 0 时,0 才表示不限制。硬顶 256

5.2 动作白名单

  • 允许:open_urlopen_moduleemit_event
  • 禁止:eval、动态脚本注入、未经声明的跨域代理请求

5.3 动作放行建议

  • open_url 需校验域名白名单。
  • open_module 仅可访问宿主预注册模块 ID。
  • emit_event 限定允许字段,避免透传敏感数据。

5.4 回答内功能导航链接(当前实现)

智能体在 Markdown 回答中可输出(知识文档需教会模型):

`打开待审批订单`
  • 用户点击后,挂件触发 action 事件,action.type === "emit_event"payload.kind === "mindlink_action"payload.action 为路径(如 page.orders),payload.params 为查询参数对象(含筛选字段与可选 label)。
  • 宿主页widget.on("action", …) 中白名单处理;不会自动跳转业务路由。
  • entry.auto_execute_navigation(默认 true):用户消息匹配「帮我打开 / 跳转 / 前往…」等意图时(亦匹配句首「打开|去|进入…」、英文 open|navigate|go to 等,见 mindlinkAction.ts),流式回答结束后挂件 自动执行正文中首条在嵌入表面可点击的 mindlink://action/ 链接(跳过主站专用动作,与点击过滤一致;仍走宿主白名单)。实现见 sdk/host-embed/widget/src/mindlinkAction.tsEmbedApp.tsx
  • 与主站帮助一致的 mindlink://action/module.workspace 等在嵌入表面不可点击(提示「请在 Cadau 中打开」);宿主自定义 page.* / host.* / 非主站 module.* 可执行。
  • 详见 网站集成说明.md §5、§5.6;宿主知识撰写见 宿主知识文档撰写要求.md §6.2。

尚未实现:后端在 SSE 流中直接下发结构化 open_url / open_module / emit_event 动作卡片。宿主侧 handleHostNavigation 可预留这些 action.type,但当前嵌入路径仅通过 Markdown mindlink://action/emit_event + mindlink_action 触发。


6. 嵌入界面(当前交付)

6.1 展示形态

  • 悬浮窗模式(默认)position: bottom-right(亦支持 bottom-leftmiddle-right 右侧居中、center 页面正中);角落或指定位置入口,点击展开面板。entry.greeting 为真时,该浏览器第一次来访会在按钮旁出一句招呼(打开或关掉后不再出)。data-entrycorner(默认)/ greeting / open(打开即展开)。
  • 侧边栏模式未实现(无独立 sidebar position)。
  • 行内模式(inline)position: inline + container;适合帮助中心、配置页内嵌。

6.2 theme 与宿主页面

  • light / dark:固定浅色或深色面板。
  • auto优先读取宿主 <html data-theme="dark|light">(若存在则以此为准);否则若 htmlbody 带有 class dark,视为深色;最后再使用浏览器 prefers-color-scheme。宿主切换主题时嵌入端会监听并同步亮暗,避免「系统浅色、应用内深色」时面板仍停留在浅色。

6.3 当前已交付(embed-sdk,供联调)

能力状态
Shadow DOM + window.MindLinkWidget.init / <mindlink-widget>(含 Host API:on 等)已交付
chat/stream 流式对话、会话列表与历史已交付
ready / message / action / error / close / updateAuth / updateHostActor / sendMessage已交付
init.host_actor → chat client_context.host_actor(会话隔离 / 数据策略)已交付
B 路径:历史会话 / 人工客服 / 工单按 host_actor.external_user_id 只显示本人已交付
A 路径:历史会话 / 人工客服 / 工单按浏览器访客标识只显示本人(与工单同一套隔离)已交付
mindlink://action/ 链接点击 → actionmindlink_action已交付
用户明确要求打开时自动执行首条宿主可执行导航(entry.auto_execute_navigation,默认 true)已交付
入口/面板拖拽与尺寸记忆(按 app_id 键;B 路径会话键另含宿主用户)已交付
A 路径精简 init:base_url + user_agent_id + auth.tokenworkspace_id / app_id / expires_at 可选)已交付
挂件「人工客服」:GET …/human-support/statusenabled / live_available / tickets_available)+ /embed/cs-tickets*(排队、结束、评价、改提工单;A:浏览器访客标识;B:宿主登录用户)已交付
挂件「提交工单 / 我的工单」:/embed/support-cases*(异步;可从即时改提;隔离规则同上)已交付
多人同时对话;超额 embed_generation_limit(智能体可配同时回复上限)已交付
宿主 LLM 服务:POST /api/v1/host/agent-runs(集成账号;指定智能体代答,必带 host_actor;任务型可 fresh 新会话)已交付
上下文用量环(context_budget已交付
回答末尾「下一步」建议芯片(与主站同解析)已交付
locale 切换多语言文案未交付(字段保留,UI 固定中文)
操作卡片、移动端全屏抽屉未交付
面板标题 / 首次招呼(entry.title / entry.greeting;脚本 data-title / data-entry / data-greeting已交付
令牌过期专用 UI / embed_token_expired 错误码未交付(依赖宿主 updateAuth
SSE 直接下发结构化动作卡片未交付

7. 时序(端到端)

  1. 在 Cadau 签发嵌入令牌(embed-token API,登记 app_id + user_agent_id);A 路径在「网站嵌入」生成;B 路径可由宿主后端代调。
  2. 宿主前端加载 widget 并 init(A:base_url + user_agent_id + token;B 须传 host_actor,换用户时 updateHostActor)。
  3. widget 触发 ready 事件。
  4. 用户发消息,widget 调用 /api/v1/chat/stream
  5. 流式返回助手正文(可含 mindlink://action/ 链接)。
  6. (可选)用户点击导航链接,或自动导航 → 宿主白名单执行。
  7. (可选)开启人工客服后,挂件可提交 /api/v1/embed/cs-tickets(即时)或 /api/v1/embed/support-cases(工单);客服在 Cadau 工作台处理(本区席位或已授权客服小组),列表实时刷新。小组工作台接单不切换顶栏当前工作区。宿主 不必 调用客服小组管理 API。
  8. 令牌失效:unauthorized / embed_token_revoked;B 路径可 updateAuth / updateHostActor

8. 联调检查清单

  • [ ] 可正常加载 widget(含 Shadow DOM)。
  • [ ] A 路径仅 base_url + user_agent_id + auth.token 可对话。
  • [ ] user_agent_id / auth.token 缺失时 init 失败或无法发消息(当前为初始化抛错)。
  • [ ] chat/stream 可收发;request_id 可追踪。
  • [ ] 开启人工客服后挂件可「人工客服」(须有人上班)与「提交工单」;未开启则无入口。客服工作台无需整页刷新即可看到新单。本区席位或已授权客服小组均可接单。
  • [ ] (B)两名登录用户互看不到对方的历史会话、进行中客服与工单;host_actor.external_user_id 已传入。
  • [ ] (A)两名网站访客互看不到对方的历史会话、进行中客服与工单(按浏览器访客标识)。
  • [ ] 两名访客可同时提问并各自收到回复;过载时挂件提示「当前对话人数已达上限,请稍后再试」。
  • [ ] mindlink://action/ 链接可点击并触发 actionkind: mindlink_action);宿主已实现白名单。
  • [ ] 用户说「帮我打开 xx」时,回答完成后自动导航符合预期(或已设 auto_execute_navigation: false);主站专用动作不会被自动执行。
  • [ ] (传软)host_actor 已传入;换用户后 updateHostActor 生效。
  • [ ] 收回令牌后请求返回 embed_token_revoked
  • [ ] 令牌刷新后 updateAuth 可继续对话。
  • [ ] (生产)已配置 http.allowed_origins;未登记来源返回 embed_origin_not_allowed
  • [ ] 用户可见错误为自然语言,非裸错误码。

9. 错误码

状态说明
embed_token_revoked已实现嵌入登记已收回或过期
unauthorized已实现缺令牌、无效或 JWT 过期
embed_generation_limit已实现同时正在回复的人数已达上限(HTTP 429);文案「当前对话人数已达上限,请稍后再试」
embed_token_expired规划当前并入 unauthorized
embed_token_invalid规划当前并入 unauthorized
embed_origin_not_allowed已实现已配置来源白名单且请求 Origin 不在名单内
forbidden_embed_token已实现用嵌入令牌调用了仅集成账号可用的接口(如 Host Agent Run)
embed_agent_forbidden规划
embed_action_not_allowed规划
embed_workspace_mismatch规划

10. 版本记录

  • V1.5.14(2026-08-18):网站嵌入「放在哪一边」增加右侧(middle-right)与中间(center)。未写 data-position 时仍为右下角。
  • V1.5.13(2026-08-18):网站嵌入复制脚本可选入口形态——角落按钮 / 首次招呼 / 打开即展开;可写面板名称与招呼一句(data-entry / data-title / data-greeting / data-position)。未写这些属性时行为与 V1.5.12 相同。
  • V1.5.12(2026-08-17):挂件脚本从约 8MB 降到约 500KB(gzip 约 150KB)——不再打进主站文件预览库与整份 API 客户端;示意图按需从 Cadau 站点加载 Mermaid,HTML 围栏在新窗口预览。
  • V1.5.11(2026-08-17):签发可绑定 host_actor(对话/查数以登记为准);http.allowed_origins 启用后来源白名单与 embed_origin_not_allowed;Host Agent Run 拒绝嵌入令牌。
  • V1.5.10(2026-08-17):文档与实现对齐——max_embed_streams 解析(服务器上限封顶;智能体填 0 在服务器默认 > 0 时回落默认)、回答「下一步」芯片已交付、data-app-id / data-theme、代签响应补 token_type / expires_in / permanent
  • V1.5.9(2026-08-17):人工客服运营对齐——本区席位或客服小组均可接嵌入来单;live_available 计入覆盖该工作区的上班客服;小组工作台接单不切换顶栏工作区。挂件接口不变。
  • V1.5.8(2026-08-13):文档与实现对齐——HostActor 字段、human-support/status 分项、会话附件/停止/编辑重发、嵌入同时回复上限(max_embed_streams)。
  • V1.5.7(2026-08-13):Host Agent Run 支持 fresh 每次新会话;HR 范例「按部门建议岗位」走 .env / 宿主设置指定的分析智能体(只预览不落库)。
  • V1.5.6(2026-08-13):嵌入助手允许多位访客同时对话;超额返回 embed_generation_limit
  • V1.5.5(2026-08-13):A 路径历史会话按浏览器访客标识隔离(与工单一致);嵌入未标明访客时会话列表返回空,避免串话。
  • V1.5.4(2026-08-13):B 路径历史会话 / 人工客服 / 工单按 host_actor.external_user_id 只显示当前登录用户自己的内容。
  • V1.5.3(2026-08-13):B 路径与静态嵌入对齐——挂件人工客服 + 异步工单(/embed/support-cases);客服工作台实时刷新。
  • V1.5.2(2026-08-12):A 路径公开客服——base_url 精简 init、挂件人工客服与 /embed/cs-tickets;静态范例 examples/cadau-embed-site/
  • V1.5.1(2026-08-11):文档精简——删除未交付 UI 规划长文与线框图清单;功能导航独立文档并入 网站集成说明.md §5。
  • V1.5(2026-08-11):与实现对齐:补充 host_actor / updateHostActorclient_context 服务端解析与会话隔离、Web Component Host API、自动导航与点击过滤一致、SSE 扩展事件;标明 locale 与结构化动作卡片未交付。
  • V1.4(2026-05-26):补充 entry.auto_execute_navigation(默认 true)、自动导航行为与联调项;集成说明见 网站集成说明.md §5.6。
  • V1.3(2026-05-19):与 embed-sdk / 后端实现对齐:补充 chat/streamembed-token 签发、mindlink_action 导航、Web Component auth/container;区分已交付与规划 UI/错误码。
  • V1.2(2026-04-27):新增线框图级组件清单、页面骨架示意与前端状态机建议(已于 V1.5.1 移除)。
  • V1.1(2026-04-27):新增嵌入界面设计说明(规划节已于 V1.5.1 精简)。
  • V1(2026-04-27):首版,覆盖初始化参数、TS 契约、鉴权、安全、动作白名单与联调清单。