跳转到内容

自定义自动化节点

自动化工作流的节点库也是插件可扩展的:内置的图片生成(image-gen)、JS 转换(js-transform)都是插件贡献的节点。一个节点 = manifest 声明(配置面板长什么样、输出什么变量)+ 后端执行(node 运行时,defineAutomationNode 注册)。

配置面板是声明式的 —— 宿主用内建控件渲染,不是 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 构造工作流时的工具描述,按写给模型看的质量写。

后端(完整骨架基础上)注册执行逻辑,宿主把节点任务 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')

ctx 上的关键成员:

成员用途
inputs已解析的节点配置(模板变量已展开)
progress(text)进度上报 —— 用户在跑历史面板实时看到
cap / callCtx()写表必经这对:callCtx() 注入了 actor(工作流 owner 署名)、projectId 与防回环标记 —— 你的写入不会再触发同一个工作流形成死循环
uploadResultAsset(bytes, name, mime?)大产物上行:传进资产库,返回附件 cell 元素 {ref,name,size,mime}
dryRun整图测试运行(声明 execution.supportsDryRun 才会收到)
  • 大产物不进返回值(host 侧 256KB 上限):图片、文件先 uploadResultAsset,返回引用 —— image-gen 就是这么把生成图挂进附件字段的;
  • 抛错要写人话:execute 抛出的错误文案原样进跑历史,用户按它排障;
  • 写表用 ctx.cap + ctx.callCtx(),别自己造 CallContext —— 署名、审批沙箱(整图测试时写入自动改投审核单)、防回环全在里面。

配置面板里 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 []
},
})

声明 claim: 'llm'(v1 白名单仅 llm)可以接管内建 LLM 节点:你的插件在场时,节点面板与执行都归你,node.Type 照存内建名 —— 存量工作流零迁移,插件卸载自动回退内建实现。

  • version 是你配置结构的版本号:老工作流带着老配置来,execute 里自己向后兼容(宿主不做迁移);
  • execution.timeoutMs 缺省 120 秒、上限 30 分钟;idempotent: true 才允许失联重投(图片生成这类收费副作用节点保持缺省 false —— 至多一次,不重复扣费)。
  • image-gen —— 大产物上行(uploadResultAsset → 附件字段)、dynamicSelect 选 provider、进度上报的完整形态;
  • js-transform —— 轻量纯计算节点(输入 → 变换 → 输出变量)。