Repository navigation
feat(eve): label every attachment and inline only verified media - #4629
AndrewBarba wants to merge 2 commits into
Conversation
Bundle + Package Summary:
|
| 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" } }, |
There was a problem hiding this comment.
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 asimage/png, passinlinesSandboxRefAsBytes, then reach the provider asapplication/octet-stream. - JPEG bytes declared
image/pngorimage/jpgget labeledimage/jpegbut sent asimage/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 |
There was a problem hiding this comment.
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.
| - 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. |
There was a problem hiding this comment.
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>
706d3e4 to
aa86601
Compare
ecb3ae3 to
04415ab
Compare
|
Collapsed into #4635. |
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 tobashor open it again. Now every attachment renders a label with its path, such asAttached 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-stube2e eval relied on anapplication/octet-streampayload 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
attachment-staging.integration.test.tscases 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-stubine2e/fixtures/agent-compaction-regressions: passes (5/5). It fails without the fixture change (nocompaction.completed).EVE_E2E_MODEL=mock pnpm exec eve eval --strict static-tools/read-file-reopens-compacted-image static-tools/to-model-output-content-partsine2e/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, andpnpm docs:checkpass.Checklist
evepackagegit commit --signoff)