迁移指南
本指南将 Flue 代码库从 1.0.0-beta.9 迁移到 Flue 2。它是为可用的 beta 应用编写的:每个部分将 beta API 与其替代方案配对,末尾的清单排列了工作顺序。
该版本是一次破坏性版本升级和核心内部架构的重大重新设计。五个概念性变化驱动了升级:
flue build/flue devCLI 命令——被带有flue()插件的 Vite 替代;vite dev和vite build是唯一的命令。- 自动挂载的
flue()路由器和按目录发现——被app.ts中的显式路由替代;'use agent'扫描注册智能体。 defineAgent(async initializer => config)配置包——智能体现在就是函数:一个导出的大写智能体函数,使用智能体钩子组合行为;defineAgent已完全移除。- 工作流(
defineWorkflow、invoke()、运行、运行事件)——已移除。使用被等待的init()句柄、持久工具或你自己的编排器。参见工作流。 - 部署级 SDK 客户端(
client.agents.*、client.workflows.*)——被 Flue 智能体 SDK 的对话级客户端替代:每个对话 URL 一个客户端。
本指南将旧代码映射到新 API;它不教授新 API。请先阅读智能体、智能体钩子、路由和工作流——以下部分假设你知道替代方案是什么,只涵盖需要更改的内容。
开始之前:持久化状态重置
当前版本存储 Flue 模式版本 8;beta 存储版本 5。1.0 之前的持久化模式是仅重置——运行时在任何应用代码运行之前拒绝旧数据库,没有就地迁移。
- 如果 beta 对话状态是可丢弃的,计划排空部署:退役旧的智能体(在 Cloudflare 上,使用
deleted_classes迁移)并创建新的。共享智能体存储的应用数据(base/wrapDO 扩展、在 Flue 表旁写入的值)会随之一并删除——先导出你需要的任何内容。 - 如果 beta 状态必须存活,在升级之前通过 beta 应用导出它,然后在之后重新填充。
本指南中的其他所有内容都可以分阶段进行;这是一个硬性边界。
构建和开发命令
flue build 和 flue dev 已被移除。Flue 应用现在是一个 Vite 项目:添加 vite、@flue/vite 和 hono 作为依赖(在 Cloudflare 上,还有 @cloudflare/vite-plugin)并编写 vite.config.ts——flue() 必须在 cloudflare() 之前:
import { cloudflare } from '@cloudflare/vite-plugin'; // Cloudflare target only
import { flue } from '@flue/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [flue(), cloudflare()],
});flue dev——现在是vite dev(开发服务器从端口 3583 移到 Vite 的 5173)。flue build——现在是vite build;在 Node 上,然后是node dist/server.mjs和以前一样。- 通过
--target选择目标——现在从插件数组自动检测,或在flue.config.ts中设置target。
更新 package.json 脚本和构建项目的每个 CI 流水线。在 Cloudflare 上,插件生成两个 Cloudflare 插件消费的输入——.flue-vite/(Worker 入口)和 .flue-vite.wrangler.jsonc(你编写的 wrangler.jsonc 与生成的绑定合并)。将两者添加到 .gitignore。
如果你有 flue.config.ts,两个变化:
defineConfig现在来自@flue/runtime/config;@flue/cli/config子路径已删除。root和output字段已弃用——Vite 拥有两者。严格验证在除flue run外的所有地方拒绝它们,flue run静默丢弃未知键——删除它们。
.env 加载也变了:vite dev 加载 Vite 的标准 .env 文件,flue run 加载 .env(传 --env 指定替代文件)。构建的服务器永不加载 .env。
路由:自动路由器已移除
beta 的 flue() 路由器(来自 @flue/runtime/routing 的 app.route('/', flue()),或生成的默认 app)不再存在。app.ts 现在是必需的,它显式挂载每个路由:
import { flue } from '@flue/runtime/routing';
const app = new Hono();
app.use('/agents/*', requireUser);
app.route('/', flue()); // agents, workflows, channels — discovered and mounted
export default app;import { createAgentRouter } from '@flue/runtime/routing';
import { Hono } from 'hono';
import { Triage } from './agents/triage.ts';
import { channel } from './channels/slack.ts';
const app = new Hono();
app.use('/agents/*', requireUser);
app.route('/agents/triage', createAgentRouter(Triage)); // explicit, per agent
app.route('/channels/slack', channel.route()); // explicit, per channel
export default app;createAgentRouter(fn)是一个纯路由器工厂,相对于挂载点提供POST /:id、GET|HEAD /:id、POST /:id/abort和GET /:id/attachments/:attachmentId。URL 形状由你决定——如果已部署的客户端使用旧的/agents/<name>路径就保留它们。- 注册来自
'use agent'扫描,而非挂载。 仅调度的智能体保持未挂载仍然工作;挂载不注册任何东西。 - 智能体模块的
export const route和export const attachments约定已删除。每个智能体的中间件变成在挂载前注册的普通 Hono 中间件;附件下载存在于每个已挂载的智能体上。 POST /:id请求体已更改:{ "message": "...", "images": [...] }变成纯消息对象——{ "message": { "kind": "user", "body": "..." } }——带有可选的顶层initialData和uid。?wait查询已移除;客户端跟随返回的streamUrl或使用 SDK 的wait()。- 工作流路由(
POST /workflows/<name>、/runs/<runId>)随工作流一起移除,runs模块导出和WorkflowRouteHandler/WorkflowRunsHandler类型也是。
定义智能体
beta 的返回配置包的异步初始器变成一个同步智能体函数,使用钩子组合行为,位于由 'use agent' 指令标记的模块中:
import { defineAgent } from '@flue/runtime';
export default defineAgent(async ({ id, env }) => ({
model: 'anthropic/claude-sonnet-4-6',
instructions: `Help with ticket ${id}.`,
tools: [lookupOrder],
skills: [refundsSkill],
subagents: [reviewerProfile],
sandbox: bash(myFactory),
cwd: '/workspace',
durability: { maxAttempts: 5 },
}));'use agent';
import {
type AgentProps,
useModel,
useSandbox,
useSkill,
useSubagent,
useTool,
} from '@flue/runtime';
export function Support({ id }: AgentProps) {
useModel('anthropic/claude-sonnet-4-6');
useSandbox(myFactory, { cwd: '/workspace' });
useTool(lookupOrder);
useSkill(refundsSkill);
useSubagent({ name: 'reviewer', description: '…', agent: Reviewer });
return `Help with ticket ${id}.`;
}
Support.durability = { maxAttempts: 5 };智能体就是导出的函数——没有包装器、没有配置包、没有默认导出。发现不再关心 src/agents/ 目录:构建扫描源码根目录的 'use agent' 指令,标记模块中每个导出的大写函数都是一个智能体。没有该指令的转换模块被静默地不视为智能体。
逐字段说明:
model——现在是useModel(model, options?):必需,每次渲染恰好一次,仅根渲染。instructions——现在是智能体函数的返回字符串;useInstruction()追加更多内容。tools——现在每个工具使用useTool()。skills——现在每个技能使用useSkill()。subagents(配置文件)——现在使用useSubagent({ name, description, agent, model?, thinkingLevel? });委托是一个智能体函数,而不是配置文件。defineAgentProfile已移除;defineSubagent()定义跨智能体共享的委托。thinkingLevel、compaction——现在是useModel(model, { thinkingLevel, compaction })。sandbox、cwd——现在是useSandbox(factory, { cwd }):每次渲染最多一次;存在性可以是条件性的。durability——现在是durability静态属性:Support.durability = { maxAttempts: 5 }。是静态属性而非钩子,因为平台在函数未运行时应用它;环境相关的策略放在赋值表达式中(flag ? x : y)。profile——已移除;改用自定义钩子(调用钩子的普通函数)组合。actions——随 Actions 一起移除。将可重用操作表达为工具(harness: true用于应用驱动的模型工作)。description(配置)——已删除,无替代。- 初始器
ctx.id——现在是AgentProps:根智能体函数接收{ id }。 - 初始器
ctx.env——现在是平台导入(import { env } from 'cloudflare:workers')或process.env;初始器上下文已移除。 async初始器——智能体函数必须是同步的;异步工作移入工具、生命周期钩子(useAgentStart/useAgentFinish)或资源工厂(如沙箱工厂的createSandbox())。
没有 beta 等价物的规则,因为渲染会重复:
- 智能体函数在每个模型轮次前重新渲染。资源(
useTool、useSkill、useSubagent)可以是条件性的——变化作为resources信号通知模型——useSandbox也可以(存在性翻转在下一个轮次边界交换环境,作为environment信号通知),usePersistentState(其存储按名称为键),以及事件钩子(useAgentStart、useAgentFinish、useResponseStart、useResponseFinish——每个接缝运行当前渲染声明的内容,至少一次)。唯一不变量:useDataWriter名称必须在每次渲染中相同地声明。 - 标识是导出函数的名称,或
fn.agentName = '...'字符串字面量静态覆盖;PascalCase 和小写 kebab-case 都有效,标识在每个应用中唯一。重命名没有agentName固定的智能体函数是存储标识变更;重命名文件什么都不改变。beta 的文件名派生标识不需要保留——beta 存储无法通过模式重置延续——所以现在选择好的函数名称。 - 每个智能体的 Durable Object 类名规则:
export function Triage()→ 类FlueTriageAgent,绑定FLUE_TRIAGE_AGENT(每个智能体函数一个类;一个文件可以携带多个)。迁移历史保持用户编写的——添加智能体始终是三步:'use agent'模块中的导出智能体函数、挂载(除非仅调度),以及new_sqlite_classes条目。重命名使用renamed_classes——但记住模式重置:beta 时代的数据库即使在重命名的类下也会被拒绝,因此 beta 智能体通常被退役(deleted_classes)以支持新标识。 - 你编写的
wrangler.jsonc永不被修改;构建将其合并到生成的、被 gitignore 的.flue-vite.wrangler.jsonc中,vite build将最终配置写入dist/带有部署重定向——从项目根目录用普通wrangler deploy部署,不需要--config标志。 cloudflare.ts从.flue/cloudflare.ts移到src/cloudflare.ts。生成的入口导出每个智能体类加上你的app.tsfetch 处理程序;应用拥有的导出(你自己的 DO、工作流、scheduled处理程序)来自cloudflare.ts,定时工作使用dispatch()启动,而不是invoke()。- 将
run_worker_first从 beta 的["/api/*", "/_flue/*"]更新为覆盖你的实际挂载点,例如["/api/*", "/agents/*", "/channels/*"]。 - 最低
compatibility_date是2026-04-01,在构建时验证。
CLI
flue init、flue add、flue update 和 flue docs 保留(flue init 现在是完整的交互式项目脚手架,而不是配置文件编写器)。flue dev 和 flue build 已移除(Vite 拥有两者)。flue run 不再与构建的服务器通信;它在进程中执行一个智能体模块:
# Beta
flue run support --target node --input '{"ticket": 42}'
# Now
flue run src/agents/support.ts --message "Handle ticket 42." --id ticket-42
- 必需:模块路径和
-m/--message。--name在一个模块中的多个智能体间选择。 --input→--data '<json>'(创建数据,由initialData静态验证)。- 随 HTTP 表单一起移除:
--server、--header、--target、--root、--output、--config和工作流名称。要调用已部署的服务器,改用 SDK 的对话客户端。 - 新增:
--uid/--new发送条件和--json(结果信封)。Stdout 仅是回复;日志输出到 stderr。 flue run永不加载app.ts——如果你依赖应用启动时的setProvider(),请在智能体模块中注册提供商。
迁移清单
- 版本锁定。 将
@flue/*@1.0.0-beta.x替换为当前版本;添加vite、@flue/vite、hono,以及(Cloudflare)@cloudflare/vite-plugin。放弃 beta 时代的补丁和供应商构建——在移植任何内容之前,针对新运行时重新验证每个被修补的行为。 - 构建。 编写
vite.config.ts(flue()在cloudflare()之前);将包脚本改为vite dev/vite build;修复flue.config.ts(@flue/runtime/config,无root/output);gitignore 生成的文件。 - 路由。 在
app.ts中编写显式挂载;删除flue()路由器使用;挂载每个频道的route();决定哪些智能体仅用于调度。 - 智能体。 将每个初始器转换为
'use agent'模块中导出的大写智能体函数:钩子用于行为,静态属性(agentName、initialData、durability)用于契约,AgentProps用于 id,平台环境变量替代ctx.env。将配置文件转换为useSubagent智能体函数。使用隐式虚拟沙箱的智能体声明一个:useSandbox(bash(() => new Bash({ fs: new InMemoryFs() })))。 - 工具。 将
run({ input })重命名为run({ data });在工具提示会话的地方采用harness: true;考虑对副作用序列使用durable: true。 - 技能。 删除导入属性;让
SKILL.md导入自行打包;在需要时用defineSkill包装其他 markdown。 - 工作流。 用最小合适的方案替代每个:被等待的
init()句柄、持久工具或应用自有的编排器。 - 频道和数据库。 将
conversationKey/parseConversationKey重命名为instanceId/parseInstanceId;围绕你自己的驱动重写数据库适配器;将db.ts移到源码根目录。 - 提供商。 将
registerProvider()/registerApiProvider()调用替换为 Pi 的createProvider()+setProvider()(将@earendil-works/pi-ai添加到依赖);将 Cloudflare 绑定注册替换为@flue/runtime/cloudflare/workers-ai的cloudflareBindingProvider();可选用flue({ providers: [...] })缩小附带的提供商范围(名称'cloudflare'保留 Workers AI)。 - 可观测性。 将
run_*处理迁移到agent_start/agent_end/submission_settled和instanceId/submissionId关联字段。 - 客户端。 将 SDK 和 React 使用迁移到对话级客户端和
useFlueAgent({ url | client })。 - 部署。 为
FlueRegistry和工作流类追加deleted_classes;为新智能体添加new_sqlite_classes;为模式重置计划排空部署。 - 验证。 类型检查、测试、生产
vite build,以及在部署前检查构建产物(导出、合并的 wrangler 配置)。