Skip to content

fix(eve): persist text streams as deltas - #2867

Merged
ruiconti merged 10 commits into
mainfrom
rui/prototype-delta-stream-events
Sep 2, 2026
Merged

fix(eve): persist text streams as deltas#2867
ruiconti merged 10 commits into
mainfrom
rui/prototype-delta-stream-events

Conversation

@ruiconti

@ruiconti ruiconti commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Before

{ "messageDelta": "Revenue", "messageSoFar": "Revenue" }
{ "messageDelta": " increased", "messageSoFar": "Revenue increased" }
{ "messageDelta": " by 12%", "messageSoFar": "Revenue increased by 12%" }

After

{ "messageDelta": "Revenue" }
{ "messageDelta": " increased" }
{ "messageDelta": " by 12%" }

reasoning.appended and action.input.appended now have the same shape: each event persists only the new chunk plus its existing turn, step, and call coordinates. Empty tool-input starts no longer emit an append event; the first append contains actual input text.

Consumers that need text-so-far accumulate chunks in stream order. The default reducer, TUI, Slack, Chat SDK, and Next.js trace consumer now do that locally. Slack still posts final answers from message.completed; its progressive reasoning accumulator resets at reasoning completion and turn/step boundaries.

The durable event index remains the reconnect cursor, and stable event IDs deduplicate replay overlap. The protocol does not add a second text position or block-boundary mechanism.

The stream version advances from 24 to 25. The client and server normalize v21-v24 cumulative message/reasoning events and v24 tool-input offsets into the current delta-only shape. Missing deltas and append fields that contradict the declared version fail at the decode boundary. Published extensions whose capability contract changed must be rebuilt and republished.

Provider retries remain append-only: events emitted by an interrupted attempt stay durable. A later completed event can replace provisional text in replaceable consumers; the TUI now replaces its still-live block before committing the completed text. A block completed before its attempt later fails cannot be retracted without adding attempt identity.

Reproduction

The same 159-call, 414,436-event sequence was encoded with the cumulative and delta-only formats:

Measurement Cumulative format Delta-only format Difference
Total serialized eve protocol 11,381,164,093 bytes 85,280,426 bytes -11,295,883,667 bytes (-99.25%)
reasoningSoFar payload 9,666,376,952 bytes 0 bytes -9,666,376,952 bytes
messageSoFar payload 1,629,506,715 bytes 0 bytes -1,629,506,715 bytes

The cumulative stream was 133.46 times the delta-only size; the new stream is 0.75% of the previous size. These are serialized eve protocol bytes before Workflow framing, not billed Workflow Data Written.

Validation

The matched replay sends the same chunk sequence through the cumulative and current eve emitters and protocol encoders. The delta full branch passed 7,758 unit tests and 711 integration tests. The final TUI repair passes 298 focused TUI tests, both provider-retry integration tests, and eve typecheck; CI remains the authoritative full-commit result.

Tests cover delta accumulation and coalescing, provider retry output, legacy replay, reconnects across stream versions, malformed v25 events, and built-in client, Chat SDK, Slack, TUI, ACP, and trace consumers. The TUI regression asserts that discarded retry text is absent from the committed transcript and the recovered answer appears once.

Checklist

  • This change was requested or approved by a maintainer
  • I ran the relevant checks from CONTRIBUTING.md
  • I added tests and documentation where relevant
  • I added a changeset if this touches the published eve package
  • DCO sign-off passes for every commit (git commit --signoff)

Diff size

Docs — 4 files · +112 / -8

Explains the delta-only wire format, consumer migration, reconnect semantics, and retry limitation.

Implementation — 29 files · +627 / -190

Removes cumulative snapshots and tool-input offsets, normalizes supported historical streams, validates the v25 shape, and migrates first-party consumers. Eight generated capability reports record the breaking author-facing event contract.

Tests — 30 files · +933 / -129

Covers byte scaling, accumulation, coalescing, retry behavior, legacy replay, reconnects, malformed events, and first-party consumer behavior.

Signed-off-by: Rui Conti <ruiconti@gmail.com>
@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated
eve-docs Ready Ready Preview, v0 Sep 2, 2026 9:09pm UTC
eve-docs-4759 Ready Ready Preview, v0 Sep 2, 2026 9:09pm UTC
eve-pkg Ready Ready Preview, v0 Sep 2, 2026 9:09pm UTC

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Bundle + Package Summary: apps/fixtures/weather-agent

Key takeaways

  • No notable deltas vs main (23a4b59).

Delta vs main (23a4b59)

Area Metric Baseline Current Delta
Package Packed tarball 8.62 MB 8.62 MB +2.6 kB ⚠️
Package Unpacked publish size 32.46 MB 32.48 MB +21.9 kB ⚠️
Package Installed footprint 77.62 MB 77.64 MB +21.9 kB ⚠️
Package Published files 3769 3775 +6
Package Installed files 7615 7621 +6
Package Installed package instances 35 35 0
Package Distinct installed package names 34 34 0
Package Installed dependency edges 53 53 0
Package Installed optional peer edges 47 47 0
Runtime Unique function payloads 2 2 0
Runtime Total function bytes 20.31 MB 20.32 MB +7.9 kB ⚠️
Runtime Public routes 18 18 0
Changed function payloads vs main (23a4b59) (2)
Function Status Baseline Current Delta Route changes
functions/__server.func changed 10.16 MB 10.16 MB +4.0 kB ⚠️ none
functions/.well-known/workflow/v1/flow.func changed 10.16 MB 10.16 MB +4.0 kB ⚠️ none

eve init install

Metric Baseline Current Delta
Installed footprint 116.06 MB 116.08 MB +21.9 kB ⚠️
Installed packages 120 120 0
dependencies 4 4 0
devDependencies 2 2 0
Dependency package bytes 48.52 MB 48.54 MB +21.9 kB ⚠️
devDependency package bytes 5.04 MB 5.04 MB 0 B ➖
Build Metadata
  • Preset: vercel
  • Nitro: nitro@3.0.260610-beta
  • Output directory: apps/fixtures/weather-agent/.vercel/output
  • Build metadata timestamp: 2026-09-02T21:09:29.791Z
  • Route aliases: 18 public, 1 internal (19 total aliases)
  • Vercel routes in config: 21
  • Severity legend: 🔴 dominant/large, 🟠 notable, 🟡 watch, ⚪ small
Package Drill-Down

Package Details

  • Package: eve@0.49.0
  • Package directory: packages/eve
  • Tarball: 8.62 MB (eve-0.49.0.tgz)
  • Unpacked payload: 32.48 MB across 3775 published files
  • Installed footprint: 77.64 MB across 7621 installed files
  • Installed root package: 31.02 MB
  • Installed dependencies: 46.63 MB
  • Installed package instances: 35
  • Distinct installed package names: 34
  • Installed dependency edges: 53
  • Installed optional peer edges: 47
  • Runtime dependencies: 2
  • Peer dependencies: 5 (4 optional)

Installed footprint is measured from an isolated temporary npm install of the packed tarball.
Graph metrics read only package.json files in package directories directly beneath a node_modules boundary, including nested boundaries. Each directory is one package instance; distinct names come from those manifests. Dependency edges count each unique name in dependencies or optionalDependencies per instance; optional peer edges count peerDependencies marked optional.

Heavy installed dependencies

  • eve: 31.02 MB (39.9%)
  • @rolldown/binding-linux-x64-gnu: 19.31 MB (24.9%)
  • ai: 6.98 MB (9.0%)
  • zod: 6.41 MB (8.3%)
  • undici: 3.50 MB (4.5%)
Publish payload breakdown
Published file size
🔴 dist/src/compiled/shadcn-registry/index.js       [#############...........] 9.76 MB 30.1%
🟠 dist/src/compiled/@photon-ai/chat-adapter-ime... [###.....................] 2.27 MB 7.0%
🟠 dist/src/compiled/@ai-sdk/code-mode/index.js     [#.......................] 1.03 MB 3.2%
🟡 dist/src/compiled/@vercel/blob/index.js          [#.......................] 901.8 kB 2.8%
🟡 dist/src/compiled/_chunks/workflow/undici-Dfx... [#.......................] 512.5 kB 1.6%
🔴 Other published files                            [########################] 18.01 MB 55.4%
Installed footprint breakdown
Installed package size
🔴 eve                             [########################] 31.02 MB 39.9%
🔴 @rolldown/binding-linux-x64-gnu [###############.........] 19.31 MB 24.9%
🔴 ai                              [#####...................] 6.98 MB 9.0%
🔴 zod                             [#####...................] 6.41 MB 8.3%
🟠 undici                          [###.....................] 3.50 MB 4.5%
🟠 nitro                           [##......................] 2.41 MB 3.1%
🔴 Other installed packages        [######..................] 8.00 MB 10.3%
Runtime dependencies (2)
Package Range Notes
nitro 3.0.260610-beta
undici 8.9.0
Peer dependencies (5)
Package Range Notes
@opentelemetry/api ^1.0.0 optional peer
ai catalog:
braintrust ^3.0.0 optional peer
just-bash ^3.1.0 optional peer
microsandbox ^0.5.0 optional peer
eve init install drill-down

eve init install details

  • Command: eve init my-agent
  • Package manager: npm
  • Installed footprint: 116.08 MB across 9517 installed files
  • Installed packages: 120 total (114 transitive-only)
  • dependencies: 4 direct packages totaling 48.54 MB
  • devDependencies: 2 direct packages totaling 5.04 MB
  • Other transitive package files: 62.50 MB

Installed footprint is measured from an isolated temporary eve init my-agent using the current packed eve tarball.

Heavy installed dependencies

  • eve: 31.02 MB (26.7%)
  • @typescript/typescript-linux-x64: 27.95 MB (24.1%)
  • @rolldown/binding-linux-x64-gnu: 19.31 MB (16.6%)
  • zod: 10.37 MB (8.9%)
  • ai: 6.98 MB (6.0%)
Installed footprint breakdown
Installed package size
🔴 eve                              [########################] 31.02 MB 26.7%
🔴 @typescript/typescript-linux-x64 [######################..] 27.95 MB 24.1%
🔴 @rolldown/binding-linux-x64-gnu  [###############.........] 19.31 MB 16.6%
🔴 zod                              [########................] 10.37 MB 8.9%
🔴 ai                               [#####...................] 6.98 MB 6.0%
🟠 undici                           [###.....................] 3.50 MB 3.0%
🔴 Other installed packages         [#############...........] 16.94 MB 14.6%
dependencies (4)
Package Range Installed size Share
@vercel/connect 1.0.0 167.9 kB 0.1%
ai ^7.0.82 6.98 MB 6.0%
eve file:eve-0.49.0.tgz 31.02 MB 26.7%
zod 4.5.4 10.37 MB 8.9%
devDependencies (2)
Package Range Installed size Share
@types/node 24.x 2.54 MB 2.2%
typescript 7.0.2 2.50 MB 2.2%
Function Drill-Down

Payload Size Graph

Unique function payload size and share of total
🔴 functions/.well-known/workflow/v1/flow.func     [########################] 10.16 MB 50.0%
🔴 functions/__server.func                         [########################] 10.16 MB 50.0%

Top Function Payloads

🟠 functions/.well-known/workflow/v1/flow.func • 1 public route • 10.16 MB
Metric Value
Public routes /.well-known/workflow/v1/flow
Runtime nodejs24.x
Handler index.mjs
Payload 10.16 MB
Function files 10.16 MB across 111 files
Traced dependencies 0 B
Signal 🟠 Bundled file index.mjs is 2.15 MB (21.1%)

🟠 🔎 Dependency Analysis

📦 Bundled files:

Bundled file size
🟠 index.mjs                       [##########..............] 2.15 MB 21.1%
🟡 _libs/undici.mjs                [#####...................] 980.5 kB 9.7%
🟡 _chunks/decode_jwt-Col8JOnf.mjs [###.....................] 702.6 kB 6.9%
🟡 _chunks/rename-with-retry.mjs   [###.....................] 695.6 kB 6.8%
🟡 _chunks/frames-CZ9eHShe.mjs     [###.....................] 679.1 kB 6.7%
🔴 Other bundled files             [########################] 4.96 MB 48.8%

🧾 Vercel Config

{
  "handler": "index.mjs",
  "launcherType": "Nodejs",
  "shouldAddHelpers": false,
  "supportsResponseStreaming": true,
  "runtime": "nodejs24.x",
  "maxDuration": "max",
  "experimentalTriggers": [
    {
      "type": "queue/v2beta",
      "topic": "__eve776561746865722d6167656e74_wkf_workflow_*",
      "consumer": "default",
      "retryAfterSeconds": 5,
      "initialDelaySeconds": 0
    }
  ],
  "environment": {
    "WORKFLOW_PRECONDITION_GUARD": "1"
  }
}

🟠 functions/__server.func • 17 public routes, 1 internal alias • 10.16 MB
Metric Value
Public routes /
/.well-known/workflow/v1/webhook/[token]
/eve/v1/activity/[token]
/eve/v1/callback/[token]
/eve/v1/connections/[name]/callback/[attemptId]/[token]
/eve/v1/connections/[name]/callback/[token]
/eve/v1/health
/eve/v1/info
/eve/v1/session
/eve/v1/session/[parentSessionId]/subagents/[callId]/[childSessionId]/stream
/eve/v1/session/[sessionId]
/eve/v1/session/[sessionId]/cancel
/eve/v1/session/[sessionId]/clear
/eve/v1/session/[sessionId]/compact
/eve/v1/session/[sessionId]/reset
/eve/v1/session/[sessionId]/stream
/eve/v1/task-input/[token]
Internal aliases /__server
Runtime nodejs24.x
Handler index.mjs
Payload 10.16 MB
Function files 10.16 MB across 111 files
Traced dependencies 0 B
Signal 🟠 Bundled file index.mjs is 2.15 MB (21.1%)

🟠 🔎 Dependency Analysis

📦 Bundled files:

Bundled file size
🟠 index.mjs                       [##########..............] 2.15 MB 21.1%
🟡 _libs/undici.mjs                [#####...................] 980.5 kB 9.7%
🟡 _chunks/decode_jwt-Col8JOnf.mjs [###.....................] 702.6 kB 6.9%
🟡 _chunks/rename-with-retry.mjs   [###.....................] 695.6 kB 6.8%
🟡 _chunks/frames-CZ9eHShe.mjs     [###.....................] 679.1 kB 6.7%
🔴 Other bundled files             [########################] 4.96 MB 48.8%

🧾 Vercel Config

{
  "handler": "index.mjs",
  "launcherType": "Nodejs",
  "shouldAddHelpers": false,
  "supportsResponseStreaming": true,
  "runtime": "nodejs24.x"
}

Build Timing: e2e/fixtures/agent-tools-sandbox

This is an informational timing measurement inside eve build, from preflight through publication. Output-size measurement and profile writing are excluded.

Build mode: deployable Vercel build with sandbox template prewarm included.

  • Build pipeline: 2.81 s -> 2.68 s (-121.9 ms) vs main (23a4b59).
  • Timing is informational: shared GitHub runners are too variable for a hard timing budget.
Detailed phase timings vs `main (23a4b59)`
Phase Baseline Current Delta
extension.check 12.7 ms 1.1 ms -11.6 ms
project.resolve 0.4 ms 0.4 ms 0.0 ms
workspace.create 0.7 ms 0.8 ms +0.1 ms
host.prepare 543.9 ms 475.0 ms -68.9 ms
vercel.service-prefix.resolve 1.8 ms 1.9 ms +0.1 ms
nitro.create 495.0 ms 484.3 ms -10.7 ms
sandbox.prewarm 261.5 ms 247.7 ms -13.8 ms
nitro.cache.prepare 0.2 ms 0.3 ms +0.1 ms
nitro.prepare 0.7 ms 0.7 ms 0.0 ms
nitro.public-assets 0.7 ms 0.7 ms 0.0 ms
nitro.prerender 0.4 ms 0.5 ms +0.1 ms
nitro.bundle 1.44 s 1.42 s -16.9 ms
nitro.cache.write 0.3 ms 0.3 ms 0.0 ms
vercel.workflow-function.materialize 43.0 ms 42.6 ms -0.4 ms
agent-summary.emit 0.7 ms 0.7 ms 0.0 ms
nitro.close 0.1 ms 0.1 ms 0.0 ms
output.publish 3.1 ms 3.3 ms +0.2 ms
workspace.remove 1.9 ms 1.8 ms -0.1 ms

@vercel vercel Bot left a comment

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.

Additional Suggestion:

Trace viewer reads removed cumulative stream fields reasoningSoFar/messageSoFar, so progressive streaming text never renders during reasoning.appended/message.appended.

Fix on Vercel

Signed-off-by: Rui Conti <ruiconti@gmail.com>
Signed-off-by: Rui Conti <ruiconti@gmail.com>
Signed-off-by: Rui Conti <ruiconti@gmail.com>
Signed-off-by: Rui Conti <ruiconti@gmail.com>
@ctgowrie

ctgowrie commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Why do we have an offset vs just using the chunk which is closer to what providers and ai sdk use?

Signed-off-by: Rui Conti <ruiconti@gmail.com>
Signed-off-by: Rui Conti <ruiconti@gmail.com>
@ruiconti ruiconti changed the title fix(eve): persist text streams as offset deltas fix(eve): persist text streams as deltas Sep 2, 2026
@ruiconti

ruiconti commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Why do we have an offset vs just using the chunk which is closer to what providers and ai sdk use?

The reasoning was to provide a way for clients, during reconnect midstream, to distinguish if the current reasoning-delta event:

  • should be appended or not e.g offset !== 0
  • has skewed from current local state e.g last known offset was 13 and it received 45

But these are theoretical and not consistent with other -delta usage, so looks like a theoretical issue.

Signed-off-by: Rui Conti <ruiconti@gmail.com>
Comment thread packages/eve/src/cli/dev/tui/runner.ts Outdated
Signed-off-by: Rui Conti <ruiconti@gmail.com>
@ruiconti
ruiconti merged commit 70c8a2e into main Sep 2, 2026
339 of 352 checks passed
@ruiconti
ruiconti deleted the rui/prototype-delta-stream-events branch September 2, 2026 23:35
mechiland added a commit to evelandhq/eveland that referenced this pull request Sep 11, 2026
…#533)

## Summary

The hourly sweep in `apps/worker/src/runtime/workflow-world-reaper.ts`
only ever pruned `workflow_stream_chunks` in the legacy `eveland_wf_*`
per-project databases that `@workflow/world-postgres` deployments used.
No legacy Deployment remains: every build bakes in
`@evelandhq/workflow-world`, whose dispatcher runs its own bounded
stream and graph retention every minute, so the worker-side sweep had
nothing left to scan.

Removed:
- `workflow-world-reaper.ts`, `workflow-stream-retention.ts` and their
tests; the scheduler wiring and shutdown hook in `worker.ts`.
- `EVELAND_WORKFLOW_SWEEP_INTERVAL_MS`,
`EVELAND_WORKFLOW_STREAM_RETENTION_MS`,
`EVELAND_WORKFLOW_SWEEP_BATCH_SIZE` from config diagnostics, the systemd
env example and both reference docs.

Untouched: the `WORKFLOW_POSTGRES_URL` legacy bootstrap/drop path, which
is tied to release attestation's `workflow_world_kind` and the
delete-project flow; that is a separate data-model cleanup.

Context: vercel/eve#1441 (source fix landed as vercel/eve#2867),
#213.

## Test plan

- [x] `pnpm typecheck` (worker, core), `pnpm lint`
- [x] `pnpm --filter ./packages/core test` and `pnpm --filter
./apps/worker test` against a local Postgres 17 with
`EVELAND_POSTGRES_TEST_URL`
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