Skip to content

feat(eve): label every attachment and inline only verified media - #4629

Closed
AndrewBarba wants to merge 2 commits into
barba/attachments-eve-fetches-linksfrom
barba/attachments-labels-verified-media
Closed

AndrewBarba wants to merge 2 commits into
barba/attachments-eve-fetches-linksfrom
barba/attachments-labels-verified-media

Conversation

@AndrewBarba

@AndrewBarba AndrewBarba commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Two gaps make attachments fragile at the model call. First, eve inlined any image/* up to 3 MiB on the declared type alone. A HEIC photo, an image over a provider's pixel limit, or a mislabeled file then failed every later call. Tool results inlined with no check at all. Second, an inlined image reached the model without its sandbox path, so the agent could not pass a visible file to bash or open it again. Now every attachment renders a label with its path, such as Attached file /workspace/.eve/attachments/<hash>/chart.png (image/png). Bytes follow the label only for verified formats: PNG, JPEG, GIF, and WebP images up to 3 MiB and 8000 px per side, and PDFs up to 20 MiB.

Staging checks image and PDF media types against the bytes. The PDF header must be at the start of the file. A declared image or PDF that the bytes don't confirm becomes application/octet-stream. Inbound files and tool results now follow the same rule, including the verified type the bytes go out with, and token estimates match it.

The content-output-file-stub e2e eval relied on an application/octet-stream payload reaching the model, and that payload is now label-only. Its payload is now a verified PNG, so it still inlines and still adds compaction pressure. The labels change how existing messages render, so each live session pays one prompt-cache rewrite after upgrade.

Part of the stack from the research plan in #4625.

Validation

  • New attachment-staging.integration.test.ts cases cover a mismatched PNG, HEIC, an 8001 px image, a corrected JPEG type, and the same rule on tool results, including a mislabeled tool file.
  • EVE_E2E_MODEL=mock pnpm exec eve eval --strict content-output-file-stub in e2e/fixtures/agent-compaction-regressions: passes (5/5). It fails without the fixture change (no compaction.completed).
  • EVE_E2E_MODEL=mock pnpm exec eve eval --strict static-tools/read-file-reopens-compacted-image static-tools/to-model-output-content-parts in e2e/fixtures/agent-tools: both pass. I updated fixtures that used fake image and PDF bytes to use real headers.
  • pnpm --filter eve exec vitest run --config vitest.unit.config.ts: 9438 passed, 1 skipped.
  • pnpm --filter eve exec vitest run --config vitest.integration.config.ts src/harness src/execution/sandbox src/tools src/public/channels: all pass after the fixture updates.
  • 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)

@AndrewBarba
AndrewBarba requested a review from a team as a code owner October 10, 2026 16:32
@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 4:57pm UTC
eve-pkg Ready Ready Preview, v0 Oct 10, 2026 4:57pm 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 barba/attachments-eve-fetches-links (04415ab).

Delta vs barba/attachments-eve-fetches-links (04415ab)

Area Metric Baseline Current Delta
Package Packed tarball 7.58 MB 7.58 MB +1.8 kB ⚠️
Package Unpacked publish size 26.69 MB 26.69 MB +2.9 kB ⚠️
Package Installed footprint 74.49 MB 74.50 MB +2.9 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.39 MB 20.39 MB +2.9 kB ⚠️
Runtime Public routes 18 18 0
Changed function payloads vs barba/attachments-eve-fetches-links (04415ab) (2)
Function Status Baseline Current Delta Route changes
functions/__server.func changed 10.19 MB 10.20 MB +1.5 kB ⚠️ none
functions/.well-known/workflow/v1/flow.func changed 10.19 MB 10.20 MB +1.5 kB ⚠️ none

eve init install

Metric Baseline Current Delta
Installed footprint 112.79 MB 112.79 MB +2.9 kB ⚠️
Installed packages 97 97 0
dependencies 4 4 0
devDependencies 2 2 0
Dependency package bytes 44.78 MB 44.78 MB +2.9 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-10T16:58:14.220Z
  • 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.51 s -> 3.46 s (-47.2 ms) vs barba/attachments-eve-fetches-links (04415ab).
  • Timing is informational: shared GitHub runners are too variable for a hard timing budget.
Detailed phase timings vs `barba/attachments-eve-fetches-links (04415ab)`
Phase Baseline Current Delta
extension.check 19.4 ms 18.1 ms -1.3 ms
project.resolve 0.5 ms 0.3 ms -0.2 ms
workspace.create 0.5 ms 0.4 ms -0.1 ms
host.prepare 786.6 ms 698.6 ms -88.0 ms
vercel.service-prefix.resolve 1.6 ms 1.6 ms 0.0 ms
nitro.create 585.8 ms 591.7 ms +5.9 ms
sandbox.prewarm 284.8 ms 338.3 ms +53.5 ms
nitro.cache.prepare 0.2 ms 0.2 ms 0.0 ms
nitro.prepare 0.6 ms 0.6 ms 0.0 ms
nitro.public-assets 0.8 ms 0.7 ms -0.1 ms
nitro.prerender 0.5 ms 0.4 ms -0.1 ms
nitro.bundle 1.68 s 1.64 s -34.6 ms
nitro.cache.write 0.3 ms 0.3 ms 0.0 ms
vercel.workflow-function.materialize 59.2 ms 75.9 ms +16.7 ms
agent-summary.emit 0.7 ms 0.7 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 3.6 ms 3.9 ms +0.3 ms
workspace.remove 2.4 ms 2.3 ms -0.1 ms

Signed-off-by: Andrew Barba <barba@hey.com>
if (bytes === null) return [renderMissingSandboxRef(ref)];
return [
label,
{ ...part, data: { data: Buffer.from(bytes).toString("base64"), type: "data" } },

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.

Tool-result files never pick up the verified media type. writeSandboxRef can retype the file (verifyMediaType returns the detected format), but staging at L305 only replaces data and keeps part.mediaType, and this spread does the same thing again. So the label and the inline decision follow ref.mediaType, while the bytes go out under whatever the tool declared:

  • PNG bytes declared application/octet-stream (MCP blobs do this) get verified as image/png, pass inlinesSandboxRefAsBytes, then reach the provider as application/octet-stream.
  • JPEG bytes declared image/png or image/jpg get labeled image/jpeg but sent as image/png / image/jpg, which Anthropic rejects.

That breaks the "tool results follow the same rule" / "no provider receives bytes it would reject" promise. The user-message path already does this right at L344 (mediaType: ref.mediaType). Do the same here (or at L305 so history stores the verified type too), and add a tool-result case with a mismatched declaration to the "applies the same rule to files a tool returns" test, since right now every file in that test is declared image/png.

return (
ref.size <= INLINE_IMAGE_MAX_BYTES &&
(ref.width ?? 0) <= INLINE_IMAGE_MAX_SIDE_PX &&
(ref.height ?? 0) <= INLINE_IMAGE_MAX_SIDE_PX

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.

If the dimensions are unknown, this check passes anyway. detectImageMediaType accepts a PNG from its 8-byte signature and a JPEG from 3 bytes, but readMediaMetadata leaves out width/height whenever the header doesn't parse (a PNG under 24 bytes, a JPEG with no SOF segment found). So a truncated or corrupt file still "verifies" and gets inlined, and the provider can fail the whole request on it, which is the failure this PR is trying to remove. Since every ref staged after this change has run through readMediaMetadata, it seems safer to require both dimensions before inlining an image. One tradeoff: refs from releases before #4224 have no dimensions and would drop to label-only.

Comment thread docs/sandbox/index.mdx
- A PNG, JPEG, GIF, or WebP image up to 3 MiB and at most 8000 pixels per side.
- A PDF up to 20 MiB.

Other files, such as CSV, HEIC, audio, and video, reach the model as the label alone. eve checks image and PDF media types against the file's bytes when it stages the file. A file whose bytes don't match its declared image or PDF type is staged as `application/octet-stream`, so a provider never receives bytes it would reject.

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 doesn't match what the code does. When the bytes are a different format that eve recognizes, the file gets retyped to that format rather than to application/octet-stream. The new integration test stages PNG bytes declared image/jpeg as image/png and inlines them. application/octet-stream only happens when the declared type is PNG/JPEG/GIF/WebP/PDF and the bytes match none of those formats. Also, a declared application/octet-stream file can get upgraded to an image or PDF. Suggest something like: "eve sets image and PDF media types from the file's bytes when it stages the file. A file declared as one of these types whose bytes match none of them is staged as application/octet-stream." The changeset has the same issue: "a mislabeled file renders as its label" is only true when the bytes are unrecognized.

…he compaction eval inlined

Signed-off-by: Andrew Barba <barba@hey.com>
@AndrewBarba

Copy link
Copy Markdown
Collaborator Author

Collapsed into #4635.

This branch was successfully deployed

2 active deployments
Preview – eve-docs — aa866016 Deployed Oct 10, 2026 by vercel[bot]
Preview – eve-pkg — aa866016 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

Development

Successfully merging this pull request may close these issues.

1 participant