The Apr 21 "refactor(runtime): Support durable compaction of threads" commit
re-added a2ui_dynamic_schema.py and a2ui_fixed_schema.py to the
langgraph-python-threads example in a stripped form. Most of the simplification
was cleanup, but two docstrings carried load-bearing instructions for the
sub-LLM and those got lost:
- render_a2ui's Args block said the root component must have id "root".
Without it, the LLM emits a valid flat component list with no entry point;
the A2UI renderer (A2uiSurface.tsx:152) hard-codes id="root" and falls
through to a shimmer placeholder — the "Sales Dashboard (A2UI Dynamic)"
demo renders as an empty white square.
- search_flights' docstring spelled out airline logo URLs, date format,
and status-icon colors, producing consistently-styled flight cards.
This restores both files verbatim from the non-threads example, which is
the known-good template. All differences in the agent/src dir are now
removed. Debug prints and headers come back with the restore; happy to
trim them in a follow-up if the intent was to keep the -threads version
terser.
Wrap <ExampleLayout> in <CopilotChatConfigurationProvider agentId="default"
threadId={threadId}> so the canvas's useAgent() inherits the active threadId
via the existing fallback in use-agent.tsx. Without this wrapper, the canvas
calls useAgent() with no args and resolves to the registry agent instead of
the per-thread clone that the chat's /connect replay populates, so
STATE_SNAPSHOT events never reach it — todos rendered blank on thread resume
even though the final persisted snapshot contained them.
CopilotChat no longer needs explicit agentId/threadId props; it inherits
from the same provider, keeping one source of truth.
- Skip copilotkit.connectAgent when CopilotChat lacks a caller-supplied
threadId — a locally-minted UUID has no backend record, so /connect
would always 404 on the intelligence platform.
- Suppress the welcome screen while a connect is in flight and
unconditionally when the caller has supplied a threadId
(hasExplicitThreadId). Prevents the "How can I help you today?"
flash on thread switch.
- Gate suggestions on !isConnecting && !isRunning to avoid painting
them against a mid-replay message tree.
- Defer the isConnecting release by one animation frame so trailing
bootstrap renders commit before the flag flips.
- Reserve room for the "Powered by CopilotKit" license badge via a
new --copilotkit-license-banner-offset CSS var published by the
banner on mount; chat input consumes it only when bottom-anchored.
- Sort and display threads by lastRunAt (fallback to updatedAt →
createdAt) so metadata-only actions like archive/rename don't
reshuffle the list.
- useThreads waits for runtimeConnectionStatus === Connected before
dispatching the store context, eliminating the speculative /threads
fetch that fired before /info returned wsUrl.
Threads example polish: restore button + tooltips on
archive/restore/delete, segmented Active/All filter, graceful error
state, skeleton rows on initial load, stable scrollbar gutter,
pre-paint dark-mode class, logo position stable across app/chat
modes, drop dynamic-import drawer wrapper that caused null first
paint, archived-row dimming via child colors instead of opacity.
Tests:
- CopilotChat.absentThreadConnect: connect is skipped without a
threadId, fires when supplied via prop or config.
- CopilotChatView.connectingGate: isConnecting suppresses welcome;
hasExplicitThreadId suppresses welcome on empty chat.
- threads (core): lastRunAt sort fallback ordering.
- use-threads: Connecting-state gate defers /threads until Connected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The scaffolded BFF was hitting two issues out of the box:
1. tsx doesn't auto-load .env, and the template's .env lives at the
monorepo root. process.env.COPILOTKIT_LICENSE_TOKEN was undefined
at runtime so the runtime logged 'No license token configured'
even when the user had populated .env via `copilotkit license`.
2. @copilotkit/runtime: next resolved to 1.55.0-next.9, which
predates the thread-naming UUID fix (v1.55.3). The BFF blew up
creating LangGraph threads with 'Invalid thread ID: must be a
UUID' because the runtime passed a compound thread-name:<uuid>:
<uuid> string.
Fix both:
- Switch dev script to `tsx watch --env-file=../../.env src/server.ts`
so tsx loads the monorepo root .env.
- Pin @copilotkit/runtime to `latest` so scaffolds get the
thread-naming fix. (The next dist-tag is still stale on npm.)