跳转到内容

输入关键词开始搜索文档。

迁移指南

最后更新 查看 Markdown 源文件

本指南将 Flue 代码库从 1.0.0-beta.9 迁移到 Flue 2。它是为可用的 beta 应用编写的:每个部分将 beta API 与其替代方案配对,末尾的清单排列了工作顺序。

该版本是一次破坏性版本升级和核心内部架构的重大重新设计。五个概念性变化驱动了升级:

  • flue build / flue dev CLI 命令——被带有 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/wrap DO 扩展、在 Flue 表旁写入的值)会随之一并删除——先导出你需要的任何内容。
  • 如果 beta 状态必须存活,在升级之前通过 beta 应用导出它,然后在之后重新填充。

本指南中的其他所有内容都可以分阶段进行;这是一个硬性边界。

构建和开发命令

flue build 和 flue dev 已被移除。Flue 应用现在是一个 Vite 项目:添加 vite、@flue/vite 和 hono 作为依赖(在 Cloudflare 上,还有 @cloudflare/vite-plugin)并编写 vite.config.ts——flue() 必须在 cloudflare() 之前:

vite.config.ts
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 现在是必需的,它显式挂载每个路由:

src/app.ts (beta)
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;
src/app.ts (now)
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' 指令标记的模块中:

src/agents/support.ts (beta)
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 },
}));
src/agents/support.ts (now)
'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.ts fetch 处理程序;应用拥有的导出(你自己的 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(),请在智能体模块中注册提供商。

迁移清单

  1. 版本锁定。 将 @flue/*@1.0.0-beta.x 替换为当前版本;添加 vite、@flue/vite、hono,以及(Cloudflare)@cloudflare/vite-plugin。放弃 beta 时代的补丁和供应商构建——在移植任何内容之前,针对新运行时重新验证每个被修补的行为。
  2. 构建。 编写 vite.config.ts(flue() 在 cloudflare() 之前);将包脚本改为 vite dev/vite build;修复 flue.config.ts(@flue/runtime/config,无 root/output);gitignore 生成的文件。
  3. 路由。 在 app.ts 中编写显式挂载;删除 flue() 路由器使用;挂载每个频道的 route();决定哪些智能体仅用于调度。
  4. 智能体。 将每个初始器转换为 'use agent' 模块中导出的大写智能体函数:钩子用于行为,静态属性(agentName、initialData、durability)用于契约,AgentProps 用于 id,平台环境变量替代 ctx.env。将配置文件转换为 useSubagent 智能体函数。使用隐式虚拟沙箱的智能体声明一个:useSandbox(bash(() => new Bash({ fs: new InMemoryFs() })))。
  5. 工具。 将 run({ input }) 重命名为 run({ data });在工具提示会话的地方采用 harness: true;考虑对副作用序列使用 durable: true。
  6. 技能。 删除导入属性;让 SKILL.md 导入自行打包;在需要时用 defineSkill 包装其他 markdown。
  7. 工作流。 用最小合适的方案替代每个:被等待的 init() 句柄、持久工具或应用自有的编排器。
  8. 频道和数据库。 将 conversationKey/parseConversationKey 重命名为 instanceId/parseInstanceId;围绕你自己的驱动重写数据库适配器;将 db.ts 移到源码根目录。
  9. 提供商。 将 registerProvider()/registerApiProvider() 调用替换为 Pi 的 createProvider() + setProvider()(将 @earendil-works/pi-ai 添加到依赖);将 Cloudflare 绑定注册替换为 @flue/runtime/cloudflare/workers-ai 的 cloudflareBindingProvider();可选用 flue({ providers: [...] }) 缩小附带的提供商范围(名称 'cloudflare' 保留 Workers AI)。
  10. 可观测性。 将 run_* 处理迁移到 agent_start/agent_end/submission_settled 和 instanceId/submissionId 关联字段。
  11. 客户端。 将 SDK 和 React 使用迁移到对话级客户端和 useFlueAgent({ url | client })。
  12. 部署。 为 FlueRegistry 和工作流类追加 deleted_classes;为新智能体添加 new_sqlite_classes;为模式重置计划排空部署。
  13. 验证。 类型检查、测试、生产 vite build,以及在部署前检查构建产物(导出、合并的 wrangler 配置)。