实验性项目 WorkFly 完全由 AI 生成,可能存在缺陷或错误,仅供内部测试,非用友官方产品,不代表公司立场。
开发者中心会话与 Surface

会话与 Surface 集成

让结构化结果既能被 Agent 理解,也能由你的小程序在会话卡、首页或 Spotlight 中可信呈现。

让你的小程序数据,能在 WorkFly 主会话里被点进去由你自己渲染——而不是被大模型转述成一段文字。两个一等能力:引用(Reference)渲染面(Surface)

前置:本页建立在 开发指南 · 贡献模型 之上——引用与渲染面,就是「卡片 / 详情渲染器」贡献在主会话里的应用,建议先读完开发指南。

全文用一个贯穿示例:一个审批小程序(appId com.acme.approval),把「待审批单据」接进会话。

为什么需要

用户在会话里说「看看我有哪些待审批」,你希望:

  • 返回的列表/详情长成你应用本来的样子(你的 UI、你的样式),用户一眼认出「这是该应用的真数据」,而非模型二次加工;
  • 其中每一条都能点击跳进你应用里的对应界面。

这两件事,平台都给了统一、通用的接入点——所有小程序(内置与第三方)一视同仁

引用 Reference:会话里的可点击对象

一个 Reference 就是「指向某业务对象、可点击的引用」:

interface Reference {
  kind: string // '<你的appId>.<entity>',如 'com.acme.approval.bill'
  id: string // 业务对象主键
  label: string // 展示文字(标题 / 名称)
  payload?: Record<string, unknown> // 跳转需要的附加信息
}

产出引用

你的工具(tool)在结果里带上 details.refs,会话会自动把它们渲染成可点击的 chip:

return {
  content: [{ type: 'text', text: '你有 2 条待审批单据。' }],
  details: {
    refs: [
      { kind: 'com.acme.approval.bill', id: '1024', label: '张三的请假申请(3 天)' },
      { kind: 'com.acme.approval.bill', id: '1025', label: '市场部采购付款 ¥12,000' }
    ]
  }
}

点击后怎么跳(导航)

平台按 kind 决定跳转,优先级:

  1. 你贡献了该 kind 的「详情渲染器」 → 在会话上就地展开你的详情视图(最常见,见下);
  2. 否则 → 通用默认:平台用已注册 manifest 中与 kind 匹配的最长 App id 前缀解析归属,启动你的 standalone 界面,并把这条 ref 作为启动参数投递。你在界面里用 wf.getLaunchOptionsSync() 读出来、定位到该对象。

第三方沙箱小程序零额外宿主代码即可被导航:产出 ref + 在自己界面读启动参数定位,就通了。

渲染面 Surface:列表 / 详情,由你自己渲染

把结构化数据由你的渲染器呈现进会话,两种模式:

  • list:行式、可翻页,行点击钻取详情;
  • detail:单对象完整视图。

Manifest v2 的第三方卡片通过高信任 React UI Module 贡献:Manifest 用 module + component 指向预编译 ESM,宿主提供 workfly-react@1 runtime,并把样式挂入 Shadow Root。完整应用页面仍运行在 Sandbox。平台负责统一外壳:

  • 来源标识:卡片上的“卡片来自于 + 小程序类型 + 应用图标 + 应用名”标识,让用户确信数据归属;应用图标和名称是同一可点击区;
  • 列表翻页:会话内点击翻页,交互与聊天一致;
  • 行钻取:点击列表行 → 展开 detail。

卡片还要给 Agent 一份概要

用户能看见卡片,不代表 Agent 能读取卡片 DOM 或沙箱数据。Tool 返回使用两个通道:details.card 给用户渲染,content 给 Agent 保存上下文。第三方 launch 和声明式只读 query Tool 都可在 manifest 中用 resultCard 关联业务卡,并用 summary 提供业务概要:

"resultCard": {
  "kind": "com.acme.approval.bill",
  "summary": "待审批卡展示单据标题、申请人、金额、状态和业务编号,可按编号继续查询详情。"
}

summary 是必填的非空字符串。它要覆盖卡片的业务对象、关键口径和缓存/实时状态,不能只写“已展示卡片”;Token、Cookie、一次性 code 等敏感信息不得写入。launch Tool 不执行小程序业务 JavaScript,因此它的摘要是静态语义概要。声明式 query Tool 则由主进程执行固定 HTTPS 只读请求:字段受限的实时投影同时进入 Agent content 和内部会话卡的 card.data.result。Agent 用这些上下文理解后续指代,但不应逐字复述卡片已展示的内容。外部 MCP 没有卡片通道,仍只返回 query Tool 原有的字段受限结果。

卡片贡献“下一步建议”

卡片渲染器可在 cardRenderers[].suggestions 中声明最多 4 条与当前业务卡自然衔接的候选:

"suggestions": [
  { "label": "查看最近订单", "text": "查询我最近的个人订单", "act": "send" },
  { "label": "填写评价", "text": "为这笔订单填写评价", "act": "fill" }
]

label 为 1-14 字,text 可选且最多 200 字。查询、查看、分析类可用 send 点击即发;提交、发送、删除等有副作用的动作必须用 fill 预填待用户确认。宿主会再做长度、去重和风险复核,与辅助模型建议融合;辅助模型不可用时也可直接展示本地候选。用户关闭建议或处于角色态时不展示,外部 MCP 也不接收这些候选。

卡片 UI 建议:精简摘要,别堆长

会话里的卡片是摘要,不是完整页面。务必克制——长卡片会撑爆会话流、逼用户在对话里上下滚动,体验很差:

  • 只放重点:列表每行一句话(标题 + 一两个关键信息),详情只放最重要的几个字段 + 一段简短描述;
  • 不滚动、不超高:内容超了就截断(描述截断到两三行、字段只显前几项),别在卡片里塞滚动条;列表用翻页而不是拉长;
  • 完整引导进应用:更全的内容(长描述、附件、评论、全部字段、操作)放一个「打开完整 / 在应用中查看」入口,点进应用或详情宿主里看——卡片负责「一眼看懂 + 快速进入」,不负责「全都铺开」。

平台内建的通用列表 / 详情卡(kind:'list' / kind:'detail')已按此约束实现(行截断、描述截断、字段截断、列表翻页、统一「打开完整」)。自写卡片也请遵守同一尺度。

贡献「详情渲染器」

让你的对象在会话里就地展开详情(而非整屏切走):在贡献清单里按 kind 注册一个详情渲染器,平台的通用详情宿主会据此渲染。它拿到 { reference, onClose },你决定长什么样。

// 贡献清单(与 cards 平行)
details: [{ kind: 'com.acme.approval.bill', renderer: { type: 'native', component: BillDetail } }]

当前 details 只消费内置 App 的代码贡献,第三方 manifest 尚不接受详情渲染器。第三方 Reference 在没有详情渲染器时走上述通用默认导航。

小结:你要做的

想要 你提供
会话里出现可点击引用 工具结果带 details.refs
点击就地展开详情 贡献该 kind 的详情渲染器
会话摘要是你应用的样子 贡献 React 卡片渲染器,来源由平台补齐
Agent 能理解卡片内容 launch 提供 resultCard.summary;query 还同步实时投影
卡片出现后提示自然后续 cardRenderers[].suggestions,有副作用动作使用 fill
点击跳进你的完整界面 啥都不用做(通用默认)或自定义导航

设计原则:应用自渲染增强可信度平台基建所有小程序共享。务必给会话里的数据带上「来源标识」,让用户分清「这是应用真数据」与「模型生成的话」。


下一步