feat(chat + c-a2ui): LLM-generated labels — thread titles + drop KNOWN_LABELS#474
Merged
Conversation
Two related fixes in one design pass: - Thread titles via inline per-cap node + LangGraph SDK metadata write (Pattern D from the design discussion — fully inline, no shared helper, matches per-cap pedagogical purpose). - Action message labels derived from the authored Button's child Text at emit time, killing the hardcoded KNOWN_LABELS map in libs/chat/src/lib/a2ui/action-label.ts (PR #464). Both backed by deep cross-library research (Open Canvas, Vercel, assistant-ui, CopilotKit, ChatGPT/Claude reference UX) showing universal consensus: titles are LLM-generated post-first-turn from thread metadata; action labels come from the authored UI element, never a centralized map in the rendering primitive. Scope: c-a2ui first (proves the pattern), document for other caps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10-task plan covering: - libs/a2ui type extension (A2uiActionMessage.action.label?: string) - libs/chat/a2ui/build-action-message.ts label derivation + 4 new spec cases - libs/chat/a2ui/action-label.ts: drop KNOWN_LABELS, prefer authored label, fall back to camelCase humanizer; 11-case new spec - cockpit/chat/a2ui/python/src/graph.py: inline generate_title node (Pattern D from spec), wired between terminal nodes and END Implementer = Tasks 1-9 (code, tests, smoke). Orchestrator = Task 10 (push, PR, CI watch, merge). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
6 tasks
blove
added a commit
that referenced
this pull request
May 20, 2026
PR #474 added a generate_title node to c-a2ui mirroring the examples/chat pattern — including the same broken localhost:2024 fallback. Same fix: pass `url=None` (via unset env) so the SDK uses its in-process ASGI transport. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
blove
added a commit
that referenced
this pull request
May 20, 2026
…tes (#493) * fix(graph): use SDK in-process ASGI transport for thread metadata writes Root cause of the production "all threads Untitled" bug (diagnosed via PR #492's @Traceable wrapper): error_type: ConnectError error_message: All connection attempts failed sdk_url: http://localhost:2024 The Python helper was calling get_client(url='http://localhost:2024') when LANGGRAPH_API_URL was unset, then trying to HTTP-call back into the runtime. In local dev this accidentally works because `langgraph dev` listens on 2024. In prod the runtime is on a different port, so every title write threw ConnectError and the bare except swallowed it. Fix: pass `url=os.environ.get("LANGGRAPH_API_URL")` (no fallback). When None, the SDK uses its in-process ASGI transport — the canonical path for graph-to-server self-calls. Docstring excerpt: > If `None`, the client first attempts an in-process connection via > ASGI transport. ... This only works if the client is used from > within the Agent server. Applies to both: - examples/chat/python (canonical demo, where the bug surfaced) - cockpit/chat/threads/python (same anti-pattern, would've failed on prod for the same reason) The @Traceable instrumentation from #492 stays — it'll confirm the fix on the next prod probe by surfacing `wrote_title: <slice>` in the LangSmith run output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(c-a2ui): same in-process ASGI fix for generate_title node PR #474 added a generate_title node to c-a2ui mirroring the examples/chat pattern — including the same broken localhost:2024 fallback. Same fix: pass `url=None` (via unset env) so the SDK uses its in-process ASGI transport. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.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
Implements the LLM-generated labels design (spec 2026-05-19-llm-generated-labels-design.md). Two related fixes in one PR.
1. Action labels — drop hardcoded `KNOWN_LABELS`
PR #464 added a hardcoded map in libs/chat (`bookingSubmit → 'Search flights'`) that embedded app-specific knowledge in the rendering primitive. Removed entirely. Replaced with derivation from the authored UI: when emitting an `A2uiActionMessage`, `buildA2uiActionMessage` walks from the source Button to its child Text and stamps the literal as `action.label`. The transcript renderer (`a2uiActionLabel`) prefers `action.label` and falls back to camelCase humanization. Chat-lib stops knowing about specific app actions.
`deriveActionLabel` accepts both wire forms for the Text `text` field:
2. Thread titles — inline LLM node per-cap
Added `generate_title` as a normal LangGraph node in c-a2ui's graph.py (Pattern D from spec — fully inline, ~30 lines, visible in the topology). After the cap's terminal nodes, fires a cheap LLM call (`gpt-5-mini`) summarizing the first user message in 3-5 words and persists via `client.threads.update(thread_id, metadata={'thread_title': ...})`. Idempotent; errors swallowed; never blocks the user-visible response.
Files
Test plan
Out of scope
c-a2ui only for the inline title node — proves the pattern. Other cockpit caps (c-generative-ui, c-tool-calls, c-subagents, c-interrupts, c-messages, c-input, c-debug, c-theming, c-threads, c-timeline) adopt the same inline pattern in follow-up PRs, one at a time. Frontend SDK adapter mapping `thread.metadata.thread_title → Thread.title` may need verification — backend write is the deliverable for this PR.
Plan: `docs/superpowers/plans/2026-05-19-llm-generated-labels.md`
🤖 Generated with Claude Code