mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
bdeb2bf1b1
## Failure Workflow SDK `5.0.0-beta.40` produces an invalid workflow bundle when a Chat SDK serializable class such as `Message`, `ThreadImpl`, or `ChannelImpl` crosses a workflow step boundary. The Workflow compiler imports the emitted module containing each class to register its `@workflow/serde` methods. In Chat SDK `4.37.0`, tsup emits those classes in `dist/index.js`. The root entry also imports the conversation-scoping implementation added in #751, which uses `AsyncLocalStorage` from `node:async_hooks`. Serializer registration therefore pulls Node-only code into the sandboxed workflow bundle before any workflow or step executes. Build warning: ```text Serde warning for classes "ChannelImpl", "Message", "ThreadImpl": Workflow bundle contains Node.js built-in imports: async_hooks. These will fail at runtime in the workflow sandbox. ``` Deployed workflows then fail during module initialization: ```text var import_async_hooks = require("async_hooks"); ^ ReferenceError: require is not defined ``` ## Minimal reproduction ```json { "dependencies": { "chat": "4.37.0", "workflow": "5.0.0-beta.40" } } ``` ```ts import { Message } from "chat"; async function createMessageStep(value: string): Promise<Message> { "use step"; return new Message({ id: "message", threadId: "slack:C123:123.456", text: value, formatted: { type: "root", children: [ { type: "paragraph", children: [{ type: "text", value }], }, ], }, raw: {}, author: { userId: "U123", userName: "user", fullName: "User", isBot: false, isMe: false, }, metadata: { dateSent: new Date(), edited: false }, attachments: [], }); } export async function testWorkflow(value: string): Promise<string> { "use workflow"; const message = await createMessageStep(value); return message.text; } ``` Running `workflow build` on `4.37.0` emits the warning; deploying the output produces the runtime failure above. ## Fix - Add a dedicated `chat/serialization` package entry for `Message`, `ThreadImpl`, `ChannelImpl`, `reviver`, and their serialized DTO types. - Make serializer code a second tsup entry and explicitly enable splitting. The serializer-bearing classes are now emitted into a shared chunk with no dependency on `Chat` or its Node-only conversation context. - Preserve the existing root exports and automatic `@workflow/serde` behavior. Existing `import { Message } from "chat"` workflow code remains valid. - Add a post-build module-graph assertion that fails if any emitted serializer registration can transitively import a Node.js builtin. - Test against Workflow SDK `5.0.0-beta.40`, the compiler version that exposed the invalid bundle. - Add a minor changeset for the fixed-version Chat SDK packages, producing the `4.38.0` release line. After the change, the emitted serializer classes live in a sandbox-safe shared chunk while `AsyncLocalStorage` remains in a separate Node runtime chunk. The exact reproduction compiles successfully with `5 steps, 1 workflow` and no Serde warning. ## Control cases The failure requires a serializable Chat class to cross a durable boundary. These cases were already safe and remain unchanged: - `AsyncLocalStorage` used entirely inside a `"use step"` function. - A Chat `Message` created and consumed within one step while returning plain data. - Request handlers that convert Chat objects to plain workflow DTOs before starting a workflow. - `@vercel/sandbox` used entirely inside a step. ## Validation - Committed beta.40 reproduction fixture: type-correct and compiled during every Chat package build with no Node builtin / Serde warning. - Emitted serializer module graph: no transitive Node.js builtins. - Chat package: 1,113 tests pass. - Chat package typecheck passes. - Repository formatting and lint checks pass. - Package build passes. Full repository validation reaches the pre-existing `knip` baseline and reports unrelated unused dependencies and unlisted binaries in examples and adapter packages. --------- Signed-off-by: bryan-hunter <bryan.hunter@vercel.com>
41 lines
1.1 KiB
JSON
41 lines
1.1 KiB
JSON
{
|
|
"$schema": "https://unpkg.com/knip@5/schema.json",
|
|
"ignoreDependencies": ["@biomejs/biome", "@vercel/oidc"],
|
|
"ignore": [
|
|
"apps/docs/**/*",
|
|
"packages/create-chat-sdk/_template/next.config.ts",
|
|
"packages/create-chat-sdk/_template/src/app/api/webhooks/[platform]/route.ts",
|
|
"examples/nextjs-chat/src/app/.well-known/workflow/**/*"
|
|
],
|
|
"workspaces": {
|
|
"packages/chat": {
|
|
"entry": ["fixtures/workflow-serialization.ts"]
|
|
},
|
|
"examples/nuxt-chat": {
|
|
"nuxt": {
|
|
"entry": [
|
|
"nuxt.config.ts",
|
|
"app/app.vue",
|
|
"app/error.vue",
|
|
"app/pages/**/*.{vue,jsx,tsx}",
|
|
"app/layouts/**/*.{vue,jsx,tsx}",
|
|
"app/middleware/**/*.ts",
|
|
"app/plugins/**/*.ts",
|
|
"app/assets/css/**/*.css",
|
|
"server/api/**/*.ts",
|
|
"server/middleware/**/*.ts",
|
|
"server/plugins/**/*.ts",
|
|
"server/routes/**/*.ts",
|
|
"server/lib/**/*.ts"
|
|
]
|
|
},
|
|
"ignoreDependencies": ["vue-tsc"]
|
|
}
|
|
},
|
|
"rules": {
|
|
"duplicates": "off",
|
|
"types": "off",
|
|
"optionalPeerDependencies": "off"
|
|
}
|
|
}
|