Skip to content

fix(ai): preserve provider tool identity across step boundaries#1663

Merged
gr2m merged 2 commits intomainfrom
fix/provider-tool-identity
Apr 9, 2026
Merged

fix(ai): preserve provider tool identity across step boundaries#1663
gr2m merged 2 commits intomainfrom
fix/provider-tool-identity

Conversation

@gr2m
Copy link
Copy Markdown
Contributor

@gr2m gr2m commented Apr 8, 2026

Summary

  • Port of fix(workflow): preserve provider tool identity across step boundaries ai#14229 to the workflow SDK
  • toolsToModelTools was converting all tools into LanguageModelV3FunctionTool objects with type: 'function', stripping type: 'provider', id, and args from provider tools (e.g. anthropic.tools.webSearch, webFetch, codeExecution)
  • This caused the Anthropic Gateway to not recognize them as provider-executed tools, leading to errors like GatewayInternalServerError: Unexpected value(s) for the anthropic-beta header
  • The fix checks tool.type === 'provider' and returns a LanguageModelV3ProviderTool preserving identity, while regular function tools continue to be serialized as before
  • Adds provider-tool-call mock response type for testing provider-executed tool behavior end-to-end

Related issues & PRs

Changes

File What changed
packages/ai/src/agent/tools-to-model-tools.ts Check for type: 'provider' and return LanguageModelV3ProviderTool preserving id, name, args
packages/ai/src/agent/tools-to-model-tools.test.ts New: 4 unit tests (function tools, provider tools, mixed, missing args default)
packages/ai/src/providers/mock.ts Add provider-tool-call variant to MockResponseDescriptor (emits tool-call with providerExecuted: true + tool-result)
workbench/example/workflows/100_durable_agent_e2e.ts New: agentProviderToolE2e and agentMixedToolsE2e workflow functions
packages/core/e2e/e2e-agent.test.ts New: provider tools describe block with 2 E2E tests

Test plan

  • Unit tests pass (pnpm --filter @workflow/ai test — 173 tests, 10 files)
  • @workflow/ai builds cleanly (pnpm --filter @workflow/ai build)
  • Example workbench builds with new workflows (cd workbench/example && pnpm build)
  • New workflows appear in manifest
  • E2E: agentProviderToolE2e — provider tool identity preserved across step boundaries
  • E2E: agentMixedToolsE2e — mixed provider + function tools in same agent

Port of vercel/ai#14229. Provider tools (e.g. anthropic.tools.webSearch)
were converted to plain function tools in toolsToModelTools, stripping
type, id, and args fields. This caused providers like Anthropic Gateway
to not recognize them as provider-executed tools.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gr2m gr2m requested a review from a team as a code owner April 8, 2026 23:11
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

🦋 Changeset detected

Latest commit: 9bc8db3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@workflow/ai Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Apr 9, 2026 1:02am
example-nextjs-workflow-webpack Ready Ready Preview, Comment Apr 9, 2026 1:02am
example-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-astro-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-express-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-fastify-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-hono-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-nitro-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-nuxt-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-sveltekit-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workbench-vite-workflow Ready Ready Preview, Comment Apr 9, 2026 1:02am
workflow-swc-playground Ready Ready Preview, Comment Apr 9, 2026 1:02am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
workflow-docs Skipped Skipped Apr 9, 2026 1:02am

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 912 0 67 979
✅ 💻 Local Development 886 0 182 1068
✅ 📦 Local Production 886 0 182 1068
✅ 🐘 Local Postgres 886 0 182 1068
✅ 🪟 Windows 81 0 8 89
❌ 🌍 Community Worlds 137 64 24 225
✅ 📋 Other 225 0 42 267
Total 4013 64 687 4764

❌ Failed Tests

🌍 Community Worlds (64 failed)

mongodb (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNSGFHPFFMAA8H38BRH1037T
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNSGQY3GWBTG8ND3HPHKX47R
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNSGYACXRNBD7XDK8V1YH39S

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNSGFHPFFMAA8H38BRH1037T
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNSGQY3GWBTG8ND3HPHKX47R
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNSGYACXRNBD7XDK8V1YH39S

turso (58 failed):

  • addTenWorkflow | wrun_01KNSGEARX3SK20464GQYH34C6
  • addTenWorkflow | wrun_01KNSGEARX3SK20464GQYH34C6
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQW70VW9T3KB6GB889Q01SH
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNSGEHD68J2A9DT5VFCDVH0T
  • promiseRaceWorkflow | wrun_01KNSGEQ4SNX484AJ030YB3PF6
  • promiseAnyWorkflow | wrun_01KNSGES8WXH81XXJ4F8VER4WZ
  • importedStepOnlyWorkflow | wrun_01KNQW7BP2BT3QB90Y6S6K06H4
  • hookWorkflow | wrun_01KNSGF5XF3TZEJG4NZV6XRKYD
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNSGFHPFFMAA8H38BRH1037T
  • webhookWorkflow | wrun_01KNSGFW96WVWTWERDY50KKWGS
  • sleepingWorkflow | wrun_01KNSGG332P8D3KHFW2787BTBT
  • parallelSleepWorkflow | wrun_01KNSGGFXEN2FFDCAHVFDB65WY
  • nullByteWorkflow | wrun_01KNSGGMC9Y92175VM97PHX9GS
  • workflowAndStepMetadataWorkflow | wrun_01KNSGGPRX2QY5D0PW07WM63FH
  • fetchWorkflow | wrun_01KNSGKJTBACJ4Z75A5JD4KMKY
  • promiseRaceStressTestWorkflow | wrun_01KNSGKP9MCDDXR15SC2YD85JT
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • error handling not registered WorkflowNotRegisteredError fails the run when workflow does not exist
  • error handling not registered StepNotRegisteredError fails the step but workflow can catch it
  • error handling not registered StepNotRegisteredError fails the run when not caught in workflow
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNSGQ8ZQSH649M39EVE8AYS8
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNSGQY3GWBTG8ND3HPHKX47R
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNSGRKVT3RQWZMHCYKY0HZ37
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNSGS8E6NJV1EQXQS7CVPGDW
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNSGSH1R595ZXGKJR5ZWASJX
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNSGSPRYGW1RAN77QA54AKY2
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNSGSS0DM9FDG1MYE08TZB41
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNSGT746R2FDCYN8N48HAJ9S
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNSGTCXVCX0J8QC3KX34E5Q4
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNSGTMPVNXKJG9HZ684CWVTM
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNSGTVBGW24HV66DB3CM9BT0
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNSGV223PVAG0GGJ7D3ZTJJ9
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNSGV9TSRCMCARSG52190SDC
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNSGVGD247K4HE02HPR2EV7Q
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNSGVVMJQS639WC25H1ND3RE
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNSGW3G3W1YXQ14KXH6SYP2K
  • cancelRun - cancelling a running workflow | wrun_01KNSGWA576RNBPCXTRV6HQF01
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNSGWK96Y606FHSFJP6P7NM7
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep | wrun_01KNSGWZ0B4TG2V5CVSWBB5PQR
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNSGXKGZ469J60NVHKTT8S3M
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNSGXZ8CA1YTQ890QJVWWW00
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNSGY5T3M5JWG9SQPR98T6T5
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNSGY860FA9ZSWY45X3FZ3DB
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNSGYACXRNBD7XDK8V1YH39S
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNSGYDW8RFVMFT59A3XDR00C

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 82 0 7
✅ example 82 0 7
✅ express 82 0 7
✅ fastify 82 0 7
✅ hono 82 0 7
✅ nextjs-turbopack 87 0 2
✅ nextjs-webpack 87 0 2
✅ nitro 82 0 7
✅ nuxt 82 0 7
✅ sveltekit 82 0 7
✅ vite 82 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 75 0 14
✅ express-stable 75 0 14
✅ fastify-stable 75 0 14
✅ hono-stable 75 0 14
✅ nextjs-turbopack-canary 62 0 27
✅ nextjs-turbopack-stable 81 0 8
✅ nextjs-webpack-canary 62 0 27
✅ nextjs-webpack-stable 81 0 8
✅ nitro-stable 75 0 14
✅ nuxt-stable 75 0 14
✅ sveltekit-stable 75 0 14
✅ vite-stable 75 0 14
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 75 0 14
✅ express-stable 75 0 14
✅ fastify-stable 75 0 14
✅ hono-stable 75 0 14
✅ nextjs-turbopack-canary 62 0 27
✅ nextjs-turbopack-stable 81 0 8
✅ nextjs-webpack-canary 62 0 27
✅ nextjs-webpack-stable 81 0 8
✅ nitro-stable 75 0 14
✅ nuxt-stable 75 0 14
✅ sveltekit-stable 75 0 14
✅ vite-stable 75 0 14
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 75 0 14
✅ express-stable 75 0 14
✅ fastify-stable 75 0 14
✅ hono-stable 75 0 14
✅ nextjs-turbopack-canary 62 0 27
✅ nextjs-turbopack-stable 81 0 8
✅ nextjs-webpack-canary 62 0 27
✅ nextjs-webpack-stable 81 0 8
✅ nitro-stable 75 0 14
✅ nuxt-stable 75 0 14
✅ sveltekit-stable 75 0 14
✅ vite-stable 75 0 14
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 81 0 8
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 5 0 0
❌ mongodb 59 3 8
✅ redis-dev 5 0 0
❌ redis 59 3 8
✅ turso-dev 5 0 0
❌ turso 4 58 8
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 75 0 14
✅ e2e-local-postgres-nest-stable 75 0 14
✅ e2e-local-prod-nest-stable 75 0 14

📋 View full workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 0.042s (-3.7%) 1.006s (~) 0.964s 10 1.00x
🐘 Postgres Express 0.043s (-26.3% 🟢) 1.009s (~) 0.966s 10 1.03x
💻 Local Nitro 0.043s (~) 1.005s (~) 0.962s 10 1.04x
🌐 Redis Next.js (Turbopack) 0.046s 1.005s 0.959s 10 1.10x
💻 Local Next.js (Turbopack) 0.050s 1.005s 0.955s 10 1.18x
🐘 Postgres Nitro 0.054s (-13.7% 🟢) 1.009s (~) 0.955s 10 1.30x
🐘 Postgres Next.js (Turbopack) 0.058s 1.010s 0.952s 10 1.37x
🌐 MongoDB Next.js (Turbopack) 0.095s 1.007s 0.912s 10 2.27x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 0.256s (+22.5% 🔺) 2.425s (+11.6% 🔺) 2.168s 10 1.00x
▲ Vercel Nitro 0.306s (+31.4% 🔺) 2.018s (-3.5%) 1.711s 10 1.20x
▲ Vercel Next.js (Turbopack) 0.417s (+81.3% 🔺) 2.150s (-5.1% 🟢) 1.733s 10 1.63x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 1.106s 2.006s 0.901s 10 1.00x
🐘 Postgres Express 1.112s (-2.8%) 2.008s (~) 0.896s 10 1.01x
💻 Local Next.js (Turbopack) 1.123s 2.006s 0.883s 10 1.02x
💻 Local Express 1.127s (~) 2.007s (~) 0.880s 10 1.02x
💻 Local Nitro 1.129s (~) 2.006s (~) 0.877s 10 1.02x
🐘 Postgres Next.js (Turbopack) 1.136s 2.009s 0.874s 10 1.03x
🐘 Postgres Nitro 1.138s (-0.6%) 2.010s (~) 0.873s 10 1.03x
🌐 MongoDB Next.js (Turbopack) 1.317s 2.009s 0.692s 10 1.19x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.878s (+1.7%) 3.541s (-3.2%) 1.663s 10 1.00x
▲ Vercel Next.js (Turbopack) 1.956s (-5.1% 🟢) 3.678s (-3.7%) 1.723s 10 1.04x
▲ Vercel Nitro 2.040s (+7.1% 🔺) 3.600s (-4.8%) 1.560s 10 1.09x

🔍 Observability: Express | Next.js (Turbopack) | Nitro

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 10.590s 11.023s 0.433s 3 1.00x
🐘 Postgres Express 10.690s (-2.0%) 11.019s (~) 0.329s 3 1.01x
💻 Local Next.js (Turbopack) 10.795s 11.024s 0.229s 3 1.02x
💻 Local Express 10.912s (~) 11.024s (~) 0.112s 3 1.03x
💻 Local Nitro 10.923s (~) 11.023s (~) 0.100s 3 1.03x
🐘 Postgres Next.js (Turbopack) 10.944s 11.019s 0.075s 3 1.03x
🐘 Postgres Nitro 10.947s (~) 11.023s (~) 0.075s 3 1.03x
🌐 MongoDB Next.js (Turbopack) 12.278s 13.024s 0.746s 3 1.16x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 16.907s (-1.2%) 18.602s (-5.8% 🟢) 1.694s 2 1.00x
▲ Vercel Next.js (Turbopack) 17.256s (~) 19.035s (-2.0%) 1.779s 2 1.02x
▲ Vercel Express 17.674s (-7.1% 🟢) 18.832s (-10.2% 🟢) 1.158s 2 1.05x

🔍 Observability: Nitro | Next.js (Turbopack) | Express

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 13.911s 14.028s 0.117s 5 1.00x
🐘 Postgres Express 14.006s (-3.7%) 14.219s (-5.3% 🟢) 0.213s 5 1.01x
🐘 Postgres Next.js (Turbopack) 14.486s 15.023s 0.536s 4 1.04x
🐘 Postgres Nitro 14.524s (-0.6%) 15.017s (~) 0.493s 4 1.04x
💻 Local Next.js (Turbopack) 14.801s 15.030s 0.229s 4 1.06x
💻 Local Express 14.973s (~) 15.280s (+1.7%) 0.306s 4 1.08x
💻 Local Nitro 14.992s (~) 15.280s (+1.7%) 0.287s 4 1.08x
🌐 MongoDB Next.js (Turbopack) 17.859s 18.028s 0.169s 4 1.28x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 30.966s (-6.1% 🟢) 32.187s (-7.8% 🟢) 1.221s 2 1.00x
▲ Vercel Next.js (Turbopack) 31.012s (-8.4% 🟢) 32.629s (-9.0% 🟢) 1.616s 2 1.00x
▲ Vercel Express 31.672s (-1.2%) 33.365s (~) 1.693s 2 1.02x

🔍 Observability: Nitro | Next.js (Turbopack) | Express

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 12.779s 13.169s 0.390s 7 1.00x
🐘 Postgres Express 12.912s (-8.8% 🟢) 13.161s (-12.4% 🟢) 0.249s 7 1.01x
🐘 Postgres Next.js (Turbopack) 13.837s 14.166s 0.330s 7 1.08x
🐘 Postgres Nitro 14.039s (-0.7%) 14.597s (-1.0%) 0.558s 7 1.10x
💻 Local Next.js (Turbopack) 15.866s 16.029s 0.163s 6 1.24x
💻 Local Express 16.746s (+2.3%) 17.031s (~) 0.285s 6 1.31x
💻 Local Nitro 16.789s (+1.4%) 17.031s (~) 0.241s 6 1.31x
🌐 MongoDB Next.js (Turbopack) 20.344s 21.027s 0.683s 5 1.59x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 47.932s (-76.8% 🟢) 49.164s (-76.4% 🟢) 1.232s 2 1.00x
▲ Vercel Next.js (Turbopack) 51.169s (-15.6% 🟢) 52.170s (-16.6% 🟢) 1.001s 2 1.07x
▲ Vercel Nitro 53.916s (-73.9% 🟢) 55.513s (-73.4% 🟢) 1.596s 2 1.12x

🔍 Observability: Express | Next.js (Turbopack) | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.201s (-4.7%) 2.010s (~) 0.809s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.223s 2.009s 0.787s 15 1.02x
🌐 Redis Next.js (Turbopack) 1.248s 2.006s 0.758s 15 1.04x
🐘 Postgres Nitro 1.266s (-1.9%) 2.009s (~) 0.743s 15 1.05x
💻 Local Next.js (Turbopack) 1.471s 2.006s 0.534s 15 1.23x
💻 Local Express 1.498s (~) 2.006s (~) 0.508s 15 1.25x
💻 Local Nitro 1.925s (+25.2% 🔺) 2.391s (+19.2% 🔺) 0.466s 13 1.60x
🌐 MongoDB Next.js (Turbopack) 2.265s 3.108s 0.843s 10 1.89x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.297s (-11.9% 🟢) 3.580s (-17.2% 🟢) 1.284s 9 1.00x
▲ Vercel Express 2.388s (-13.1% 🟢) 3.699s (-17.0% 🟢) 1.311s 9 1.04x
▲ Vercel Next.js (Turbopack) 2.447s (~) 4.007s (-11.6% 🟢) 1.559s 8 1.07x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.286s (-3.9%) 3.009s (~) 0.723s 10 1.00x
🐘 Postgres Nitro 2.354s (~) 3.009s (~) 0.654s 10 1.03x
🌐 Redis Next.js (Turbopack) 2.394s 3.008s 0.614s 10 1.05x
🐘 Postgres Next.js (Turbopack) 2.403s 3.008s 0.605s 10 1.05x
💻 Local Next.js (Turbopack) 2.778s 3.108s 0.330s 10 1.21x
💻 Local Express 2.974s (+5.2% 🔺) 3.564s (+14.6% 🔺) 0.590s 9 1.30x
💻 Local Nitro 3.024s (+3.3%) 3.760s (+21.0% 🔺) 0.736s 8 1.32x
🌐 MongoDB Next.js (Turbopack) 9.639s 10.015s 0.376s 3 4.22x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.637s (-7.2% 🟢) 4.090s (-14.6% 🟢) 1.453s 8 1.00x
▲ Vercel Express 2.736s (-10.5% 🟢) 4.057s (-13.2% 🟢) 1.321s 9 1.04x
▲ Vercel Nitro 2.825s (-17.7% 🟢) 4.342s (-13.8% 🟢) 1.517s 7 1.07x

🔍 Observability: Next.js (Turbopack) | Express | Nitro

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.368s (-3.1%) 4.011s (~) 0.643s 8 1.00x
🐘 Postgres Nitro 3.456s (~) 4.013s (~) 0.557s 8 1.03x
🐘 Postgres Next.js (Turbopack) 3.653s 4.009s 0.356s 8 1.08x
🌐 Redis Next.js (Turbopack) 3.929s 4.295s 0.366s 7 1.17x
💻 Local Next.js (Turbopack) 7.156s 7.766s 0.610s 4 2.13x
💻 Local Nitro 8.258s (+0.9%) 9.023s (~) 0.765s 4 2.45x
💻 Local Express 8.354s (+9.7% 🔺) 9.022s (+9.1% 🔺) 0.668s 4 2.48x
🌐 MongoDB Next.js (Turbopack) 20.324s 20.521s 0.197s 2 6.04x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.764s (-15.7% 🟢) 4.584s (-6.8% 🟢) 1.819s 7 1.00x
▲ Vercel Express 2.794s (-8.8% 🟢) 4.453s (-7.3% 🟢) 1.659s 7 1.01x
▲ Vercel Next.js (Turbopack) 3.647s (-10.3% 🟢) 5.366s (-14.5% 🟢) 1.719s 6 1.32x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.193s (-5.7% 🟢) 2.008s (~) 0.815s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.229s 2.009s 0.779s 15 1.03x
🐘 Postgres Nitro 1.255s (~) 2.008s (~) 0.753s 15 1.05x
🌐 Redis Next.js (Turbopack) 1.262s 2.006s 0.744s 15 1.06x
💻 Local Next.js (Turbopack) 1.479s 2.006s 0.527s 15 1.24x
💻 Local Nitro 1.550s (+1.2%) 2.006s (~) 0.456s 15 1.30x
💻 Local Express 1.562s (+3.7%) 2.006s (~) 0.445s 15 1.31x
🌐 MongoDB Next.js (Turbopack) 3.029s 3.758s 0.729s 8 2.54x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.040s (-12.9% 🟢) 3.115s (-25.4% 🟢) 1.075s 10 1.00x
▲ Vercel Nitro 2.044s (-10.9% 🟢) 3.397s (-14.1% 🟢) 1.353s 9 1.00x
▲ Vercel Express 2.170s (-4.8%) 3.806s (-4.0%) 1.636s 9 1.06x

🔍 Observability: Next.js (Turbopack) | Nitro | Express

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.243s (-4.6%) 3.009s (~) 0.766s 10 1.00x
🐘 Postgres Nitro 2.353s (-0.9%) 3.009s (~) 0.657s 10 1.05x
🐘 Postgres Next.js (Turbopack) 2.368s 3.007s 0.639s 10 1.06x
🌐 Redis Next.js (Turbopack) 2.386s 3.008s 0.622s 10 1.06x
💻 Local Next.js (Turbopack) 3.022s 3.760s 0.737s 8 1.35x
💻 Local Express 3.160s (+10.5% 🔺) 4.010s (+33.3% 🔺) 0.850s 8 1.41x
💻 Local Nitro 3.245s (+4.7%) 4.013s (+3.3%) 0.768s 8 1.45x
🌐 MongoDB Next.js (Turbopack) 9.059s 9.763s 0.704s 4 4.04x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.152s (-99.3% 🟢) 3.635s (-98.8% 🟢) 1.483s 9 1.00x
▲ Vercel Express 2.374s (-97.0% 🟢) 3.577s (-95.6% 🟢) 1.203s 9 1.10x
▲ Vercel Next.js (Turbopack) 2.831s (~) 3.983s (-16.1% 🟢) 1.152s 8 1.32x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.392s (-2.4%) 4.011s (~) 0.618s 8 1.00x
🐘 Postgres Nitro 3.470s (~) 4.011s (~) 0.542s 8 1.02x
🐘 Postgres Next.js (Turbopack) 3.638s 4.010s 0.372s 8 1.07x
🌐 Redis Next.js (Turbopack) 3.996s 4.440s 0.443s 7 1.18x
💻 Local Next.js (Turbopack) 8.087s 8.773s 0.686s 4 2.38x
💻 Local Nitro 8.774s (-2.1%) 9.023s (-2.7%) 0.249s 4 2.59x
💻 Local Express 8.909s (+11.1% 🔺) 9.273s (+5.7% 🔺) 0.364s 4 2.63x
🌐 MongoDB Next.js (Turbopack) 19.413s 20.019s 0.606s 2 5.72x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.888s (-35.2% 🟢) 4.274s (-28.9% 🟢) 1.387s 8 1.00x
▲ Vercel Nitro 3.001s (~) 4.347s (-7.2% 🟢) 1.347s 7 1.04x
▲ Vercel Next.js (Turbopack) 3.638s (+1.3%) 5.217s (-2.2%) 1.579s 6 1.26x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 0.559s 1.004s 0.446s 60 1.00x
🐘 Postgres Express 0.593s (-30.5% 🟢) 1.006s (~) 0.413s 60 1.06x
🐘 Postgres Next.js (Turbopack) 0.765s 1.006s 0.241s 60 1.37x
🐘 Postgres Nitro 0.833s (+1.1%) 1.006s (~) 0.172s 60 1.49x
💻 Local Next.js (Turbopack) 0.840s 1.021s 0.181s 59 1.50x
💻 Local Express 0.984s (-3.6%) 1.076s (-30.3% 🟢) 0.091s 56 1.76x
💻 Local Nitro 1.001s (+1.7%) 1.303s (+10.3% 🔺) 0.301s 47 1.79x
🌐 MongoDB Next.js (Turbopack) 2.122s 3.007s 0.885s 20 3.80x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 8.561s (-16.9% 🟢) 10.244s (-14.8% 🟢) 1.683s 6 1.00x
▲ Vercel Nitro 8.938s (-1.8%) 10.767s (-3.7%) 1.829s 6 1.04x
▲ Vercel Next.js (Turbopack) 9.169s (-11.3% 🟢) 11.004s (-11.7% 🟢) 1.834s 6 1.07x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 1.310s 2.006s 0.696s 45 1.00x
🐘 Postgres Express 1.431s (-30.4% 🟢) 2.007s (-30.4% 🟢) 0.576s 45 1.09x
🐘 Postgres Next.js (Turbopack) 1.882s 2.075s 0.193s 44 1.44x
🐘 Postgres Nitro 2.006s (+1.7%) 2.376s (+6.7% 🔺) 0.370s 38 1.53x
💻 Local Next.js (Turbopack) 2.607s 3.008s 0.401s 30 1.99x
💻 Local Nitro 3.022s (+0.6%) 3.689s (+4.0%) 0.667s 25 2.31x
💻 Local Express 3.049s (~) 3.800s (+4.2%) 0.752s 24 2.33x
🌐 MongoDB Next.js (Turbopack) 5.228s 6.012s 0.784s 15 3.99x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 26.962s (-6.8% 🟢) 28.229s (-8.0% 🟢) 1.267s 4 1.00x
▲ Vercel Express 27.015s (-3.8%) 28.217s (-6.2% 🟢) 1.202s 4 1.00x
▲ Vercel Next.js (Turbopack) 30.133s (-2.2%) 31.303s (-4.8%) 1.170s 3 1.12x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 2.648s 3.007s 0.359s 40 1.00x
🐘 Postgres Express 2.988s (-26.6% 🟢) 3.369s (-30.0% 🟢) 0.381s 36 1.13x
🐘 Postgres Next.js (Turbopack) 3.788s 4.009s 0.221s 30 1.43x
🐘 Postgres Nitro 4.078s (-1.5%) 4.625s (-5.4% 🟢) 0.547s 26 1.54x
💻 Local Next.js (Turbopack) 8.332s 9.018s 0.686s 14 3.15x
💻 Local Nitro 9.206s (~) 9.864s (-0.8%) 0.659s 13 3.48x
💻 Local Express 9.284s (+3.8%) 10.019s (+6.6% 🔺) 0.735s 12 3.51x
🌐 MongoDB Next.js (Turbopack) 10.363s 11.018s 0.654s 11 3.91x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 70.807s (-6.6% 🟢) 72.025s (-7.3% 🟢) 1.218s 2 1.00x
▲ Vercel Nitro 73.198s (~) 74.383s (-0.6%) 1.186s 2 1.03x
▲ Vercel Next.js (Turbopack) 76.448s (-8.4% 🟢) 78.866s (-7.7% 🟢) 2.417s 2 1.08x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.218s (-22.1% 🟢) 1.007s (~) 0.789s 60 1.00x
🌐 Redis Next.js (Turbopack) 0.230s 1.004s 0.774s 60 1.06x
🐘 Postgres Next.js (Turbopack) 0.239s 1.007s 0.768s 60 1.10x
🐘 Postgres Nitro 0.274s (-4.4%) 1.007s (~) 0.732s 60 1.26x
💻 Local Next.js (Turbopack) 0.527s 1.004s 0.477s 60 2.42x
💻 Local Express 0.581s (-1.6%) 1.005s (~) 0.424s 60 2.67x
💻 Local Nitro 0.591s (~) 1.004s (~) 0.413s 60 2.72x
🌐 MongoDB Next.js (Turbopack) 3.248s 3.884s 0.636s 16 14.93x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.458s (-23.6% 🟢) 2.760s (-22.4% 🟢) 1.302s 22 1.00x
▲ Vercel Nitro 1.459s (-18.8% 🟢) 2.641s (-25.9% 🟢) 1.182s 23 1.00x
▲ Vercel Next.js (Turbopack) 1.576s (-5.2% 🟢) 3.007s (-7.1% 🟢) 1.431s 20 1.08x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.355s (-28.2% 🟢) 1.006s (~) 0.651s 90 1.00x
🐘 Postgres Next.js (Turbopack) 0.482s 1.006s 0.525s 90 1.36x
🐘 Postgres Nitro 0.490s (-2.6%) 1.007s (~) 0.517s 90 1.38x
🌐 Redis Next.js (Turbopack) 1.032s 1.641s 0.609s 55 2.91x
💻 Local Next.js (Turbopack) 2.442s 3.009s 0.567s 30 6.88x
💻 Local Nitro 2.530s (-1.2%) 3.009s (~) 0.479s 30 7.13x
💻 Local Express 2.546s (+4.1%) 3.010s (~) 0.464s 30 7.17x
🌐 MongoDB Next.js (Turbopack) 9.307s 9.914s 0.607s 10 26.22x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.619s (~) 4.232s (-2.7%) 1.613s 22 1.00x
▲ Vercel Nitro 2.644s (+6.7% 🔺) 4.341s (+4.0%) 1.697s 22 1.01x
▲ Vercel Next.js (Turbopack) 3.238s (-8.8% 🟢) 4.394s (-14.6% 🟢) 1.156s 21 1.24x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.558s (-29.3% 🟢) 1.007s (~) 0.448s 120 1.00x
🐘 Postgres Next.js (Turbopack) 0.744s 1.006s 0.262s 120 1.33x
🐘 Postgres Nitro 0.782s (-9.4% 🟢) 1.007s (-5.3% 🟢) 0.226s 120 1.40x
🌐 Redis Next.js (Turbopack) 2.610s 3.007s 0.396s 40 4.67x
💻 Local Next.js (Turbopack) 10.094s 10.693s 0.599s 12 18.07x
💻 Local Nitro 11.192s (+1.2%) 11.849s (+1.6%) 0.657s 11 20.04x
💻 Local Express 11.283s (+7.0% 🔺) 11.939s (+8.2% 🔺) 0.655s 11 20.20x
🌐 MongoDB Next.js (Turbopack) 19.894s 20.357s 0.463s 6 35.62x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 6.462s (+3.3%) 7.890s (~) 1.428s 16 1.00x
▲ Vercel Express 6.699s (-5.6% 🟢) 8.361s (-5.3% 🟢) 1.663s 15 1.04x
▲ Vercel Nitro 6.706s (-2.6%) 8.242s (-4.1%) 1.536s 16 1.04x

🔍 Observability: Next.js (Turbopack) | Express | Nitro

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 0.150s 1.001s 0.001s 1.007s 0.857s 10 1.00x
🐘 Postgres Express 0.151s (-26.7% 🟢) 0.999s (~) 0.001s (-15.4% 🟢) 1.008s (~) 0.857s 10 1.00x
💻 Local Next.js (Turbopack) 0.173s 1.003s 0.010s 1.016s 0.843s 10 1.15x
🐘 Postgres Next.js (Turbopack) 0.187s 1.001s 0.002s 1.011s 0.824s 10 1.24x
💻 Local Express 0.205s (+1.0%) 1.004s (~) 0.012s (+24.0% 🔺) 1.018s (~) 0.813s 10 1.36x
🐘 Postgres Nitro 0.205s (+1.5%) 0.994s (~) 0.001s (+7.7% 🔺) 1.009s (~) 0.804s 10 1.37x
💻 Local Nitro 0.212s (+4.3%) 1.004s (~) 0.011s (-5.7% 🟢) 1.018s (~) 0.805s 10 1.41x
🌐 MongoDB Next.js (Turbopack) 0.520s 0.933s 0.002s 1.009s 0.489s 10 3.45x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.309s (-24.5% 🟢) 2.388s (-26.6% 🟢) 0.642s (+85.6% 🔺) 3.354s (-16.7% 🟢) 2.045s 10 1.00x
▲ Vercel Nitro 1.520s (-36.2% 🟢) 2.792s (-26.5% 🟢) 0.539s (+45.9% 🔺) 3.667s (-21.1% 🟢) 2.148s 10 1.16x
▲ Vercel Next.js (Turbopack) 1.578s (-1.7%) 2.718s (-13.7% 🟢) 0.604s (+92.7% 🔺) 3.680s (-7.0% 🟢) 2.102s 10 1.21x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 0.397s 1.002s 0.003s 1.011s 0.614s 60 1.00x
🐘 Postgres Express 0.507s (-18.9% 🟢) 1.007s (~) 0.003s (-21.0% 🟢) 1.020s (~) 0.513s 59 1.27x
🐘 Postgres Next.js (Turbopack) 0.610s 1.009s 0.006s 1.024s 0.415s 59 1.53x
🐘 Postgres Nitro 0.624s (~) 1.004s (~) 0.004s (-4.1%) 1.022s (~) 0.398s 59 1.57x
💻 Local Next.js (Turbopack) 0.663s 1.011s 0.009s 1.023s 0.359s 59 1.67x
💻 Local Nitro 0.723s (-1.0%) 1.013s (~) 0.010s (+1.6%) 1.024s (~) 0.301s 59 1.82x
💻 Local Express 0.727s (-5.6% 🟢) 1.011s (~) 0.009s (~) 1.023s (~) 0.296s 59 1.83x
🌐 MongoDB Next.js (Turbopack) 1.316s 1.958s 0.003s 2.013s 0.696s 30 3.31x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.913s (+3.4%) 5.499s (+4.1%) 0.234s (-39.1% 🟢) 6.059s (~) 2.146s 10 1.00x
▲ Vercel Express 3.938s 5.138s 0.446s 5.942s 2.004s 11 1.01x
▲ Vercel Next.js (Turbopack) 6.408s (+51.1% 🔺) 8.159s (+41.0% 🔺) 0.487s (+25.8% 🔺) 9.021s (+36.0% 🔺) 2.613s 7 1.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 0.883s 1.017s 0.000s 1.021s 0.138s 59 1.00x
🐘 Postgres Express 0.906s (-6.6% 🟢) 1.052s (-10.2% 🟢) 0.000s (-10.5% 🟢) 1.059s (-11.4% 🟢) 0.153s 57 1.03x
🐘 Postgres Next.js (Turbopack) 0.927s 1.111s 0.000s 1.119s 0.192s 54 1.05x
🐘 Postgres Nitro 0.944s (-1.4%) 1.107s (-3.6%) 0.000s (+28.4% 🔺) 1.119s (-3.7%) 0.175s 54 1.07x
💻 Local Next.js (Turbopack) 1.237s 2.020s 0.000s 2.023s 0.786s 30 1.40x
💻 Local Express 1.242s (+1.2%) 2.023s (~) 0.000s (-7.1% 🟢) 2.025s (~) 0.783s 30 1.41x
💻 Local Nitro 1.249s (~) 2.022s (~) 0.000s (+225.0% 🔺) 2.024s (~) 0.776s 30 1.41x
🌐 MongoDB Next.js (Turbopack) 2.350s 2.957s 0.000s 3.007s 0.657s 20 2.66x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.637s (-91.5% 🟢) 3.631s (-88.7% 🟢) 0.000s (+Infinity% 🔺) 4.095s (-87.5% 🟢) 1.458s 16 1.00x
▲ Vercel Express 2.697s (+3.6%) 3.639s (-1.5%) 0.000s (-87.5% 🟢) 4.050s (-1.8%) 1.352s 15 1.02x
▲ Vercel Next.js (Turbopack) 3.226s (-3.2%) 4.369s (-6.1% 🟢) 0.003s (+869.2% 🔺) 4.794s (-5.9% 🟢) 1.568s 13 1.22x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.630s (-13.2% 🟢) 2.105s (-8.2% 🟢) 0.000s (NaN%) 2.112s (-8.4% 🟢) 0.482s 29 1.00x
🌐 Redis Next.js (Turbopack) 1.660s 2.001s 0.000s 2.006s 0.346s 30 1.02x
🐘 Postgres Nitro 1.767s (-1.1%) 2.176s (+1.7%) 0.000s (+50.0% 🔺) 2.209s (+2.7%) 0.443s 28 1.08x
🐘 Postgres Next.js (Turbopack) 1.843s 2.140s 0.000s 2.148s 0.305s 29 1.13x
💻 Local Next.js (Turbopack) 3.412s 4.034s 0.001s 4.038s 0.626s 15 2.09x
💻 Local Express 3.558s (+4.2%) 4.099s (+1.6%) 0.000s (-25.0% 🟢) 4.102s (+1.6%) 0.544s 15 2.18x
💻 Local Nitro 3.563s (+0.5%) 4.034s (~) 0.001s (+11.1% 🔺) 4.036s (~) 0.474s 15 2.19x
🌐 MongoDB Next.js (Turbopack) 4.372s 4.960s 0.000s 5.009s 0.638s 12 2.68x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.701s (-10.3% 🟢) 5.109s (-4.4%) 0.000s (-100.0% 🟢) 5.459s (-5.9% 🟢) 1.757s 11 1.00x
▲ Vercel Express 4.135s (+9.7% 🔺) 5.265s (+8.0% 🔺) 0.000s (+118.2% 🔺) 5.583s (+4.7%) 1.448s 11 1.12x
▲ Vercel Next.js (Turbopack) 4.255s (+5.9% 🔺) 5.267s (-1.2%) 0.000s (+Infinity% 🔺) 5.613s (-3.9%) 1.358s 11 1.15x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Next.js (Turbopack) 20/21
🐘 Postgres Express 21/21
▲ Vercel Express 9/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 🐘 Postgres 18/21
Next.js (Turbopack) 🌐 Redis 14/21
Nitro 🐘 Postgres 15/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run

Copy link
Copy Markdown
Member

@TooTallNate TooTallNate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Port of vercel/ai#14229. Clean fix with solid test coverage.

What I verified

Core fix (toolsToModelTools): The type === 'provider' check correctly short-circuits before the function tool serialization path. Provider tools get { type: 'provider', id, name, args } — preserving identity. Function tools are unchanged. The return type widens from LanguageModelV3FunctionTool[] to Array<LanguageModelV3FunctionTool | LanguageModelV3ProviderTool>, which is compatible with the downstream doStreamStep parameter type (LanguageModelV3CallOptions['tools'] — already a union).

args default: (tool as any).args ?? {} defaults to empty object when args is undefined. This matches the AI SDK convention where provider tools may omit args (e.g. anthropic.tools.codeExecution). The test covers this case.

Mock model: The provider-tool-call variant correctly emits both tool-call with providerExecuted: true AND tool-result in the same stream — matching how real providers (Anthropic Gateway) return provider-executed tool results.

E2E workflows: agentProviderToolE2e (provider-only) and agentMixedToolsE2e (provider + function) cover the two critical scenarios. Both use as any for the provider tool definition, which is fine since ToolSet doesn't natively type provider tools.

Changeset: patch for @workflow/ai — correct. The changeset description is clear and references the root cause.

One observation (non-blocking)

The (tool as any).type === 'provider' cast works but is opaque. If ai ever exports a ProviderTool type or type guard (e.g. isProviderTool(tool)), consider switching to that for type safety. For now, as any matches the upstream fix pattern.

LGTM.

tools: ToolSet
): Promise<LanguageModelV3FunctionTool[]> {
): Promise<Array<LanguageModelV3FunctionTool | LanguageModelV3ProviderTool>> {
return Promise.all(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: (tool as any).type === 'provider' is the same pattern used in the upstream AI SDK fix (vercel/ai#14229). If ai later exports a type guard or the ToolSet type is widened to include provider tools natively, this could be made type-safe. Fine for now.

…github.com>

I, Gregor Martynus <39992+gr2m@users.noreply.github.com>, hereby add my Signed-off-by to this commit: b1930b3

Signed-off-by: Gregor Martynus <39992+gr2m@users.noreply.github.com>
@workflow-devkit-release-bot
Copy link
Copy Markdown
Contributor

Backported to stable (4d31619 -> 7faedb7).

workflow-devkit-release-bot bot pushed a commit that referenced this pull request Apr 9, 2026
* fix(ai): preserve provider tool identity across step boundaries

Port of vercel/ai#14229. Provider tools (e.g. anthropic.tools.webSearch)
were converted to plain function tools in toolsToModelTools, stripping
type, id, and args fields. This caused providers like Anthropic Gateway
to not recognize them as provider-executed tools.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* DCO Remediation Commit for Gregor Martynus <39992+gr2m@users.noreply.github.com>

I, Gregor Martynus <39992+gr2m@users.noreply.github.com>, hereby add my Signed-off-by to this commit: b1930b3

Signed-off-by: Gregor Martynus <39992+gr2m@users.noreply.github.com>

---------

Signed-off-by: Gregor Martynus <39992+gr2m@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-stable Cherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants