feat(c-threads): real SDK-backed threads + inline title generation#481
Merged
Conversation
Replace c-threads' hardcoded fake thread array with real LangGraph
SDK calls. The threads sidenav now reflects actual server-side
threads with LLM-generated titles instead of static placeholders.
Backend (graph.py): adds inline generate_title node (Pattern D from
spec 2026-05-19-llm-generated-labels-design.md) that writes a 3-5
word title to thread metadata on the first turn. Idempotent and
error-swallowing — title is a UX nicety, never a blocker.
Frontend (threads.component.ts): drops the hardcoded
[{id:'thread-1',...}] array. Constructs a LangGraph SDK Client and
calls client.threads.search() on init + after every agent turn,
mapping metadata.thread_title → Thread.title with a UUID-slice
fallback for brand-new threads.
Verified end-to-end: programmatic SDK smoke confirms
"What is the capital of Japan?" produces
metadata.thread_title = "Capital of Japan", and threads.search
returns it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…r pattern Mirror examples/chat/angular's shell/threads.service.ts wiring: dedicated injectable ThreadsService that owns the SDK Client and exposes refresh/create/delete/rename/archive, plus a ThreadActionAdapter on the component that hooks the framework's right-click menu into the service. Also fixes a latent bug: passing `apiUrl: '/api'` directly to the LangGraph SDK Client fails (SDK requires an absolute URL). Apply the same `window.location.origin + apiUrl` rewrite the streaming transport uses internally (libs/langgraph/src/lib/transport/fetch-stream.transport.ts). Refresh trigger switched from agent.isLoading() to agent.status() (the typed public API), matching demo-shell.component.ts. The service is a near-copy of the demo's because @ngaf/langgraph does not yet expose a shared LangGraphThreadsAdapter — see follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
blove
added a commit
that referenced
this pull request
May 20, 2026
The same SDK-backed ThreadsService has been duplicated across consumers
(canonical demo, c-threads cap, future caps). Hoist it into @ngaf/langgraph
so one implementation serves them all.
What's exported:
- createLangGraphClient(apiUrl) — wraps `new Client({ apiUrl })` with
the absolute-URL rewrite (`/api` → `window.location.origin + /api`)
the SDK requires. Single source of truth — fetch-stream.transport
now goes through it instead of inlining the same workaround.
- LangGraphThreadsAdapter — Angular service wrapping
client.threads.search/create/delete/rename/update with the SDK→Thread
mapping. Configurable via LANGGRAPH_THREADS_CONFIG which titleMetadataKey
to read ('title' for the demo, 'thread_title' for c-threads — spec
2026-05-19-llm-generated-labels-design). Pin/archive/projects/sort
supported. Failures log to console.error (no more silent catches —
that's been hiding prod issues; see PR #486).
- refreshOnRunEnd(agent, fn) — collapses the
`lastStatus = ...; effect(...)` snippet both consumers duplicated for
"refresh threads when a run finishes" into one line.
Converts examples/chat to consume the adapter directly via
inject(LangGraphThreadsAdapter), drops the local 138-line
shell/threads.service.ts. c-threads' adapter conversion lands in a
follow-up (waiting on #481 merge).
@ngaf/chat stays adapter-agnostic — no new LangChain dependency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blove
added a commit
that referenced
this pull request
May 20, 2026
PR #481 added a c-threads-local ThreadsService; this drops it in favor of the shared LangGraphThreadsAdapter (exported from @ngaf/langgraph in this same PR). Configures the adapter via LANGGRAPH_THREADS_CONFIG with titleMetadataKey: 'thread_title' to match the cap's Python graph. Inline run-end refresh effect collapses to refreshOnRunEnd(agent, fn). c-threads is now the second consumer of the hoisted adapter — proves the per-cap titleMetadataKey config works (demo uses 'title', c-threads uses 'thread_title') without duplicating the SDK glue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blove
added a commit
that referenced
this pull request
May 20, 2026
…488) * feat(langgraph): hoist threads adapter + Client helper out of demos The same SDK-backed ThreadsService has been duplicated across consumers (canonical demo, c-threads cap, future caps). Hoist it into @ngaf/langgraph so one implementation serves them all. What's exported: - createLangGraphClient(apiUrl) — wraps `new Client({ apiUrl })` with the absolute-URL rewrite (`/api` → `window.location.origin + /api`) the SDK requires. Single source of truth — fetch-stream.transport now goes through it instead of inlining the same workaround. - LangGraphThreadsAdapter — Angular service wrapping client.threads.search/create/delete/rename/update with the SDK→Thread mapping. Configurable via LANGGRAPH_THREADS_CONFIG which titleMetadataKey to read ('title' for the demo, 'thread_title' for c-threads — spec 2026-05-19-llm-generated-labels-design). Pin/archive/projects/sort supported. Failures log to console.error (no more silent catches — that's been hiding prod issues; see PR #486). - refreshOnRunEnd(agent, fn) — collapses the `lastStatus = ...; effect(...)` snippet both consumers duplicated for "refresh threads when a run finishes" into one line. Converts examples/chat to consume the adapter directly via inject(LangGraphThreadsAdapter), drops the local 138-line shell/threads.service.ts. c-threads' adapter conversion lands in a follow-up (waiting on #481 merge). @ngaf/chat stays adapter-agnostic — no new LangChain dependency. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(c-threads): consume shared LangGraphThreadsAdapter PR #481 added a c-threads-local ThreadsService; this drops it in favor of the shared LangGraphThreadsAdapter (exported from @ngaf/langgraph in this same PR). Configures the adapter via LANGGRAPH_THREADS_CONFIG with titleMetadataKey: 'thread_title' to match the cap's Python graph. Inline run-end refresh effect collapses to refreshOnRunEnd(agent, fn). c-threads is now the second consumer of the hoisted adapter — proves the per-cap titleMetadataKey config works (demo uses 'title', c-threads uses 'thread_title') without duplicating the SDK glue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docs): regenerate api docs --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.
Summary
cockpit/chat/threads/python/src/graph.py): adds inlinegenerate_titlenode (Pattern D from spec2026-05-19-llm-generated-labels-design.md) — same shape that landed in c-a2ui via feat(chat + c-a2ui): LLM-generated labels — thread titles + drop KNOWN_LABELS #474. First turn writes a 3-5 word title tothread.metadata.thread_title; idempotent on subsequent turns.cockpit/chat/threads/angular/src/app/threads.component.ts): removes the hardcoded fake-thread array. Constructs a@langchain/langgraph-sdkClientand callsclient.threads.search()on init + after every agent turn, mappingmetadata.thread_title → Thread.titlewith a UUID-slice fallback for brand-new threads.c-threads is the cap that's supposed to demonstrate threads — it now actually does, end-to-end, against the real LangGraph SDK.
Test plan
nx build cockpit-chat-threads-angular— greenfrom src.graph import graph)metadata.thread_title = "Capital of Japan"client.threads.search()returns the title for the frontend to consume🤖 Generated with Claude Code