From dc0784a3990a3327d60b7ac68400b44183ea6960 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Thu, 27 Aug 2026 21:06:27 -0700 Subject: [PATCH] docs(website): filterSubagentMessages is a no-op for plain subgraph nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The subgraphs post tells readers that child text lands in the parent transcript unless `filterSubagentMessages` opts out. That holds for a child dispatched from a `@tool` body, but not for the graph shape the post spends its best section on. `filterSubagentMessages` is checked inside a branch guarded by `isSubagentNamespace()`, which matches only `tools:`. A plain subgraph node emits `research:`, never enters that branch, and so ignores the option entirely — its tokens merge into the transcript no matter how it's set. The lever for that shape is `transcriptNodeNames`. This matters because the post showcases `cockpit/langgraph/subgraphs`, which is exactly the plain-node shape. A reader who follows it, sees the child's brief appear as its own bubble, and reaches for `filterSubagentMessages` will find it does nothing. Also records the failure mode, which is the expensive part: the leak is mid-stream with a clean end state. The parent's final `values` event rewrites the message list from authoritative graph state, so the stray bubble disappears once the run settles. A final-state assertion cannot catch it — measured against a live model in #838, where the message count transiently hit 3 before collapsing to 2. Verified: website builds; blog + sitemap specs 26/26. Co-Authored-By: Claude Opus 5 --- .../2026-08-27-langgraph-subgraphs-when-to-split.mdx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/website/content/blog/2026-08-27-langgraph-subgraphs-when-to-split.mdx b/apps/website/content/blog/2026-08-27-langgraph-subgraphs-when-to-split.mdx index 52747c5b2..b37ae7a9b 100644 --- a/apps/website/content/blog/2026-08-27-langgraph-subgraphs-when-to-split.mdx +++ b/apps/website/content/blog/2026-08-27-langgraph-subgraphs-when-to-split.mdx @@ -140,6 +140,16 @@ Our `filterSubagentMessages` is off unless you set it, so a child's tokens flow That isn't a quirk of our config. Any consumer reading a namespaced stream has to decide what a child's tokens mean, and "append them like everything else" is the path of least resistance — so unless something opts out, child text lands in the parent transcript and the same content renders twice. +There's a trap in that option's name, and it bites the exact graph shape this post has been holding up. +`filterSubagentMessages` only fires inside a branch guarded by the `tools:` namespace check. +A plain subgraph node's namespace looks like `research:`, never reaches that branch, and so ignores the option entirely — its tokens merge into the transcript however you set it. +The lever for that shape is `transcriptNodeNames`, which whitelists the graph nodes whose messages count as transcript. + +It's also a mid-stream bug with a clean end state, which is the part that will waste your afternoon. +The parent's final `values` event rewrites the message list from authoritative graph state, so the stray bubble disappears on its own once the run settles. +Assert on the finished DOM and everything looks right; watch the streaming pass and you'll see the child's internal notes render as their own message and then vanish. +A final-state test cannot catch it. + ### How does a child get attributed? By id — and this is the part I find well-designed: the namespace segment _is_ the identifier.