跳到主要内容

defineExecutor

workflow.defineExecutor<Input, Output>() 定义项目的执行协议。Workflow 使用它声明默认入口和多个独立 entrypoints;Conversation 继续把 workflow、参数和输入构造直接声明在 executor 上。

签名

workflow.defineExecutor<Input, Output>(
definition: WorkflowExecutorDefinition<Input, Output>,
): WorkflowExecutorDefinition<Input, Output>

参数

参数类型说明
definitionWorkflowExecutorDefinition<Input, Output>平台发现和执行 workflow 的入口配置。

Workflow executor

字段类型说明
projectType"workflow"Workflow 项目的类型标记。必填。
defaultEntrypointstring省略入口选择时使用的入口 ID。必须是静态字符串并命中 entrypoints
entrypointsWorkflowEntrypointDefinition[]非空静态入口数组;每项必须直接调用 workflow.defineEntrypoint()

Workflow 的 workflowparamscreateInputresolveParamscreateContextrequiredProviderstoolstokenUsageregistry 全部属于具体 entrypoint,不能放在 executor 顶层。入口按声明顺序展示;选择任一入口会直接创建该入口的 run,不会先执行默认入口。

Workflow 可以在 package.json.workflowCode.schedulePresets 中声明建议计划。每项静态引用一个 entrypoint,并包含 IANA 时区、时间窗口或五字段 Cron,以及默认参数值。该目录会进入 Structure 报告,但宿主必须显示确认界面,不能因导入或发布项目自动创建计划。Conversation 和 Kanban 声明此字段会被 Structure 拒绝。完整格式与运行边界参见 Workflow 定时运行

Conversation executor

字段类型说明
projectType"conversation"Conversation 项目的类型标记。必填。
workflowWorkflowDefinition<Input, Output>Conversation 的唯一 workflow。必填。
createInput(context) => Input把 args、环境和会话 ID 转成业务输入。必填。
resolveParams(context) => WorkflowParamResolveResult可选参数联动回调。
createContext(context) => Partial<WorkflowContext>增补 providers、metadata 和 hooks。
requiredProvidersExecutorProviderName[]声明必需 provider。
paramsWorkflowParamDefinition[]Conversation 的结构化参数。
toolsWorkflowToolPermissionDefinition[]Conversation 可调用的工具和默认策略。
conversationWorkflowConversationDefinition配置默认输入框、附件和输入队列。
tokenUsageWorkflowTokenUsageDefinition开启 token 用量统计。
registryWorkflowNodeRegistryEntry[]注册可单独调试的节点。

Conversation 不声明 defaultEntrypointentrypoints。CLI、Desktop 和 Server 收到非空入口选择时会返回错误,不会忽略该值。

WorkflowExecutorContext

字段类型说明
workflowNamestring当前 workflow 名称。
workflowDirstring当前 workflow 目录。
entrypointIdstring | undefinedWorkflow 当前所选入口 ID;Conversation 为 undefined
entrypointTitlestring | undefinedWorkflow 当前所选入口标题;Conversation 为 undefined
argsstring[]原始 CLI 风格参数。
paramValuesRecord<string, string | string[]>params 解析后的结构化值。单值保持字符串,多选为字符串数组。
envNodeJS.ProcessEnv环境变量集合。
abortSignalAbortSignal中断信号;Desktop/server 取消运行时会传递到 workflow 和支持 signal 的 SDK/provider 调用。
conversationIdstring | undefined会话 ID。
toolPermissionPoliciesWorkflowToolPermissionPolicyMap | undefined宿主传入的工具策略覆盖值。workflow 通常不直接读取该字段,而是使用 context.toolPermissionsworkflow.createToolApprovalGate()

WorkflowParamDefinition

字段类型说明
namestring参数名。必填。
flagstring长参数,例如 --message
shortFlagstring短参数,例如 -m
typeWorkflowParamType参数类型。必填。
requiredboolean是否必填。
descriptionstring参数说明。
defaultValuestring默认值。
multipleboolean是否允许多个值。
control"text" | "textarea" | "radio" | "select" | "checkboxes" | "date" | "time" | "datetime" | "date-range"Desktop/server Run workspace 的表单控件提示;日期相关控件仍使用 type: "string"
panel"main" | "auxiliary" | "quick"表单展示区域;auxiliary 收进 Advanced,quick 进入 composer 的组合快捷选择器。
resolveOnInputboolean是否在主输入内容变化时执行 resolveParams。默认 false;只有联动确实依赖输入文本时才设为 true
options{ value, label?, description? }[]枚举选项;有选项时表单会渲染单选、下拉或多选控件。
acceptstring[]文件类型限制。
format"json"file param 使用 JSON 引用格式。

WorkflowParamStatePatch

字段类型说明
valuestring | string[] | null替换当前参数值;null 表示显式清空。
visibleboolean控制参数是否显示。
disabledboolean控制参数是否可操作。
resolvedOptions{ value, label?, description? }[] | null数组替换参数当前的完整选项列表;null 恢复静态 options
optionsRecord<string, { visible?, disabled? }>修改当前选项列表中单个值的显示或禁用状态。

WorkflowNodeRegistryEntry

字段类型说明
namestringregistry 中的调试节点名。必填。
nodeNodeDefinition | StreamNodeDefinition实际执行的节点对象。必填。
metadataWorkflowNodeMetadataInput覆盖节点展示元信息。
streamboolean标记节点是否按流式节点执行。
createInput(context) => Input单节点调试时的输入构造函数。

执行流程

阶段说明
平台选择配置Workflow 按显式 ID 或 defaultEntrypoint 选择一个入口;Conversation 使用 executor 本身。
创建上下文runtime 根据 args、env、workflowName、入口和 conversationId 创建 WorkflowExecutorContext
createInput调用所选入口或 Conversation executor 的输入构造。
createContext调用同一执行配置的可选上下文扩展。
workflow run只执行所选入口的 workflow,或 Conversation 的唯一 workflow。

快捷参数和联动

panel: "quick" 适用于运行前需要频繁调整的枚举参数。Workflow 把这些字段写在具体 entrypoint 中,Conversation 写在 executor 中。composer 底部只显示一个组合摘要入口:存在 modelreasoningEfforteffortvariant 时优先显示“模型 · Effort”,否则回退到其它已选快捷值。

打开入口后,一级菜单按声明顺序列出全部可见快捷参数及当前值,选择参数后再进入二级单选或多选列表。Provider、Permission、Sandbox 等字段仍可配置,不会因摘要只突出模型与 Effort 而省略。宽屏会把二级列表放在一级菜单相邻侧,窄屏则在同一弹层中钻取并提供返回操作。

“重置为默认值”会一次恢复全部快捷参数并只触发一次 resolveParams 联动,不会清空 Main、Advanced、Raw 中的未知参数,也不会清空 Conversation 尚未发送的正文或附件。所有选择最终仍写入真实 argsparamValues

params: [
{
name: "tone",
flag: "--tone",
type: "string",
panel: "quick",
resolveOnInput: true,
control: "select",
defaultValue: "balanced",
options: [
{ value: "balanced", label: "Balanced" },
{ value: "precise", label: "Precise" },
{ value: "creative", label: "Creative" },
],
},
{
name: "sources",
flag: "--sources",
type: "string",
panel: "quick",
control: "checkboxes",
options: [
{ value: "web", label: "Web" },
{ value: "docs", label: "Docs" },
],
},
],
resolveParams({ draftText, paramValues }) {
const docsQuestion = draftText.includes("文档");
return {
params: {
tone: {
value: docsQuestion ? "precise" : paramValues.tone,
options: { creative: { disabled: docsQuestion } },
},
sources: { value: docsQuestion ? ["docs"] : paramValues.sources },
},
};
},
createInput({ paramValues }) {
return {
tone: String(paramValues.tone),
sources: Array.isArray(paramValues.sources) ? paramValues.sources : [],
};
},

resolveParams 会在初始化以及 main、Advanced、Quick 中任意 Form 参数值变化时执行。主输入内容变化只有在至少一个参数设置 resolveOnInput: true 时才会触发,避免普通消息输入造成无关的远程求值。它应保持无写入副作用和幂等,不执行写文件、写 KV 或修改外部状态;只读动态目录应传入回调提供的 abortSignal。补丁中的 visible / disabled 不会隐式清空已有值;需要清空时显式返回 value: null。初始化在 Raw 模式返回值补丁时,宿主只更新对应已声明参数,保留其它 Raw 参数及其值。

resolvedOptions 用于动态替换枚举:返回数组会完整替换参数的静态 options,返回 null 恢复静态选项,省略则保留当前动态选项。数组中的 value 必须是非空唯一字符串,labeldescription 必须是字符串。替换选项时旧 option 状态会清除;宿主会统一把动态选项应用到 Quick 与 Advanced,并区分 loading、empty、error。conversation 宿主按 conversation ID 重新求值,已经过期的异步响应不会覆盖当前会话。

日期参数

日期相关控件使用固定的本地时间字符串,不进行时区转换:

control字符串格式行为
dateYYYY-MM-DD选择单个日期后立即写回。
timeHH:mm:ss24 小时制,包含秒。
datetimeYYYY-MM-DDTHH:mm:ss选择日期和时间后通过“确定”写回。
date-rangeYYYY-MM-DD/YYYY-MM-DD闭区间;只在起止日期完整且结束不早于开始时写回。

这些控件只支持 type: "string"panel: "main" / panel: "auxiliary",不能声明 optionsmultiple: truepanel: "quick";TypeScript、静态结构分析和 runtime 都会拒绝非法组合。日期参数也不能通过 resolveParams 返回 resolvedOptions 或 option 状态补丁。

空值保持 "";可选参数可以清除,必填参数不显示清除操作。非空无效默认值、Raw 参数或 resolveParams 返回值会原样进入表单并显示字段错误,不会被静默修正;修正前 Run、Send 或 Submit 保持禁用,不会把已知无效值传给 createInput。合法值的 argsparamValues 仍按原字符串传递。

点击日历标题会打开紧凑的年份、月份双列滚动选择器;滚动过程只更新草稿,选择“完成”后才切换日历,“取消”保持原月份。年份限制为 00019999,滚轮只加载当前年份附近的有限选项。在宽屏界面中,date-range 会显示两个可独立切换年月的日历;重新打开时分别定位到已选的开始月份和结束月份,起止在同一个月时右侧显示下一个月。切换其中一个日历不会改变另一个日历当前展示的月份。窄屏界面使用单个日历,日期范围的值格式和完整范围提交规则保持不变。

params: [
{ name: "publishDate", flag: "--publish-date", type: "string", control: "date" },
{ name: "startsAt", flag: "--starts-at", type: "string", control: "datetime", panel: "auxiliary" },
{ name: "period", flag: "--period", type: "string", control: "date-range" },
],
resolveParams({ paramValues, trigger }) {
const publishDate = typeof paramValues.publishDate === "string" ? paramValues.publishDate : "";
const period = typeof paramValues.period === "string" ? paramValues.period : "";
const preferPeriod = trigger.kind === "param" && trigger.paramName === "period";
const usePeriod = period !== "" && (preferPeriod || publishDate === "");
const useDate = publishDate !== "" && !usePeriod;

return {
params: {
publishDate: usePeriod
? { visible: false, value: null }
: { visible: true },
period: useDate
? { visible: false, value: null }
: { visible: true },
},
};
},
createInput({ paramValues }) {
return {
publishDate: String(paramValues.publishDate ?? ""),
startsAt: String(paramValues.startsAt ?? ""),
period: String(paramValues.period ?? ""),
};
},

该互斥示例在选择单日后隐藏并清空范围,选择范围后隐藏并清空单日;清除当前值后两个字段重新显示。初始化时若外部 args 同时提供两者,会确定性地保留单日并清空范围。只返回 visible: false 会保留旧值,并继续把它放入 argsparamValues,不适合互斥参数。

每个 executor 都必须静态声明 projectTypeprojectType: "conversation" 会自动启用 conversation ID、上下文和会话存储,workflow 代码可以调用 context.conversation.setTitle(title) 给 Desktop 或 server embed 提供可读会话标题。projectType: "workflow" 禁止声明 conversation,其会话上下文保持禁用,并必须声明静态 defaultEntrypointentrypoints。缺失、未知类型或遗留 conversation.enabled 都会作为迁移错误拒绝加载,不会回退成 Workflow。

workflow.defineExecutor(...) 必须接收内联对象字面量,并把返回值作为模块的 executor 命名导出或默认导出。不能先把配置保存到变量后再传入,也不能继续使用顶层 workflowcreateInputprojectType 等旧式分散导出;静态结构分析不会执行配置代码,runtime 也不会再把这些字段拼装成 executor。

如果 conversation workflow 想复用 Desktop、server embed 和公开 embed 的共享默认输入框,可以在 conversation 下声明:

export const executor = workflow.defineExecutor<Input, Output>({
projectType: "conversation",
workflow: conversationWorkflow,
conversation: {
inputQueue: {
enabled: true,
},
defaultInput: {
enabled: true,
attachments: {
images: true,
files: true,
},
},
},
createInput({ args }) {
return workflow.parseConversationDefaultInputArgs(args);
},
});

defaultInput 只是宿主 UI 协议,不会自动改写 WorkflowContext。workflow 仍需在 createInput({ args }) 中显式读取固定参数名:

  • 文本:--message
  • 图片附件:--images
  • 普通文件附件:--files

推荐直接使用 workflow.parseConversationDefaultInputArgs(args)

createInput({ args }) {
const defaults = workflow.parseConversationDefaultInputArgs(args);
return {
message: defaults.message,
images: defaults.images,
files: defaults.files,
};
}

--images / --files 复用现有 file reference 协议,可以是 managed file JSON refs,也可以是本地 path。宿主负责把粘贴、拖拽或上传的 File 先转成 managed refs,再写回这些固定参数。

如果还声明了 conversation.inputQueue: { enabled: true },Desktop 和 server/web embed 会在当前会话运行中允许继续提交新输入。新增输入不会立刻执行,而是进入共享输入队列:

  • 队列只在 Desktop 和 Web 宿主中生效,CLI 不使用这个能力。
  • 宿主会持久化等待中的输入;Desktop 重启或 embed 刷新后,队列仍保留。
  • 恢复后的队列不会自动续跑,需要先手动发送一条新输入,后续排队项才会按顺序继续执行。
  • 当前 run 完成、失败或取消后,宿主会清理该会话的 active 运行标记;后续新输入恢复为普通发送,不会继续进入等待队列。
  • 队列项支持引导、编辑、删除和拖动排序;引导会先中断当前运行,再立即执行目标队列项。

开启 tokenUsage.enabled 后,runtime 会把 token 用量写入 KV,并把本次 run 聚合写入运行 report。聚合包含 inputTokensoutputTokenstotalTokensreasoningTokenscachedInputTokenscacheCreationTokenscallsdisplay 省略时默认等于 enabled,Desktop 和 server embed 只在 display === true 且有数据时展示 badge;badge 默认显示总量,hover/focus 分别展示 Input、Output、Reasoning、Cache read、Cache write 和 Calls。

工具权限

tools 用于注册 workflow 业务工具的默认权限。每个工具包含稳定 name,以及可选 labeldescriptionenabledautoApproveenabled 默认 trueautoApprove 默认 false。Desktop 和 server embed 可以在运行前缓存用户选择并传入覆盖值;runtime 只接受已注册工具的 enabled/autoApprove 覆盖,未知工具会被忽略。

workflow 代码可以使用 workflow.createToolApprovalGate() 包装工具函数。工具未注册时会以 input_validation 失败;工具被禁用时会以 tool_permission_denied 拒绝;工具启用但未自动批准时,会复用 workflow.createUserInputNode(...) 的等待/恢复协议生成 tool-approval 请求,批准后继续同一个 run,拒绝后返回 tool_permission_denied

示例

export const executor = workflow.defineExecutor<Input, Output>({
projectType: "workflow",
defaultEntrypoint: "main",
entrypoints: [
workflow.defineEntrypoint<Input, Output>({
id: "main",
title: "完整流程",
workflow: exampleWorkflow,
tokenUsage: { enabled: true, display: true },
tools: [
{
name: "search",
label: "Search",
description: "调用外部搜索工具。",
enabled: true,
autoApprove: false,
},
],
params: [
{
name: "message",
flag: "--message",
type: "string",
required: true,
control: "textarea",
description: "输入文本。",
},
],
createInput({ args }) {
return { message: readMessage(args) };
},
}),
],
});

注意事项

规则说明
createInput 是必填每个 Workflow entrypoint 和 Conversation executor 都必须声明。
paramValues 是正式结构化值createInput 可直接读取参数值;args 继续用于需要完整 CLI 参数或未知参数的场景。
Workflow 运行配置属于 entrypoint顶层旧字段会给出迁移错误,不再保留兼容别名。
tools 必须静态声明Desktop/server embed 只能展示所选入口或 Conversation executor 静态分析到的工具;工具名必须稳定。
tokenUsage.enabled 默认关闭未配置时不会写 KV,也不会展示用量。关闭时 context.tokenUsage.report() 是 no-op。
registry 用于单节点调试Workflow 只搜索所选入口的 registry;没有注册的节点不能通过 debug API 单独运行。