You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
eveChannel({ onMessage }) has no way to rewrite/redact inbound text — and the documented workaround (defineChannel) means giving up the CLI entirely
#2828
I need to redact PII (emails, phone numbers, account numbers) from inbound user text before it's dispatched to the model and written into durable session history. The default channel — the one every out-of-the-box client (CLI, useEveAgent(), curl, any generic HTTP client) talks to — gives no supported way to do this.
No text field, and unlike other channels' equivalents, not even nullable — there's no "handle this myself and drop the original" escape hatch at all. onMessage can steer auth and prepend context, but the original inbound text is always the one that gets dispatched and persisted. There's structurally nowhere in this contract to put a redaction step. Checked this against both 0.27.13 and 0.47.6 — identical gap in both, so it's not a version-lag issue.
The documented workaround, and why it doesn't actually solve this
The docs point at replacing agent/channels/eve.ts with a defineChannel(...) custom channel — redact in a hand-authored route, then call from(...).send(...) yourself.
I built this. It works: I stood up a custom route, redact-then-.send() inside it, and pointed our own UI client at that endpoint. Masking is confirmed working there.
But this is not a fix for the default channel — it's a full replacement of it. defineChannel(...) only exposes the routes you explicitly declare; there is no partial-override mode. Concretely, in my setup:
Our own UI → hits the custom route → masked, works correctly.
The CLI → still goes through the default agent/channels/eve.ts route (POST /eve/v1/session etc.) → completely unmasked, because the CLI has no way to know about or use the custom route, and the custom channel doesn't touch /eve/v1 at all.
So the redaction guarantee only holds for exactly the one client I built a bespoke endpoint for. Any other consumer of this agent — the CLI being the most obvious one, since it's the framework's own first-party client — bypasses redaction entirely, silently, with no error or warning that it's happening.
To close that gap the "supported" way, I'd have to either reimplement the entire documented /eve/v1 contract by hand inside my custom channel — session creation, follow-ups, NDJSON streaming, cancel/clear/compact/reset, error shapes, x-eve-session-id, HITL input responses, everything — well enough that the CLI can't tell the difference, just to get one onMessage-shaped redaction step in front of it, or accept that redaction is UI-only and the CLI (and any future first-party client) is a permanent hole. Neither feels like a reasonable tradeoff for what should be a small, local change to one request's text before dispatch.
Slack, as a side note
Worth mentioning only because it shows the gap isn't universal: slackChannel({ onMessage/onAppMention/onDirectMessage })'s context does carry a real dispatch primitive (SlackSessionOperations.send), so await ctx.send(maskText(text)); return null; works there without giving up any of Slack's built-in machinery (signature verification, threading, HITL buttons, etc.) — confirmed working end-to-end against a live workspace. Not the ask here, just evidence that "intercept and rewrite before dispatch, without replacing the channel" is achievable elsewhere in the framework — it's just missing specifically on the default HTTP channel, the one every generic client depends on.
Discussion
I can see a couple of shapes this could take — curious what others think, or whether there's a supported pattern I'm missing entirely:
A dispatch primitive on EveMessageContext mirroring SlackSessionOperations, paired with a nullable return, so a handler can dispatch its own rewritten message and suppress the original.
A direct rewrite path on onMessage's return value (e.g. { message: string | UserContent, auth, ... }), which feels like it might fit more naturally here since the default channel's response is the caller's own request/response cycle, not a separate async delivery the way Slack's is.
Something else entirely — has anyone else hit this and found a different way through it that doesn't mean reimplementing /eve/v1?
Has anyone building on eve needed inbound redaction/transformation (PII, profanity, normalization, whatever) on the default channel specifically, and if so, what did you end up doing?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
I need to redact PII (emails, phone numbers, account numbers) from inbound user text before it's dispatched to the model and written into durable session history. The default channel — the one every out-of-the-box client (CLI,
useEveAgent(),curl, any generic HTTP client) talks to — gives no supported way to do this.eveChannel({ onMessage })'s handler context is:caller,request,sessionId— nothing else. No dispatch primitive, no way to substitute the message. The return type doesn't help either:No text field, and unlike other channels' equivalents, not even nullable — there's no "handle this myself and drop the original" escape hatch at all.
onMessagecan steer auth and prepend context, but the original inbound text is always the one that gets dispatched and persisted. There's structurally nowhere in this contract to put a redaction step. Checked this against both0.27.13and0.47.6— identical gap in both, so it's not a version-lag issue.The documented workaround, and why it doesn't actually solve this
The docs point at replacing
agent/channels/eve.tswith adefineChannel(...)custom channel — redact in a hand-authored route, then callfrom(...).send(...)yourself.I built this. It works: I stood up a custom route, redact-then-
.send()inside it, and pointed our own UI client at that endpoint. Masking is confirmed working there.But this is not a fix for the default channel — it's a full replacement of it.
defineChannel(...)only exposes the routes you explicitly declare; there is no partial-override mode. Concretely, in my setup:agent/channels/eve.tsroute (POST /eve/v1/sessionetc.) → completely unmasked, because the CLI has no way to know about or use the custom route, and the custom channel doesn't touch/eve/v1at all.So the redaction guarantee only holds for exactly the one client I built a bespoke endpoint for. Any other consumer of this agent — the CLI being the most obvious one, since it's the framework's own first-party client — bypasses redaction entirely, silently, with no error or warning that it's happening.
To close that gap the "supported" way, I'd have to either reimplement the entire documented
/eve/v1contract by hand inside my custom channel — session creation, follow-ups, NDJSON streaming, cancel/clear/compact/reset, error shapes,x-eve-session-id, HITL input responses, everything — well enough that the CLI can't tell the difference, just to get oneonMessage-shaped redaction step in front of it, or accept that redaction is UI-only and the CLI (and any future first-party client) is a permanent hole. Neither feels like a reasonable tradeoff for what should be a small, local change to one request's text before dispatch.Slack, as a side note
Worth mentioning only because it shows the gap isn't universal:
slackChannel({ onMessage/onAppMention/onDirectMessage })'s context does carry a real dispatch primitive (SlackSessionOperations.send), soawait ctx.send(maskText(text)); return null;works there without giving up any of Slack's built-in machinery (signature verification, threading, HITL buttons, etc.) — confirmed working end-to-end against a live workspace. Not the ask here, just evidence that "intercept and rewrite before dispatch, without replacing the channel" is achievable elsewhere in the framework — it's just missing specifically on the default HTTP channel, the one every generic client depends on.Discussion
I can see a couple of shapes this could take — curious what others think, or whether there's a supported pattern I'm missing entirely:
EveMessageContextmirroringSlackSessionOperations, paired with a nullable return, so a handler can dispatch its own rewritten message and suppress the original.onMessage's return value (e.g.{ message: string | UserContent, auth, ... }), which feels like it might fit more naturally here since the default channel's response is the caller's own request/response cycle, not a separate async delivery the way Slack's is./eve/v1?Has anyone building on eve needed inbound redaction/transformation (PII, profanity, normalization, whatever) on the default channel specifically, and if so, what did you end up doing?
All reactions