Skip to content

fix(eve): resolve every attachment to a staged file or a note - #4635

Merged
AndrewBarba merged 2 commits into
mainfrom
barba/attachments-core
Oct 10, 2026
Merged

AndrewBarba merged 2 commits into
mainfrom
barba/attachments-core

Conversation

@AndrewBarba

@AndrewBarba AndrewBarba commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

One attachment eve can't resolve, or one a provider rejects, stays in session history, and every later model call fails until the session is reset. This PR fixes the pipeline around one rule: every attachment becomes a file staged in the sandbox, or a note, before it enters history. Every attachment the model sees carries a label with its sandbox path. Bytes inline only for formats the bytes prove. This keeps today's storage and adds no new primitive. It replaces #4223.

Behavior changes:

  • A turn cancelled before its first model call stages its attachments inside the framework providers, so a photo sent just before a follow-up survives (Cancelled turn with an attachment persists a raw eve-url: file part when the cancellation lands before the harness step starts; every later model call fails with AI_DownloadError #3419). Without a sandbox, or for unreadable data, a file becomes a note.
  • A string with any URL scheme reaches the channel's fetchFile instead of being decoded as base64. Byte-valued parts cross the queue as data: URLs, which may resolve File parts fail the model call with image.source.base64.data: Input should be a valid string under @workflow/world-postgres #497; I couldn't test against world-postgres. message.received reports an inline file's size instead of storing its data: URL in the session stream.
  • When fetchFile returns null, or the channel has none, eve downloads a public https: link itself instead of leaving it for the provider. eve uses the SSRF-safe request, a 25 MB cap, and a 30 s timeout, at most 10 links per message, one at a time. Other links and failed downloads become notes. History that already holds an unresolved link renders a note, so broken sessions recover. This changes the documented null contract, so this changeset is minor.
  • Staging applies a channel adapter's upload policy to every inbound file, on its final bytes and verified media type. eve's own downloads use the policy's size cap. A channel with no policy is checked as before, so built-in channels with raised caps keep them. feat(eve): add fetchFile to eveChannel and let resolvers give the model a reason #4636 lets channels set the policy.
  • Staging checks image and PDF types against the bytes. Only PNG, JPEG, GIF, and WebP images up to 3 MiB and 8000 px per side, and PDFs up to 20 MiB, inline. Tool results follow the same rule. HEIC, oversized, or mislabeled files render as their label. Live sessions pay one prompt-cache rewrite for the new labels.
  • read_file shows PDFs up to 20 MiB. Its image output field is now file, a public type change, so that changeset is minor too.

The web template shows a file icon instead of a thumbnail for images a user sent, because message.received no longer carries their bytes. The content-output-file-stub e2e eval now uses a verified PNG payload, so the file still inlines.

Closes #3419. Related to #855 and #497. Stacked under #4636 and #4637.

Validation

  • pnpm --filter eve exec vitest run --config vitest.unit.config.ts: 9442 passed, 1 skipped.
  • A new staging integration test covers the upload policy: a link over the cap, a declared PDF whose bytes are a PNG, and the download cap.
  • pnpm --filter eve exec vitest run --config vitest.integration.config.ts src/harness/attachment-staging.integration.test.ts: passed. The broader src/harness src/execution src/public src/channel src/tools integration runs also passed. One test in entry-handoff-lifetime.integration.test.ts fails under load, then passes when run alone. It also fails on an unrelated docs-only PR.
  • The turn-step.test.ts regression for Cancelled turn with an attachment persists a raw eve-url: file part when the cancellation lands before the harness step starts; every later model call fails with AI_DownloadError #3419 fails without the fix.
  • EVE_E2E_MODEL=mock pnpm exec eve eval --strict content-output-file-stub (agent-compaction-regressions): passed 5/5. It fails without the fixture change.
  • EVE_E2E_MODEL=mock pnpm exec eve eval --strict static-tools/read-file-reopens-compacted-image static-tools/to-model-output-content-parts (agent-tools): both pass.
  • pnpm --filter eve run typecheck, pnpm lint, pnpm fmt, pnpm guard:invariants, and pnpm docs:check pass.

Checklist

  • 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)

Signed-off-by: Andrew Barba <barba@hey.com>
@AndrewBarba
AndrewBarba requested a review from a team as a code owner October 10, 2026 17:15
@vercel

vercel Bot commented Oct 10, 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 Oct 10, 2026 5:54pm UTC
eve-pkg Ready Ready Preview, v0 Oct 10, 2026 5:54pm UTC

@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

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

Key takeaways

  • No notable deltas vs main (220cd09).

Delta vs main (220cd09)

Area Metric Baseline Current Delta
Package Packed tarball 7.58 MB 7.58 MB +2.1 kB ⚠️
Package Unpacked publish size 26.69 MB 26.69 MB +6.1 kB ⚠️
Package Installed footprint 74.49 MB 74.50 MB +6.1 kB ⚠️
Package Published files 4115 4115 0
Package Installed files 8120 8120 0
Package Installed package instances 34 34 0
Package Distinct installed package names 32 32 0
Package Installed dependency edges 51 51 0
Package Installed optional peer edges 9 9 0
Runtime Unique function payloads 2 2 0
Runtime Total function bytes 20.38 MB 20.39 MB +13.4 kB ⚠️
Runtime Public routes 18 18 0
Changed function payloads vs main (220cd09) (2)
Function Status Baseline Current Delta Route changes
functions/__server.func changed 10.19 MB 10.20 MB +6.7 kB ⚠️ none
functions/.well-known/workflow/v1/flow.func changed 10.19 MB 10.20 MB +6.7 kB ⚠️ none

eve init install

Metric Baseline Current Delta
Installed footprint 112.79 MB 112.79 MB +6.1 kB ⚠️
Installed packages 97 97 0
dependencies 4 4 0
devDependencies 2 2 0
Dependency package bytes 44.78 MB 44.78 MB +6.1 kB ⚠️
devDependency package bytes 5.11 MB 5.11 MB 0 B ➖
Build Metadata
  • Preset: vercel
  • Nitro: nitro@3.0.260903-beta
  • Output directory: apps/fixtures/weather-agent/.vercel/output
  • Build metadata timestamp: 2026-10-10T17:55:20.842Z
  • 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.76.2
  • Package directory: packages/eve
  • Tarball: 7.58 MB (eve-0.76.2.tgz)
  • Unpacked payload: 26.69 MB across 4115 published files
  • Installed footprint: 74.50 MB across 8120 installed files
  • Installed root package: 26.69 MB
  • Installed dependencies: 47.80 MB
  • Installed package instances: 34
  • Distinct installed package names: 32
  • Installed dependency edges: 51
  • Installed optional peer edges: 9
  • Runtime dependencies: 2
  • Peer dependencies: 7 (6 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: 26.69 MB (35.8%)
  • @rolldown/binding-linux-x64-gnu: 19.62 MB (26.3%)
  • ai: 8.14 MB (10.9%)
  • zod: 6.14 MB (8.2%)
  • undici: 3.56 MB (4.8%)
Publish payload breakdown
Published file size
🟠 dist/src/compiled/shadcn-registry/index.js       [#####...................] 3.85 MB 14.4%
🟠 dist/src/compiled/@photon-ai/chat-adapter-ime... [###.....................] 2.29 MB 8.6%
🟠 dist/src/compiled/@ai-sdk/code-mode/index.js     [#.......................] 1.03 MB 3.8%
🟡 dist/src/compiled/@vercel/blob/index.js          [#.......................] 604.9 kB 2.3%
🟡 dist/src/compiled/_chunks/workflow/undici-D-I... [#.......................] 521.9 kB 2.0%
🔴 Other published files                            [########################] 18.40 MB 68.9%
Installed footprint breakdown
Installed package size
🔴 eve                             [########################] 26.69 MB 35.8%
🔴 @rolldown/binding-linux-x64-gnu [##################......] 19.62 MB 26.3%
🔴 ai                              [#######.................] 8.14 MB 10.9%
🔴 zod                             [######..................] 6.14 MB 8.2%
🟠 undici                          [###.....................] 3.56 MB 4.8%
🟠 nitro                           [##......................] 1.89 MB 2.5%
🔴 Other installed packages        [########................] 8.44 MB 11.3%
Runtime dependencies (2)
Package Range Notes
nitro 3.0.260903-beta
undici 8.10.2
Peer dependencies (7)
Package Range Notes
@opentelemetry/api ^1.0.0 optional peer
ai catalog:
braintrust ^3.0.0 optional peer
chat ^4.41.0 optional peer
dd-trace ^6.13.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: 112.79 MB across 10015 installed files
  • Installed packages: 97 total (91 transitive-only)
  • dependencies: 4 direct packages totaling 44.78 MB
  • devDependencies: 2 direct packages totaling 5.11 MB
  • Other transitive package files: 62.90 MB

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

Heavy installed dependencies

  • @typescript/typescript-linux-x64: 27.95 MB (24.8%)
  • eve: 26.69 MB (23.7%)
  • @rolldown/binding-linux-x64-gnu: 19.62 MB (17.4%)
  • zod: 9.76 MB (8.6%)
  • ai: 8.14 MB (7.2%)
Installed footprint breakdown
Installed package size
🔴 @typescript/typescript-linux-x64 [########################] 27.95 MB 24.8%
🔴 eve                              [#######################.] 26.69 MB 23.7%
🔴 @rolldown/binding-linux-x64-gnu  [#################.......] 19.62 MB 17.4%
🔴 zod                              [########................] 9.76 MB 8.6%
🔴 ai                               [#######.................] 8.14 MB 7.2%
🟠 undici                           [###.....................] 3.56 MB 3.2%
🔴 Other installed packages         [###############.........] 17.07 MB 15.1%
dependencies (4)
Package Range Installed size Share
@vercel/connect 2.2.0 188.7 kB 0.2%
ai ^7.0.128 8.14 MB 7.2%
eve file:eve-0.76.2.tgz 26.69 MB 23.7%
zod 4.5.4 9.76 MB 8.6%
devDependencies (2)
Package Range Installed size Share
@types/node 24.x 2.61 MB 2.3%
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.20 MB 50.0%
🔴 functions/__server.func                         [########################] 10.20 MB 50.0%

Top Function Payloads

🟠 functions/.well-known/workflow/v1/flow.func • 1 public route • 10.20 MB
Metric Value
Public routes /.well-known/workflow/v1/flow
Runtime nodejs24.x
Handler index.mjs
Payload 10.20 MB
Function files 10.20 MB across 118 files
Traced dependencies 0 B
Signal 🟠 Bundled file _chunks/vercel.web.mjs is 2.25 MB (22.1%)

🟠 🔎 Dependency Analysis

📦 Bundled files:

Bundled file size
🟠 _chunks/vercel.web.mjs                         [############............] 2.25 MB 22.1%
🟠 _libs/undici.mjs                               [#####...................] 1.01 MB 9.9%
🟡 _chunks/sandbox3.mjs                           [####....................] 815.4 kB 8.0%
🟡 _chunks/compiled-artifacts-instrumentation.mjs [####....................] 757.3 kB 7.4%
🟡 _chunks/token-util-Bla5Z0G9.mjs                [####....................] 704.7 kB 6.9%
🔴 Other bundled files                            [########################] 4.66 MB 45.7%

🧾 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.20 MB
Metric Value
Public routes /
/.well-known/workflow/v1/webhook/[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/session/[sessionId]/stubs
/eve/v1/task-input/[token]
Internal aliases /__server
Runtime nodejs24.x
Handler index.mjs
Payload 10.20 MB
Function files 10.20 MB across 118 files
Traced dependencies 0 B
Signal 🟠 Bundled file _chunks/vercel.web.mjs is 2.25 MB (22.1%)

🟠 🔎 Dependency Analysis

📦 Bundled files:

Bundled file size
🟠 _chunks/vercel.web.mjs                         [############............] 2.25 MB 22.1%
🟠 _libs/undici.mjs                               [#####...................] 1.01 MB 9.9%
🟡 _chunks/sandbox3.mjs                           [####....................] 815.4 kB 8.0%
🟡 _chunks/compiled-artifacts-instrumentation.mjs [####....................] 757.3 kB 7.4%
🟡 _chunks/token-util-Bla5Z0G9.mjs                [####....................] 704.7 kB 6.9%
🔴 Other bundled files                            [########################] 4.66 MB 45.7%

🧾 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: 3.52 s -> 3.09 s (-431.9 ms) vs main (220cd09).
  • Timing is informational: shared GitHub runners are too variable for a hard timing budget.
Detailed phase timings vs `main (220cd09)`
Phase Baseline Current Delta
extension.check 19.0 ms 18.8 ms -0.2 ms
project.resolve 0.3 ms 0.4 ms +0.1 ms
workspace.create 0.6 ms 0.6 ms 0.0 ms
host.prepare 807.6 ms 607.8 ms -199.8 ms
vercel.service-prefix.resolve 1.4 ms 1.4 ms 0.0 ms
nitro.create 541.4 ms 532.0 ms -9.4 ms
sandbox.prewarm 249.4 ms 265.8 ms +16.4 ms
nitro.cache.prepare 0.3 ms 0.2 ms -0.1 ms
nitro.prepare 0.7 ms 0.8 ms +0.1 ms
nitro.public-assets 0.8 ms 0.8 ms 0.0 ms
nitro.prerender 0.4 ms 0.4 ms 0.0 ms
nitro.bundle 1.75 s 1.52 s -224.5 ms
nitro.cache.write 0.3 ms 0.3 ms 0.0 ms
vercel.workflow-function.materialize 84.1 ms 57.2 ms -26.9 ms
agent-summary.emit 0.8 ms 0.8 ms 0.0 ms
connect-manifest.emit 0.3 ms 0.3 ms 0.0 ms
nitro.close 0.1 ms 0.1 ms 0.0 ms
output.publish 4.1 ms 3.9 ms -0.2 ms
workspace.remove 2.8 ms 2.5 ms -0.3 ms

Comment thread packages/eve/src/internal/attachments/public-link.ts Outdated
Comment thread .changeset/attachments-read-file-pdf.md Outdated
Signed-off-by: Andrew Barba <barba@hey.com>
@vercel-security-reviewer

Copy link
Copy Markdown

Security review details

@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:

Channel staging reads adapter.uploadPolicy, but no channel factory ever sets it on the adapter, so per-byte upload policy enforcement is dead for every real channel (including the eve HTTP channel).

Fix on Vercel

@AndrewBarba

Copy link
Copy Markdown
Collaborator Author

Re the Vercel Agent suggestion that adapter.uploadPolicy is never set: on #4635 alone that's intentional. The field is the staging hook, and #4636 (next in the stack) adds defineChannel({ uploadPolicy }), which eveChannel passes its policy through. The suggestion did surface a real gap: Slack, Telegram, and Teams take their own uploadPolicy but never put it on the adapter. #4636 now passes each one through, so eve's fallback downloads and verified-type checks follow the channel's policy. A channel without a configured policy behaves as before.

@AndrewBarba
AndrewBarba merged commit 0248e69 into main Oct 10, 2026
158 checks passed
@AndrewBarba
AndrewBarba deleted the barba/attachments-core branch October 10, 2026 22:31

This branch was successfully deployed

2 active deployments
Preview – eve-docs — 8bd678cd Deployed Oct 10, 2026 by vercel[bot]
Preview – eve-pkg — 8bd678cd Deployed Oct 10, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant