mirror of
https://github.com/vercel/workflow.git
synced 2026-09-14 19:59:43 +08:00
nathanc/shared-queue-http-handler
45 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
11dc036854 |
ci: stop deploying changeset-release/main, run its e2e against production (#3243)
* ci: stop deploying changeset-release/main, run its e2e against production The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so when both a production deployment (from main) and a preview deployment (from changeset-release/main) are built for the same commit, whichever finishes last owns the status. On 2026-07-30 the preview finished last, so `vercel/wait-for-deployment-action` — which reads the deployment ID out of that status — handed production e2e runs a preview deployment ID and forked runs across environments. Disable git deployments for that branch in every Vercel project rooted in this repo, and give the changeset PR's Vercel e2e lanes a deployment to test that actually exists: main's production deployment for the PR's base SHA, resolved by SHA so a mid-flight production build is waited out rather than silently replaced by an older one. Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * ci: resolve changeset-release e2e deployments with the wait action, tokenless Per review: with changeset-release/main no longer deployed, main SHAs can never again be deployed to a second environment of these projects, so the per-SHA commit status the action reads is unambiguous for exactly this lane. Reuse vercel/wait-for-deployment-action with environment: production and sha pinned to the PR base SHA instead of the Vercel-API polling script, drop the script and its VERCEL_TOKEN usage, and inherit the action's inactive/skipped-build handling. Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> |
||
|
|
f11e9fe56f | fix: upgrade next to 16.2.11 to address CVE-2026-64641 (#3071) | ||
|
|
9a2770ab34 |
test: regression coverage for hook.resume() from isolated route bundles (o2flow beta.26 incident) (#3001)
* test: regression coverage for hook.resume() from isolated route bundles (o2flow beta.26 incident) Reproduces the o2flow v5 upgrade failure (workflow@5.0.0-beta.26, fixed by #2752 in beta.28): a plain API route importing defineHook() from the root `workflow` entry and calling .resume() failed with Turbopack's "Cannot find module as expression is too dynamic" stub, because the world registration was tree-shaken out of the route bundle and getWorldLazy()'s dynamic-import fallback got stubbed. The bug only manifests when a route bundle loads in isolation (a Vercel lambda): local `next dev`/`next start` evaluates next.config.ts, whose workflow/next import chain registers the world process-wide and masks it — which is why no existing server-driven suite caught it. - route-bundle-isolation.test.ts: production Turbopack build of the nextjs-turbopack workbench, then loads ONLY the compiled route bundle in a bare Node subprocess (cold-lambda simulation) and invokes its POST handler. Fails with the exact incident error on regressed code; passes on main. Wired into the build-error-messages CI job. - e2e: plainModuleDoneHook round-trip through a plain API route on the two Next workbenches (deployed matrix covers real lambda isolation). - Workbench fixtures mirroring o2flow: a directive-less defineHook module shared by a workflow (create) and a plain route (resume). The webpack workbench gets a real route file because `next dev` (webpack) does not serve directory-symlinked app routes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * test: authenticate plain hook resume request * test: address review — marker-based harness output parsing, changeset summary - route-bundle-isolation: prefix the harness result line with a unique marker and locate it explicitly instead of JSON.parse()ing the last stdout line, so stray logging from the route bundle or the world can't break parsing; failures now include the full subprocess stdout. - changeset: add a human-readable summary to the (release-less) changeset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com> Co-authored-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com> |
||
|
|
421ff4f349 |
Bump e2e framework versions (#2814)
* Fix SvelteKit config loading * Bump e2e framework versions |
||
|
|
68d225d510 | chore: ignore workflow swc caches (#2640) | ||
|
|
3859d338e3 |
Propagate trace context to vercel-workflow.com in workbench instrumentation (#2601)
* Propagate trace context to vercel-workflow.com in workbench instrumentation @vercel/otel only propagates W3C trace context to Vercel deployment URLs by default, so outgoing requests to the workflow-server (vercel-workflow.com) got a client span with no `traceparent` header — breaking the APM trace link to workflow-server's spans. Add `instrumentationConfig.fetch.propagateContextUrls` for the workflow-server domain in every workbench that uses @vercel/otel: example, nextjs-turbopack, nextjs-webpack, and sveltekit. The Next.js and SvelteKit apps already declared @vercel/otel but weren't registering it at all; they now do. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Also propagate trace context to the Vercel Queue Service (vercel-queue.com) The workflow-server queue path (@vercel/queue) sends to regional vercel-queue.com subdomains (e.g. iad1.vercel-queue.com) when not using the queues proxy, which were missing a `traceparent` header for the same reason as vercel-workflow.com. Add `/vercel-queue\.com/` to propagateContextUrls in all four workbench instrumentation configs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
070bd0cea9 |
[next] make lazyDiscovery the default in withWorkflow (#1805)
* [next] make lazyDiscovery the default in withWorkflow
Flips the default for `workflows.lazyDiscovery` from `false` to `true`
so new projects get deferred workflow discovery automatically on Next.js
versions that support deferred entries (>= 16.2.0-canary.48). Older
versions continue to fall back to eager discovery.
Users can still opt back into eager discovery explicitly by passing
`workflows: { lazyDiscovery: false }`.
Also:
- Remove the now-redundant `lazyDiscovery: true` from the Next.js
workbench apps.
- Reword the fallback warning for clarity when lazy is the default.
- Update the local-build e2e assertion to match the new warning text.
- Update the withWorkflow docs with the new default.
* [workbench] remove commented 'export default nextConfig' lines
|
||
|
|
09a0c1d6d1 |
Remove instrumentation from workbench (#1959)
* Remove instrumentation from workbench * bump |
||
|
|
5f22832675 |
Serialize run_failed/step_failed errors through serialization pipeline (#1851)
* Serialize run_failed/step_failed errors through serialization pipeline
Switch run_failed, step_failed, and step_retrying events to persist
the full thrown value via the workflow serialization pipeline (as
SerializedData / Uint8Array) instead of a lossy { message, stack, code }
StructuredError shape. Consumers hydrate via hydrateRunError /
hydrateStepError to reconstruct the original thrown value, preserving
Error subclass identity, cause chains, and custom properties.
- WorkflowRun.error and Step.error are now SerializedData
- WorkflowRun gains a top-level errorCode plaintext field
- WorkflowRunFailedError.cause is now the hydrated thrown value
- Adds world-postgres migration 0010_add_error_code.sql
- Legacy pre-pipeline errorJson records surface as undefined on read
* Update Next.js workbenches for new WorkflowRunFailedError.cause type
cause is now `unknown` (the hydrated thrown value) rather than
`Error & { code }`. Defensively extract Error-shaped fields when the
hydrated value is an Error, otherwise round-trip the raw value, and
expose the new `errorCode` classification field.
* Update docs for WorkflowRunFailedError.cause: unknown
The hydrated `cause` is now `unknown` (the original thrown value
through the serialization pipeline) and the error classification has
moved to the top-level `errorCode` property. Update the two affected
docs pages and the `TSDoc` interface to reflect the new shape, and
narrow `cause` with `instanceof Error` before accessing fields.
* Expand test coverage for the run/step error serialization pipeline
Unit tests:
- 19 new dehydrate/hydrate{Step,Run}Error round-trip tests covering
FatalError, plain Error, built-in Error subclasses, non-Error thrown
values (string, plain object), cause chains, encryption round-trip,
the binary format prefix contract, and the unserializable / unknown-
format error paths.
- 5 new tests for Run.returnValue when the run is failed: hydrated
FatalError + cause as cause, plain Error preservation, non-Error
thrown values surfaced verbatim, cross-class cause chains, and the
hydration-failure fallback that still surfaces errorCode.
E2E tests (new, in 99_e2e.ts + e2e.test.ts):
- Step throw → workflow catch round-trips a FatalError with a TypeError
cause chain, asserting class identity, fatal marker, and cause name +
message all survive the step_failed event pipeline.
- Workflow throw → run_failed reaches status with the new
top-level errorCode metadata exposed (cause-shape coverage lives at
the unit level, since the SWC plugin's class registration is not
invoked in the plain-Node e2e runner).
- Workflow throw of a non-Error value round-trips that value verbatim
as WorkflowRunFailedError.cause.
Adjustments to existing assertions:
- error.cause is now ; tests narrow with
and use the new top-level field instead of .
- step.error / run.error from CLI --withData are now hydrated payloads:
unregistered class instances surface as Instance refs whose
carries the original message + stack.
Observability hydration:
- hydrateStepIO / hydrateWorkflowIO in serialization-format.ts now
hydrate the field via hydrateData, so the CLI and web UI
continue to surface readable run/step error messages and stacks.
* Tighten error serialization changeset description
* Trim error serialization changeset to a single sentence
* Resolve FatalError/RetryableError revivers via cross-realm registry
When a workflow runs in a Node `vm` context, its bundled
`@workflow/errors` is a different module instance than the host's
import (separate prototype chains, separate class identity). Calling
`new FatalError(...)` from the host-side reviver produces a
host-realm instance that fails `err instanceof FatalError` checks
in the workflow code — even when the serialized payload was correctly
tagged via the dedicated `FatalError` reducer.
Surfaced by the local-prod e2e "step throw round-trips FatalError"
test on Next.js Turbopack: each route gets its own bundled chunk, so
the flow handler's `@workflow/errors` and the workflow VM bundle's
`@workflow/errors` are two distinct copies of the same module.
Fix:
- Each bundled copy of `@workflow/errors` self-registers its
`FatalError` and `RetryableError` classes on `globalThis` via
`Symbol.for("@workflow/errors//FatalError")` /
`Symbol.for("@workflow/errors//RetryableError")`. First load wins
per realm; the descriptor is non-writable / non-configurable to make
accidental clobbering loud.
- The revivers in `@workflow/core`'s common reducers module read the
consumer's `globalThis` (passed in as `global`) to pick up the
realm-local class, falling back to the host-imported class when no
registration is present (e.g. in the CLI / test runner).
* Use `types.isNativeError` to remap workflow stacks across VM realms
The runtime's run-failure path computes a source-map-remapped stack
and then assigns it back onto the thrown value via `if (err
instanceof Error) err.stack = errorStack`. Workflows run inside a
Node `vm` context, so a workflow-thrown error is an instance of the
VM realm's `Error` — `instanceof` against the host realm's
`Error` returns `false`, the assignment is skipped, and the
serialized `run_failed` event carries the un-remapped (bundled-line-
number) stack instead of the source-mapped one.
Switch the gate to `types.isNativeError`, which uses V8's internal
type tag and works across realms — same approach already in place
for the serialization reducers.
Caught by the local-prod e2e "nested function calls preserve message
and stack trace" and "cross-file imports preserve message and stack
trace" tests, which assert that the persisted run-error stack
contains `99_e2e.ts` / `helpers.ts`.
* Sync CLI revivers with core + add toJSON shim for Error subclasses
Two issues with the CLI's hand-rolled reviver list:
1. It hadn't been updated for the new first-class Error subclass
reducers (`TypeError`, `RangeError`, `FatalError`, `RetryableError`,
etc.). devalue throws "Unknown type X" when it encounters a
reduced value with no matching reviver, and `hydrateResourceIO`
swallows that error and surfaces the raw `Uint8Array` payload —
so `step.error` / `run.error` showed up as raw byte dumps in
`workflow inspect` output.
2. Even with all the right revivers, `Error.prototype`'s `message`
/ `stack` / `cause` are non-enumerable, so `JSON.stringify`
(used by `workflow inspect --json`) drops them — leaving the
subclass-specific enumerable fields (e.g. `FatalError.fatal`)
visible but the actual error data missing.
Fix:
- Build the CLI reviver set on top of `getCommonRevivers()` from
`@workflow/core` so the CLI stays in sync with the runtime's
reducer set automatically. New core reducers/revivers will Just
Work without any CLI-side change.
- Wrap each Error reviver from the common set with a thin shim that
attaches a non-enumerable `toJSON` method to the produced
`Error` instance. `JSON.stringify` calls `toJSON` and gets a
full object (`name` + `message` + `stack` + `cause` + any
enumerable subclass fields like `fatal` / `retryAfter` /
`errors`); `util.inspect` ignores `toJSON` and renders the
canonical `Error: msg\\n at ...` format. Best of both worlds for
CLI output without compromising the runtime hydration path.
Caught by the local-prod e2e "basic step error preserves" and
"cross-file step error preserves" tests, which read
`failedStep.error.message` / `.stack` from the CLI's JSON output.
* Clarify parseErrorJson JSDoc to match its always-null return
The previous JSDoc described preserving legacy values "for best-effort
hydration" which contradicted the implementation, where legacy errors
are intentionally surfaced as absent (the pre-pipeline shapes can't be
hydrated by the new error revivers). Rewrite the comment so the contract
matches behavior. Also rename the now-unused parameter to `_errorJson`
to reflect that the function ignores it.
Caught by a code review on #1851.
* Refine error-handler ergonomics on the step / run hot paths
Three review-driven adjustments that all touch the queue handlers and
their interaction with the error serialization pipeline:
1. Memoize the per-run encryption key fetch. The step handler used to
eagerly fetch + import the key at the top of every step delivery so
the value would be in scope for every potential dehydrateStepError
path. That pessimized step-started early-return cases (the fetch
happens unconditionally even when the step never reaches user code)
and required duplicating the same boilerplate at four call sites in
runtime.ts. Introduce `memoizeEncryptionKey(world, run)` in
runtime/helpers.ts that returns a lazy, single-fetch accessor;
step-handler / runtime call sites use `await getEncryptionKey()`
instead. The first caller pays the fetch cost, subsequent callers
await the cached promise, and steps that fail before any
encryption-aware work happens skip the fetch entirely.
2. Preserve the prior attempt's serialized error as the cause on the
defensive max-retries-exceeded `step_failed` re-invocation guard.
The existing comment explicitly opted out of cause attachment, but
the symmetric post-failure path below already does this and the
reviewer is right that consumers shouldn't have to walk the
step_retrying event history to recover the underlying error. Best-
effort: if hydration of the prior `step.error` throws, fall back
to a FatalError without cause rather than letting the event write
itself fail.
3. Document the intentional `unflatten` throw in
`hydrateStepError` / `hydrateRunError` for non-Uint8Array input.
SDK version is pinned per workflow run via skew protection so the
non-binary branch is dead in production; if a misshapen value
reaches it, surfacing the throw via the surrounding o11y try/catch
is more debuggable than masking it. Add a comment so future
reviewers don't reach for a defensive fallback.
A standalone `falls back to plaintext` suggestion on the run_failed
key fetch was rejected: when encryption is configured we should fail
loudly rather than silently emit plaintext error data. The queue's
redelivery semantics will retry the key fetch; persistent KMS outages
get logged with the existing "persistent error preventing the run from
being terminated" message rather than a security regression.
* Hydrate `event.eventData.error` in event listings
`hydrateEventData` enumerated the per-event fields that need
hydration (`result`, `input`, `output`, `metadata`, `payload`)
but omitted the new `error` field on `step_failed`,
`step_retrying`, and `run_failed` events. Without this branch,
o11y tools that list events (e.g. `workflow inspect events`) surface
the raw `Uint8Array` payload instead of a hydrated
`{ name, message, stack, … }` object even though the entity-level
`Run.error` / `Step.error` paths already hydrate.
Mirrors the existing per-field branches; the `try/catch` leaves the
field un-hydrated on parse failure rather than failing the whole
event view. Adds a unit test.
* Use `.is()` static checks in `classifyRunError` for cross-realm safety
Workflows execute inside a separate `vm` realm: the
`WorkflowRuntimeError` class bundled into the workflow code and the
host-imported one are distinct constructors, so an
`err instanceof WorkflowRuntimeError` check on a VM-thrown error
returns `false` and we'd misclassify genuine runtime errors (corrupted
event log, missing timestamps, workflow/step not registered) as user
errors.
Switch to each subclass's `.is()` static (a name-based duck check that
works across realms). Since `WorkflowRuntimeError.is` only matches its
own concrete name, enumerate every concrete subclass we want to
recognize (`StepNotRegisteredError`, `WorkflowNotRegisteredError`)
in a `RUNTIME_ERROR_CHECKS` table; keep that table in sync with the
class hierarchy in `@workflow/errors`.
Existing `classify-error.test.ts` already covers `WorkflowRuntimeError`
and `WorkflowNotRegisteredError` cases — both still pass.
* Add e2e coverage for step throws of non-Error values
We had `errorWorkflowThrowNonErrorValue` (workflow body throws a plain
object — round-trips verbatim as `WorkflowRunFailedError.cause`) but
no symmetric coverage for the step-throw side. Step-throw goes through
a different code path: non-Error values aren't recognized as
`FatalError` (no `name === 'FatalError'`) nor `RetryableError`,
so they take the transient retry path. After max retries the runtime
wraps the original thrown value as `cause` on a fresh `FatalError`
which the workflow's catch block then sees.
Add a workflow that throws a recognizable plain object from a step
with `maxRetries = 0` (so we exhaust on first attempt and avoid a
long test wait) and a workflow that asserts the wrapped FatalError
shape: `isFatal`, `instanceof FatalError`, message includes the
original object's serialized form, `cause` is the original non-Error
object verbatim with structure preserved.
Documents the current retry-then-wrap behavior so any future change
to "non-Error throws skip retries" semantics has to update the test.
* Note legacy postgres error-data loss in the run/step error changeset
Pre-upgrade failed runs that wrote into world-postgres's deprecated
`error` text column can't be hydrated through the new pipeline (the
shape is incompatible with the new revivers). The new runtime
intentionally surfaces them as `error: undefined` on read; the
original payload is still readable directly from the `errorJson`
column for manual inspection. Add a one-sentence note to the
changeset's migration text so consumers upgrading don't get blindsided
by suddenly-empty error fields on historical runs.
|
||
|
|
8ea1532e48 | [core] Combine flow+step bundle and process steps eagerly (#1338) | ||
|
|
cdf90d5a38 |
Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall (#1541)
* Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall - Rename "Workflow DevKit" to "Workflow SDK" across all files (~108 files) - Rename standalone "WDK" references to "Workflow SDK" - Remove beta badge from homepage hero - Add tweet wall component to homepage with 4 builder testimonials Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall - Rename "Workflow DevKit" to "Workflow SDK" across all files (~108 files) - Rename standalone "WDK" references to "Workflow SDK" - Remove beta badge from homepage hero - Add tweet wall component to homepage with 4 builder testimonials Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com> * Address review: fix missed trigger phrase renames and bump skill versions - Rename "workflow devkit" to "workflow sdk" in trigger phrases for both skill files - Bump workflow-init SKILL.md version to 1.1 - Bump workflow SKILL.md version to 1.5 - Note: CLAUDE.md is a symlink to AGENTS.md, already renamed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com> * link correct tweet --------- Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com> |
||
|
|
ef4ca00b77 |
chore: bump next to 16.2.1 and fix deferred build (#1496)
* chore: bump next to 16.2.1 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: run deferred Next dev e2e assertions on stable Bump Next.js to 16.2.1 in docs and swc-playground and update lockfile. * fix(next): copy all deferred step sources for step-mode transforms --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: JJ Kasper <jj@jjsweb.site> Co-authored-by: Peter Wielander <mittgfu@gmail.com> |
||
|
|
5010ebe7c5 |
fix(next): stabilize deferred canary e2e in nextjs workbenches (#1468)
* Revert "[ci] Fix nextjs lazy disocvery impacting e2e tests, disable experimental DurableAgent tests (#1400)"
This reverts commit
|
||
|
|
1959f2b8e7 |
Use relative import for _workflows in webpack trigger-pages (#1405)
esbuild's discovery build cannot resolve @/ path aliases when the tsconfig does not have baseUrl set. Use a relative import so the discovery can trace through _workflows.ts to find all workflow files. |
||
|
|
74aea7b0af |
Add DurableAgent compat tests, e2e tests, and migrate to AI SDK v6 (#1362)
* Add DurableAgent compat tests, e2e agent tests, and migrate to AI SDK v6 - Port ToolLoopAgent test suite as DurableAgent compatibility spec (34 tests, all expected to fail — each maps to a feature gap to implement) - Add e2e workflow definitions using mock LLM providers (no API keys needed) - Add e2e test file for DurableAgent workflows - Migrate all AI SDK types from V2 to V3 (LanguageModelV2 → V3, etc.) - Drop AI SDK v5 support: ai peer dep ^5||^6 → ^6, @ai-sdk/provider ^2||^3 → ^3 - Update ai catalog version from 5.0.104 to 6.0.116 - Simplify CompatibleLanguageModel to just LanguageModelV3 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address PR review feedback - Remove providerExecuted guard on tool-result stream parts (V3: all tool-results are provider-executed by definition) - Remove providerExecuted spread from tool-output-available UI chunks - Replace inline MockLanguageModelV3 with import from ai/test (works without msw in AI SDK v6) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove streamTextIterator mock from compat tests, use it.fails for gaps Tests now exercise the real DurableAgent code path instead of mocking the core iterator. 5 tests pass (features DurableAgent already has), 29 are marked it.fails() for known API gaps that will alert when fixed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Implement Tier 1+2 gaps, add @workflow/ai/test mock provider, wire e2e in CI DurableAgent API additions: - Add `instructions` (string | SystemModelMessage | SystemModelMessage[]) as alias for deprecated `system` on constructor - Add `onStepFinish` and `onFinish` on constructor, merged with stream options (constructor first, then stream — matching ToolLoopAgent) - Add `timeout` on stream options (converted to AbortSignal) - Add `text`, `finishReason`, `totalUsage` to onFinish event Test infrastructure: - Add @workflow/ai/test export with `mockModel()` wrapper that wraps MockLanguageModelV3 from ai/test as an async step function - E2e workflows now use mockModel() + convertArrayToReadableStream from @workflow/ai/test instead of inline V2 mock models - Add e2e-agent.test.ts to test:e2e script so it runs in CI - Flip 6 compat tests from it.fails → it (now passing) Score: 11 passing / 23 it.fails (was 5/29) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove e2e agent tests — mock models can't serialize across step boundary The workflow runtime serializes step arguments, and function closures (like mock model doStream callbacks) aren't serializable. Mock models only work in unit tests where 'use step' is a no-op. Real e2e agent tests would need either a mock HTTP server or real provider credentials. Also removes 'use step' from mockModel wrapper (closures aren't serializable) and reverts test:e2e script and example workbench dep. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add working e2e agent tests with mock model step factories Mock model factories use the same 'use step' pattern as real providers (anthropic, openai). Closure variables are bound to locals at the step body level so the SWC plugin detects them via __private_getClosureVars. All 4 e2e tests pass against local dev server: - agentBasicE2e: text response (11s) - agentToolCallE2e: single tool call + text (11s) - agentMultiStepE2e: 3 sequential tool calls (12s) - agentErrorToolE2e: FatalError recovery (11s) Also adds e2e-agent.test.ts to test:e2e script for CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Use @workflow/ai/test package imports for e2e mock models Split mock provider into two files to work around SWC constructor closure bug: mock-create.ts has the model creation logic, mock.ts has the 'use step' wrappers that capture only serializable args (strings, plain object arrays). Exports mockTextModel(text) and mockSequenceModel(responses) — same 'use step' pattern as real providers (anthropic, openai, etc.). E2e workflows now import directly from @workflow/ai/test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Simplify mock provider, add comprehensive e2e tests for all features + gaps Mock provider: - Replace mock-create.ts with mock-function-wrapper.ts that simply wraps MockLanguageModelV3 constructor in a function (SWC class closure bug) - mockTextModel/mockSequenceModel use mockProvider() from wrapper file - Bind closure vars at step body level (_text = text) for SWC detection - Fix AbortController not available in workflow VM sandbox E2e tests (13 total, all passing): - Core: basic text, tool call, multi-step, error recovery (4) - Callbacks: onStepFinish constructor+stream, onFinish constructor+stream (2) - Features: instructions, timeout (2) - GAPs documented: onStart, onStepStart, onToolCallStart, onToolCallFinish, prepareCall (5 — complete but callbacks not called) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add tool approval (needsApproval) gap tests, fix SWC closure var binding Unit tests: 2 new it.fails() tests for tool approval - needsApproval: true should pause agent (pending tool call, no result) - needsApproval as function should receive tool input E2e tests: 1 new test for tool approval gap - Documents that needsApproval is currently ignored (tool executes anyway) Also fixes: - Bind closure vars at step body level in mock provider (_text = text, _responses = responses) so SWC plugin detects them - Guard AbortController usage in workflow VM (not available in sandbox) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add default args for agent e2e workflows in UI definitions The nextjs-turbopack UI calls workflows with hardcoded default args. Without these entries, agent workflows were called with no args, causing prompt=undefined → ModelMessage validation failure. Also removes debug logging. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add DurableAgent chat UI with tools, update docs for AI SDK v6 Chat UI: - Tab-based layout with Workflows (existing) and DurableAgent Chat tabs - Chat powered by DurableAgent + WorkflowChatTransport + ai-elements - Tools: getWeather (fake data), calculate (math expressions) - Uses createUIMessageStreamResponse for proper stream serialization - Reconnect route at /api/chat/[runId]/stream - ai-elements components: conversation, message, prompt-input, tool - onStepFinish + onFinish callbacks with console logging Docs (AI SDK v6 migration): - system → instructions in DurableAgent constructor examples (10 places) - LanguageModelV2Prompt → LanguageModelV3Prompt in type references (3 places) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix tool rendering, add reasoning support, model picker, observability links - Fix tool part rendering: use `input`/`output` props (not `args`/`result`) and `tool-{name}` part type (AI SDK v6 format) - Add reasoning support for Opus 4.5 via providerOptions - Model picker: Haiku 4.5, Sonnet 4, Opus 4.5 (reasoning), GPT-5.2, GPT-5.3 - Fix observability links: localhost:3456 for local, Vercel dashboard for prod - Add suggestions above prompt input - Add MessageParts component handling text, tool, reasoning, step-start - Add loading spinner for submitted state - Update docs: system → instructions, LanguageModelV2Prompt → V3 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix tool output rendering: use input/output props on ToolInput/ToolOutput Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix: Documentation for `PrepareStepInfo` and `PrepareStepResult` interfaces references the obsolete `LanguageModelV2` type while the codebase has fully migrated to `LanguageModelV3`. This commit fixes the issue reported at docs/content/docs/ai/message-queueing.mdx:36 **Bug explanation:** The codebase migrated from AI SDK V2 to V3. In `packages/ai/src/agent/types.ts`, `CompatibleLanguageModel` is defined as `LanguageModelV3` (from `@ai-sdk/provider`). The actual TypeScript interfaces in `packages/ai/src/agent/durable-agent.ts` use `string | (() => Promise<CompatibleLanguageModel>)` which resolves to `LanguageModelV3`. However, the documentation in `docs/content/docs/ai/message-queueing.mdx` at lines 36 and 43 still referenced `LanguageModelV2` for the `model` field in both `PrepareStepInfo` and `PrepareStepResult`. This is inconsistent because: 1. The `messages` fields in the same interfaces were correctly updated to `LanguageModelV3Prompt` 2. The actual source code uses `LanguageModelV3` via `CompatibleLanguageModel` 3. There is no `LanguageModelV2` type anywhere in the codebase This would mislead developers reading the documentation into using the wrong type. **Fix explanation:** Changed both `LanguageModelV2` references to `LanguageModelV3` on lines 36 and 43 of the documentation file, matching the actual codebase types. Verified no other stale `LanguageModelV2` references remain in the docs directory. Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> Co-authored-by: pranaygp <pranay.gp@gmail.com> * Fix instructions tests: flip from it.fails to it, update snapshots The 3 instructions tests (string, SystemModelMessage, array) now pass. The snapshots include the assistant reply message from the agent loop, which is a behavioral difference from ToolLoopAgent (DurableAgent captures the prompt after the full loop iteration). Score: 14 passing / 22 it.fails (was 11/25) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix getReadable call: pass startIndex as options object Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix docs type errors and turbopack build Docs: - Add await to convertToModelMessages() calls (now async in AI SDK v6) - Change LanguageModelV3Prompt → ModelMessage[] in type references - Change LanguageModelV3 → LanguageModel in PrepareStepInfo - Update docs-globals.d.ts convertToModelMessages return type - Add LanguageModel to import inference map DurableAgent: - Update OutputSpecification to match AI SDK v6 Output interface (type→name, parsePartial→parsePartialOutput, parseOutput→parseCompleteOutput, responseFormat now PromiseLike) Turbopack build: - Remove streamdown plugins from MessageResponse (plugins prop API changed in streamdown 2.4.0, causing type mismatch in CI) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix pnpm-workspace.yaml: use double quotes for catalog entries The stage-workbench-with-tarballs.mjs script only strips double quotes when parsing catalog keys. Single-quoted @-scoped entries (e.g., '@types/node') weren't matched, causing "unresolved catalog dependencies" errors in CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix CI build failures, add changeset - Remove streamdown plugins from reasoning.tsx (same CI type mismatch) - Cast ToolHeader type prop and WorkflowChatTransport to fix type errors - Fix pnpm-workspace.yaml single→double quotes for staging script - Add minor changeset for @workflow/ai (breaking: AI SDK v6 migration) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Sync webpack workbench with turbopack: add chat UI deps and symlinks - Symlink app-shell.tsx, chat-client.tsx, agent_chat workflow, chat API routes into nextjs-webpack - Add matching deps: streamdown, @streamdown/*, shiki, cmdk, nanoid, motion, @radix-ui/react-use-controllable-state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix circular symlink: restore chat-client.tsx as real file in turbopack The previous commit accidentally converted turbopack's chat-client.tsx into a circular symlink pointing to itself. Webpack's symlink to it then couldn't resolve, breaking both builds on Vercel. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add missing deps to webpack: use-stick-to-bottom, radix-ui, @vercel/blob Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix model picker: merge body params via prepareSendMessagesRequest WorkflowChatTransport sends { messages } by default, ignoring the body option from ChatRequestOptions. Use prepareSendMessagesRequest to merge { messages, ...body } so the model selection reaches the API. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix WorkflowChatTransport: forward body/headers from ChatRequestOptions The transport hardcoded body: undefined when calling prepareSendMessagesRequest, so extra body params (like model selection) from sendMessage({ body: { model } }) were silently dropped. Now forwards options.body and options.headers to both prepareSendMessagesRequest and the default request body. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix model IDs: use real AI Gateway model names gpt-5.2 and gpt-5.3 don't exist in the AI Gateway. Replace with gpt-4o and gpt-4o-mini. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Use correct AI Gateway model IDs: Opus 4.5, GPT-5.2, GPT-5.3 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Enable reasoning for all model providers - Anthropic: thinking.type='enabled' with 10k token budget - OpenAI: reasoningEffort='high' - Instructions kept for all models (no longer conditionally removed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix OpenAI reasoning: use 'medium' effort (GPT-5.3 doesn't support 'high') Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address all PR review comments - Change changeset from minor to patch (repo convention) - Use ?? instead of || for system/instructions fallback - Clean up timeout: store ID, clearTimeout in finally, { once: true } listeners - Update class docstring example to use instructions - Map unrecognized finish reasons to 'other' with validation - Fix duplicate test, align assertion for unrecognized type - Support ^ exponentiation in calculate tool - Remove debug console.log from chat client - Fix ReactNode/ComponentProps type imports in UI components - Remove unused MockLanguageModelV3 re-exports from mock.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove accidentally created empty mock2.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Change changeset back to minor for breaking AI SDK v6 migration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix agent e2e tests: add Vercel world setup for CI The agent e2e tests only configured the local filesystem world but not the Vercel world backend. On CI (Vercel prod tests), this caused VercelOidcTokenError because the world wasn't initialized. Now matches the setup pattern from e2e.test.ts: configures Vercel world with OIDC token and project config from CI environment variables. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Deduplicate e2e test utilities: extract shared code to utils.ts Extract manifest fetching, workflow lookup, world setup, and types into shared utils.ts. Both e2e.test.ts and e2e-agent.test.ts now import from the same source, eliminating ~200 lines of duplication. Shared utilities: - WorkflowManifest interface - fetchManifest() with caching - getWorkflowMetadata() with retry and fallback - setupWorld() handling local/Vercel/Postgres backends Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix missing deploymentUrl args in e2e.test.ts after utils refactor Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add @workflow/ai dep to all workbenches for agent e2e tests All workbenches now have @workflow/ai as a dependency and the 100_durable_agent_e2e.ts symlink, so agent e2e tests run everywhere. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix missing imports in e2e.test.ts: add fetchManifest and sleep The utils refactor removed these imports but they're still used: - fetchManifest: used in stepFunctionAsStartArgWorkflow test - sleep (setTimeout): used in webhookWorkflow test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> |
||
|
|
d72c82220f |
Fix bug where the SWC compiler bug prunes step-only imports in the client-mode transformation
* first pass * fix failing test * Update changeset to fix SWC compiler issue Fix bug where the SWC compiler bug prunes step-only imports in the client-mode transformation Signed-off-by: Nathan Rajlich <n@n8.io> * DCO Remediation Commit for nathancolosimo <nathancolosimo@gmail.com> I, nathancolosimo <nathancolosimo@gmail.com>, hereby add my Signed-off-by to this commit: |
||
|
|
a9fea9132e |
Update workbench tests to build and run outside of monorepo (#1230)
* Setup fixes * ci: run local e2e against staged tarball workbenches * ci: update staged workbench tarball setup script * chore: set nextjs workbenches back to next 16.1.6 * update lock * test(e2e): resolve workbench path from WORKBENCH_APP_PATH * fix: address deferred builder issues outside monorepo * ci: stage tarball workbenches only for nextjs local e2e * fix(next): discover deferred steps imported via workflows * test(core): gate deferred step-discovery dev test to canary * test(e2e): cover cross-file imported step in build/start lanes * fix(e2e): use local manifest in local runs and relax dev rebuild timeout * fix(workbench): add imported-step workflow symlink for sveltekit/astro * test(e2e): scope imported-step workflow test to nextjs lanes * fix(next): rebuild deferred entries on discovered file updates * fix(next): watch transitive deferred step deps for dev rebuilds * fix(next): restore socket-driven deferred step rebuilds * add changeset * chore: address review feedback on deferred e2e updates * fix(cli): guard stream flush against closed write streams |
||
|
|
809339ba1c |
fix(builders): enable directive discovery in dot-prefixed files and directories (#1228)
* fix(builders): enable directive discovery in dot-prefixed files and directories The glob-based file scanning in getInputFiles() was using tinyglobby's default behavior which skips dot-prefixed files/directories. This prevented discovering files with 'use step' / 'use workflow' directives inside paths like .config/step.ts or .hidden-workflow.ts. Switch to relative glob patterns with per-directory cwd and dot: true to ensure dot-files are scanned while still respecting the explicit ignore list (.git, .next, .vercel, etc.). * test: add E2E tests for dot-directory directive discovery Add workbench fixtures and E2E tests verifying that 'use step' / 'use workflow' directives inside dot-prefixed directories (.well-known/agent/) are correctly discovered, included in manifests, and executed at runtime. * fix: normalize paths in getInputFiles tests for Windows compatibility tinyglobby returns forward-slash paths even on Windows, while Node's path.join() uses backslashes. Normalize both sides to forward slashes before comparison. * refactor: use dirname() instead of join(.., '..') in test helper Cleaner and more idiomatic way to get the parent directory. * fix: add .nuxt and other build tool dot-directories to ignore list With dot: true enabled, framework build output directories like .nuxt/ are now traversed and their generated files picked up as input files. This caused a circular dependency in the nuxt builder where generated .nuxt/workflow/steps.mjs was being re-discovered as an input file. Add .nuxt, .turbo, .cache, .yarn, and .pnpm-store to the ignore list, matching the directories already ignored by the eager builder's watcher. |
||
|
|
54879835f3 | Fix pages router default args: use empty array instead of [42] (#1081) | ||
|
|
0946dad01b |
Remove "workflow/internal/serialization" export (#1082)
* Remove "workflow/internal/serialization" export Was only being used in these two e2e test files and the data being passed in those tests don't rely on any specialized data types, so just use JSON there. * Fix: Removing the `workflow/internal/serialization` export from package.json breaks 5 files in `packages/world-testing` that still import `hydrateWorkflowReturnValue` from that path. Co-authored-by: TooTallNate <n@n8.io> * lockfile --------- Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> |
||
|
|
30076ecea8 | Enable lazyDiscovery in workbench (#1044) | ||
|
|
5b5b36a03b |
[e2e] Remove /api/hook and /api/test-health-check endpoints, call APIs directly
- Remove debug logging from bench.bench.ts - Remove awaitReturnValue() wrapper, use run.returnValue directly in benchmarks - Add changeset for Nitro builder manifest fix - Refactor hookWorkflow tests to call getHookByToken()/resumeHook() directly (pass hook object to resumeHook to avoid duplicate lookups) - Refactor queue-based health check test to call healthCheck() directly - Assert specific error message for invalid hook token test - Remove /api/hook and /api/test-health-check endpoints from all workbench apps (nextjs-turbopack, nextjs-webpack, vite, hono, express, fastify, sveltekit, astro, nuxt, nitro-v2, nitro-v3, nest, example) |
||
|
|
82c209c669 | Add missing env for tests on deploy (#973) | ||
|
|
86f62f2779 |
Refactor e2e tests to no longer use "trigger" endpoint (#958)
## Summary
Refactors the E2E tests to call `start()` from `workflow/api` directly instead of going through the `/api/trigger` HTTP endpoint in each workbench app. This removes a layer of indirection — the tests now use the same API that users would use to start workflows programmatically.
### Before
```ts
const run = await triggerWorkflow('addTenWorkflow', [123]);
const returnValue = await getWorkflowReturnValue(run.runId);
```
- `triggerWorkflow()` sent an HTTP POST to `/api/trigger` on the workbench app
- The workbench app looked up the workflow function, called `start()`, and returned the run ID
- `getWorkflowReturnValue()` polled `GET /api/trigger?runId=...` until the workflow completed
### After
```ts
const run = await start(await e2e('addTenWorkflow'), [123]);
const returnValue = await run.returnValue;
```
- `e2e()` / `getWorkflowMetadata()` fetches the manifest from `/.well-known/workflow/v1/manifest.json` to look up the correct `workflowId`
- `start()` is called directly from the test process via the configured World
- `run.returnValue` polls for completion via the World (no HTTP polling endpoint needed)
### Changes
**`packages/core/e2e/e2e.test.ts`**
- Removed `triggerWorkflow()` and `getWorkflowReturnValue()` helpers
- Added `fetchManifest()` to fetch and cache the workflow manifest from the deployment
- Added `getWorkflowMetadata(file, fn)` to look up `{ workflowId }` from the manifest
- Added `e2e(fn)` shorthand for the common case of `workflows/99_e2e.ts`
- All tests call `start()` and `run.returnValue` directly
- Error tests use `.catch()` to inspect `WorkflowRunFailedError`
- Output stream tests use `run.getReadable()` directly (skipped on local world where cross-process streaming isn't supported)
- `beforeAll` configures the local World with the correct data directory and base URL
- Pages Router tests use `startWorkflowViaHttp()` to specifically validate the HTTP trigger path
**Workbench apps (hono, express, fastify, nest)**
- Removed `/api/trigger` route handlers
- Kept `/api/hook`, `/api/test-direct-step-call`, `/api/test-health-check` endpoints
- Re-added `_workflows.js` side-effect import for hono/express/fastify to maintain Nitro's HMR dependency graph
**Deleted trigger-only route files** from: nextjs-turbopack, nextjs-webpack, vite, sveltekit, astro, nuxt, nitro-v2, nitro-v3, example
**`.github/workflows/tests.yml`**
- Added `WORKFLOW_PUBLIC_MANIFEST: '1'` to all E2E test jobs
### Dependencies
Stacked on #963 which adds `WORKFLOW_PUBLIC_MANIFEST` support to all framework builders.
|
||
|
|
fed805a15f |
Bump Next.js and React in workbenches (#944)
* Bump Next.js and React in workbenches - Next.js: 16.0.10 → 16.1.6 in nextjs-turbopack, nextjs-webpack, swc-playground workbenches - Next.js: 16.0.10 → 16.1.6 in @workflow/next devDependencies (for type compatibility) - React/React-DOM: ^19.0.0/19.2.1 → 19.2.4 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add changeset Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
b5296a7a32 |
Add discovered serializable classes in all context modes (#874)
This PR ensures that all classes with custom serialization are automatically included in all bundle contexts (step, workflow, client) to ensure proper serialization/deserialization when crossing execution boundaries: - Classes defined in any context can now be properly serialized when passing data between: - Client → Workflow (when starting workflows) - Workflow → Step (when calling steps) - Step → Workflow (when returning step results) - Workflow → Client (when returning workflow results) - The build system now automatically discovers all files containing serializable classes and includes them in each bundle, regardless of where the class is originally defined. - No manual configuration is required - cross-registration happens automatically during the build process. |
||
|
|
1060f9d04a | Change user input/output to be binary data at the World interface (#853) | ||
|
|
344c90ff9f |
Add Next.js pages router entries handling (#792)
* Add Next.js pages router entries handling * update trigger-pages * Apply suggestions from code review Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Signed-off-by: JJ Kasper <jj@jjsweb.site> --------- Signed-off-by: JJ Kasper <jj@jjsweb.site> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
a2fc53a0dc |
Support class static methods with "use step" / "use workflow" (#753)
The SWC compiler plugin had logic to walk through class static methods with "use step" / "use workflow", but no actual transformation was being applied. This fixes that. |
||
|
|
61fdb41e1b |
Add queue-based health check (#743)
* feat: add queue-based health check to bypass Deployment Protection
- Add HealthCheckPayloadSchema and HEALTH_CHECK_STREAM_PREFIX to @workflow/world
- Add healthCheck() method to Queue interface
- Update workflow and step handlers to detect and respond to health check messages
- Implement healthCheck() in world-local, world-vercel, and world-postgres
The queue-based health check sends a message through the queue pipeline,
which bypasses Vercel's Deployment Protection. The handler writes a response
to a stream that the caller reads to confirm health.
This complements the existing HTTP-based ?__health approach which still works
for local development and when bypass headers are available.
* refactor: move healthCheck to core package as utility function
Instead of adding healthCheck to the World interface (which duplicated
the same implementation across all worlds), this is now a utility function
in @workflow/core that takes the World as a parameter.
Usage:
import { healthCheck } from '@workflow/core';
const result = await healthCheck(world, 'workflow');
This is cleaner because:
- Single implementation instead of 3 identical ones
- World implementations remain simple
- No changes needed to the World interface
* .
* refactor: move health check types from world to core
Health check types (HealthCheckPayloadSchema, HealthCheckResult, etc.)
are now defined in @workflow/core since that's where they're used.
The HealthCheckPayloadSchema is still part of QueuePayloadSchema in
world (so the queue accepts health check messages), but it's not
exported from the public API.
* .
* Refactor health check implementation based on code review feedback (#746)
* Initial plan
* Address PR review comments: export types, fix race condition, improve error handling
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* Add queue-based health check test and document security considerations
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* Replace 'any' type with proper type guards for health check response
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* Extract health check queue names as constants and improve type guards
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* .
* Fix e2e test
* .
* .
* .
* fix(ai): preserve providerMetadata as providerOptions in multi-turn tool calls (#733)
When tool calls are added to the conversation history, map providerMetadata
to providerOptions following the AI SDK convention. This fixes Gemini thinking
models that require thoughtSignature to be preserved across multi-turn tool calls,
preventing the error 'function call is missing a thought_signature'.
Fixes #727
* Local ui cli flag (#744)
* [web] Increase contrast on attribute items in sidebar (#736)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
* [world] Remove pause and resume events, actions and states (#751)
* Version Packages (beta) (#735)
* .
* .
* Update turbo inputs to include shared config (#752)
* Update turbo inputs to include shared config
* Apply suggestions from code review
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
---------
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
* feat(web): add self-hosted mode for world configuration (#747)
* feat(web): add self-hosted mode for world configuration
When WORKFLOW_TARGET_WORLD env var is set, the web UI operates in
self-hosted mode where the world configuration is locked to server-side
environment variables and cannot be changed via query params or UI.
- Add getHardcodedConfig server action to detect self-hosted mode
- Modify getWorldFromEnv to use server env vars in hardcoded mode
- Create WorldConfigContext to provide config state app-wide
- Update settings sidebar to show locked state with disabled inputs
- Update connection status to show PostgreSQL backend info
- Mask sensitive values (postgres URL) in hardcoded mode UI
* fix: address PR review feedback
- Remove unused ConfigMode type export
- Fix postgres substring to undefined (tooltip has details)
- Extract buildEnvMapFromProcessEnv helper to reduce duplication
- Remove unused EnvMap import from layout-client
- Import HardcodedConfig from web-shared/server instead of re-defining
* Fix: PostgreSQL URL parameter missing from configParsers, causing loss of postgres URL configuration on page reload in dynamic mode
* fix(cli): clear WORKFLOW_TARGET_WORLD when spawning web server
The CLI sets WORKFLOW_TARGET_WORLD as an env var, which the spawned
Next.js server inherits. This caused the web UI to enter self-hosted
mode even when launched via CLI.
Now we explicitly clear WORKFLOW_TARGET_WORLD from the server's
environment so it starts in dynamic mode where config comes from
query params as intended.
* refactor(web): use server-side env vars for world config
BREAKING CHANGE: The web UI no longer supports configuring the world
backend via URL query parameters. Configuration is now read exclusively
from server-side environment variables.
Changes:
- Remove query param parsing from @workflow/web config.ts
- Add ServerConfig interface with non-sensitive display info
- Update all components to use useServerConfig() hook
- Settings sidebar is now read-only
- CLI passes env vars to spawned web server instead of query params
- Server actions use process.env directly (envMap param reserved for future use)
This simplifies the architecture and improves security by never sending
sensitive data (connection strings, auth tokens) to the client.
* fix(web): fix settings sidebar overflow and shorten data dir path
- Add truncate/overflow handling to settings sidebar config values
- Add shortenPath() helper to abbreviate long file paths:
- Replaces home directory with ~
- Shows .../last-two-segments if still too long
- Add title attributes for full path on hover
* Update changeest
---------
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
* Version Packages (beta) (#755)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Update packages/world/src/queue.ts
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
* [web] Tidy wake-up and re-enqueue buttons (#737)
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
* [cli] Use dotenv to resolve .env and .env.local files on startup (#765)
* Use temporary workflow-server deployment URL
* feat: add queue-based health check to bypass Deployment Protection
- Add HealthCheckPayloadSchema and HEALTH_CHECK_STREAM_PREFIX to @workflow/world
- Add healthCheck() method to Queue interface
- Update workflow and step handlers to detect and respond to health check messages
- Implement healthCheck() in world-local, world-vercel, and world-postgres
The queue-based health check sends a message through the queue pipeline,
which bypasses Vercel's Deployment Protection. The handler writes a response
to a stream that the caller reads to confirm health.
This complements the existing HTTP-based ?__health approach which still works
for local development and when bypass headers are available.
* refactor: move healthCheck to core package as utility function
Instead of adding healthCheck to the World interface (which duplicated
the same implementation across all worlds), this is now a utility function
in @workflow/core that takes the World as a parameter.
Usage:
import { healthCheck } from '@workflow/core';
const result = await healthCheck(world, 'workflow');
This is cleaner because:
- Single implementation instead of 3 identical ones
- World implementations remain simple
- No changes needed to the World interface
* .
* refactor: move health check types from world to core
Health check types (HealthCheckPayloadSchema, HealthCheckResult, etc.)
are now defined in @workflow/core since that's where they're used.
The HealthCheckPayloadSchema is still part of QueuePayloadSchema in
world (so the queue accepts health check messages), but it's not
exported from the public API.
* .
* Refactor health check implementation based on code review feedback (#746)
* Initial plan
* Address PR review comments: export types, fix race condition, improve error handling
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* Add queue-based health check test and document security considerations
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* Replace 'any' type with proper type guards for health check response
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* Extract health check queue names as constants and improve type guards
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
* .
* Fix e2e test
* .
* .
* .
* .
* .
* Update packages/world/src/queue.ts
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
* Use temporary workflow-server deployment URL
* .
* .
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Vercel Release Bot <88769842+vercel-release-bot@users.noreply.github.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
||
|
|
e3f0390469 |
Workflows graph extractor (#455)
--------- Signed-off-by: Karthik Kalyanaraman <karthik@scale3labs.com> |
||
|
|
f5db6ed52c | CVE-2025-55184 (#603) | ||
|
|
8b70f2d113 | Update to latest Next.js (#528) | ||
|
|
ac7997b855 | Update to latest swc/core and preserve JSX (#507) | ||
|
|
a8f48c5a08 | add benchmarking (#460) | ||
|
|
3aee6d7efb |
Port Peter's Workbench UI to nextjs-turbopack (#458)
* Port Peter's Workspace UI * Add symlinks for webpack workbench to share UI with turbopack - Add symlinks for components, hooks, lib directories - Add symlinks for app/workflows and app/api/workflows - Install UI dependencies in webpack workbench package.json - Both webpack and turbopack workbenches now share the same UI code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Use allWorkflows from @/_workflows instead of custom examples.ts - Update workflow definitions to include workflowFile field - Change start route to use allWorkflows like trigger route - Remove unused examples.ts file - This allows accessing workflows from any workflow file, not just 99_e2e 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Dynamically generate workflow definitions from allWorkflows - Remove manual workflow definitions, now auto-generated from _workflows.ts - Add workflowFile path display in UI (tooltip and fallback description) - Sort workflows by file name first, then by workflow name - Fix duplicate key issue by using workflowFile:name as key - Make description optional since it's inferred from file path 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add default arguments map for workflows that require parameters - Create DEFAULT_ARGS_MAP to provide sensible defaults for workflows with parameters - Includes defaults for: addTenWorkflow, hookWorkflow, webhookWorkflow, hookCleanupTestWorkflow, closureVariableWorkflow - Workflows without entries in the map get empty args array This allows all workflows to be started from the UI without needing manual argument input for now. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix terminal log colors for better visibility on black background - Change info logs from text-primary (black in light mode) to text-cyan-400 - Change error logs from text-destructive to text-red-400 - Update stream logs to text-blue-400 - Update result logs to text-green-400 - Change prefix color from text-gray-500 to text-gray-400 All colors now work properly with the terminal's black background regardless of light/dark mode. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Remove toTitleCase transformation, use raw workflow names - Display workflow names exactly as they are in code (e.g., "addTenWorkflow") - Remove the toTitleCase helper function - Simpler and more direct mapping from code to UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Use monospace font for workflow names - Apply font-mono to workflow displayName in both card and tooltip - Makes workflow names more readable and consistent with code style 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Filter out step functions using workflowId property - Check for 'workflowId' property added by compiler to identify workflow functions - More reliable than checking function name endings - Only functions with "use workflow" directive have workflowId property - Prevents step functions from appearing in the UI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add symlinks for remaining workflow files and dependencies - Add symlinks for 2_control_flow.ts, 4_ai.ts, 5_hooks.ts to both workbenches - Install openai and mixpart dependencies needed by these workflows - Update DEFAULT_ARGS_MAP with arguments for new workflows: - ai: sample weather prompt - agent: sample weather prompt for Muscat - handleUserSignup: example email address - All 9 workflow files now available in both workbenches 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Group workflows by file with section headers in UI - Group workflows by workflowFile and render each group separately - Add section headers showing the file path for each group - Use monospace font for file path headers - Increase spacing between sections (space-y-4) - Improves visual organization when browsing workflows 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Show default arguments instead of file path in workflow cards - Display default arguments in the card description line (if present) - Remove redundant file path since it's now shown in section headers - Use monospace font for argument display - Workflows without arguments show no description line 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Display default arguments with multi-line formatting - Use JSON.stringify with indentation (null, 2) for better readability - Change from <p> to <pre> with whitespace-pre-wrap - Arguments now display across multiple lines when needed - Easier to read complex arguments like webhook tokens 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add workflow runtime duration display with millisecond precision - Add formatDuration helper to calculate and format runtime - Show duration in ms, seconds, or minutes based on length - Formats: "123ms", "5.234s", "2m 15.678s" - Display duration in monospace font below end time - Only shown when invocation has completed (endTime exists) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Update default arguments to match e2e test values - Use arguments from packages/core/e2e/e2e.test.ts for accuracy - addTenWorkflow: 123 (instead of 5) to match test expectations - closureVariableWorkflow: 7 (instead of 42) to match test expectations - Use Math.random().toString(36) for hook/webhook tokens (matches test pattern) - Add comment referencing e2e test source 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
4f09e128a8 | Remove unused dependencies (#405) | ||
|
|
10ce313d56 |
postgres: fix tests (#394)
* postgres: use non-deprecated drizzle signatures Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * postgres: store metadata in the hook Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * core: do not rely on module cache for world config. instead, use a global and a symbol. this makes sure that streamers can use in-memory event emitters and that it won't be compiled away into the different flow.js and step.js files. this was figured out when i was adding a hooks tests to world-testing. Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * add postgres world to all workbench packages we try to run them with the postgres world but it's not installed Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * Replace jsonb with cbor because zero byte does not work in jsonb :( Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * fix error handling: attempts start at 0 now, and not 1 like when we released. so initial attempt in postgres should reflect that. Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * drain stuff Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * fallback metadata to metadataJson Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * Make code more readable Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> * apply Vade fix Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> --------- Signed-off-by: Gal Schlezinger <gal@spitfire.co.il> |
||
|
|
945a946812 |
Normalize Workbenches (#283)
* Normalize Workbenches Normalize trigger scripts across workbenches fix: include hono in local build test test: include src dir for test test: add workflow dir config in test to fix sveltekit dev tests add temp 7_full in example wokrflow format fix(sveltekit): detecting workflow folders and customizable dir Remove 7_full and 1_simple error replace API symlink in webpack workbench Fix sveltekit and vite tests Fix sveltekit symlinks Test fixes Fix sveltekit workflows path Dont symlink routes in vite Include e2e tests for hono and vite fix error tests post normalization wip - attempted fixes * Add claude demo command * fix: normalize workbench tests (#292) * Proper stacktrace propogation in world Proper stacktrace propogation in world * Standardize the error type in the world spec * Normalize Workbenches Normalize trigger scripts across workbenches fix: include hono in local build test test: include src dir for test test: add workflow dir config in test to fix sveltekit dev tests add temp 7_full in example wokrflow format fix(sveltekit): detecting workflow folders and customizable dir Remove 7_full and 1_simple error replace API symlink in webpack workbench Fix sveltekit and vite tests Fix sveltekit symlinks Test fixes Fix sveltekit workflows path Dont symlink routes in vite Include e2e tests for hono and vite * fix error tests post normalization * fix(sveltekit): reading file on hmr delete * changeset * fix(vite): add resolve symlink script * fix(vite): missing building on hmr * test local builder in vite * test: increase timeout on hookWorkflow * test: ignore vite based apps in crossFileWorkflow * test: fix nitro based apps status codes * fix: intercept default vite spa handler on 404 workflow routes * fix: vite hook route returning 422 * test: use 422 for hookWorkflow expected * test: fix hono returning 404 * chore: add comment to middleware to clarify * make api route for duplicate case * revert * revert: nitro builder * add back nitro unhandled rejection logic * test: add hono * changeset * fix: unused method * fix: remove duplicate import * remove * chore: add comments to clarify * test remove vite symlink script --------- Co-authored-by: Pranay Prakash <pranay.gp@gmail.com> * refactor: add top level resolve symlinks script * fix: cleanup builder directories (#319) * fix: add sveltekit server routes to builder * fix: remove root workflow dir check * fix missing root level workflow route * Fix: The constructor now hardcodes `dirs: ['src/routes', 'src/lib']` which silently ignores any user\-provided `dirs` option passed to the plugin\, breaking the documented API and removing support for custom workflow directories\. * Fix: The test expectations don\'t match the new implementation of `getWorkflowDirs()`\. The mock provides `scanDirs` which the new code no longer uses\, and the new implementation adds scanning of `routesDir` and `apiDir` instead\. * fix(nitro): use src dir --------- Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> * refactor(nitro): use suppressUndefinedRejections * revert: sveltekit builder --------- Co-authored-by: Adrian <me@adriandlam.com> Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
6ec95c37b3 |
Actually use webpack (#284)
After bumping to next 16, we forgot to set --webpack in next dev and build |
||
|
|
98c36f1eb0 |
feat: add hmr and fix dev tests (#199)
* add hmr and dev tests for nitro and sveltekit * changeset * revert: e2e testing code * add streams.ts to workbench apps * fix: test confnigs * fix: hmr failing on new files for sveltekit plugin * lockfile * switch testing to use 3_stream.ts * fix: sveltekit hmr test file import * fix: nextjs testing file * remove stuff * changeset * refactor(tests): expose config through matrix config * fix: add symlink for nextjs turbopack * add resolve symlinks script * fix: nextjs-webpack resolve symlinks script |
||
|
|
f973954bd3 |
Switching from MIT to Apache + DCO (#191)
* Switching from MIT to Apache + DCO * Add DCO github app |
||
|
|
5e3ba7bad0 | Bump Next.js workbench apps to v16 (#126) | ||
|
|
6a44f40d3c |
chore: fix clean scripts (#61)
* chore: fix clean scripts * vade fix |
||
|
|
4ca9a3edbd |
Introducing Workflow DevKit
build durable, resilient, and observable workflows. Co-authored-by: Nathan Rajlich <n@n8.io> Co-authored-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Adrian <me@adriandlam.com> Co-authored-by: JJ Kasper <jj@jjsweb.site> Co-authored-by: Vercel Release Bot <88769842+vercel-release-bot@users.noreply.github.com> Co-authored-by: Peter Wielander <mittgfu@gmail.com> Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com> Co-authored-by: Gal Schlezinger <gal@spitfire.co.il> Co-authored-by: Manuel Muñoz Solera <mamuso@mamuso.net> Co-authored-by: Garrett <garrett.tolbert@vercel.com> Co-authored-by: Lars Grammel <lars.grammel@gmail.com> Co-authored-by: Pooya Parsa <pyapar@gmail.com> Co-authored-by: Tom Dale <tom@tomdale.net> Co-authored-by: Vishal Yathish <135551666+visyat@users.noreply.github.com> Co-authored-by: josh <144584931+dancer@users.noreply.github.com> |