feat(langgraph)!: classify any namespaced event as child content - #844
Open
blove wants to merge 2 commits into
Open
feat(langgraph)!: classify any namespaced event as child content#844blove wants to merge 2 commits into
blove wants to merge 2 commits into
Conversation
One classification question, answered once: an event with any namespace belongs to a child graph. Consistent with the terminal-evidence guard, which has always refused ANY namespaced event — the transcript merge was the only site still using the narrow tools:-only test. - Child message events route to their child stream and never merge into the parent transcript (kills the mid-stream leak class structurally) - A child's values/updates no longer replace or spread-merge into the parent's values$ - Plain subgraph children now appear in subagents(), keyed by namespace segment, named by node prefix, settled by the run's terminal outcome - filterSubagentMessages removed (exclusion is the semantic, not an option) - Attribution ladder scoped to tool children so a plain child can never be absorbed by an unrelated pending tool call 340/340 lib tests; classification mutation-tested (narrowing it back to tools: fails exactly the 4 new pinning tests). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweeps every surface that taught the old limitation: the subgraphs guide's warning callout (now describes where child tokens actually go), the provide-agent option table and workaround paragraph, agent-architecture, langgraph-basics, the blog post's two stale sections, and the cockpit example's prompts/guide/docstrings. The cockpit example's sidebar gains a 'Child streams' section fed by agent.subagents() — the same child shown as state boundary (value()) and as stream, and the e2e asserts 'research — complete' renders, which exercises the new tracker path against a real langgraph server. api-docs regenerated (option removed, transcriptNodeNames doc updated). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
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.
Implements the library-level fix behind the
transcriptNodeNamesworkaround that #838 shipped and three docs PRs (#839/#841–#843) documented. Breaking change, deliberately: best architecture over compatibility.The inconsistency this removes
The bridge answered "is this event the parent's?" three different ways:
tools:onlymessages()mid-streamvalues/updatesroutingtools:onlyvaluesevent replaced the parent'svalues$; itsupdatesspread-merged into itNow there is one classification, answered once: an event with any namespace belongs to a child graph. Which child owns it is a separate (attribution) question.
What changes
Child content never merges into the parent transcript. Not opt-out — structural. Shared-state children still arrive at settle via the authoritative top-level
valuessync, so no content is lost, only the accidental mid-stream preview. The leak class #842 documented ("mid-stream bug with a clean end state") is now impossible rather than configurable.filterSubagentMessagesis removed (breaking). Exclusion is the semantic, so the option has nothing left to govern. Survey before removal: zero consumers set it anywhere in-repo, and its documented behavior was already a no-op for the plain-node shape.Plain subgraph children appear in
subagents(). Keyed by namespace segment (unique per invocation), named by node prefix, registered on first streamed event, settled by the run's terminal outcome infinalizeAttempt(success→complete, error/aborted→error; paused/interrupted leave them running — a child can resume with the thread). This reverses the freshly-documented limitation — the docs described a real gap honestly, and removing the gap beats documenting it.Attribution ladder scoped to tool children. The last-resort "any unmapped pending/running subagent" fallback could otherwise absorb a plain child's first message into an unrelated pending tool call. Pinned by a test.
Tool-path behavior is byte-equivalent. Same key extraction, same
addMessageToSubagent, same ladder, same settle-by-tool-result.Downstream sweep (same PR so docs never contradict the lib)
cockpit/langgraph/subgraphs: sidebar gains a "Child streams" section fed bysubagents()— the same child shown as state boundary (value()) and as stream. Its e2e now assertsresearch — completerenders, which exercises the new tracker path against a real langgraph server.transcriptNodeNamesdocs updated — its "top-level" scope is now literally true, and it keeps its real job (routers, title generators).api-docs.jsonregenerated.Verification
tools:fails exactly those 4.12); child stream showedresearch — runningmid-flight,research — completeat settle; topic + 2.5k-char brief populated.messages|tools:<id>events captured; the namespace carries an internal UUID, not the tool-call id, so early-chunk drops before ladder attribution ("0 message(s)" on cards) reproduce on the untouched code path — pre-existing, not a regression from this PR.Breaking-change notes for consumers
filterSubagentMessagesis a compile-time error on upgrade — delete it; the behavior it opted into is now the default (and broader).messages()should render them fromsubagents()instead.subagents()may now contain more entries; tool children are distinguishable by theircall_*-style keys andsubagent_typenames.Per repo policy this ships as a patch bump (0.0.x always patches).
🤖 Generated with Claude Code