Repository navigation
Private-audience session content is visible in Vercel Agent Runs via Workflow-persisted payloads (0.58.1) #3634
Description
Summary
On a Vercel preview deployment of an eve 0.58.1 app, a session whose custom channel classifies its audience as private shows its full model input (the user message plus the substituted dynamic system instructions) and its full model output in Vercel Observability → Agent Runs, even though eve's OpenTelemetry capture for that session is metadata-only and the run carries $eve.is_trace_content_visible: false.
Expected
docs/guides/instrumentation/overview.md: "In Vercel's preview and production deployments, eve records inputs and outputs only forpublicsessions."- CHANGELOG 0.44.1 (85b2dc8): content-denied Workflow runs "carry a metadata marker … so dashboards can exclude them."
So a private session's content should not be viewable in Agent Runs.
Observed
A one-shot task-mode session created from a custom channel route with from(id).send(message, { auth, mode: "task", state, title }), where the channel defines audience: () => "private", running on a preview deployment (VERCEL_ENV=preview, EVE_DEV unset, no EVE_TRACES_CONTENT): the Agent Runs run view renders the input text, the substituted system-prompt text and the model's JSON output.
Analysis against the installed 0.58.1 source
shared/instrumentation-content.js→shouldCaptureInstrumentationContent:audience === "public" || environment === "development".internal/application/dev-environment.js→resolveInstrumentationEnvironment:EVE_DEV=1orVERCEL_ENV=development→development;VERCEL_ENV=preview→preview; elseproduction. So on a preview the trace path is metadata-only for a private session, which a reproduction confirms (below).- The content is persisted outside the trace path:
execution/workflow-runtime.jscreateSessionstarts the Workflow run with{ kind: "initial", input, serializedContext };execution/session/turn-step.jsandturn-step-result.jsreturnoutput,serializedContext(includingeve.sessionDynamicInstructionswith the substituted system prompt) andsessionState.snapshot.session.history;execution/eve-workflow-attributes.jssets$eve.is_trace_content_visible: falsebut nothing redacts the Workflow initial input, step outputs, durable stream or checkpoints. An explicit instrumentationtracePolicywithrecordInputs/recordOutputsfalse does not change what is persisted either.
Reproduction (credential-free)
- Scaffold an app with a mock model (
ai/testMockLanguageModelV3or similar) and a custom channel:with dynamic instructions that interpolate a distinctive marker string.export default defineChannel({ audience: () => "private", state: null, routes: [POST("/run", async (req, { from }) => { const { text } = await req.json(); const s = await from(`job:${crypto.randomUUID()}`).send(text, { auth: <service principal>, mode: "task", state: null, title: "job" }); return Response.json({ id: s.id }); })], });
- Build without the Vercel preset and start with
eve start,VERCEL_ENV=preview,EVE_DEVunset,EVE_TRACES_CONTENTunset; enable the managed instrumentation provider layout with a fake platform exporter. - POST a message containing a second marker; let the turn complete.
- Inspect (a) the exported spans and (b) the local Workflow storage for the run.
Result: (a) ~95 spans, the activation span carries audience private, input/output capture false, and no marker appears in any span; a public control run captures all markers (harness sanity check). (b) The Workflow step output and checkpoint contain the input marker, the system-instruction marker and the output. The Workflow run's metadata carries $eve.is_trace_content_visible: false. Local Workflow storage is zstd+devalue with executionContext.encryption: false.
Impact
Any eve 0.58.1 app on Vercel exposes private conversation content (user input, dynamic system instructions, model output) to everyone with dashboard access to Agent Runs, regardless of the channel's audience classification. The documented audience gate protects traces only.
Ask
Either
- (a) eve omits or redacts non-public session content from the Workflow-persisted payloads (initial input,
serializedContextdynamic instructions, history, step outputs) when the trace-content decision is false, or - (b) Agent Runs hides run payloads when
$eve.is_trace_content_visibleisfalse.
If (b) is the intended contract, a note in the instrumentation guide that Workflow payloads are governed by the dashboard, not by the audience gate, would help operators assess exposure.
Environment
eve 0.58.1, ai 7.0.105, @ai-sdk/gateway 4.0.85, Node 24, Vercel Fluid Compute, framework preset eve.
Activity
roboeve commentedon Sep 22, 2026
Confirmed the durable-payload portion on current
origin/main(505601b3f448a20aecc133e5d132d70c2ec3ee35, eve0.60.0).I ran a local Workflow SDK integration reproduction with
VERCEL_ENV=preview,EVE_DEVunset,EVE_TRACES_CONTENTunset, aprivateconversation context, and distinct input/system/output markers. The persisted workflow input contained the input and durableeve.sessionDynamicInstructionsmarkers; the hydrated persistedturnStepresult contained those markers and the model output, while the stored run attribute remained$eve.is_trace_content_visible: "false".I also ran the focused OTel policy tests: the private trace path redacts content from exported spans. The evidence therefore confirms that the trace-content decision and durable Workflow payload persistence are separate on the current branch.
Not yet verified here: a real Vercel preview deployment and the Agent Runs UI/service behavior. The local reproduction uses the built-in HTTP adapter with the resulting private conversation context because the in-memory runtime cannot rehydrate an undeclared custom channel; it does not establish whether the hosted dashboard currently honors the false marker when rendering payloads.
No duplicate with the same marker/symptom was found in open or closed issue searches. The next smallest check is an Agent Runs service/UI reproduction against a preview run with this false marker; that determines whether the fix belongs in dashboard filtering or in eve's durable-payload contract.
pcfds commentedon Oct 19, 2026
A data point from production. We hit the same tension in our own product with driver conversations that can include health information (sensitive data under Argentine privacy law).
What worked for us was not deciding at record time by audience but at read time by permission:
For Agent Runs this would mean viewer-level access to content (a project role or an explicit permission) instead of an audience ceiling applied when spans are exported, so teams don't have to choose between the span tree and the content.