自定义自动化节点
自动化工作流的节点库也是插件可扩展的:内置的图片生成(image-gen)、JS 转换(js-transform)都是插件贡献的节点。一个节点 = manifest 声明(配置面板长什么样、输出什么变量)+ 后端执行(node 运行时,defineAutomationNode 注册)。
声明:配置面板与输出变量
Section titled “声明:配置面板与输出变量”配置面板是声明式的 —— 宿主用内建控件渲染,不是 iframe(核心原因:valueSelector 要接宿主的上游变量域,iframe 拿不到):
{ "runtime": "node", "entry": "src/server.ts", "capabilities": ["dataEngine"], "contributes": { "automationNodes": [ { "typeKey": "summarize", "version": 1, "name": { "zh-CN": "汇总文本", "en-US": "Summarize" }, "description": { "zh-CN": "把输入文本压缩成一句摘要" }, "category": "integration", "configSchema": [ { "key": "text", "label": { "zh-CN": "文本" }, "widget": "valueSelector", "required": true }, { "key": "style", "label": { "zh-CN": "风格" }, "widget": "select", "options": [ { "value": "brief", "label": { "zh-CN": "简短" } }, { "value": "detailed", "label": { "zh-CN": "详细" } } ], "default": "brief" } ], "outputSchema": [ { "key": "summary", "type": "string", "label": { "zh-CN": "摘要" } } ], "execution": { "timeoutMs": 60000, "sideEffects": "none" } } ] }}configSchema的 widget 全集与dependsOn联动规则见 manifest 参考;valueSelector让用户插上游节点的变量,引擎执行时替你展开成裸值;outputSchema是给下游节点的静态承诺 —— 编辑期变量选择器靠它列出你的输出;description兼作 AI 构造工作流时的工具描述,按写给模型看的质量写。
执行:defineAutomationNode
Section titled “执行:defineAutomationNode”后端(完整骨架基础上)注册执行逻辑,宿主把节点任务 POST /automation/<typeKey> 投过来:
import Koa from 'koa'import { CapabilityClient, defineAutomationNode, automationNodesMiddleware,} from '@xinghan/plugin-sdk/server'
const cap = new CapabilityClient({ baseUrl: process.env.CAPABILITY_BASE_URL, token: process.env.CAPABILITY_TOKEN,})
const nodes = [ defineAutomationNode({ typeKey: 'summarize', async execute(ctx) { // ctx.inputs:引擎已解析的配置(valueSelector 已展开成裸值) const text = String(ctx.inputs.text ?? '') const style = String(ctx.inputs.style ?? 'brief')
ctx.progress('分析中…') // 实时出现在跑历史面板(host 侧节流)
const summary = await summarize(text, style)
// 返回值 = outputSchema 承诺的变量,下游节点用 {{#本节点.summary#}} 引用 return { summary } }, }),]
const app = new Koa()app.use(automationNodesMiddleware(nodes, { cap }))app.listen(Number(process.env.PORT ?? 0), '127.0.0.1')执行上下文能干什么
Section titled “执行上下文能干什么”ctx 上的关键成员:
| 成员 | 用途 |
|---|---|
inputs | 已解析的节点配置(模板变量已展开) |
progress(text) | 进度上报 —— 用户在跑历史面板实时看到 |
cap / callCtx() | 写表必经这对:callCtx() 注入了 actor(工作流 owner 署名)、projectId 与防回环标记 —— 你的写入不会再触发同一个工作流形成死循环 |
uploadResultAsset(bytes, name, mime?) | 大产物上行:传进资产库,返回附件 cell 元素 {ref,name,size,mime} |
dryRun | 整图测试运行(声明 execution.supportsDryRun 才会收到) |
三条执行纪律
Section titled “三条执行纪律”- 大产物不进返回值(host 侧 256KB 上限):图片、文件先
uploadResultAsset,返回引用 —— image-gen 就是这么把生成图挂进附件字段的; - 抛错要写人话:
execute抛出的错误文案原样进跑历史,用户按它排障; - 写表用
ctx.cap+ctx.callCtx(),别自己造 CallContext —— 署名、审批沙箱(整图测试时写入自动改投审核单)、防回环全在里面。
dynamicSelect:选项来自你的后端
Section titled “dynamicSelect:选项来自你的后端”配置面板里 widget: 'dynamicSelect' 的字段,选项由你的 options 回调提供(宿主经 GET /automation/<typeKey>/options?field=<key> 反代过来):
defineAutomationNode({ typeKey: 'summarize', async execute(ctx) { /* … */ }, async options(field, actor) { if (field === 'model') { return [{ value: 'fast', label: { 'zh-CN': '快速' } }, { value: 'best', label: { 'zh-CN': '最佳' } }] } return [] },})认领内建节点
Section titled “认领内建节点”声明 claim: 'llm'(v1 白名单仅 llm)可以接管内建 LLM 节点:你的插件在场时,节点面板与执行都归你,node.Type 照存内建名 —— 存量工作流零迁移,插件卸载自动回退内建实现。
version是你配置结构的版本号:老工作流带着老配置来,execute里自己向后兼容(宿主不做迁移);execution.timeoutMs缺省 120 秒、上限 30 分钟;idempotent: true才允许失联重投(图片生成这类收费副作用节点保持缺省 false —— 至多一次,不重复扣费)。
image-gen—— 大产物上行(uploadResultAsset→ 附件字段)、dynamicSelect 选 provider、进度上报的完整形态;js-transform—— 轻量纯计算节点(输入 → 变换 → 输出变量)。