Repository navigation
FE-1766: Make the chat transport break loudly when Flue or the AI SDK drifts - #9854
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
lunelson
had a problem deploying
to
pull-request
September 28, 2026 16:24 — with
GitHub Actions
Error
lunelson
had a problem deploying
to
pull-request
September 28, 2026 16:24 — with
GitHub Actions
Error
lunelson
force-pushed
the
ln/fe-1766-ai-sdk-transport-compat
branch
from
September 28, 2026 16:24
feba010 to
d8c5b9f
Compare
Merging this PR will not alter performance
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
as_constant |
< 1 ns | < 1 ns | N/A | |
constant_equal |
< 1 ns | < 1 ns | N/A | |
constant_not_equal |
< 1 ns | < 1 ns | N/A | |
access |
< 1 ns | < 1 ns | N/A | |
runtime_equal |
< 1 ns | < 1 ns | N/A | |
runtime_not_equal |
< 1 ns | < 1 ns | N/A |
Comparing ln/fe-1766-ai-sdk-transport-compat (1135def) with main (8c14928)
lunelson
force-pushed
the
ln/fe-1766-ai-sdk-transport-compat
branch
from
September 29, 2026 08:17
d8c5b9f to
cc16444
Compare
lunelson
force-pushed
the
ln/fe-1766-ai-sdk-transport-compat
branch
from
September 29, 2026 15:47
cc16444 to
1d4e677
Compare
This reverts 8c97f37. Petrinaut's packages should not carry agent-host concerns, and the runtime metadata schema existed only because Brunch feeds agent metadata into the panel. Petrinaut keeps its PetrinautAiMessageMetadata type; the website's Brunch adapter now owns the schema, checked at compile time to produce that type and to cover every one of its keys. Co-authored-by: Cursor <cursoragent@cursor.com>
Every Brunch package is private and their publishing status is unsettled, so the ban that kept them independent of @Local packages protects nothing yet. Lifting it lets a Brunch front end use @local/flue-aisdk-transport. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ting each other Co-authored-by: Cursor <cursoragent@cursor.com>
…remaining decisions Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… SDK transport Co-authored-by: Cursor <cursoragent@cursor.com>
…ugin Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…o the SDCPN plugin Co-authored-by: Cursor <cursoragent@cursor.com>
…the README Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…rt them Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…files Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
kube
previously approved these changes
Oct 12, 2026
TimDiekmann
previously approved these changes
Oct 12, 2026
hashdotai
previously approved these changes
Oct 12, 2026
kube
approved these changes
Oct 12, 2026
kube
approved these changes
Oct 12, 2026
TimDiekmann
approved these changes
Oct 12, 2026
hashdotai
approved these changes
Oct 12, 2026
Merged
This branch was successfully deployed
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.
🌟 What is the purpose of this PR?
Brunch's chat panel talks to its Flue agent through a hand-written adapter that turns Flue's conversation stream and stored history into the AI SDK's chat messages. That adapter restated both libraries' behaviour in its own terms, with tests that compared its output to hand-written expectations, so a change in either Flue or the AI SDK could have kept compiling and passing while the panel quietly showed the wrong thing. It also mixed Brunch and Petrinaut conventions into what should be product-neutral code, including a
stoppedmarker written into message metadata that agents can also write to.This PR makes that adapter break loudly when either side drifts. It becomes the unpublished, product-neutral package
@local/flue-aisdk-transport, tested against the AI SDK's own reducer, schema and chat state machine at the exact locked version, and against a real in-process Flue runtime whose stored history must reopen to the same message the live stream produced. Its types now bind to the upstream owners, and hosts declare their message metadata through the AI SDK's own schema type: the Petrinaut website's Brunch adapter validates metadata against Petrinaut's message type, and Brunch's stop marker lives in Brunch. The suites surfaced and this PR fixes two bugs: agent-authored response metadata was dropped, and a live tool subscriber could be disconnected by its first event. One behaviour remains an open decision, described under known issues.🔗 Related links
ai@6.0.286, the upstream source the compatibility cases are derived from🚫 Blocked by
Nothing. The branch is based on
main; the persona CLI (#9833) no longer sits underneath it, and the two do not depend on each other.🔍 What does this change?
@local/flue-aisdk-transport, deletes@hashintel/brunch-agent-transport-aisdk, and moves Brunch's browser-tool envelope, contextual message framing and conversation identity into core's browser-safe slices (4bd1516).validateUIMessages, and adds a parity suite on a real Flue runtime (cbf6afa).AbstractChat(1326bad), and labels each with its upstream source and as a guarantee, observed behaviour or decision (49db29b).createFlueAiSdkAdapter, one host configuration shared by the live transport and reopened history, with a required metadata schema for narrowed message types. Brunch'sstoppedprojection moves to core, and the Petrinaut website builds one adapter for its panel and history (97ee2e5). Reopened history is typed as the adapter's message type, which removes the website's cast (cfef85d).petrinaut-core(56fdd78) is reverted, and the website's Brunch adapter owns it, checked at compile time againstPetrinautAiMessageMetadata(a631f3d). A website test proves Brunch's stop marker and Petrinaut's schema compose, live and on reopen (b42bdcf).petrinautDiagnosticsContextMessageIdfrompetrinaut-core, so the website recognises Petrinaut's diagnostics message without restating its id in two places (1eada80).test/(065fc3f), moves the metadata projection contract out of a one-fileshared/directory (fb276a8), and lints the client and server entries against importing each other (62bc68c).@localpackages while they are private (43550d5).Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
turbo.json's have been updated to reflect thisWith the live tool-input channel on, as it is in the Petrinaut panel, text the model writes just before a tool call can render below that tool's card while streaming, then move above it after a reload. The live channel opens the tool part before Flue delivers the earlier text, and the AI SDK reducer cannot reorder parts, so fixing it means trading away some of the channel's early display. This is an open decision; a unit test pins the current behaviour and the parity suite compares only the set of parts in that case.
Reopened messages have no step boundaries, because Flue's stored history does not keep them. Reopened tool parts take the host's tool types without a runtime check, as the AI SDK does for streamed tool chunks; only metadata has a schema. Petrinaut's metadata schema drops keys it does not render rather than rejecting them.
🐾 Next steps
brunchBrowserResultenvelope check acrossapps/brunch-agentandapps/petrinaut-website, and its construction inplugin-sdcpn, with core'sbrowserToolOutput.MISSION.mdreference inapps/brunch-agent/AGENTS.md.🛡 What tests cover this?
libs/@local/flue-aisdk-transport: unit tests for the transport, projections and live channel, all reduced through the AI SDK, plus the in-process Flue suites intest/(upstream reducer cases,AbstractChatcases, live/reopen parity, the metadata contract). Every real Flue turn asserts that the live message equals the reopened one.❓ How to test this?
yarn install.yarn workspace @local/flue-aisdk-transport test:unit.npx turbo run build test:unit lint:tsc lint:eslint --filter @local/flue-aisdk-transport --filter @hashintel/brunch-agent --filter @hashintel/brunch-agent-plugin-sdcpn --filter @apps/brunch-agent --filter @apps/petrinaut-website --filter @hashintel/petrinaut --filter @hashintel/petrinaut-core.@apps/brunch-agentand runtest:integrationinapps/brunch-agentandapps/petrinaut-website.Execution record
Compatibility baseline.
ai@6.0.286(vercel/ai38f42fce),@flue/sdkand@flue/runtime2.0.3. The decisions table inlibs/@local/flue-aisdk-transport/README.mdis the single record of decisions, observed behaviours and accepted gaps; re-derive any case whose upstream source changes when either dependency moves. Flue documentsConversationStreamChunkas a first-party presenter surface rather than semver-covered API, so the exhaustive switches over it plus the exact version pin are the protection.Metadata contract.
metadataSchematakes the Standard Schema member of the AI SDK'sFlexibleSchema, because projection runs synchronously and the AI SDK's own schema wrapper validates asynchronously. A narrowed message type without a schema fails to compile (covered by a@ts-expect-errortest). The projection returns raw values and the schema is the authority for the type.Verification, on the branch rebased onto
main(404cc96e9b), after FE-1763 merged:turbo run build test:unit lint:tsc lint:eslintfor the seven touched packages: 60 of 60 tasks pass. One earlier run, before the rebase, had a single@apps/brunch-agentunit failure while all 60 tasks ran in parallel; it passed on every rerun, alone and under Turbo.@local/flue-aisdk-transport: 82 tests.apps/petrinaut-websiteintegration: 5 of 5.apps/brunch-agentintegration: 21 of 21.oxfmt --checkclean on every changed file.lint:tscandoxfmt --checkclean, andapps/petrinaut-websiteintegration 5 of 5.Review. Two independent reviews ran: one on standards, spec, subtraction and type ownership before 56fdd78, and a structural review of authority and ownership at cbff748. Each finding was fixed in a later commit or is recorded above as a known issue or next step.