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.
## What does this PR do?
Fixes the guillotine cut where long messages hit the flat top of the
chat input and get sliced mid-line. Most visible in
`autoScroll=\"pin-to-send\"` mode (where the user reads at their own
pace and routinely lingers with a line butted against the input), but
applies to all scroll modes.
### The problem
`CopilotChatView` rendered the attachment queue + input as flex siblings
beneath the scroll area, so the scroll content stopped at the input's
flat rectangular boundary. The previously-shipped feather gradient
masked this visually but clashed with host themes whose `--background`
didn't match its hard-coded white / near-black —
[b621e96ee](https://github.com/CopilotKit/CopilotKit/commit/b621e96ee)
defaulted the feather to an empty div, which then revealed the
underlying layout bug.
### The fix
Wrap attachments + input in a single absolute-positioned overlay wrapper
at the `CopilotChatView` level. The scroll content now fills full height
and passes behind the rounded pill, matching ChatGPT's layout. The
scroll content's bottom padding reflects the measured overlay height so
the last line clears the pill when scrolled to the bottom.
Changes:
- `CopilotChatView.tsx` — replace flex-sibling attachments + input with
a single absolute overlay wrapper; move `inputContainerRef` onto the
wrapper so the `ResizeObserver` measures the full stack (attachments +
pill + disclaimer); add `inputContainerHeight` to scroll-content bottom
padding
- `CopilotChatAttachmentQueue.tsx` — add
`data-testid=\"copilot-attachment-queue\"` for test hooks
- `CopilotChatView.stories.tsx` — add a `PinToSend` story as
manual-verification scaffolding
- New test file `CopilotChatView.inputOverlay.test.tsx` with four tests:
overlay wrapper is absolute-positioned, attachments render above the
input inside the wrapper, welcome-screen input is NOT wrapped, scroll
content reserves `inputContainerHeight` as bottom padding
Not changed:
- `CopilotChatInput.tsx` public API (still accepts `positioning:
\"static\" | \"absolute\"`, same `bottomAnchored` flag, same
`containerRef`)
- `use-pin-to-send.ts` anchor math
- The `feather` slot itself — still empty-div default from
[b621e96ee](https://github.com/CopilotKit/CopilotKit/commit/b621e96ee);
hosts who want a themed fade supply their own via `scrollView={{
feather: ... }}`
- Welcome-screen input (stays inline)
- Angular parallel (follow-up if desired)
## Related PRs and Issues
- Builds on [#4158](https://github.com/CopilotKit/CopilotKit/pull/4158)
(pin-to-send anchoring/spacer/feather fixes)
- Builds on
[b621e96ee](https://github.com/CopilotKit/CopilotKit/commit/b621e96ee)
(feather defaulted to empty div)
## Checklist
- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [ ] If the PR changes or adds functionality, I have updated the
relevant documentation
## Test plan
- [x] Unit tests — 4 new tests in
`CopilotChatView.inputOverlay.test.tsx` cover overlay structure,
attachment ordering, welcome-screen exclusion, and padding formula
- [x] Full `@copilotkit/react-core` suite (1153 tests) passes
- [x] Manual verification in Storybook (`UI/CopilotChatView → Default`,
`PinToSend`): content flows cleanly under the pill, last line reachable,
no guillotine cut
- [ ] Reviewer: check `WithSuggestions` story (padding formula switches
between `+4` and `+32`)
- [ ] Reviewer: check that `scrollView={{ feather: MyFeather }}`
override still works (the `slots.e2e` test covers this, but worth a
manual sanity check)
Replace `RUN curl -LsSf https://astral.sh/uv/install.sh | sh` across all
starter Dockerfiles with `COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx
/usr/local/bin/`. The curl|sh form has a pipe-swallow latent bug: when
astral.sh returns a 5xx, curl fails but `sh` gets no stdin and exits 0,
so the layer "succeeds" with no uv binary. A later `RUN uv sync` then
crashes with `uv: not found` (exit 127). This already bit the agno
starter today (run 24809910399) when astral.sh had a transient outage;
upstream recovered on its own so this is latent-bug cleanup, not a
hotfix.
Using the official uv image is uv's own recommended pattern: it's
cache-friendly, network-free at build time, and sidesteps the pipe
failure mode entirely.
Scope: all 20 Dockerfiles under examples/integrations/*/Dockerfile,
examples/integrations/*/docker/Dockerfile.agent, and
examples/showcases/scene-creator/agent/Dockerfile.
Verified locally: `docker build -f docker/Dockerfile.agent ./agent`
for agno succeeds against the new pattern.
`CopilotChatView` rendered the attachment queue + input as flex siblings
beneath the scroll area, so long messages hit the input's flat top edge
and were sliced mid-line. Most visible in pin-to-send mode where the user
reads at their own pace. The previously-shipped feather gradient masked
this but clashed with host themes whose `--background` didn't match its
hard-coded white/near-black (b621e96ee defaulted it to an empty div).
Wrap attachments + input in a single absolute-positioned overlay so the
scroll content fills full height and passes behind the rounded pill. Pad
scroll-content bottom by the measured overlay height so the last line
clears the pill. Welcome-screen input is unchanged (stays inline). The
`feather` slot remains — hosts who want a themed fade supply their own
gradient.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Fix the long-standing typo across the example directory name + module
identifiers, align imports + package names. Also touches examples/integrations/adk
docker-compose fixtures and examples/e2e agents reference doc.
- 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>
ag-ui-crewai 0.1.5 contains three defects that took down crewai-crews
in prod for 9h on 2026-04-21: unguarded .messages access, orphan
asyncio.create_task, and sync completion() calls. All three are fixed
in 0.2.0 (ag-ui PR #1550).
Showcase already moved to 0.2.x in PR #4115. Dojo is the user-facing
reference — leaving it on 0.1.5 means every reader clones the broken
version. This closes the validate-pins drift.
Pip dry-run resolves ag-ui-crewai-0.2.0 cleanly with no conflicts.
Grep of examples/integrations/crewai-crews/ confirms no consumer code
touches the 0.1.5 defect paths (.state.messages, create_task,
completion sync).
- Keep deletion of sdk-python/copilotkit/langgraph_agent.py (deprecated LangGraphAgent
removed in this PR; main's unrelated bug fixes are superseded by our removal)
- Resolve poetry.lock conflict by taking main's ag_ui_langgraph 0.0.33
Co-Authored-By: Claude Sonnet 4.6 <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.)
Switch docker-compose to pull app-api, db-migrations, and realtime-gateway
from public.ecr.aws/cpk/intelligence/* at tag 0.1.0-rc.5 instead of locally
built cpki/*:local images, and drop the build-local-images prerequisite
from the README and compose header.
- langgraph-python: replace ephemeral pkg.pr.new URLs with stable @copilotkit/*@1.56.2
- mastra: wire dev to run ui + agent via concurrently (was only starting UI)
- Restore `|| scripts\setup-agent.bat` / `|| scripts\run-agent.bat` fallback across
12 starter templates so npm install + npm run dev work on Windows without Git Bash
- Add --validate-on-load to all aimock invocations (4 workflows/scripts
+ 13 integration docker-compose files)
- Replace hardcoded 2-file fixture list with dynamic discovery across
showcase/, examples/integrations/*/, scripts/doc-tests/ (16 fixtures)
- Add sanity check to prevent silent zero-test pass when discovery fails
- Extend showcase_validate.yml path filter to trigger on
examples/integrations/**/fixtures/** and scripts/doc-tests/fixtures/**
- Import and use ValidationResult type for callback parameters
- Fix scripts/doc-tests/fixtures/default.json to use { fixtures: [...] }
envelope shape
Playwright install stderr is diagnostic signal — version/network errors,
missing system libs, or browser download failures all surface here. Only
suppress stderr on the noisy npm install step. Also pin the image-tag /
client-version relationship with a code comment on one compose file so
future bumps know to keep them aligned.
The Playwright Docker image (mcr.microsoft.com/playwright:v1.52.0-noble)
ships with all Chromium system libraries and browsers pre-installed, so
`--with-deps` adds no runtime value — it only forces a redundant
`apt-get update && apt-get install` inside the tests container.
That apt-get call is the sole source of the intermittent
"Installation process exited with code: 100" / "Failed to install
browsers" failures that rotate across the 12 smoke matrix entries. The
underlying cause is transient Ubuntu archive mirror hash/size mismatches
("File has unexpected size ... Mirror sync in progress?", "Hash Sum
mismatch"), which cause apt to abort with exit 100. Because each matrix
job races apt against archive.ubuntu.com independently, the failing
subset rotates per run (run 24526747926 hit 5 starters; run 24509673514
hit a different 5; run 24495760568 hit 3) — classic flake, not a per-
starter regression.
Dropping --with-deps eliminates the apt-get call entirely. The browsers
themselves are already present at /ms-playwright/chromium-* in the base
image, and `npx playwright install chromium` remains as a cheap no-op
that self-heals if the pinned Playwright version ever drifts from the
image's bundled browser build.
- Remove @langchain/community from sdk-js peerDependencies (unused,
was blocking @langchain/core@1.x resolution)
- Add langchain@^1.0.0 to langgraph-js agent deps to prevent
transitive resolution to 0.3.x
- Add postcss.config.mjs to mcp-apps threejs-server
- Remove '|| .bat' fallback from all starter package.json scripts so
real errors on Linux/macOS are not masked by a failing .bat attempt
- Fix typos: 'isseus' -> 'issues', 'interactin' -> 'interacting'
- Fix crewai-crews README title/body saying 'Flow' instead of 'Crew'
- Fix a2a-a2ui README wrong agent name and file path
- Remove phantom lint/dev:debug scripts from README Available Scripts
sections where those scripts don't exist in package.json
- Add missing dev:ui and dev:agent to mastra README
- chmod +x all new .sh scripts so they work on Linux/macOS
- Use --ignore-scripts in langgraph-js Dockerfiles to avoid postinstall
failure (agent/ dir not yet copied during npm install stage)
- Install agent deps in production Dockerfile after COPY agent/
- Fix hardcoded pnpm commands in agent-spec README
Reorder package manager instructions to show npm first as the default.
Remove stale 'ignores lock files' notes since lock file entries were
removed from .gitignore. All starters now work with npm, pnpm, yarn,
or bun — user's choice.
Starters should not constrain users to a specific package manager.
The .gitignore gets cloned into the user's project, so ignoring
certain lock files would prevent them from committing their chosen
package manager's lock file.
Flatten langgraph-python, langgraph-js, and mcp-apps starters so
npm install && npm run dev works out of the box. Replace Turborepo
with concurrently, move apps/* to root, update Dockerfiles, READMEs,
and entrypoints. Also remove stray pnpm-lock.yaml from a2a-a2ui and
ms-agent-framework-dotnet starters.
## Summary
- **console.css + input.css:** Scope `.dark` CSS selectors to CopilotKit
container elements (`.copilotKitDevConsole
.copilotKitDebugMenuTriggerButton` and `.poweredBy` respectively). The
original selectors had bare `.dark,` as standalone entries in
comma-separated selector lists, which applied styles to *any* element
with class `.dark` instead of scoping to CopilotKit elements.
- **colors.css:** Remove broken `:root` pseudo-element from
`body[style*="color-scheme: dark"] :root` — `:root` is `<html>`, which
cannot be a descendant of `<body>`, so this selector never matched
anything.
- **E2E tests:** 4 Playwright regression tests verifying dark mode
styles don't leak into host application elements.
Prevents CopilotKit dark-mode styles from leaking into the host
application.
Closes#2920
---
*Split from #3847*
## Summary
- Widen `TanStackChatMessage.content` from `TanStackContentPart[]`
to `any[]` so messages from `convertInputToTanStackAI` are directly
passable to any TanStack AI adapter without `as any` casts
- Split `TanStackContentPart` into a proper discriminated union with
separate variants per modality
- Add `env.d.ts` with `vite/client` reference for CSS import types
- Fix `onError` callback shape in the example
## Test plan
- [x] All 17 multimodal TanStack tests pass
- [x] All 294 agent tests pass
- [ ] Verify no TS errors in react-router example IDE
🤖 Generated with [Claude Code](https://claude.com/claude-code)