fix(eve): fail closed on mangled empty-delivery markers and unattended retry filler - #2386
Open
ace139 wants to merge 2 commits into
Open
fix(eve): fail closed on mangled empty-delivery markers and unattended retry filler#2386ace139 wants to merge 2 commits into
ace139 wants to merge 2 commits into
Conversation
Contributor
|
@ace139 is attempting to deploy a commit to the Vercel Team on Vercel. A member of the Team first needs to authorize it. |
The sentinel matcher was two exact includes() checks, so a model that typed <evedev-empty-delivery/> fell through to the channel's message.completed default and the literal control token was posted into a team channel. Treat a whole message that is nothing but a sentinel-shaped tag as the marker: a corrupted eve* tag name, any casing, `_` separators, inner whitespace, an optional self-closing slash, a closing or paired tag form, attributes, escaped angle brackets, wrapping backticks or a code fence, and trailing sentence punctuation. The tolerant pattern is anchored to the normalized message rather than matched anywhere, because every caller acts on the entire message on a match; a fuzzy anywhere-match would let a reply that merely discusses the marker suppress itself. The exact sentinel keeps its anywhere semantics. Matching happens in two anchored passes — a bracketed lone-tag shape, then the tag body — so the only variable-length quantifier costs O(n) split attempts of O(1) work. The obvious single-pattern spelling puts `\s*` on both sides of an optional `/`, which backtracks quadratically: ~6s on a 120k-char tag, on a matcher that reads raw model output. Signed-off-by: Soumyo <heysoumyo@gmail.com>
When conditional delivery is enabled the recovery nudge appended "Answer now from the tool results above" and only then mentioned the marker. On schedule app-auth runs there is no human to answer, and that framing reliably produced conversational filler — channels received "I now have all the data I need." as the delivered message, contradicting the conditional-delivery contract the same turn injects as a system instruction. Lead with the marker option, name the filler shapes as forbidden, and leave the non-conditional nudge untouched. The note stays a trailing user message: extraSystemNote is how a chained recovery repeats its own call shape, so claiming it here would clobber the unsupported-tool recovery's note and invalidate the cached prompt prefix. Also stop discarding a step's whole response on a marker match unless the marker message is the entire response. resolveAssistantStepText reads only the last assistant message, so a step that replied twice erased the earlier, genuinely delivered reply from durable history along with the marker. Signed-off-by: Soumyo <heysoumyo@gmail.com>
ace139
force-pushed
the
fix/empty-delivery-fail-closed
branch
from
August 21, 2026 17:29
e6bb52b to
b3b7532
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A downstream production agent posted the literal string
<evedev-empty-delivery/>into a team Slack channel: a model mistyped the empty-delivery marker, the exact-match sentinel check missed it, and the control token was delivered as an ordinary message. Investigating that incident surfaced a second, related failure in the empty-response retry path. This PR fixes both — the sentinel now fails closed where it previously failed open — and pins each fix with regression tests.Bug 1 — a mangled marker is delivered as channel text
hasEmptyDeliverySentinelwas two exactincludes()checks. A model that means silence but corrupts the token fell through to the channel'smessage.completeddefault, and the token went out as the message.<eve-empty-delivery/><evedev-empty-delivery/>(the incident)<eve-empty-delivery></eve-empty-delivery>`<evedev-empty-delivery/>`.(fenced, trailing dot)<evedev-empty-delivery/>is corrupted."The fix: a reply that is nothing but a sentinel-shaped tag now counts as the marker — a corrupted
eve*name, closing or paired forms, casing,_separators, inner whitespace, attributes, HTML-escaped brackets, wrapping backticks or a code fence, and trailing sentence punctuation. The exact sentinel keeps its existing match-anywhere behavior.Bug 2 — unattended retries recover into conversational filler
When a scheduled app-auth run (no human present) replied empty, the recovery nudge led with "Answer now from the tool results above." Models complied: "I now have all the data I need." was delivered as the channel message — contradicting the conditional-delivery instruction injected as a system message in that same turn.
The fix: with conditional delivery enabled, the nudge leads with the marker option, offers answering second, and names filler as forbidden. It is unchanged when conditional delivery is off.
Also fixed while here:
rawResponseMessagesis now cleared only when the step's response contains a single assistant message.resolveAssistantStepTextreads only the last assistant message, so a step that replied twice used to erase the earlier, genuinely delivered reply from durable history along with the marker.Design decisions worth review attention
\s*on both sides of an optional/— backtracks quadratically (~6s on a 120k-character tag). Two anchored passes (a[^<>]*tag shape and a lookahead-terminated body) remove the ambiguity structurally. Tests pin the linearity, not just the behavior.<eve-empty-delivery>(missing slash) was previously asserted as not the sentinel; treating it as one is the point of this change, and the test carries a comment saying so.usermessage. The in-code comment documents why:extraSystemNoteis owned by chained tool-recovery for its own call shape, and a system prepend would invalidate the provider's cached prompt prefix.Known limitations (called out in code rather than papered over)
stepOutput.Validation
Checklist
CONTRIBUTING.mdevepackagegit commit --signoff)The marker is an internal control token with no published documentation, so the changesets are the only user-facing prose this needs. Closes #2388, which reports both bugs with the observed production shapes.
Diff size
Docs — 2 files ·
+10 / -0Two patch changesets, one per user-visible behavior change.
Implementation — 2 files ·
+137 / -13The matcher accounts for most of it. Roughly half of
empty-delivery.tsis comment explaining why the tolerant arm is anchored while the exact sentinel is not, and why the pattern is spelled to avoid catastrophic backtracking — both are non-obvious constraints that a future simplification would otherwise undo. The tool-loop change is small: the nudge text and the single-assistant-message condition on discarding a response.Tests — 2 files ·
+169 / -3Larger than the fix because the interesting property is a boundary, not a case: tables enumerate mangled spellings that must be silenced against near-misses that must still be delivered. The linearity assertions are separate, since a matcher this permissive is only safe if it cannot be made to backtrack.