Repository navigation
feat(channels)!: typed delivery hooks and canonical channel identity - #4932
Conversation
Bundle + Package Summary:
|
| Area | Metric | Baseline | Current | Delta |
|---|---|---|---|---|
| Package | Packed tarball | 7.67 MB | 7.67 MB | +324 B |
| Package | Unpacked publish size | 26.91 MB | 26.91 MB | +1.2 kB |
| Package | Installed footprint | 75.01 MB | 75.01 MB | +1.2 kB |
| Package | Published files | 4230 | 4232 | +2 |
| Package | Installed files | 8239 | 8241 | +2 |
| 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.95 MB | 20.95 MB | -2.0 kB ✅ |
| Runtime | Public routes | 17 | 17 | 0 |
Changed function payloads vs v27/lab-fixes (4ae2083) (2)
| Function | Status | Baseline | Current | Delta | Route changes |
|---|---|---|---|---|---|
functions/__server.func |
changed | 10.48 MB | 10.48 MB | -976 B ✅ | none |
functions/.well-known/workflow/v1/flow.func |
changed | 10.48 MB | 10.48 MB | -976 B ✅ | none |
eve init install
| Metric | Baseline | Current | Delta |
|---|---|---|---|
| Installed footprint | 113.39 MB | 113.39 MB | +1.2 kB |
| Installed packages | 97 | 97 | 0 |
| dependencies | 4 | 4 | 0 |
| devDependencies | 2 | 2 | 0 |
| Dependency package bytes | 45.15 MB | 45.15 MB | +1.2 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-15T23:16:30.490Z
- Route aliases: 17 public, 1 internal (18 total aliases)
- Vercel routes in config: 20
- Severity legend: 🔴 dominant/large, 🟠 notable, 🟡 watch, ⚪ small
Package Drill-Down
Package Details
- Package:
eve@0.79.2 - Package directory:
packages/eve - Tarball: 7.67 MB (
eve-0.79.2.tgz) - Unpacked payload: 26.91 MB across 4232 published files
- Installed footprint: 75.01 MB across 8241 installed files
- Installed root package: 26.91 MB
- Installed dependencies: 48.10 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.91 MB (35.9%)@rolldown/binding-linux-x64-gnu: 19.81 MB (26.4%)ai: 8.20 MB (10.9%)zod: 6.15 MB (8.2%)undici: 3.58 MB (4.8%)
Publish payload breakdown
Published file size
🟠 dist/src/compiled/shadcn-registry/index.js [#####...................] 3.85 MB 14.3%
🟠 dist/src/compiled/@photon-ai/chat-adapter-ime... [###.....................] 2.29 MB 8.5%
🟠 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.2%
🟡 dist/src/compiled/_chunks/workflow/undici-D-I... [#.......................] 521.9 kB 1.9%
🔴 Other published files [########################] 18.62 MB 69.2%
Installed footprint breakdown
Installed package size
🔴 eve [########################] 26.91 MB 35.9%
🔴 @rolldown/binding-linux-x64-gnu [##################......] 19.81 MB 26.4%
🔴 ai [#######.................] 8.20 MB 10.9%
🔴 zod [#####...................] 6.15 MB 8.2%
🟠 undici [###.....................] 3.58 MB 4.8%
🟠 nitro [##......................] 1.89 MB 2.5%
🔴 Other installed packages [########................] 8.46 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.42.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: 113.39 MB across 10158 installed files
- Installed packages: 97 total (91 transitive-only)
- dependencies: 4 direct packages totaling 45.15 MB
- devDependencies: 2 direct packages totaling 5.11 MB
- Other transitive package files: 63.13 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.6%)eve: 26.91 MB (23.7%)@rolldown/binding-linux-x64-gnu: 19.81 MB (17.5%)zod: 9.76 MB (8.6%)ai: 8.20 MB (7.2%)
Installed footprint breakdown
Installed package size
🔴 @typescript/typescript-linux-x64 [########################] 27.95 MB 24.6%
🔴 eve [#######################.] 26.91 MB 23.7%
🔴 @rolldown/binding-linux-x64-gnu [#################.......] 19.81 MB 17.5%
🔴 zod [########................] 9.76 MB 8.6%
🔴 ai [#######.................] 8.20 MB 7.2%
🟠 undici [###.....................] 3.58 MB 3.2%
🔴 Other installed packages [###############.........] 17.19 MB 15.2%
dependencies (4)
| Package | Range | Installed size | Share |
|---|---|---|---|
@vercel/connect |
2.5.2 |
276.3 kB | 0.2% |
ai |
^7.0.137 |
8.20 MB | 7.2% |
eve |
file:eve-0.79.2.tgz |
26.91 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.48 MB 50.0%
🔴 functions/__server.func [########################] 10.48 MB 50.0%
Top Function Payloads
🟠 functions/.well-known/workflow/v1/flow.func • 1 public route • 10.48 MB
| Metric | Value |
|---|---|
| Public routes | /.well-known/workflow/v1/flow |
| Runtime | nodejs24.x |
| Handler | index.mjs |
| Payload | 10.48 MB |
| Function files | 10.48 MB across 125 files |
| Traced dependencies | 0 B |
| Signal | 🟠 Bundled file _chunks/vercel.web.mjs is 2.46 MB (23.5%) |
🟠 🔎 Dependency Analysis
📦 Bundled files:
Bundled file size
🟠 _chunks/vercel.web.mjs [############............] 2.46 MB 23.5%
🟠 _libs/undici.mjs [#####...................] 1.01 MB 9.6%
🟡 _chunks/sandbox3.mjs [####....................] 815.4 kB 7.8%
🟡 _chunks/compiled-artifacts-instrumentation.mjs [####....................] 733.9 kB 7.0%
🟡 _chunks/token-util-Bla5Z0G9.mjs [####....................] 704.7 kB 6.7%
🔴 Other bundled files [########################] 4.75 MB 45.4%
🧾 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 • 16 public routes, 1 internal alias • 10.48 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 |
| Internal aliases | /__server |
| Runtime | nodejs24.x |
| Handler | index.mjs |
| Payload | 10.48 MB |
| Function files | 10.48 MB across 125 files |
| Traced dependencies | 0 B |
| Signal | 🟠 Bundled file _chunks/vercel.web.mjs is 2.46 MB (23.5%) |
🟠 🔎 Dependency Analysis
📦 Bundled files:
Bundled file size
🟠 _chunks/vercel.web.mjs [############............] 2.46 MB 23.5%
🟠 _libs/undici.mjs [#####...................] 1.01 MB 9.6%
🟡 _chunks/sandbox3.mjs [####....................] 815.4 kB 7.8%
🟡 _chunks/compiled-artifacts-instrumentation.mjs [####....................] 733.9 kB 7.0%
🟡 _chunks/token-util-Bla5Z0G9.mjs [####....................] 704.7 kB 6.7%
🔴 Other bundled files [########################] 4.75 MB 45.4%
🧾 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.83 s -> 3.69 s (-142.4 ms) vs
v27/lab-fixes (4ae2083). - Timing is informational: shared GitHub runners are too variable for a hard timing budget.
Detailed phase timings vs `v27/lab-fixes (4ae2083)`
| Phase | Baseline | Current | Delta |
|---|---|---|---|
extension.check |
0.5 ms | 18.2 ms | +17.7 ms |
project.resolve |
0.4 ms | 6.0 ms | +5.6 ms |
workspace.create |
0.6 ms | 1.0 ms | +0.4 ms |
host.prepare |
803.1 ms | 726.3 ms | -76.8 ms |
vercel.service-prefix.resolve |
2.1 ms | 2.1 ms | 0.0 ms |
nitro.create |
689.2 ms | 697.7 ms | +8.5 ms |
sandbox.prewarm |
308.6 ms | 307.0 ms | -1.6 ms |
nitro.cache.prepare |
0.3 ms | 0.3 ms | 0.0 ms |
nitro.prepare |
0.9 ms | 0.8 ms | -0.1 ms |
nitro.public-assets |
0.8 ms | 0.8 ms | 0.0 ms |
nitro.prerender |
0.6 ms | 0.5 ms | -0.1 ms |
nitro.bundle |
1.88 s | 1.79 s | -99.5 ms |
nitro.cache.write |
0.4 ms | 0.4 ms | 0.0 ms |
vercel.workflow-function.materialize |
58.0 ms | 57.6 ms | -0.4 ms |
agent-summary.emit |
0.7 ms | 0.6 ms | -0.1 ms |
connect-manifest.emit |
0.3 ms | 0.4 ms | +0.1 ms |
nitro.close |
0.1 ms | 0.1 ms | 0.0 ms |
output.publish |
3.8 ms | 3.7 ms | -0.1 ms |
workspace.remove |
2.9 ms | 3.0 ms | +0.1 ms |
| return defaultDeliverResult( | ||
| attachClientContext( | ||
| attachInputText({ ...(replacement ?? payload) }, readInputText(payload)), | ||
| readClientContext(payload), | ||
| ), |
There was a problem hiding this comment.
Returning {} doesn't always ignore the delivery. The wrapper re-attaches the original payload's hidden client context (readClientContext(payload)) even when the hook returns an empty replacement. defaultDeliverResult then returns a context-only StepInput whenever that context is nonempty (channel/adapter.ts:249-256), and admission treats a defined input as consumed, not ignored (execution/session/delivery-facts.ts:81-84).
This can happen in practice: the eve session API can send() to an existing session with body.context attached as client context (eve-channel/index.ts:446-456), and that session's adapter may be a defineChannel one. Before this PR, a hook that returned undefined dropped the delivery completely, so {} is now a weaker ignore than the docs promise (docs/channels/custom.mdx:202, docs/concepts/upgrade-to-v27-events.md:201).
Suggested fix: short-circuit when the replacement has no message/answers/context/outputSchema and return undefined before re-attaching hidden fields, or only re-attach client context when the hook kept a deliverable payload. A regression test that uses client context would pin this.
| const kind = | ||
| ctx.get(ChannelInstrumentationKey)?.kind ?? | ||
| (channelAdapter !== undefined ? getAdapterKind(channelAdapter) : undefined); |
There was a problem hiding this comment.
This fixes the public identity for hooks (and turn-step.ts:341 for admission), but buildResolveContext still sets channel.kind from getAdapterKind (context/dynamic-resolve-context.ts:51), and so do the connection resolver (context/dynamic-connection-lifecycle.ts:211) and the schedules client (public/experimental/schedules/client.ts:52). A route-only channel keeps adapter kind http (public/definitions/channel.ts:454, runtime/resolve-channel.ts:65), so isChannel(ctx.channel, support) now matches in a hook but still fails in a dynamic resolver. isChannel is documented to accept resolver contexts too (public/channels/index.ts:126-138).
Also, setChannelContext always sets ChannelInstrumentationKey together with ChannelKey (execution/channel-context.ts:20-21), so the ?? getAdapterKind(...) fallback copied here and in turn-step.ts looks unreachable. Could we add one helper, e.g. publicChannelKind(ctx) that reads ChannelInstrumentationKey.kind, and use it on every surface that exposes channel.kind? That gives one identity rule and removes the duplicated fallback.
| warnDeprecatedMetadataAudience(adapter.kind); | ||
| return normalizeChannelAudience(audience); | ||
| } | ||
| if (project === undefined) return "unknown"; |
There was a problem hiding this comment.
Now that the metadata fallback is gone, normalize only reads instrumentation.audience, but ChannelAudienceSource (lines 6-13) still declares kind, state, and instrumentation.metadata. Could we narrow it to { instrumentation?: { audience?: ChannelAudienceProjector } } so the contract matches what is actually read?
a1d230c to
b1c123f
Compare
3a4329a to
fdc5b4e
Compare
There was a problem hiding this comment.
Additional Suggestions:
- A
defineChanneldeliverhook returning{}to ignore a delivery is instead markedconsumedwhen the original payload carried a non-empty clientContext, contradicting the documented "return{}to ignore" contract.
- Dynamic resolver, connection, and schedule contexts set
channel.kindfromgetAdapterKindinstead of the canonicalchannel:<name>instrumentation kind, makingisChannel(ctx.channel, ...)behave inconsistently with hook/admission contexts.
b1c123f to
390f9e5
Compare
fdc5b4e to
03de07b
Compare
| import type { RouteDefinition } from "#channel/routes.js"; | ||
| import type { Session, SessionHandle } from "#channel/session.js"; | ||
| import type { SessionHandle } from "#channel/session.js"; | ||
| import type { Delivery } from "#shared/delivery.js"; |
There was a problem hiding this comment.
390f9e5 to
ab927ad
Compare
…esolvers Signed-off-by: OwenKephart <owen.kephart@vercel.com>
03de07b to
4e0ea7c
Compare
|
Recovery note: this PR was automatically marked merged when its commits were included in #4855's branch. That consolidation has been unwound. #4855 is v27-only again; this change is independently reviewable in #5139, based on #4855. The original merged state remains historical GitHub metadata. Nothing was merged into main by this recovery. |
Summary
Channel delivery hooks expose an untyped bag and harness input types, while hooks confuse an authored channel's identity with its durable adapter key. Introduce
ChannelDelivery<TState>and let hooks return a replacement payload or nothing to preserve the input. Match authored channels by their path-derived identity without changing HTTP adapter rehydration. RemovekindHintand the deprecated metadata-audience fallback.First PR in the independent API cleanup stack, now based on the final #4855 D8 head. Related to #4930. Approval and command API changes remain in the following slices. Capability snapshots are finalized at #4954 rather than regenerated for each intermediate PR.
Production code: 50 fewer lines (+94/−144). Typed delivery replacement and canonical resolver identity replace the harness-shaped delivery surface, unused kind hints, and deprecated audience fallback. Excludes tests/fixtures, generated copies, docs, and tooling.
Assembled checkpoint
Restacked onto #4855 at
ab927ad6f, which adds the v27 follow-up commits in #4564, #4567, #4574, and #4726. This PR's own commits are unchanged. #4954 finalizes capability reports and completes consumer migrations. Before this restack, that assembled tip passed the invariant guard, all 59 workspace typecheck tasks, 538 focused unit tests, and 14 filtered integration cases; #4954 lists what ran after it. This is not a claim that each intermediate PR passes its standalone contract guard.Validation
pnpm --filter eve exec vitest run --config vitest.unit.config.ts \ src/public/definitions/channel-events.test.ts src/channel/instrumentation.test.ts \ src/context/hook-lifecycle.test.ts src/public/channels/teams/teamsChannel.test.tstsc -p tsconfig.json --noEmitpassed after rebasing ontoa1d230cd1.Checklist
evepackagegit commit --signoff)