Skip to content

docs: fix checkpointer guidance and document chat-sidenav - #813

Merged
blove merged 1 commit into
mainfrom
blove/dogfooding-docs-fixes
Aug 14, 2026
Merged

docs: fix checkpointer guidance and document chat-sidenav#813
blove merged 1 commit into
mainfrom
blove/dogfooding-docs-fixes

Conversation

@blove

@blove blove commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Three fixes found by building both tutorial apps from scratch against the published @threadplane/*@0.0.57 packages and driving them in a browser against live backends.

1. The persistence guide's checkpointer advice breaks langgraph dev

docs/langgraph/guides/persistence.mdx opened with "Every LangGraph agent needs a checkpointer" and showed builder.compile(checkpointer=MemorySaver()). The quickstart, meanwhile, tells you to run langgraph dev.

Doing both doesn't degrade gracefully — the server refuses to load the graph and exits:

ValueError: Heads up! Your graph 'graph' from './graph.py' includes a custom
checkpointer (type <class 'langgraph.checkpoint.memory.InMemorySaver'>)…
Application startup failed. Exiting.

Verified by compiling a checkpointer into a graph and starting langgraph dev against it. The guide now splits by how the graph is served: no checkpointer when serving through langgraph dev / Platform (use POSTGRES_URI), checkpointers when you embed the graph in your own process — including ag-ui-langgraph servers, which need one for aget_state.

2. <chat-sidenav> had no docs page and no JSDoc

Every ng-content slot on the composition is named, so a <chat> placed between the tags is silently dropped — you get a sidebar and an empty pane, no error. This is the opposite of <chat-sidebar>, which does project app content. It cost me a debugging pass while writing the tutorial.

Adds docs/chat/components/chat-sidenav.mdx (inputs, outputs, Thread contract, ThreadActionAdapter, drawer mode) plus a JSDoc block showing the chat as a sibling. Also documents two contract facts that are easy to miss: status is not auto-filtered and pinned is not auto-sorted — consumers pre-filter and pre-sort.

3. Client-tool results carry no tool name

A client-tool result arrives as a tool message keyed by tool_call_id with no name, so the intuitive server-side filter matches nothing — silently, forever:

# Always empty.
[m for m in state["messages"] if isinstance(m, ToolMessage) and m.name == "add_link"]

Documented with the id-based lookup. Worth noting this is not fixable on the AG-UI side: ToolMessageSchema in @ag-ui/core defines only id / role / content / toolCallId / optional error / encryptedValue, and parses in strip mode, so an added name would be dropped on the wire. The LangGraph adapter could send one, but that would create cross-adapter asymmetry in the durable-write path (the subsystem behind #807/#809/#810) while "match on the id" stays the portable advice either way. Docs felt like the right call — happy to revisit if you'd rather have the field.

Verification

  • nx lint chat, nx lint website — 0 errors
  • libs/chat vitest — 1102 passed / 123 files
  • apps/website vitest — 12 failed / 76 passed, identical to a clean main checkout (confirmed by stashing); no new failures
  • api-docs.json regenerated and committed so the CI bot doesn't have to push
  • All three changed/added MDX pages compile through the site's own remark/rehype pipeline

One pre-existing failure is unrelated and left alone: docs.spec.ts > auto-rendered API pages resolve generated entries fails on main because the middleware "LangGraph.js Helpers" page is a group page whose title matches no single generated export.

🤖 Generated with Claude Code

Found by building both tutorial apps from scratch against the published
packages and running them.

- langgraph/persistence: the guide opened with "every LangGraph agent needs
  a checkpointer" and showed `compile(checkpointer=MemorySaver())`, while
  the quickstart tells you to run `langgraph dev`. Doing both does not
  degrade — the platform rejects a graph carrying its own checkpointer and
  the server exits on startup with GraphLoadError. Split the guidance by
  how the graph is served and quote the actual failure.

- chat/components/chat-sidenav: the composition had no docs page and no
  JSDoc. Its ng-content slots are all named, so a <chat> placed inside is
  silently dropped — you get a sidebar and an empty pane with no error.
  Add the page (inputs/outputs, Thread contract, ThreadActionAdapter) and
  a JSDoc example showing the chat as a sibling.

- chat/client-tools: client-tool results come back keyed by tool_call_id
  with no tool name, so the intuitive server-side filter by name matches
  nothing, silently. Document the id-based lookup. This is fixed by the
  protocol on AG-UI, whose ToolMessageSchema has no name field and parses
  in strip mode, so matching on the id is the portable approach.

api-docs.json regenerated for the new JSDoc.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
threadplane Ready Ready Preview Aug 14, 2026 3:57am

Request Review

@blove
blove enabled auto-merge (squash) August 14, 2026 03:55

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit 4d02844 into main Aug 14, 2026
8 checks passed
blove added a commit that referenced this pull request Aug 14, 2026
Pushes to main do not cancel in-progress runs (cancel-in-progress is
true only for pull_request), so runs serialize and a slower older run
can reach its deploy job long after a newer commit has already shipped.
It then rebuilds --prod from its own older checkout and promotes it,
silently overwriting production.

Observed 2026-08-14: the CI run for #813 promoted at 04:37, replacing
the deployment that had published two blog posts from #814 at 04:13.
Both posts 404'd until the next merge happened to redeploy them. Nothing
failed; CI was green the whole time.

Add a freshness check to each job that promotes: resolve the current tip
of main and skip promotion when it no longer matches github.sha, logging
a warning so the skip is visible. Setup and change-detection steps still
run; only the production-touching steps are gated.

Covers all five promotions — website, cockpit, Angular examples, the
canonical demo, and the ag-ui demo. The last of those was found by the
new spec assertion, not by reading the file.

Notes on the implementation:
- Uses `git ls-remote`, not `git fetch --depth=1`: a shallow fetch would
  mark the deploy job's full clone shallow and break the --affected
  history checks that run right after it.
- Fails loudly when the tip cannot be resolved, rather than treating an
  empty result as "stale" and silently skipping every deploy.
- Gates the demo build-stamp verification too, since it asserts the
  deployed SHA equals this run's SHA.

This narrows the race to the build window rather than closing it
entirely; a commit landing mid-build can still be overtaken. Fixing that
completely means either serializing promotions or having Vercel resolve
the alias, which is a larger change.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@blove
blove deleted the blove/dogfooding-docs-fixes branch August 14, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant