Skip to content

[core] Support negative startIndex for streaming#1460

Merged
VaguelySerious merged 12 commits into
mainfrom
peter/negative-start
Mar 20, 2026
Merged

[core] Support negative startIndex for streaming#1460
VaguelySerious merged 12 commits into
mainfrom
peter/negative-start

Conversation

@VaguelySerious
Copy link
Copy Markdown
Member

Negative startIndex values (e.g. -3) resolve to n chunks before the known end of the stream. All world implementations (local, postgres, vercel) support this. Includes unit tests, e2e test, and doc updates.

c
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 20, 2026

🦋 Changeset detected

Latest commit: 7a2ee25

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

This PR includes changesets to release 20 packages
Name Type
@workflow/world Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/core Patch
@workflow/cli Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/world-testing Patch
@workflow/world-vercel Patch
@workflow/builders Patch
@workflow/next Patch
@workflow/nitro Patch
workflow Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch
@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 Mar 20, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 20, 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.043s (-4.9%) 1.005s (~) 0.962s 10 1.00x
💻 Local Nitro 0.043s (-8.4% 🟢) 1.005s (~) 0.962s 10 1.02x
🐘 Postgres Express 0.048s (-32.2% 🟢) 1.011s (-0.6%) 0.963s 10 1.13x
💻 Local Next.js (Turbopack) 0.050s 1.005s 0.955s 10 1.18x
🌐 Redis Next.js (Turbopack) 0.055s 1.005s 0.949s 10 1.30x
🐘 Postgres Next.js (Turbopack) 0.059s 1.011s 0.953s 10 1.38x
🐘 Postgres Nitro 0.063s (-8.8% 🟢) 1.013s (~) 0.949s 10 1.48x
🌐 MongoDB Next.js (Turbopack) 0.114s 1.008s 0.893s 10 2.68x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 0.464s (-35.6% 🟢) 2.116s (-18.2% 🟢) 1.651s 10 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.114s (-2.2%) 2.012s (~) 0.898s 10 1.00x
💻 Local Next.js (Turbopack) 1.119s 2.005s 0.886s 10 1.00x
🌐 Redis Next.js (Turbopack) 1.125s 2.006s 0.882s 10 1.01x
💻 Local Express 1.126s (~) 2.006s (~) 0.880s 10 1.01x
💻 Local Nitro 1.134s (~) 2.005s (~) 0.871s 10 1.02x
🐘 Postgres Next.js (Turbopack) 1.147s 2.012s 0.865s 10 1.03x
🐘 Postgres Nitro 1.152s (+0.8%) 2.014s (~) 0.862s 10 1.03x
🌐 MongoDB Next.js (Turbopack) 1.310s 2.009s 0.698s 10 1.18x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.083s (-10.3% 🟢) 3.346s (-12.2% 🟢) 1.263s 10 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 10.739s (-1.5%) 11.043s (~) 0.304s 3 1.00x
🌐 Redis Next.js (Turbopack) 10.778s 11.023s 0.245s 3 1.00x
💻 Local Next.js (Turbopack) 10.804s 11.023s 0.219s 3 1.01x
🐘 Postgres Next.js (Turbopack) 10.905s 11.042s 0.137s 3 1.02x
💻 Local Nitro 10.910s (~) 11.023s (~) 0.113s 3 1.02x
💻 Local Express 10.914s (~) 11.023s (~) 0.108s 3 1.02x
🐘 Postgres Nitro 11.001s (~) 11.046s (~) 0.046s 3 1.02x
🌐 MongoDB Next.js (Turbopack) 12.213s 13.016s 0.803s 3 1.14x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 17.063s (-3.9%) 18.514s (-6.5% 🟢) 1.451s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 14.176s (-2.7%) 15.041s (~) 0.865s 4 1.00x
🌐 Redis Next.js (Turbopack) 14.263s 15.030s 0.766s 4 1.01x
🐘 Postgres Next.js (Turbopack) 14.531s 15.044s 0.513s 4 1.03x
💻 Local Next.js (Turbopack) 14.559s 15.030s 0.471s 4 1.03x
🐘 Postgres Nitro 14.800s (~) 15.044s (~) 0.243s 4 1.04x
💻 Local Nitro 14.895s (~) 15.029s (~) 0.133s 4 1.05x
💻 Local Express 14.928s (~) 15.027s (-3.2%) 0.099s 4 1.05x
🌐 MongoDB Next.js (Turbopack) 17.872s 18.026s 0.154s 4 1.26x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 32.853s (+1.2%) 34.473s (-0.6%) 1.620s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 13.190s (-5.9% 🟢) 14.038s (-3.0%) 0.847s 7 1.00x
🌐 Redis Next.js (Turbopack) 13.302s 14.026s 0.723s 7 1.01x
🐘 Postgres Next.js (Turbopack) 14.132s 14.613s 0.481s 7 1.07x
🐘 Postgres Nitro 14.413s (~) 15.041s (~) 0.628s 6 1.09x
💻 Local Next.js (Turbopack) 15.756s 16.029s 0.273s 6 1.19x
💻 Local Express 16.483s (-1.2%) 17.031s (~) 0.548s 6 1.25x
💻 Local Nitro 16.489s (~) 17.029s (~) 0.539s 6 1.25x
🌐 MongoDB Next.js (Turbopack) 20.399s 21.025s 0.625s 5 1.55x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 56.806s (-9.5% 🟢) 57.958s (-10.1% 🟢) 1.153s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.211s (-4.3%) 2.011s (~) 0.800s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.266s 2.013s 0.746s 15 1.05x
🐘 Postgres Nitro 1.281s (-0.9%) 2.011s (~) 0.730s 15 1.06x
🌐 Redis Next.js (Turbopack) 1.300s 2.006s 0.706s 15 1.07x
💻 Local Next.js (Turbopack) 1.489s 2.005s 0.516s 15 1.23x
💻 Local Nitro 1.509s (+1.7%) 2.006s (~) 0.497s 15 1.25x
💻 Local Express 1.520s (+0.9%) 2.006s (~) 0.486s 15 1.25x
🌐 MongoDB Next.js (Turbopack) 2.156s 3.008s 0.852s 10 1.78x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.664s (+6.9% 🔺) 3.854s (-1.2%) 1.189s 8 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.366s (-3.8%) 3.012s (~) 0.646s 10 1.00x
🐘 Postgres Nitro 2.459s (~) 3.013s (~) 0.553s 10 1.04x
🐘 Postgres Next.js (Turbopack) 2.515s 3.012s 0.497s 10 1.06x
🌐 Redis Next.js (Turbopack) 2.523s 3.008s 0.485s 10 1.07x
💻 Local Next.js (Turbopack) 2.655s 3.007s 0.353s 10 1.12x
💻 Local Nitro 2.909s (+1.3%) 3.107s (~) 0.198s 10 1.23x
💻 Local Express 2.929s (-2.3%) 3.308s (-7.2% 🟢) 0.379s 10 1.24x
🌐 MongoDB Next.js (Turbopack) 4.824s 5.345s 0.521s 6 2.04x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.892s (+10.0% 🔺) 4.180s (+3.8%) 1.287s 8 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.522s (-1.9%) 4.014s (~) 0.492s 8 1.00x
🐘 Postgres Nitro 3.609s (-0.6%) 4.014s (~) 0.405s 8 1.02x
🐘 Postgres Next.js (Turbopack) 3.768s 4.014s 0.246s 8 1.07x
🌐 Redis Next.js (Turbopack) 4.125s 5.012s 0.887s 6 1.17x
💻 Local Next.js (Turbopack) 7.055s 7.767s 0.712s 4 2.00x
💻 Local Nitro 8.305s (+2.2%) 8.770s (~) 0.465s 4 2.36x
💻 Local Express 8.379s (-1.1%) 9.020s (~) 0.641s 4 2.38x
🌐 MongoDB Next.js (Turbopack) 10.095s 10.680s 0.585s 3 2.87x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.478s (+3.7%) 4.771s (-4.8%) 1.293s 7 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.202s (-4.6%) 2.010s (~) 0.809s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.253s 2.011s 0.758s 15 1.04x
🐘 Postgres Nitro 1.273s (~) 2.011s (~) 0.738s 15 1.06x
🌐 Redis Next.js (Turbopack) 1.319s 2.006s 0.688s 15 1.10x
💻 Local Next.js (Turbopack) 1.529s 2.006s 0.477s 15 1.27x
💻 Local Nitro 1.540s (-1.3%) 2.005s (~) 0.465s 15 1.28x
💻 Local Express 1.547s (+0.7%) 2.005s (~) 0.458s 15 1.29x
🌐 MongoDB Next.js (Turbopack) 2.181s 3.008s 0.827s 10 1.81x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.572s (-1.1%) 3.643s (-9.2% 🟢) 1.070s 10 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.341s (-4.5%) 3.012s (~) 0.671s 10 1.00x
🐘 Postgres Nitro 2.454s (~) 3.013s (~) 0.559s 10 1.05x
🐘 Postgres Next.js (Turbopack) 2.470s 3.011s 0.541s 10 1.06x
🌐 Redis Next.js (Turbopack) 2.569s 3.008s 0.439s 10 1.10x
💻 Local Next.js (Turbopack) 2.818s 3.109s 0.291s 10 1.20x
💻 Local Nitro 2.963s (-2.1%) 3.676s (~) 0.713s 9 1.27x
💻 Local Express 2.990s (-1.4%) 3.676s (-2.2%) 0.686s 9 1.28x
🌐 MongoDB Next.js (Turbopack) 4.746s 5.178s 0.432s 6 2.03x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.766s (+16.2% 🔺) 3.783s (+3.3%) 1.017s 8 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.517s (-2.3%) 4.013s (~) 0.496s 8 1.00x
🐘 Postgres Nitro 3.651s (+1.0%) 4.015s (~) 0.363s 8 1.04x
🐘 Postgres Next.js (Turbopack) 3.735s 4.014s 0.279s 8 1.06x
🌐 Redis Next.js (Turbopack) 4.147s 4.726s 0.579s 7 1.18x
💻 Local Next.js (Turbopack) 8.126s 8.773s 0.647s 4 2.31x
💻 Local Nitro 8.728s (+1.0%) 9.019s (~) 0.291s 4 2.48x
💻 Local Express 8.804s (-2.8%) 9.025s (-7.7% 🟢) 0.220s 4 2.50x
🌐 MongoDB Next.js (Turbopack) 9.951s 10.684s 0.732s 3 2.83x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.848s (-1.8%) 5.484s (~) 1.636s 6 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.652s (-24.7% 🟢) 1.009s (-1.7%) 0.357s 60 1.00x
🌐 Redis Next.js (Turbopack) 0.687s 1.004s 0.318s 60 1.05x
🐘 Postgres Next.js (Turbopack) 0.835s 1.026s 0.191s 59 1.28x
💻 Local Next.js (Turbopack) 0.850s 1.004s 0.154s 60 1.30x
🐘 Postgres Nitro 0.873s (-2.6%) 1.009s (-3.3%) 0.136s 60 1.34x
💻 Local Nitro 0.980s (+2.6%) 1.136s (+11.3% 🔺) 0.156s 53 1.50x
💻 Local Express 0.980s (~) 1.158s (+5.7% 🔺) 0.178s 52 1.50x
🌐 MongoDB Next.js (Turbopack) 2.158s 3.008s 0.851s 20 3.31x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 10.623s (+1.2%) 11.948s (-3.1%) 1.325s 6 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.572s (-25.7% 🟢) 2.010s (-33.3% 🟢) 0.438s 45 1.00x
🌐 Redis Next.js (Turbopack) 1.678s 2.006s 0.328s 45 1.07x
🐘 Postgres Next.js (Turbopack) 2.027s 2.511s 0.484s 36 1.29x
🐘 Postgres Nitro 2.148s (-0.6%) 3.012s (+1.1%) 0.864s 30 1.37x
💻 Local Next.js (Turbopack) 2.666s 3.007s 0.341s 30 1.70x
💻 Local Nitro 2.974s (+0.6%) 3.330s (+7.0% 🔺) 0.355s 28 1.89x
💻 Local Express 2.987s (-0.9%) 3.329s (-6.1% 🟢) 0.342s 28 1.90x
🌐 MongoDB Next.js (Turbopack) 5.273s 6.011s 0.739s 15 3.35x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 32.443s (-0.6%) 33.373s (-2.3%) 0.929s 3 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.263s (-23.5% 🟢) 4.013s (-19.3% 🟢) 0.750s 30 1.00x
🌐 Redis Next.js (Turbopack) 3.293s 4.008s 0.716s 30 1.01x
🐘 Postgres Next.js (Turbopack) 4.106s 4.975s 0.868s 25 1.26x
🐘 Postgres Nitro 4.367s (+0.7%) 5.015s (~) 0.648s 24 1.34x
💻 Local Next.js (Turbopack) 8.417s 9.016s 0.599s 14 2.58x
💻 Local Nitro 8.989s (~) 9.479s (~) 0.490s 13 2.75x
💻 Local Express 9.106s (~) 9.710s (-0.8%) 0.604s 13 2.79x
🌐 MongoDB Next.js (Turbopack) 10.535s 11.019s 0.484s 11 3.23x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 89.160s (-8.5% 🟢) 90.435s (-9.0% 🟢) 1.274s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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.243s (-19.5% 🟢) 1.009s (~) 0.766s 60 1.00x
🐘 Postgres Next.js (Turbopack) 0.265s 1.009s 0.744s 60 1.09x
🐘 Postgres Nitro 0.298s (+1.1%) 1.009s (~) 0.711s 60 1.22x
🌐 Redis Next.js (Turbopack) 0.401s 1.021s 0.620s 59 1.65x
💻 Local Next.js (Turbopack) 0.558s 1.021s 0.464s 59 2.29x
💻 Local Nitro 0.589s (-1.5%) 1.004s (~) 0.416s 60 2.42x
💻 Local Express 0.606s (+0.5%) 1.004s (~) 0.398s 60 2.49x
🌐 MongoDB Next.js (Turbopack) 1.655s 2.149s 0.494s 28 6.81x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 1.914s (+0.7%) 3.311s (-7.5% 🟢) 1.397s 19 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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.419s (-20.5% 🟢) 1.009s (~) 0.590s 90 1.00x
🐘 Postgres Nitro 0.540s (~) 1.009s (~) 0.469s 90 1.29x
🐘 Postgres Next.js (Turbopack) 0.569s 1.021s 0.451s 89 1.36x
🌐 Redis Next.js (Turbopack) 1.171s 2.006s 0.835s 45 2.79x
💻 Local Next.js (Turbopack) 2.377s 3.008s 0.632s 30 5.67x
💻 Local Nitro 2.495s (+0.8%) 3.008s (~) 0.513s 30 5.95x
💻 Local Express 2.545s (-1.4%) 3.009s (~) 0.464s 30 6.07x
🌐 MongoDB Next.js (Turbopack) 4.756s 5.287s 0.532s 18 11.34x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.221s (-6.3% 🟢) 4.527s (-5.8% 🟢) 1.306s 21 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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.605s (-32.6% 🟢) 1.009s (-3.1%) 0.404s 119 1.00x
🐘 Postgres Nitro 0.919s (-2.1%) 1.216s (+2.0%) 0.297s 99 1.52x
🐘 Postgres Next.js (Turbopack) 0.964s 1.345s 0.381s 90 1.59x
🌐 Redis Next.js (Turbopack) 2.741s 3.007s 0.267s 40 4.53x
🌐 MongoDB Next.js (Turbopack) 9.862s 10.432s 0.570s 12 16.29x
💻 Local Next.js (Turbopack) 10.107s 10.606s 0.499s 12 16.70x
💻 Local Nitro 10.955s (-1.4%) 11.571s (-0.8%) 0.616s 11 18.10x
💻 Local Express 11.174s (-1.0%) 11.846s (-1.5%) 0.671s 11 18.46x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 6.960s (-11.2% 🟢) 8.087s (-13.7% 🟢) 1.127s 15 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.168s (-22.4% 🟢) 0.996s (~) 0.001s (+16.7% 🔺) 1.012s (~) 0.844s 10 1.00x
🌐 Redis Next.js (Turbopack) 0.178s 1.000s 0.002s 1.007s 0.829s 10 1.06x
💻 Local Next.js (Turbopack) 0.185s 1.002s 0.010s 1.016s 0.831s 10 1.10x
💻 Local Nitro 0.198s (+0.7%) 1.003s (~) 0.011s (-5.9% 🟢) 1.017s (~) 0.819s 10 1.18x
💻 Local Express 0.201s (-1.7%) 1.003s (~) 0.012s (-2.5%) 1.017s (~) 0.816s 10 1.20x
🐘 Postgres Next.js (Turbopack) 0.218s 1.002s 0.001s 1.014s 0.796s 10 1.30x
🐘 Postgres Nitro 0.241s (+0.8%) 0.993s (~) 0.002s (+7.1% 🔺) 1.013s (~) 0.772s 10 1.43x
🌐 MongoDB Next.js (Turbopack) 0.493s 0.960s 0.001s 1.009s 0.516s 10 2.93x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 1.656s (-4.3%) 2.778s (-7.0% 🟢) 0.004s (-29.5% 🟢) 3.267s (-9.1% 🟢) 1.611s 10 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: 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.555s 1.000s 0.003s 1.011s 0.456s 60 1.00x
🐘 Postgres Express 0.616s (-11.2% 🟢) 1.022s (+1.8%) 0.003s (-18.6% 🟢) 1.042s (+1.4%) 0.425s 59 1.11x
💻 Local Next.js (Turbopack) 0.669s 1.008s 0.010s 1.024s 0.355s 59 1.20x
💻 Local Nitro 0.722s (-0.7%) 1.009s (~) 0.010s (+3.3%) 1.023s (~) 0.301s 59 1.30x
💻 Local Express 0.731s (-5.9% 🟢) 1.009s (-1.7%) 0.010s (-2.2%) 1.023s (-1.8%) 0.292s 59 1.32x
🐘 Postgres Nitro 0.733s (+1.5%) 1.021s (+1.6%) 0.004s (+11.7% 🔺) 1.044s (+1.8%) 0.311s 59 1.32x
🐘 Postgres Next.js (Turbopack) 0.751s 1.010s 0.004s 1.027s 0.276s 59 1.35x
🌐 MongoDB Next.js (Turbopack) 1.329s 1.950s 0.003s 2.013s 0.685s 30 2.39x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 5.008s (+10.1% 🔺) 5.891s (+1.8%) 0.481s (+140.2% 🔺) 6.857s (+5.0% 🔺) 1.849s 9 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: 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.802s 1.000s 0.000s 1.005s 0.203s 60 1.00x
🐘 Postgres Express 0.814s (-8.9% 🟢) 1.043s (-3.7%) 0.000s (+89.7% 🔺) 1.071s (-3.1%) 0.257s 58 1.02x
🐘 Postgres Nitro 0.933s (+1.3%) 1.150s (+8.3% 🔺) 0.000s (+64.7% 🔺) 1.180s (+9.2% 🔺) 0.247s 51 1.16x
🐘 Postgres Next.js (Turbopack) 0.985s 1.177s 0.000s 1.188s 0.203s 51 1.23x
💻 Local Nitro 1.236s (+0.9%) 2.020s (~) 0.000s (-23.1% 🟢) 2.023s (~) 0.786s 30 1.54x
💻 Local Next.js (Turbopack) 1.237s 2.018s 0.000s 2.022s 0.785s 30 1.54x
💻 Local Express 1.239s (-1.5%) 2.020s (~) 0.000s (-35.3% 🟢) 2.023s (~) 0.783s 30 1.55x
🌐 MongoDB Next.js (Turbopack) 2.360s 2.946s 0.000s 3.008s 0.648s 20 2.94x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.692s (+26.0% 🔺) 4.603s (+15.4% 🔺) 0.000s (-41.7% 🟢) 5.065s (+10.4% 🔺) 1.373s 12 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: 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
🌐 Redis 🥇 Next.js (Turbopack) 1.529s 2.034s 0.000s 2.040s 0.510s 30 1.00x
🐘 Postgres Express 1.686s (-6.6% 🟢) 2.104s (~) 0.000s (NaN%) 2.133s (+0.5%) 0.447s 29 1.10x
🐘 Postgres Nitro 1.858s (-1.7%) 2.098s (-5.5% 🟢) 0.000s (-6.9% 🟢) 2.117s (-5.5% 🟢) 0.258s 29 1.22x
🐘 Postgres Next.js (Turbopack) 2.000s 2.349s 0.000s 2.360s 0.360s 26 1.31x
💻 Local Nitro 3.382s (+1.6%) 4.033s (+1.6%) 0.000s (-14.7% 🟢) 4.037s (+1.6%) 0.655s 15 2.21x
💻 Local Next.js (Turbopack) 3.482s 4.030s 0.001s 4.036s 0.554s 15 2.28x
💻 Local Express 3.498s (+1.6%) 4.098s (~) 0.001s (+75.0% 🔺) 4.102s (~) 0.604s 15 2.29x
🌐 MongoDB Next.js (Turbopack) 4.395s 4.976s 0.000s 5.011s 0.616s 12 2.87x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.869s (-11.4% 🟢) 4.515s (-16.3% 🟢) 0.000s (-100.0% 🟢) 5.038s (-15.5% 🟢) 1.169s 13 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

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

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 🐘 Postgres 20/21
Next.js (Turbopack) 🌐 Redis 10/21
Nitro 🐘 Postgres 16/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


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 20, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
❌ ▲ Vercel Production 779 1 67 847
✅ 💻 Local Development 782 0 142 924
✅ 📦 Local Production 782 0 142 924
✅ 🐘 Local Postgres 727 0 120 847
✅ 🪟 Windows 72 0 5 77
❌ 🌍 Community Worlds 122 58 21 201
✅ 📋 Other 198 0 33 231
Total 3462 59 530 4051

❌ Failed Tests

▲ Vercel Production (1 failed)

example (1 failed):

🌍 Community Worlds (58 failed)

mongodb (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KM6EQCWA8FH8NNSY7ZGA1KTY
  • webhookWorkflow | wrun_01KM6EQNFETZMV0R06RZ9WS59M
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KM6EY2570DGB3VDP62VET1W0

redis (2 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KM6EQCWA8FH8NNSY7ZGA1KTY
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KM6EY2570DGB3VDP62VET1W0

turso (53 failed):

  • addTenWorkflow | wrun_01KM6EP9PA2VF8D6C8FZPX1DPV
  • addTenWorkflow | wrun_01KM6EP9PA2VF8D6C8FZPX1DPV
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KM6EQMFSSRJS76FW2VKYFC6X
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KM6EPGB5MHJ8YKVRWV2GKBEZ
  • promiseRaceWorkflow | wrun_01KM6EPKKCXKBHS77F1SN43AMM
  • promiseAnyWorkflow | wrun_01KM6EPNQB22J6R6YRY6NM84FM
  • importedStepOnlyWorkflow | wrun_01KM6ER2CBE39PF8CGSM5VP0JD
  • hookWorkflow | wrun_01KM6EQ25HJT2YYHAAJ3XADSAM
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KM6EQCWA8FH8NNSY7ZGA1KTY
  • webhookWorkflow | wrun_01KM6EQNFETZMV0R06RZ9WS59M
  • sleepingWorkflow | wrun_01KM6EQWAX2WSGW45X18BZM48A
  • parallelSleepWorkflow | wrun_01KM6ER8X111T19990VHTDFHXS
  • nullByteWorkflow | wrun_01KM6EREKA8MP390A0MWFDPKXY
  • workflowAndStepMetadataWorkflow | wrun_01KM6ERGYD1SHFWFEJBT7G0GT5
  • fetchWorkflow | wrun_01KM6ETBHPJ888CCD6008X0900
  • promiseRaceStressTestWorkflow | wrun_01KM6ETEZ9YDMFT5D1SWPJ6F4B
  • 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()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KM6EXEX6EBHWZPDYABKM366M
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KM6EY2570DGB3VDP62VET1W0
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KM6EYQZ9Q9GVYM8CVTMW9YEX
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KM6EZBGY895Q2T0QB7R3CWYR
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KM6EZMBHD3WX0SF21M07MJXY
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KM6EZV14JAWSMACBS0M0N4D1
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KM6EZX6CXS0CFYSDT2BWRHQ7
  • startFromWorkflow - calling start() directly inside a workflow function with hook communication
  • fibonacciWorkflow - recursive workflow composition via start()
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KM6F0CERY0X2RQKHYVV0M8CN
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KM6F0J8FCDZQ68EA8PWB8GJF
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KM6F0RZ6RFJP7415J3S6BTNR
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KM6F10P79TYKACWGFVXHKPEE
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KM6F178G30Z4VDETWFV53JPJ
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KM6F1DVYE9TNCTP39V71912Q
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KM6F1PTC83D0SYRWJA2XTXTP
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KM6F21X21AEBYXFSBTS5V6M7
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KM6F2A1JP11Z8KGDAWNB2GK3
  • cancelRun - cancelling a running workflow | wrun_01KM6F2GTPDS6HKWM3X5YQF41H
  • cancelRun via CLI - cancelling a running workflow | wrun_01KM6F2T3Z4YFC0NXTB3JXJQZ9
  • 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_01KM6F375GH61TFF6G0YZSM0KA
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KM6F3V6D7PN667T48JCEY8E7
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KM6F45ZYNS8T1RP0HNEJNGZ7

Details by Category

❌ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 70 0 7
❌ example 69 1 7
✅ express 70 0 7
✅ fastify 70 0 7
✅ hono 70 0 7
✅ nextjs-turbopack 75 0 2
✅ nextjs-webpack 75 0 2
✅ nitro 70 0 7
✅ nuxt 70 0 7
✅ sveltekit 70 0 7
✅ vite 70 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 66 0 11
✅ express-stable 66 0 11
✅ fastify-stable 66 0 11
✅ hono-stable 66 0 11
✅ nextjs-turbopack-canary 55 0 22
✅ nextjs-turbopack-stable 72 0 5
✅ nextjs-webpack-canary 55 0 22
✅ nextjs-webpack-stable 72 0 5
✅ nitro-stable 66 0 11
✅ nuxt-stable 66 0 11
✅ sveltekit-stable 66 0 11
✅ vite-stable 66 0 11
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 66 0 11
✅ express-stable 66 0 11
✅ fastify-stable 66 0 11
✅ hono-stable 66 0 11
✅ nextjs-turbopack-canary 55 0 22
✅ nextjs-turbopack-stable 72 0 5
✅ nextjs-webpack-canary 55 0 22
✅ nextjs-webpack-stable 72 0 5
✅ nitro-stable 66 0 11
✅ nuxt-stable 66 0 11
✅ sveltekit-stable 66 0 11
✅ vite-stable 66 0 11
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 66 0 11
✅ express-stable 66 0 11
✅ fastify-stable 66 0 11
✅ hono-stable 66 0 11
✅ nextjs-turbopack-stable 72 0 5
✅ nextjs-webpack-canary 55 0 22
✅ nextjs-webpack-stable 72 0 5
✅ nitro-stable 66 0 11
✅ nuxt-stable 66 0 11
✅ sveltekit-stable 66 0 11
✅ vite-stable 66 0 11
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 72 0 5
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 2
❌ mongodb 54 3 5
✅ redis-dev 3 0 2
❌ redis 55 2 5
✅ turso-dev 3 0 2
❌ turso 4 53 5
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 66 0 11
✅ e2e-local-postgres-nest-stable 66 0 11
✅ e2e-local-prod-nest-stable 66 0 11

📋 View full workflow run


Some E2E test jobs failed:

  • Vercel Prod: failure
  • Local Dev: success
  • Local Prod: success
  • Local Postgres: failure
  • Windows: success

Check the workflow run for details.

VaguelySerious and others added 2 commits March 19, 2026 19:17
Negative startIndex values (e.g. -3) resolve to n chunks before the
known end of the stream. All world implementations (local, postgres,
vercel) support this. Includes unit tests, e2e test, and doc updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread packages/world-vercel/src/utils.ts Outdated
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Copy link
Copy Markdown
Contributor

@pranaygp pranaygp left a comment

Choose a reason for hiding this comment

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

Overall this is a clean, well-tested feature. The implementation is consistent across worlds and the clamping behavior is solid. A few comments inline — the main concern is the docs could better call out the live-stream caveat, and the skill file could mention negative startIndex.

```

The `startIndex` parameter ensures the client can choose where to resume the stream from. For instance, if the function times out during streaming, the chat transport will use `startIndex` to resume the stream exactly from the last token it received.
The `startIndex` parameter ensures the client can choose where to resume the stream from. For instance, if the function times out during streaming, the chat transport will use `startIndex` to resume the stream exactly from the last token it received. Negative values are also supported (e.g. `-5` starts 5 chunks before the end), which is useful for showing the most recent output without replaying the full stream.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This sentence mentions negative values as useful for "showing the most recent output without replaying the full stream" — but in the context of WorkflowChatTransport, the transport itself never uses negative startIndex (it tracks chunkIndex incrementally). The mention here might confuse readers into thinking the transport automatically leverages this.

Consider clarifying that this is useful for custom stream consumption (e.g., a dashboard showing recent output), not something WorkflowChatTransport does internally.


This allows clients to reconnect and continue receiving data from where they left off, rather than restarting from the beginning.

`startIndex` also supports **negative values** to read relative to the end of the stream. For example, `startIndex: -5` starts 5 chunks before the current end. This is useful when you want to show the most recent output without reading the entire stream history:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Worth noting that on a live (not-yet-closed) stream, the negative startIndex resolves at connection time — so -5 means "5 before the current end at the time of connecting", and any chunks written afterward will still be delivered. This is an important subtlety the e2e test handles (via waitForCompletion: true) but the docs do not mention.

A short note like: "On an active stream, the index resolves relative to the chunk count at connection time; subsequent chunks are still delivered." would prevent misunderstanding.

Comment thread packages/world-local/src/streamer.ts Outdated
// Resolve negative startIndex relative to the number of data chunks
// (excluding the trailing EOF marker chunk, if present).
let dataChunkCount = chunkFiles.length;
if (startIndex < 0 && chunkFiles.length > 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: startIndex is typed as number | undefined (from the startIndex?: number parameter). The startIndex < 0 check works because undefined < 0 is false in JS, but it reads a bit fragile. Consider an explicit typeof startIndex === 'number' && startIndex < 0 guard to match the style used in world-vercel/src/streamer.ts:127.

if (startIndex < 0 && chunkFiles.length > 0) {
const lastFile = chunkFiles[chunkFiles.length - 1];
const lastExt = fileExtMap.get(lastFile) ?? '.bin';
const lastChunk = deserializeChunk(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This reads and deserializes the last chunk file just to check eof. On the hot path for a stream with many chunks, this is an extra disk read every time a reader connects with a negative startIndex. Not blocking, but worth a comment noting the cost, or consider whether the EOF state could be tracked more cheaply (e.g., checking for a sentinel file).

Comment thread packages/world-postgres/src/streamer.ts Outdated

// Resolve negative offset relative to the data chunk count
// (excluding the trailing EOF marker, if present)
if (offset < 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same nit as the local streamer: offset starts as startIndex ?? 0, so it can never be undefined here — but an explicit typeof guard would make the intent clearer at a glance.

{/* @skip-typecheck: incomplete code sample */}
```typescript
// Read only the last 10 chunks
const stream = run.getReadable({ startIndex: -10 });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should we add some note/callout to be careful about paginating on this. Because streams are live and will continue enqueueing chunks, relative numbers will map to different absolute chunk "IDs" on subsequent calls. I think accurate pagination is only possible when cursor based, and streams don't support cursor based pagination yet so clients should account for that limitation

Copy link
Copy Markdown
Member Author

@VaguelySerious VaguelySerious Mar 20, 2026

Choose a reason for hiding this comment

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

It's not a problem when using run.getReadable directly, but it is a big problem for resumption, i.e. WorkflowChatTransport. I'm working on this in a follow-up PR together with a metadata/tail endpoint, and cursor-based pagination. I'll add a comment in this PR to mention the limitation

// and 2 chunks to the "test" named stream:
// chunk 0: binary "Hello, named stream!"
// chunk 1: object { foo: 'bar' }
describe.skipIf(isLocalDeployment())('outputStreamWorkflow', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why are we skipping this test in local deployment? 🤔 this might be outdated and we should probably re-enable streaming tests in local deployments

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's already being done so this PR isn't changing it. I might try re-enabling in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yeah just fly by noticed this

// Negative startIndex resolves at connection time using knownChunkCount,
// so the stream must be fully written before connecting the reader.
waitForCompletion: true,
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The e2e coverage for negative startIndex only tests -1 (last chunk). The unit tests in world-local/src/streamer.test.ts are more thorough (covering -2 and clamping with -100), but consider adding a clamping case to this data-driven loop too — e.g., startIndex: -100 expecting all chunks — so the full resolution path is exercised end-to-end across all worlds.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Will add a broader test in the next PR

- Clarify that negative startIndex is for custom consumers, not WorkflowChatTransport
- Add live-stream caveat for negative startIndex resolution timing
- Add pagination limitation callout for live streams
- Use explicit typeof guards for negative startIndex checks (world-local, world-postgres)
- Add cost comment for EOF marker disk read in world-local

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread docs/content/docs/ai/resumable-streams.mdx Outdated
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost ghost mentioned this pull request Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants