Repository navigation
fix(prose): the turn's receipt names what kept its plain speech private - #953
Open
nissa-seru wants to merge 3 commits into
Open
nissa-seru wants to merge 3 commits into
nissa-seru wants to merge 3 commits into
Conversation
added 3 commits
October 30, 2026 05:15
…te (anima-research#317) The [delivered] receipt counted the plain-speech segments its hold paths keep private in one number, and named every possible cause: "kept private (skip_reply, a drafts call or a private think)". Each place that counts one knows its cause, so the turn's routing now counts them by cause, and the receipt names the cause that applied: "1 plain-speech segment(s) kept private (skip_reply)", or, with two or more, each with its count in the order skip_reply, >>>skip_reply, a drafts call, a private think: "2 plain-speech segment(s) kept private (1 by skip_reply, 1 by a private think)". - holdSilencedProse counts a 'private' round's segments as skip_reply's, a same-round private think's as the think's, and a drafts round's (the 'kept' cause without a think) as the drafts call's. A skip_reply round that also holds a private think counts once, under skip_reply. - Hybrid prose held after a >>>skip_reply (routeSilencedHybrid and deliverHybridProse) counts as >>>skip_reply's, and a drafts round's undeliberate parts as the drafts call's. - A 'private' hold is labelled skip_reply. A silent request's own turns write no receipt, and its held retry merged into a start that isn't silent doesn't bring its 'private' there: a silent start opens no logical turn, so that start opens a new one, which takes no carry. A code_execution round withheld because its turn moved on before its script calls returned no longer adds to the turn's suppressed count; its log line stays. No route that withholds one writes a receipt that reads the count: a new logical turn takes a fresh TurnRouting, a continuation of the same turn starts only once the round's tool results are in, and the stream-end withhold runs after any receipt of a turn a tool ended. The withhold's doc no longer says a later stream's receipt counts it. With that, only disabled routing feeds the suppressed count: an agent's proseRouting "disabled", or a turn that suppresses prose, which writes no receipt. So a receipt's suppressed line is always the disabled wording, which reads as before. The doc comments on TurnRouting.suppressed and TurnRouting.keptPrivate and on recordProseSuppression go, as doc comments on internals do. Tests: anima-research#928's case reads "(skip_reply)" and a private think's "(a private think)"; two causes in one turn each show with their counts, and a hybrid turn with all four shows them in order, one with a count of two; the retry test's receipt names "(>>>skip_reply)"; a skip_reply round with a private think counts once; the drafts-round and >>>skip_reply receipts name their causes; the three withheld-round tests now find the suppressed count unchanged; routing literals in tests take the new shape. Disabled mode's receipt tests are unchanged and pass.
test/present-while-acting.test.ts conflicted in two tests that main removed in c78a573 ("a silent start that throws leaves an open prose turn alone" and "a silent turn's over-budget boundary leaves no arrival on an open prose turn", both building a state the framework doesn't enter). This branch had touched them only to change their routing literal's keptPrivate from 0 to {}, so main's removal is taken.
…-research#317) agent-framework 0.24.0's changelog states that a withheld round's segments are counted as suppressed in the turn's delivery receipt, so taking that count out would change a documented rule and can't go in this pull request. The withhold's recordProseSuppression call, the receipt's non-disabled "suppressed" line, the comments that describe them and code-execution's withheld assertion are as main has them, and the changelog fragment no longer mentions the withheld round. What remains is the receipt naming the cause that kept plain speech private.
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.
A turn's
[delivered]receipt now names what kept its plain speech private, where it listed every possible cause. With one cause it names that one:1 plain-speech segment(s) kept private (skip_reply), or(>>>skip_reply),(a drafts call)or(a private think). With two or more it gives each with its count, in that order:2 plain-speech segment(s) kept private (1 by skip_reply, 1 by a private think).@antra-tess, we're asking you to review this before it's merged, since it changes what an agent reads in its turn's receipt.
Closes #317.
Problem
At
a64cfc010f, the receipt counts the plain-speech segments kept private in one number, and gives all three possible causes for it:${kept} plain-speech segment(s) kept private (skip_reply, a drafts call or a private think)(src/framework.ts:21092).main's own tests assert that wording for a round that writes prose and callsskip_reply(test/prose-drafts.test.ts:678–:686), for a private think beside a send (:694), and for a drafts round (:1439). So a resident whose wordsskip_replykept private reads two causes that didn't apply.#928 reports that case: a resident writes a short reply and calls
skip_replyin the same round, and nothing is posted. Run ata64cfc010f, a round with the prose "ok, thanks" andskip_replygot the receipt the test at:678–:686asserts:[delivered] nothing — 1 plain-speech segment(s) kept private (skip_reply, a drafts call or a private think).Changes
Line numbers are this head's.
TurnRouting.keptPrivateis now a count per cause, fromKEPT_PRIVATE_CAUSES(src/framework.ts:1541), whose order is the receipt's.holdSilencedProse(:20066) counts a round with the'private'silence thatskip_replygives under skip_reply, a same-round private think's segments under a private think, and a drafts round's under a drafts call (:20087). A round that callsskip_replyand holds a private think counts once, under skip_reply.>>>skip_replyline counts under>>>skip_reply, inrouteSilencedHybrid(:20192) anddeliverHybridEnvelope(:22769). A drafts round's undeliberate parts there count under a drafts call (:20200).:21102–:21105) names the one cause, or each cause with its count.mainhas it.N plain-speech segment(s) suppressed(:21109) names no cause. UnderproseRouting: "disabled"the receipt words it askept in the transcript (proseRouting=disabled — …)instead (:21108). Otherwise its count comes only from acode_executionround withheld because its turn moved on before its script calls returned (:25432), as 0.24.0's changelog entry says (CHANGELOG.md:4612–:4616). Not verified below says what we know of a receipt that shows it.TurnRouting.keptPrivategoes.changelog.d/317-receipt-names-why.changed.md.What counts as one segment is unchanged.
holdSilencedProsecounts prose runs, and the hybrid paths count envelopes.Open pull requests
By
git merge-treeat 22:15 UTC on October 30, this branch merges cleanly intomainata64cfc010f. Of the open pull requests that merge cleanly intoa64cfc010f, four conflict with this branch: #940 and #931 insrc/framework.ts, #844 intest/present-while-acting.test.ts, and #190 insrc/framework.tsandtest/explicit-prose-routing.test.ts.Tests
One run, from a clean checkout of this head, on Linux with Node 24.22.2 and npm 11.19.1. It deleted
node_modulesandpackage-lock.json, rannpm install --no-audit --no-fundandnpx tsc --noEmit, thennpm run buildandnpm run pretest, then each of the six test files this change touches alone, withnode --import ./dist/test/helpers/force-exit-blocking-stdout.js --test --test-force-exit. Then it put backa64cfc010f'ssrc/framework.ts, the only file undersrc/this change touches, and built and ran the same six files again.npm ls --depth=0printed@animalabs/chronicle0.5.1,@animalabs/context-manager0.24.2,@animalabs/mcpl-core0.4.0,@animalabs/membrane0.8.0,@babel/parser7.29.12,@modelcontextprotocol/client2.4.0,@modelcontextprotocol/server2.4.0,@types/node22.20.5,@types/ws8.18.2,chokidar4.0.3,discord.js14.28.0,tsx4.23.15,typescript7.0.2 andws8.22.0. This repository commits no root lockfile, so these are the versions a fresh install chose on October 30.tscreported no errors, and every test in the six files passed:prose-drafts257,explicit-prose-routing120,tool-result-guard156,code-execution99,present-while-acting93 andsend-into-closed-channel24.a64cfc010f'ssrc/framework.ts: 12 failed.prose-drafts, 9. Six assert a receipt that now names its cause, among them "deliberate privacy is never drafted: skip_reply and a same-round private think". Three are new: "a turn whose plain speech two causes kept private names each with its count", "hybrid mode: a turn whose plain speech all four causes kept private names each with its count, in order", and "a skip_reply round with a private think in it counts its plain speech once, as skip_reply's".explicit-prose-routing, 2. "hybrid: after >>>skip_reply, the next unprefixed envelope stays in the context and counts as kept private", and "hybrid: a retried turn's text waits for the replaced stream's late deliveries, and follows what they set", whose receipt now names(>>>skip_reply).tool-result-guard, 1. "a fresh turn starts new routing state in every mode, and leaves the earlier turn's as it was", for the per-cause count's empty start.code-execution,present-while-actingandsend-into-closed-channelpassed.Not verified
Line numbers are this head's.
48f26ce56c, an earliermain, each with a probe test added, neither withheld the round at all: each round was routed when itscode_executioncall answered.'private'hold.holdSilencedProse's doc comment names "a silent turn" among the deliberate silences (src/framework.ts:20056), and this change labels every'private'hold skip_reply. A probe with48f26ce56c'ssrc/, through a silent heartbeat tick whose held retry merged into a start that wasn't silent, found that the merged start ran neither silent nor'private'. This change doesn't touch that path. No test covers a receipt after a silent request's hold.mainnor this change counts. Two kinds::25354–:25357logs as not routed, with no count;>>>skip_replyenvelope, whichdeliverHybridEnvelopelogs as kept in context and returns from with no count (:22705–:22712), as the comment attest/prose-drafts.test.ts:2833says.changelog.d/317-receipt-names-why.changed.md.Nigel-2405 made this change, and Oscar-1808 and Ada-1017 made the calls on it. Ada-1017 wrote #317. Alfred-2570 read the change word for word, its merge with
mainincluded, and our internal review read its first version, then its fixes. Langston-2479 wrote this description.