Build1 publisher3 min readPublished
A test of AG-UI's truncated-stream fix compared builds a major version apart
AG-UI's fix for truncated agent streams was checked against per-commit CI builds that turned out to be versions 0.0.58 and 1.0.1. Until pull request #2354 ships, the published client still treats a stream that ends early as a successful run.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- The first draft of PR #2354 exempted cancelled runs using a single boolean on the agent, set by abortRun() and cleared by whichever run started next.
- Cancelling a run and starting another during teardown made the cancelled run report a false truncation error.
- The source tree at both commits reads 0.0.58, so neither CI artifact was built from its own commit.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- decision Frontends on the released client that want to show cut-off runs today have to add their own check for a missing RUN_FINISHED or RUN_ERROR.
- exposure Authors of custom AbstractAgent subclasses whose streams complete after an abort would have seen the false errors, and they have the most reason to retest the token-based version.
- constraint A red-to-green result on these per-commit artifacts cannot be credited to one diff until someone checks each artifact's version and dependencies against its commit's tree.
- capability A per-run token lets a cancelled run and its replacement overlap without either reading the other's state, and any stop-then-resend control relies on that overlap.
The first draft of the fix kept its cancellation exemption on the agent object, where every run could see it [4]. That is where it broke. The failing sequence, as the reviewer described it on dev.to [5]:
1. The user cancels run A, and abortRun() sets the flag [4]. 2. Run A's transport is still tearing down. 3. The user starts run B, and run B clears the flag [4]. 4. Run A's stream ends with no terminal event. The end-of-stream check finds the flag cleared and reports truncation for a run the user stopped on purpose [5].
The defect was a false truncation error on a cancelled run. According to the reviewer, its reach is narrower than that sequence suggests [6]. HttpAgent synthesizes a RUN_ERROR when its fetch aborts, so the check short-circuits before the flag is read, and two other integrations end their streams in ways that also avoid it [6]. The case the reviewer could demonstrate was an AbstractAgent subclass whose stream completes, rather than errors, some time after the abort [7].
The repair is the right one. The contributor replaced the shared boolean with a per-run cancellation token and added two tests that model the teardown window, for sixteen added lines in the source file [8]. Cancellation state now belongs to the run that was cancelled. The commit message draws the boundary exactly: an abort alone resolves both before and after, and it is the resend that fails [9].
Checking the repair took three passes [15]. The first ran both cases against the published client, and both resolved [10]. That build has no terminal-event assertion, so nothing in it could have fired [10]. The reviewer wrote that a before-run that cannot fail says nothing about an after-run that passes [11].
The second pass used the installable artifact the CI publishes for each commit sha [12]. The artifact for 1bda0cf5 rejected the cancel-then-resend case, and the one for 077cdcf7 resolved it [13]. The rejection read: "AGUIError: The stream ended without 'RUN_FINISHED' or 'RUN_ERROR'. The run was started but never terminated, so its result is incomplete." [14]
The reviewer then commented on the pull request that the compare between the two commits was one commit and two files, so the +16 -10 in agent.ts was the only difference between the runs [15]. The reviewer later called that sentence false [15]. The installed artifacts were package versions 0.0.58 and 1.0.1. They depended on zod ^3.22.4 and ^3.25.76, and shipped a dist/index.js of 65,523 and 82,982 bytes [16]. The later bundle is 17,459 bytes larger, about 27 percent [1]. Seventeen kilobytes is a lot to fit inside one commit and two files. The source tree at both commits says 0.0.58, so neither artifact was built from its own commit's tree [17]. The publishing workflow runs `on: [push, pull_request]`, and its checkout step pins no ref [18].
For the red-to-green result to credit the sixteen lines, both artifacts would have to be builds of their own commits with the same dependencies. In my view the later artifact does handle the resend case [13]. The comparison cannot say which change made it pass. Between the two artifacts sit a zod range bump and 17,459 extra bytes of bundle, alongside the sixteen lines [16][1][8].
What to watch
- PR #2354 merging, and which published AG-UI version first includes the terminal-event assertion.
- Whether the publishing workflow's checkout step gets a pinned ref, so per-commit artifacts match the commits they are named for.
- A rerun of the abort and abort-then-resend cases on builds made from each commit's own tree, to show whether the sixteen lines alone account for the fix.