跳到主要内容

createOutputNode

workflow.createOutputNode() 创建输出节点。它既可以像普通节点一样同步格式化输入,也可以提供 stream 逐段输出,最后用 format 生成最终 payload。

当前输出协议直接使用 RunOutputPayload.items。不要再把完整输出聚合到顶层 content 字段;每一段可见输出都应该是独立的 OutputItem。

签名​

workflow.createOutputNode<Input, Output>(
options: OutputStreamNodeOptions<Input, Output>,
): BaseStreamNode<Input, OutputStreamChunk, Output>

workflow.createOutputNode<Input, Output>(
options: OutputNodeOptions<Input, Output> & {
format: OutputFormatter<Input, Output>;
},
): BaseNode<Input, Output>

workflow.createOutputNode<Input>(
options?: OutputNodeOptions<Input, Input>,
): BaseNode<Input, Input>

参数​

参数类型说明
optionsOutputNodeOptions | OutputStreamNodeOptions配置格式化函数、流式输出函数和节点元信息;不传时原样返回输入。

同步输出 options​

字段类型说明
namestring输出节点名,默认 "output"。运行报告会收集名为 output 的成功输出。
format(input, context) => Output把输入转换成最终 payload;不传时原样返回 input。
historyLimitnumber节点执行历史保留条数,默认 50。
metadataNodeMetadataInput节点展示元信息。

流式输出 options​

字段类型说明
namestring输出节点名,默认 "output"。
stream(input, context) => Iterable<OutputStreamChunk>逐段产出字符串 chunk 或结构化 output item chunk。必填。
format(stream, input, context) => Output把累积后的 { text, items, chunks } 转成最终 payload。必填。
historyLimitnumber节点执行历史保留条数,默认 50。
metadataNodeMetadataInput节点展示元信息。

返回值​

模式返回类型执行方式
同步输出BaseNode<Input, Output>workflow.runNode(outputNode, input, context)
流式输出BaseStreamNode<Input, OutputStreamChunk, Output>workflow.runStreamNode(outputNode, input, context)

输出流程​

模式说明
同步接收 Input,通过 format(input, context) 生成 Output。
流式接收 Input,先输出 string 或 item chunks,再把累积后的 { text, items, chunks } 交给 format。字符串 chunk 会自动追加到默认 Markdown item,普通流式输出无需手动创建 item。

在 conversation UI 里,如果同一段 assistant 回答会先流式展示、再通过最终 report 校准,推荐使用 workflow.createOutputItemChunk() 发送带稳定 id 的 output_item_start / output_item_delta / output_item_end。这样共享运行界面会按 item id 用最终结果替换 live item,而不是把字符串 chunk 生成的实时默认 item 和最终默认 item 各渲染一份。内置 Conversation 项目的主回答使用固定 conversation-answer id 来保持单条回复只展示一次。

如果 agent 文本会和工具调用穿插出现,不要把所有正文都 patch 到同一个稳定 item。工具调用前先结束当前 inline Output item,工具 detail item 输出后,再为后续正文创建新的 inline Output item;最终 items 应保持 正文段 -> 工具 detail -> 正文段 的事件顺序。

输出 item 协议​

interface RunOutputPayload extends RunPayload {
items: OutputItem[];
}

interface OutputItem {
id: string;
title: string;
content: unknown;
icon?: string;
iconPreset?: "info" | "success" | "warning" | "error" | "note" | "code" | "list" | "quote" | "none";
contentType?: "markdown" | "text" | "json" | "audio" | "video";
display?: { type: "ring"; placement?: "inline" | "composer-right" };
collapsed?: boolean;
metadata?: Record<string, unknown>;
}

contentType 只决定 UI 渲染方式:markdown 使用 Markdown 渲染,text 使用纯文本渲染,json 使用格式化 JSON 展示,audio 使用浏览器音频播放器,video 使用浏览器原生 <video> 播放器。对象和数组可以直接放进 content,不要提前 stringify 成 Markdown code block。

display 可为辅助数值输出声明圆环展示。type: "ring" 时,content 使用 RingContent:{ value: number, total?: number, unit?: string }。value 必须是非负有限数,total 若提供必须大于零;未提供时显示空环并在提示框中注明上限未知。圆环本身只展示比例,悬停或键盘聚焦时用浅灰提示框显示 title、百分比和精确用量;超限时圆环填满,提示保留实际百分比。

placement 默认为 "inline"。设为 "composer-right" 时,Conversation 将该输出固定在输入栏右侧,不在消息正文重复显示。使用跨轮稳定的 id 更新同一个固定输出;每个会话独立恢复最近的值,后续轮次未更新该项时保留原值。同一 id 改回 "inline" 后解除固定。普通 Workflow 的输出与回放在输出列表中展示圆环。

圆环可通过 output_item_delta 的对象增量更新,例如 delta: { value: 75 } 会保留已有的 total 和 unit。正文内的圆环更新时保留键盘焦点及打开的详情;多个圆环共存时只显示当前悬停或聚焦的提示框。

workflow.createOutputItem({
id: "storage-quota",
title: "存储用量",
content: { value: 57, total: 100, unit: "MB" },
contentType: "json",
display: { type: "ring", placement: "composer-right" },
});

Core Agent 使用同一协议输出上下文用量。自定义项目也可用于配额、进度等数值,无需增加宿主专用字段。默认 assistant 的 Markdown/text 主回答仍直接在正文展示。

audio item 的 content 使用对象结构:{ src, mimeType, name, size, durationMs?, format? }。src 可以是安全的 data:audio/...;base64,...,也可以是 http(s) 音频 URL;本地 CLI 示例推荐用 data URL,避免依赖 server file storage。

video item 的 content 使用对象结构:{ src, mimeType, name, durationMs?, format? }。mimeType 仅支持 video/mp4,format 仅支持 mp4。src 可以是安全的 data:video/mp4;base64,...,也可以是 http(s) 视频 URL;远端 URL 必须可公开访问。生成的 OSS 签名 URL 也属于 http(s),但因其本身不持久,UI 端不会缓存,请勿把生成的视频资源仅以 OSS 签名 URL 形式发布到不可重建的位置。CLI 示例仍推荐用 data URL,避免依赖 server file storage。如果 video item 的内容缺失必需字段或 src 不安全,UI 会降级为文本预览,并显示 videoPlaybackUnsupported 之类的降级文案;不要在调用方把 src 留空或指向 file:// 等本地路径。

输出 helper​

API说明
workflow.createOutputItem(input)创建带稳定 id、icon 预置解析和默认 contentType 的 item。
workflow.createOutputPayload(input)创建 { errCode, errMessage, items } payload,并可保留业务扩展字段。
workflow.addOutputItem(payload, item)向现有 output payload 追加一个 item。
workflow.createOutputItemChunk(chunk)创建 output_item_start / output_item_delta / output_item_end 流式 chunk。

流式 item chunk​

类型说明
output_item_start创建一个 item,包含 id、title、icon、contentType、collapsed 等字段。
output_item_delta按 itemId 追加或合并内容;字符串拼接,数组追加,对象浅合并。可选 item patch 更新 title、icon、metadata.status 等展示字段。
output_item_end标记 item 结束;当前主要用于协议完整性和 UI 后续扩展。

示例:同步输出​

const outputNode = workflow.createOutputNode<Result, OutputPayload>({
name: "output",
format(result) {
return {
...workflow.createOutputPayload({
items: [{
title: "Result",
content: result.text,
contentType: "markdown",
collapsed: false,
}],
}),
source: result.source,
};
},
});

示例:流式输出​

const outputNode = workflow.createOutputNode<Result, OutputPayload>({
name: "output",
async *stream(result) {
yield result.prefix;
yield result.text;
},
format(stream) {
return workflow.createOutputPayload({
items: stream.items,
totalChunks: stream.chunks.length,
});
},
});

示例:流式结构化 item​

const outputNode = workflow.createOutputNode<ToolResult, OutputPayload>({
name: "output",
async *stream(result) {
yield workflow.createOutputItemChunk({
type: "output_item_start",
item: {
id: "tool-result",
title: "Tool result",
content: {},
contentType: "json",
collapsed: true,
},
});
yield workflow.createOutputItemChunk({
type: "output_item_delta",
itemId: "tool-result",
delta: result.payload,
item: {
title: "Tool result complete",
icon: "success",
metadata: { status: "success" },
},
});
yield workflow.createOutputItemChunk({
type: "output_item_end",
itemId: "tool-result",
});
},
format(stream) {
return workflow.createOutputPayload({ items: stream.items });
},
});

Payload 约束​

字段说明
errCode最终 output payload 必须包含。成功值为 0。
errMessage最终 output payload 必须包含。成功时为空字符串。
items最终 output payload 必须包含。每个 item 是一个可独立折叠/展开的输出块。