What problem are you trying to solve?
Every message.appended event carries the full accumulated message in messageSoFar alongside the delta, and every event is persisted as a durable workflow stream chunk — so a message's stored footprint is O(n²) in its number of deltas. reasoningSoFar doubles this on reasoning models.
packages/eve/src/harness/emission.ts:554 — messageSoFar: currentMessage (as of eve@0.29.2)
packages/eve/src/harness/emission.ts:529 — reasoningSoFar: currentReasoning
MessageAppendedStreamEvent has carried messageSoFar since the first commit, so this is protocol design rather than a regression.
This is the storage-side counterpart of #1051, which reports the read-side symptom (rebuilding history re-downloads every partial copy) and proposes a history endpoint. A history endpoint helps readers, but the quadratic bytes still land on disk.
Measured impact (production deployment, postgres world)
We run eve agents on @workflow/world-postgres, one database per project:
- One moderately busy agent (~300–450 runs/day) grew its
workflow_stream_chunks table to 13 GB in two weeks (~2.5 GB/day) and took the host disk to 85%.
- One representative run: 8,110 chunks, 153 MB written for a final assistant message of 21 KB — ~7,000× amplification. Per-chunk size grows linearly to the end of the run (2.2 KB in the first decile → 37 KB in the last).
- Across the whole database: 18 GB of chunk bytes, of which the sum of each stream's largest chunk — the only bytes carrying new information — is 81 MB. 99.56% of persisted bytes are redundant copies.
The snapshots are not needed for correctness: packages/eve/src/client/message-reducer.ts already accumulates deltas client-side, and since durable sessions moved program memory into workflow step results (packages/eve/src/execution/durable-session-store.ts), the chunk stream is delivery-only.
Proposed solution
Stop persisting the accumulated snapshots on per-delta events; emit them only on terminal events:
message.appended / reasoning.appended carry the delta only (drop or empty messageSoFar / reasoningSoFar).
message.completed / reasoning.completed keep the full final text (they already do).
Live consumers reduce deltas as they already do; a resuming consumer replays from its cursor or rebuilds from the *.completed events. This turns storage O(n²) → O(n) at the source — on our data it would shrink the chunk table by ~99% — and it composes with #1051's history endpoint rather than replacing it.
If dropping the fields outright is too breaking for one release, an opt-in (e.g. an emission/agent-level streamSnapshots: false, or making the fields optional in the protocol and omitting them by default in a future major) would let deployments that pay for storage opt out immediately.
Happy to contribute a PR if the direction is agreeable.
What problem are you trying to solve?
Every
message.appendedevent carries the full accumulated message inmessageSoFaralongside the delta, and every event is persisted as a durable workflow stream chunk — so a message's stored footprint is O(n²) in its number of deltas.reasoningSoFardoubles this on reasoning models.packages/eve/src/harness/emission.ts:554—messageSoFar: currentMessage(as ofeve@0.29.2)packages/eve/src/harness/emission.ts:529—reasoningSoFar: currentReasoningMessageAppendedStreamEventhas carriedmessageSoFarsince the first commit, so this is protocol design rather than a regression.This is the storage-side counterpart of #1051, which reports the read-side symptom (rebuilding history re-downloads every partial copy) and proposes a history endpoint. A history endpoint helps readers, but the quadratic bytes still land on disk.
Measured impact (production deployment, postgres world)
We run eve agents on
@workflow/world-postgres, one database per project:workflow_stream_chunkstable to 13 GB in two weeks (~2.5 GB/day) and took the host disk to 85%.The snapshots are not needed for correctness:
packages/eve/src/client/message-reducer.tsalready accumulates deltas client-side, and since durable sessions moved program memory into workflow step results (packages/eve/src/execution/durable-session-store.ts), the chunk stream is delivery-only.Proposed solution
Stop persisting the accumulated snapshots on per-delta events; emit them only on terminal events:
message.appended/reasoning.appendedcarry the delta only (drop or emptymessageSoFar/reasoningSoFar).message.completed/reasoning.completedkeep the full final text (they already do).Live consumers reduce deltas as they already do; a resuming consumer replays from its cursor or rebuilds from the
*.completedevents. This turns storage O(n²) → O(n) at the source — on our data it would shrink the chunk table by ~99% — and it composes with #1051's history endpoint rather than replacing it.If dropping the fields outright is too breaking for one release, an opt-in (e.g. an emission/agent-level
streamSnapshots: false, or making the fields optional in the protocol and omitting them by default in a future major) would let deployments that pay for storage opt out immediately.Happy to contribute a PR if the direction is agreeable.