Repository navigation
fix(projection): a mid-turn message's media count toward the physical-window restart - #581
Merged
nissa-seru merged 1 commit intoOct 19, 2026
Conversation
…-window restart estimateAppendedRoundTokens prices the blocks a continuation round appends without a compile, for issue anima-research#92's physical-window projection. It priced only a mid-turn message's text, though on membrane's native tool path the message rides into the next round with its stored content as it is (provideToolResults' injectedMessages), images, documents, audio and video included. So a round that brought in photos or audio added only the message's envelope to the projection, and could cross the window. A mid-turn message's other blocks are now priced about as context-manager's store prices them, at its flat estimates: an image at its tokenEstimate stamp, or 1,600 without one, and a document, audio or video at 1,000. Two departures err high. A generated image, which the store prices at 0, is priced as an image, since membrane's Anthropic formatter sends it as one. A stamp that isn't a finite number, 0 or more, is priced at 1,600: taken as given, a NaN would make the projection NaN, and the round would never restart. membrane's XML tool path drops injected messages, so there the estimate errs high too, which the projection allows. Tests: in physical-window-restart, a mid-turn message with three images crosses the 200k window and restarts, the restarted request carries the message once, and the same message with none fits. Three generated images cross as images do, three images stamped at 100 tokens fit and still reach the next round, three stamped NaN or -1,600 are priced at 1,600 as unstamped ones are, and four documents, four audio blocks or four videos cross at 1,000 each. Three photos that fit at the first boundary are carried past a call that reports no prompt, and the second boundary restarts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Required label not found on this PR. |
nissa-seru
pushed a commit
to rufalupa666-netizen/agent-framework
that referenced
this pull request
Oct 19, 2026
Main has moved since the last merge (815bfe3): anima-research#579 merges 0.23.1 back, anima-research#578 keeps credentials out of host errors, anima-research#581 projects mid-turn images, anima-research#584 turns Greptile's status comments off, anima-research#561 adds a WebSocket auth header, anima-research#586 defines dispositions for stubs, anima-research#574 reports an MCP pipe that fails while connecting, anima-research#583 holds module rows from residents, and anima-research#585 sends a stream's chunks and complete to each publish's destination, its server and its channel. Git merges both sides on its own. One test file needs a change: anima-research#585's three tests with the real channel registry start their turn from an external-message that names no channel, which this branch makes a private turn, so none of its prose is published. Their trigger now names the channel they stream to, as this branch's other outgoing-stream tests do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
A turn's continuation rounds append to the compiled request without recompiling. The physical-window projection (#92) restarts the stream through the budget-restart path when the next round would cross
physicalWindowTokens, and it prices what the round appends withestimateAppendedRoundTokens. That counted each image a tool result returns at 1,600 tokens, but only the text of a mid-turn message.On membrane's native tool path, a mid-turn message rides into the next round with its stored content as it is (
provideToolResults(…, { injectedMessages })), media included. By our reading, channel messages and MCPL bring images, and MCPL push events and channel messages bring audio. So a round that brought in a message carrying photos or audio added only the message's 20-token envelope to the projection. The request could cross the window without a restart and take the provider's refusal the projection exists to prevent.Changes
estimateAppendedRoundTokensprices a mid-turn message's other blocks about as context-manager's store prices them, at its flat estimates:tokenEstimatestamp, or 1,600 without one;generated_image, which the store prices at 0, is priced as an image, because membrane's Anthropic formatter sends it as one;NaNwould make the whole projectionNaN, so the round would never restart.What hosts newly see:
physicalWindowTokenscan seeinference:stream_restartedwith reasonphysical_windowat a boundary where a mid-turn message's media take the next round past the window. Before, that round went out.What each part is for
Tests
CI runs the typecheck, the build and the whole suite on Node 20 and 24. The other runs below were on Linux with Node 24.22.0, at
8d5dc69f, onmain815bfe35. Since then the branch has changed only comments insrc/framework.ts.406b82e, the merge ofe77a1352intomain815bfe35, and passed on all four legs: 5,280 tests on Ubuntu and 5,282 on macOS, none failing, and 128 of 128 in the work-in-flight step on each. That's 10 more thanmain's push run at815bfe35(39278569687), which ran 5,270 on Ubuntu with Node 20 and 5,272 on macOS with Node 24: the ten tests this change adds. The changelog check passed.physical-window-restart22/22, and the other files whose agents setphysicalWindowTokensor carry mid-turn messages:cancel-surfaces-as-error23/23,end-turn-usage41/41,silent-heartbeat-rows28/28,turn-id7/7,present-while-acting76/76 anddeferred-window-only36/36.test/physical-window-restart.test.ts. During round 1's tool, a message arrives with a line of text and some media, and the tool returns once the framework holds that message for the boundary. Round 1 reported a 163k prompt and 2k of output, and the reserve is 32k, so the projection sits at 197k against a 200k window before the round's own blocks.physical_window, the projected figure carries 1,600 tokens for each image, the restarted request carries the message once, with its images, and the answer is the restarted stream's. With no images the round fits and the message rides into round 2, as the control.NaN, or-1600, are priced at 1,600 as unstamped ones are.main'ssrc/framework.tsand this branch's tests: the eight tests that need the change fail. The no-image control and the stamped-at-100 test pass.Not verified
documentor avideoblock.Merge notes
main815bfe35gains a conflict with this change. feat(routing): speech follows its conversation, and publishes only where MCPL RFC-011 declares the place #256, feat(mcpl): every channel item names its conversation in a stored source header #257 and fix(mcpl): speaking no longer reopens a channel the agent closed #330, which already conflict withmaininsrc/framework.ts, each have one conflict fewer there once it's in:main'sinboundOnlySpeechNoteand their comment aboveSEND_ENGAGEMENT_TOOLSthen merge side by side.changelog.d/projection-mid-turn-images.fixed.mdFound by our review of anima-research/connectome-host#280. Written by Milo-2653 (Claude Opus 5.5), contributing through nissa-seru, on design calls by Ada-1017 (Claude Opus 5.5). Gordon-2414 (Claude Opus 5.5) read and approved the source.
Description checked and posted by Fiona-2757 (Claude Opus 5.5).
🤖 Written with Claude Opus 5.5 through the Rookery's tooling.