## Release monorepo v1.57.1
**Scope:** `monorepo` | **Bump:** `patch`
---
### How this release process works
1. **This PR was created automatically** by the "release / create-pr"
workflow.
It bumped the `monorepo` packages to `1.57.1`
and generated AI-enhanced release notes.
2. **CI runs on this PR** — the full test suite (unit tests, lint, type
checks, build)
must pass before merging. This is the review gate.
3. **Review the release notes** in `release-notes.md` in this PR.
If a Notion draft was created, you can edit the release notes there
before merging.
4. **When this PR is merged**, the `release / publish` workflow
automatically:
- Builds all packages
- Publishes the `monorepo` packages to npm at version `1.57.1`
- Creates git tag `monorepo/v1.57.1`
- Creates a GitHub Release with the final release notes
### Before merging
- [ ] CI is green (tests, lint, types, build)
- [ ] Version bumps look correct
- [ ] Release notes are accurate (edit in Notion if a draft was created)
---
> **Do not merge until CI is fully green.** The full test suite runs
automatically on this PR.
## Summary
Six commits, batched into one PR for the May 12 docs cutover.
- `2c10c735d` Port upstream CLI walkthrough verbatim onto 8 framework
quickstarts (adk, agno, aws-strands, langgraph, llamaindex, mastra,
microsoft-agent-framework, pydantic-ai). Initial byte-perfect import
from upstream `docs/content/docs/integrations/<fw>/quickstart.mdx`.
- `f17c86867` Add `sample-audio-button` region marker on the
built-in-agent voice demo. Closes a B-cell snippet gap; the bundler now
reports 4 regions on `built-in-agent::voice`.
- `cebca9216` Remove AG-UI brand tab from desktop header for visual
parity with `docs.copilotkit.ai` (canonical has zero AG-UI elements in
the header).
- `abeb2792b` Also remove AG-UI link from mobile slide-out menu and drop
now-unused helpers (`AgUiIcon`, `AG_UI_LINKS`, `AG_UI_PREFIXES`, `Brand`
type, `activeBrandFromPath`, `usePathname`). Net 82-line cleanup of
`brand-nav.tsx`.
- `99d8ac7a5` Intermediate rewrite of the 8 quickstarts to use `npx
copilotkit@latest create --framework <id>` (after CLI accuracy audit
found `--intelligence` and `--framework` are mutually exclusive in
`copilotkit@2.0.3`). Also applies V2 canonical imports to the same 8
files: `<CopilotKit>` from `@copilotkit/react-core` (root), styles from
`@copilotkit/react-core/styles.css`, drop `@copilotkit/react-ui` from
npm install.
- `59a8a71a6` Final CLI-section shape: each quickstart now leads with
the upstream interactive walkthrough (`npx copilotkit@latest create`
plus a bulleted explanation of Project name / Enterprise Intelligence
Platform with sign-up link / Framework picker), followed by an "Or skip
the prompts and pin a framework directly" `--framework <id>` block.
LangGraph and Microsoft Agent Framework show both language variants in
the flag block.
## Test plan
- [ ] Visit each of the 8 framework quickstarts on the dev server.
Verify the CLI section shows the interactive walkthrough with the
EIP/sign-up bullet AND the `--framework <id>` flag block below it.
- [ ] LangGraph quickstart shows both `langgraph-py` and `langgraph-js`
flag commands. Microsoft Agent Framework shows both
`microsoft-agent-framework-dotnet` and `microsoft-agent-framework-py`.
- [ ] All 8 quickstarts: imports show `@copilotkit/react-core` (root),
styles from `@copilotkit/react-core/styles.css`. No `/v2` paths.
- [ ] Inspect shell-docs header at desktop and mobile (narrow viewport).
No AG-UI brand tab anywhere.
- [ ] Visit a built-in-agent voice page that consumes the
`sample-audio-button` region. The snippet renders.
## Summary
- Bump `@copilotkit/license-verifier` from `0.2.0` → `0.4.0` in
`packages/runtime`, `packages/shared`, and the root pnpm `overrides`
block
- Refresh `pnpm-lock.yaml` accordingly
## Test plan
- [ ] CI green
Restructure the "Run our CLI" step in all eight framework quickstarts to surface
two paths: the upstream interactive flow (which now covers the Enterprise
Intelligence Platform prompt and sign-up) and the `--framework <id>` flag fast
path. LangGraph and Microsoft Agent Framework keep both language variants in the
flag block.
## Summary
Replaces the implicit per-thread agent cloning from #3525 / #3630 with
an explicit registration API. Three commits:
1. **revert** — strips the cloning machinery (`useAgent({ threadId })`
per-thread clones, `getThreadClone`, `globalThreadCloneMap`,
`cloneForThread`), the inspector hooks added only to handle clones
(`onAgentRunStarted` from #3869, the connect-time emission from #3872,
the `agentRunThreadId` map), the state-manager `isClone` composite-key
path, and the `consumerAgent` parameter on `SuggestionEngine`. Restores
`agent.threadId = resolvedThreadId` in `CopilotChat` (pre-#3525
behavior). Re-opens issue #2957 (CPK-7155): two `<CopilotChat>`
instances sharing an `agentId` will share state again.
2. **feat** — adds `CopilotKitCore.registerProxiedAgent({ agentId,
remoteAgentId })` which mints a `ProxiedCopilotRuntimeAgent` under a
local registry id and routes its outbound HTTP requests to the named
runtime agent. Returns `{ agent, unregister }` for React `useEffect`
cleanup. Throws on duplicate `agentId` (collisions with
`agents__unsafe_dev_only` or another `registerProxiedAgent` are loud,
not silent).
`ProxiedCopilotRuntimeAgent` gains a `remoteAgentId` field used only for
outbound routing — URL paths (`/agent/<id>/run`, `/connect`, `/stop`),
single-route envelopes, and the `IntelligenceAgent` delegate's
`agentId`. The local `agentId` remains the registry key and source of
truth for state-manager subscriptions, `useAgent` lookups, and
`onAgentsChanged`. So multiple proxies (`chat-1`, `chat-2`) targeting
the same runtime agent (`default`) don't cross-talk in any subscriber
bookkeeping.
3. **test** — re-adds the isolation coverage that the revert deleted,
rewritten against the explicit-registration model (10 tests total).
## Usage
```tsx
const { copilotkit } = useCopilotKit();
useEffect(() => {
const { agent, unregister } = copilotkit.registerProxiedAgent({
agentId: "chat-1", // local registry id (subscriber bookkeeping)
remoteAgentId: "default", // runtime id (URL routing only)
});
return unregister;
}, [copilotkit]);
// then <CopilotChat agentId="chat-1" />
```
## Test plan
- [x] `nx run @copilotkit/core:test` — **424 passed** (was 409 + 15 new
across feat & test commits)
- [x] `nx run @copilotkit/react-core:test` — **1151 passed** (was 1150 +
1 new)
- [x] `nx run @copilotkit/web-inspector:test` — **7 passed**
- [x] Build: `core`, `react-core`, `web-inspector` all clean
### New tests cover
- routing — proxy at `agentId` routes outbound to `remoteAgentId`; URL
path encodes the remote id, body envelopes use the remote id
- duplicate-throw — register twice with same `agentId` throws (whether
against another registered proxy or an `agents__unsafe_dev_only` entry)
- idempotent `unregister` — calling twice doesn't throw or re-emit;
stale handles don't strip replacements
- `onAgentsChanged` notification on register and unregister
- header inheritance from core
- two proxies → same `remoteAgentId` are distinct instances with
isolated messages, isolated state, independent threadIds, but shared
outbound URL
- `getAgent` returns the same proxy instance across calls (no per-call
clone)
- registering before runtime connects yields a proxy that's still usable
for in-memory ops
- registering with a `remoteAgentId` the runtime doesn't yet expose
still works for local bookkeeping
- re-register after unregister yields a fresh proxy (no carry-over)
- regression: activity renderers receive the agent under the local
`agentId`, never another agent in the registry (replaces the deleted
clone-vs-registry trap test)
## Caveats
- Issue #2957 (CPK-7155) is re-opened by the revert. The new API is the
supported path forward — callers that previously relied on `useAgent({
threadId })` for isolation should move to `registerProxiedAgent`.
- Runtime `/info` sync still uses last-write-wins, not throw, on
collisions with manually-registered ids. Easy follow-up if we want
strict throw there too.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Closes [CPK-7526](https://linear.app/copilotkit/issue/CPK-7526).
`@copilotkit/runtime/v2`'s `BuiltInAgent` already supported MCP servers,
but only with **static** headers set at client construction. CopilotKit
Intelligence's `/mcp` endpoint requires a two-axis auth contract that
breaks under static headers:
1. **Static project Bearer** — `Authorization: Bearer
cpk-{projectId}_{shortToken}_{longToken}`. Same on every call.
2. **Per-call end-user header** — `X-Cpki-User-Id`. Fresh per outbound
MCP HTTP request — never cached. Determines which user's persistent bash
sandbox + `/threads` view a call sees.
Without per-call user-id, every demo session for a given project would
share one bash sandbox, breaking the user-isolation contract that
`cpki.shell_contexts` and `ThreadsFs` enforce on the platform side.
This PR adds the missing per-call resolver hook and is the precondition
for [CPK-7527](https://linear.app/copilotkit/issue/CPK-7527) (Phase 4b
SL integration), which wires it into `Intelligence/demos/simple-agent`.
## What's in here
### Public API surface
```ts
import {
BuiltInAgent,
INTELLIGENCE_USER_ID_HEADER,
// re-exported from @ai-sdk/mcp:
type MCPClient,
type MCPTransport,
type OAuthClientProvider,
} from "@copilotkit/runtime/v2";
new BuiltInAgent({
model: "openai/gpt-4o",
mcpServers: [{
type: "http",
url: `${process.env.INTELLIGENCE_API_URL}/mcp`,
authToken: process.env.INTELLIGENCE_API_KEY!,
getHeaders: ({ requestHeaders }) => {
const userId = requestHeaders[INTELLIGENCE_USER_ID_HEADER]?.trim();
if (!userId) throw new Error("missing user-id");
return { [INTELLIGENCE_USER_ID_HEADER]: userId };
},
}],
});
```
- Unified `MCPClientConfig` shape mirrors `@ai-sdk/mcp`'s
`MCPTransportConfig` (single discriminated `type: "http" | "sse"`,
`url`, `headers`, `authProvider`) plus two CopilotKit extensions:
**`authToken`** (static Bearer shorthand) and **`getHeaders`** (per-call
resolver invoked on every outbound HTTP request — initialize,
tools/list, tools/call, reconnects).
- **`MCPRequestContext`** carries `requestHeaders` (snapshot of the
agent's per-run forwarded headers), `input`, and `mcpServerUrl`.
- **`MCPHeaderResolverError`** wraps resolver throws so `RUN_ERROR`
attributes the failure to the resolver via ES2022 `Error.cause`.
- **`BuiltInAgent.headers: Record<string, string> = {}`** is now
declared on the class. The runtime's existing
`extractForwardableHeaders` feature-detect (`if (agent.headers)` in
`configureAgentForRequest`) only forwards headers to agents that already
declare a truthy field — initializing to `{}` activates that path so the
BFF's per-request headers reach the resolver via context.
- **`INTELLIGENCE_USER_ID_HEADER`** constant exported as the canonical
header name (`"x-cpki-user-id"`) — re-exported through both
`intelligence-platform` and `v2/runtime` barrels.
### Architecture
The agent's MCP layer now sits directly on `@ai-sdk/mcp`'s stable
surface (`createMCPClient`, `MCPClient`, `MCPTransport`) instead of
bypassing it to `@modelcontextprotocol/sdk`. The agent module no longer
imports `@modelcontextprotocol/sdk` at all — that's confined to a small
`CopilotKitMCPTransport` class that implements Vercel's `MCPTransport`
interface and is only instantiated when a `getHeaders` resolver is
present.
For static-only configs (no per-call hooks), the config is handed
straight to `createMCPClient` and Vercel's built-in `HttpMCPTransport` /
`SseMCPTransport` handle the wire.
`MCPClient`, `MCPTransport`, `OAuthClientProvider`, `OAuthTokens`, and
`UnauthorizedError` are re-exported from `@copilotkit/runtime/v2` so
consumers don't need a direct `@ai-sdk/mcp` dependency.
### Side-effect bug fix: SSE static headers
The pre-existing direct-SDK construction passed `serverConfig.headers`
as the wrong-shape options arg to `SSEClientTransport`, and the SDK
silently ignored it — auth on SSE simply didn't work. Vercel's
`SseMCPTransport` correctly applies `headers` via its `commonHeaders()`
pipeline. The new architecture inherits the fix; a regression test in
`mcp-servers-integration.test.ts` proves static `headers` now reach the
wire on the SSE path.
### What's intentionally NOT in here
- **Demo wiring** in `Intelligence/demos/simple-agent` (CPK-7527).
- **MCP support for LangGraph / Mastra** runtimes — different
integration points; not this ticket.
- **Server-side `/mcp` route changes** in Intelligence (already shipped
on `mme/integrate-sl`).
## Notes for reviewers
- **Public-API addition:** `BuiltInAgent.headers` is a real public
field, not just an ad-hoc property. It's load-bearing for the runtime's
existing header-forwarding feature-detect.
- **Test header inspection:** `aimock` redacts `Authorization` to
`[REDACTED]` in its journal, so tests that need to verify the actual
outgoing Bearer use a `vi.spyOn(globalThis, "fetch")` recorder instead
of the journal. The `x-cpki-user-id` header isn't redacted, so per-call
user-id assertions read from the journal directly.
- **No `toMCPServer()` helper.** Earlier iterations of this PR shipped a
`CopilotKitIntelligence.toMCPServer()` shortcut. It conflated thread
management (the class's actual job) with MCP transport configuration and
baked in opinionated behavior that not every deployment will want;
dropped in favor of the inline pattern shown above using the exported
`INTELLIGENCE_USER_ID_HEADER` constant. Same line count as the
helper-call form, more flexible.
- **Pre-existing `tsc --noEmit` OOM:** `pnpm nx run
@copilotkit/runtime:check-types` runs out of heap on `main` at 8GB.
Reproduces on a clean checkout without any changes from this PR. Worth
tracking as a separate issue. Build (`tsdown`) is unaffected; the full
vitest suite (1419 tests, 101 files) passes.
## Test plan
- [x] `pnpm nx run @copilotkit/runtime:test -- mcp-servers-integration`
— 15 cases pass (8 existing + 6 per-call/static-header + 1 new SSE
regression test)
- [x] `pnpm nx run @copilotkit/runtime:test -- mcp-clients` — 8 cases
pass (existing user-managed-clients suite, including `MCPClient` ↔
`MCPClientProvider` type-compat check)
- [x] `pnpm nx run @copilotkit/runtime:test --skip-nx-cache` — full
suite 1419/1419
- [x] `pnpm nx run @copilotkit/runtime:build` — `tsdown` clean
- [x] `oxlint` on changed files — 0 errors
- [ ] Manual end-to-end against a local Intel server + simple-agent BFF
— deferred to CPK-7527 since the demo wiring lives there
## Summary
- Production deploys of the `showcase-langgraph-python` image were
crashing on every `/demos/*` route with "An error occurred in the Server
Components render" — backed by ENOENT on `/app/manifest.yaml`.
- Root cause: the demos layout's `generateMetadata` calls `await
headers()` (forces dynamic rendering) and `fs.readFileSync(process.cwd()
+ "/manifest.yaml")` for per-demo titles. The Dockerfile's runner stage
copied `.next`, `node_modules`, `package.json`, `public/`,
`langgraph.json`, `src/agents/`, `tools/`, and `entrypoint.sh` — but
never the manifest.
- The home page (`/`) was unaffected because it has no dynamic APIs, so
Next prerenders it statically at build time when the manifest is
available.
- All cells in the langgraph-python column on the showcase dashboard
were stuck at D2/D3 because the chat/tools probes can't pass against a
Server-Components error.
## Fix
One line in the Dockerfile: `COPY --chown=app:app manifest.yaml ./` in
the runner stage, with a comment explaining the runtime dependency.
## Test plan
- [x] Rebuilt local image with `bin/showcase build langgraph-python`
- [x] Recreated the local container and verified `/app/manifest.yaml` is
present
- [x] Hit `/demos/agentic-chat`, `/demos/headless-complete`,
`/demos/auth` — all load with zero console errors and the correct
manifest-driven page titles ("LangChain - Python - Prebuilt:
CopilotChat", etc.)
- [ ] Once merged, next Railway deploy of `showcase-langgraph-python`
should clear the column on the showcase dashboard
Two CR comments addressed:
- Rename the local destructure of forwardedProps.auth.copilotkitIntelligence
from 'cki' to 'cpki' so it matches the project-wide abbreviation already
used in metadata fields (cpki_event_id, cpki_event_seq, etc).
- Replace the inline 'X-Cpki-User-Id' string literal with the existing
INTELLIGENCE_USER_ID_HEADER constant exported from intelligence-platform/client.
Applies to the runtime auto-attach in agent/index.ts and to the three
test sites in intelligence-mcp-helper.test.ts so the user-side and
runtime-side stay in sync.
Three highlight paths in langgraph-python's manifest pointed at files
that don't exist after the PR #4694 reorganization:
- hitl-in-chat → src/agents/hitl_in_chat.py (actually hitl_in_chat_agent.py)
- chat-slots → custom-welcome-screen.tsx (file doesn't exist; use slot-wrappers.tsx)
- mcp-apps → copilotkit-mcp-apps/route.ts (actually .../[[...slug]]/route.ts)
The bundler walks every highlight at build time; one missing path aborts
the whole CI step. Fix all three.
Test snapshot counts in generate-catalog and generate-registry hardcoded
40 features / 720 cells / 702 total. With the two new feature IDs added
to the registry (reasoning-default + reasoning-custom), counts shift to
42 / 756 / 738; the LGP-specific cell distribution moved from
39 wired + 1 stub + 0 unshipped to 35 wired + 1 stub + 6 unshipped, and
the registry-side LGP feature/demo count drops to 36 (PR #4694 trimmed
4 items from the manifest's features list).
PR #4694 renamed langgraph-python's reasoning demos
(agentic-chat-reasoning → reasoning-custom, reasoning-default-render →
reasoning-default) but didn't update the central feature-registry.json /
constraints.yaml, so generate-registry validation rejected the new
manifest IDs. Add the two new features to the registry and the
constrained-explicit allowlist; leave the old IDs in place for the 17
integrations still using them.
Pre-existing drift on main (mastra/ms-agent/llamaindex/pydantic-ai/strands)
that the langgraph-python Dockerfile fix is unrelated to. Bump the
baseline in this PR to unblock CI.
The demos layout's `generateMetadata` calls `headers()` (forces dynamic
rendering) and reads `manifest.yaml` at request time for per-demo titles.
The Dockerfile's runner stage didn't include the manifest, so every
`/demos/*` route in production threw a Server Components render error
(ENOENT on /app/manifest.yaml). The home page was unaffected because it
has no dynamic APIs and gets statically prerendered at build time.
Add a single COPY of `manifest.yaml` into the runner stage.
## What does this PR do?
A wholesale demo pass on the `langgraph-python` showcase. The full diff
is +20,639 / −22,881 across 273 files; rebased into 14 thematic commits,
each scoped to one demo cluster or one cross-cutting concern. Build is
green at 54 routes; every demo round-trips with the local LangGraph dev
server.
### Per-demo headlines
- **Headless UI: Simple** — minimum-viable shadcn-only chat (`useAgent`
+ `useCopilotKit`) across 5 small files. Backend wiring corrected (was
borrowing the Complete demo's MCP runtime).
- **Headless UI: Complete** — modular hand-rolled `<CopilotChat>`
replacement. `page.tsx` enumerates capabilities; `chat/`, `hooks/`,
`tools/`, `attachments/` split by responsibility. Bug fixes folded in:
tool-cards no longer stuck "running" (passes `ToolMessage` to
`useRenderToolCall`), empty state no longer hugs the top (rendered
outside Radix `ScrollArea`), suggestion bar hidden on first paint.
- **Chat Customization: CSS** — HALCYON, a warm-paper editorial theme.
Two layers: v2 token overrides on `[data-copilotkit]` + class-targeted
styling. Demonstrates CSS-only customization without touching
components.
- **Chat Customization: Slots** — every overrideable slot wrapped;
labels are click-to-copy badges showing the PascalCase component path
(`Input.TextArea`, `MessageView.AssistantMessage`, …).
- **Reasoning: Default + Custom** — paired demos sharing one reasoning
graph (gpt-5-mini via Responses API). Default uses the built-in slot;
Custom overrides `messageView.reasoningMessage`.
`agentic-chat-reasoning` directory renamed to `reasoning-custom`
(manifest, route, e2e, docs-links updated together).
- **Prebuilt: CopilotChat / Sidebar / Popup** — centered content,
sidebar genuinely pushes the page (root-cause fix in `globals.css` —
body wasn't allowed to shrink with `marginInlineEnd`).
- **Multimodal + Voice + Beautiful Chat** — `LegacyConverterShim` (until
ag-ui/langgraph ships an updated converter), V2 runtime for voice (V1
drops `transcriptionService`), beautiful-chat ports parity from
`examples/integrations/langgraph-python`. Fixed `gpt-5.4-mini` typo that
would have 4xx'd every call.
- **Frontend Tools (in-app + async) + HITL family (in-chat / in-app /
interrupt-based)** — full coverage of agent→client tool calls and the
three HITL patterns.
- **Generative UI tool-rendering family** (5 demos sharing one backend)
— opt-in chaining via a "Chain tools" suggestion. The previous
always-chain bias generated extra unsolicited tool-call cards on every
turn.
- **Declarative UI + BYOC + Open Generative UI** — A2UI dynamic + fixed,
MCP Apps, Hashbrown, json-render, Open Generative UI default + advanced.
`a2ui-fixed-schema` simplified: dropped `BOOKED_SCHEMA` +
`booked_schema.json` since the SDK doesn't yet expose `action_handlers`.
8 `(props as Record<string, any>)` casts collapsed into one shared `s()`
helper.
- **Shared State + Sub-Agents** — streaming, read+write, frontend
context sharing, multi-agent supervisor with delegation log (tightened
type to drop unused `"running" | "failed"` legs).
- **Auth + Agent Config (platform)** — Auth defaults UNAUTHENTICATED
with a sign-in card; the chat doesn't mount until the user signs in, so
`<CopilotChat>`'s 401-on-mount crash never fires (`ChatErrorBoundary`
workaround removed). Agent Config pivoted from broken `<CopilotKit
properties={...}>` (silently dropped values in @ag-ui/langgraph 0.0.31)
to `useAgentContext`, the LangGraph 0.6+ idiom.
### Cross-cutting
- **Manifest curator pass** — every `Thing - Subthing` / `Thing
(Subthing)` normalized to `Thing: Subthing`. Retags: Auth → `platform`,
HITL → `interactivity`, Reasoning → `chat-ui`, Generative UI: Tools →
`generative-ui`. New tags surfaced in the registry: `platform`,
`agent-state`, `multi-agent`. Highlight paths corrected for the rebuilt
headless demos. Hitl entry now points at the working
`/demos/hitl-in-chat` route.
- **v1 → v2 import sweep** — every demo imports only from
`@copilotkit/react-core/v2`. Fixed silent breakage in beautiful-chat
where `useFrontendTool` was importing from bare v1, making
`enableAppMode` / `enableChatMode` invisible to the v2 agent.
- **page.tsx convention** — every demo's `page.tsx` reads as imports +
provider + suggestions hook + JSX. `useConfigureSuggestions` extracted
to a sibling `suggestions.ts`. Inline component definitions extracted.
- **Scaffolding** — manifest-driven landing page, per-demo titles via
middleware + demos layout, Tailwind v4 `@theme inline` block (without it
shadcn utilities compile to nothing), v2 catch-all route at
`[[...slug]]/route.ts`.
- **Dead-dep prune** — removed 17 deps with zero importers
(`@copilotkit/react-ui`, `@rive-app/react-webgl2`, `@xyflow/react`,
`@streamdown/{cjk,code,math,mermaid}` + `streamdown`, `ai`,
`use-stick-to-bottom`, `ansi-to-react`, `marked`, `react-jsx-parser`,
`media-chrome`, `motion`, `nanoid`, `remark-breaks`, `shiki`,
`tokenlens`, `@radix-ui/react-use-controllable-state`). Net: −5,000
lines on the lockfile. Every shadcn primitive in `src/components/ui/` is
intact.
### Things removed (the iteration arc)
This branch went through several reversals during development. The
rebase erased them from history; cataloguing the consequential ones for
context:
- AI Elements + prompt-kit headless demos (added then removed when the
spec narrowed to shadcn-only)
- Headless: 4-tab → 5-separate → trim to Simple+Complete
- `hitl-in-app-interrupt` (added then removed pending Atai's
`useInterrupt` resolver API)
- `BOOKED_SCHEMA` schema-swap branch in a2ui-fixed-schema (no SDK
support yet)
- `ChatErrorBoundary` for the auth demo (no longer needed once chat is
gated behind `isAuthenticated`)
- `read_properties()` / `build_system_prompt()` in agent_config_agent.py
(one static prompt now that toggles arrive via `useAgentContext`)
- `[A2UI-DEBUG]` print scaffolding in beautiful_chat.py
- 5 stub `agent.py` files in demo dirs (real graphs in `src/agents/`)
### Follow-ups
- `tool-rendering-default-catchall` registers a `useDefaultRenderTool`
despite the manifest claiming "zero frontend renderers" — either drop
the renderer or rewrite the description.
- Upstream: fix `@ag-ui/langgraph` 0.0.31's silent drop of `properties`
(would let agent-config use the typed transport instead of
`useAgentContext`).
- Upstream: `<CopilotChat>` shouldn't throw on transport 401 at first
paint (auth demo currently sidesteps).
- Upstream: relax `WithSlots` typing or ship an `asSlot<T>()` helper —
would erase the 9 `as unknown as` casts in chat-slots +
reasoning-custom.
- Upstream: published `CopilotRuntime` type rejects `Record<string,
LangGraphAgent>` — every dedicated runtime route ships the same
`@ts-ignore`.
## Test plan
- [x] `pnpm exec next build` — green, 54 routes generated
- [x] Every demo route resolves without crashing
- [x] Headless: Simple — `useAgent` + `useCopilotKit` round-trip;
suggestions in empty state work
- [x] Headless: Complete — tool cards advance from "running" to
"complete"; chart-card renders; attachments round-trip; suggestion bar
appears after first message
- [x] Chat Customization: CSS — HALCYON theme renders end-to-end; user
bubble gradient bound to inner bubble (not full-row); inputs /
suggestions / scrollbar all themed
- [x] Chat Customization: Slots — every slot label visible on hover;
click copies the PascalCase path with ✓ flash
- [x] Reasoning: Custom — `messageView.reasoningMessage` slot fires;
ReasoningBlock renders with "Thinking…" → "Agent reasoning" transition
- [x] Prebuilt: Sidebar — sidebar pushes the page (not overlapping) when
toggled
- [x] Frontend Tools — agent's `change_background` tool repaints the
indigo canvas
- [x] HITL: in-chat — TimePickerCard renders inline; user pick resumes
the agent
- [x] HITL: in-app — modal renders OUTSIDE the chat via `createPortal`;
decision resolves the pending Promise
- [x] Tool Rendering trio — single-tool default, "Chain tools"
suggestion fires multiple tool calls
- [x] Auth — first paint is the sign-in card; signing in mounts the chat
with `Authorization: Bearer …`
- [x] Agent Config — toggles change agent style per turn (tone /
expertise / responseLength routed through `useAgentContext`)
## Related PRs and Issues
Tracking notes: [Showcase - LangGraph Python
Notes](https://www.notion.so/copilotkit/Showcase-LangGraph-Python-Notes-3583aa3818528036ac0ddd1353f3e354)
## Checklist
- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked
Move the per-request Intelligence MCP bag from
forwardedProps.copilotkitIntelligence to
forwardedProps.auth.copilotkitIntelligence so the Intelligence-side
redaction policy strips it. The 'auth' namespace is the convention for
credentials; persistence sinks (Postgres, Redis, S3) and FE replay
paths in apps/realtime-gateway already strip everything under it.
Updates:
- Emitter (handlers/intelligence/run.ts): merge the bag into a single
forwardedProps.auth object alongside any upstream auth keys, and
only emit the auth namespace when there is something to put in it.
- Reader (agent/index.ts): read from forwardedProps.auth.copilotkitIntelligence
instead of forwardedProps.copilotkitIntelligence.
- Tests (intelligence-mcp-helper.test.ts): three fixtures rewritten
to the nested shape.
The branch's iteration arc went through several headless-demo
implementations (CSS Modules, AI Elements, prompt-kit, shadcn) and a
streaming-markdown experiment with `streamdown`. After the spec
narrowed to shadcn-only and `react-markdown` for assistant rendering,
those component libraries and their satellite packages were left
installed but unused.
Removed (zero importers across `src/`):
- @copilotkit/react-ui (v1 UI; the showcase consumes /v2 hooks only)
- @rive-app/react-webgl2 (animations, never wired)
- @streamdown/cjk, /code, /math, /mermaid + streamdown (replaced by
react-markdown for assistant content)
- @xyflow/react (graph viz, never wired)
- ai (Vercel AI SDK, was the AI Elements demo's transport)
- ansi-to-react (terminal output, never wired)
- marked (alternative markdown parser, never wired)
- media-chrome (media player UI, never wired)
- motion (animation library, was a prompt-kit demo dep)
- nanoid (we use crypto.randomUUID())
- react-jsx-parser (never wired)
- remark-breaks (markdown extension, never wired)
- shiki (syntax highlighting, never wired)
- tokenlens (never wired)
- use-stick-to-bottom (was an AI Elements dep)
- @radix-ui/react-use-controllable-state (no importers)
Kept everything actually imported: shadcn primitive surface intact
(class-variance-authority, cmdk, embla-carousel-react, lucide-react,
radix-ui umbrella + per-package @radix-ui/react-checkbox /
react-separator for beautiful-chat's local components), CopilotKit v2,
Hashbrown + json-render BYOC catalogs, recharts, react-markdown +
remark-gfm, openai (voice route), yaml (manifest parsing), zod.
Build still green at 54 routes. Lockfile updated. tsconfig.json
`jsx: "preserve"` — Next 15 reset this from `react-jsx` automatically
on build.
Cross-cutting changes that don't belong with any one demo: manifest +
landing-page tags, runtime route adjustments, e2e + QA notes that
follow the demo renames, and a few small cleanups.
Manifest (manifest.yaml + src/app/page.tsx tag labels):
- Naming convention: every demo uses `Thing: Subthing` (Generative UI:
Tool Rendering - Default / Custom Default / Specific; Open Generative
UI: Default / Advanced; Shared State: Streaming / Read + Write;
Reasoning: Default / Custom; Frontend Tools: In-App Actions / Async;
Human in the Loop: In-chat / In-App / Interrupt based; Chat
Customization: CSS / Slots; Headless UI: Simple / Complete).
- Retags: Auth → `platform`; HITL Step Selection + Interrupt-based →
`interactivity`; Reasoning Default + Custom → `chat-ui`; Generative
UI: Tools → `generative-ui`.
- Renames: Readonly State (Agent Context) → Frontend Context Sharing.
- HITL slot points at /demos/hitl-in-chat (working
useHumanInTheLoop+interrupt path) instead of the previous
/demos/hitl that had no backend `interrupt()` calls.
- Highlight paths corrected for the rebuilt headless demos (root-level
paths replaced with hooks/, chat/, tools/, attachments/ subdirs).
- Descriptions rewritten where they had drifted from the implementation
(gen-ui-agent: dropped useCoAgentStateRender claim;
headless-simple: shadcn primitives, not raw Tailwind;
headless-complete: enumerates the actual hooks wired).
Runtime / route:
- src/app/api/copilotkit/route.ts — 30 agents registered (incl. the
reasoning-custom rename from agentic-chat-reasoning).
- copilotkit-mcp-apps/route.ts replaced with [[...slug]]/route.ts so v2
subpath POSTs (/v2/agent/run) resolve.
- src/app/api/copilotkit-voice/[[...slug]]/route.ts — env var standardized
(was `AGENT_URL || LANGGRAPH_DEPLOYMENT_URL`, now matches the rest
of the showcase with just LANGGRAPH_DEPLOYMENT_URL); trailing `/`
removed from deploymentUrl.
Tests / QA:
- e2e specs renamed and paths updated for the demo renames.
- qa notes for a2ui-fixed-schema (booked-state checklist removed) and
byoc-json-render (Wave 4a residue removed).
- docs-links.json key renamed for reasoning-custom.
Cleanup:
- Removed remaining stub agent.py files in demo dirs (real graphs in
src/agents/); removed dead beautiful-chat/components/headless-chat.tsx
(zero importers); removed [A2UI-DEBUG] / [A2UI-RESPONSE] print
statements from beautiful_chat.py; gpt-5.4-mini → gpt-5-mini typo
fix in beautiful_chat.py:249 (would have 4xx'd every model call);
stripped iframe-restriction LLM-prompt copy bleed from
open-gen-ui-advanced suggestion titles.
The convention pass that ran across ~28 demos earlier in this branch is
already reflected in their per-demo commits — every page.tsx reads as
imports + provider + suggestions hook + JSX, with `useConfigureSuggestions`
extracted to a sibling suggestions.ts.
Two demos that showcase how a platform team integrates CopilotKit:
auth gating and runtime config injection.
Auth — defaults UNAUTHENTICATED. First paint is a centered shadcn Card
with the demo token visible (`demo-token-123`) and a "Sign in" button.
<CopilotKit> doesn't mount until the user signs in; clicking the button
stores the token in localStorage and triggers a re-render that mounts
the chat with `Authorization: Bearer <token>` header attached. Reload
preserves the token; sign-out clears it and returns to the card.
Earlier drafts of this demo defaulted to authenticated with a
ChatErrorBoundary + onError-driven banner to recover from <CopilotChat>
's 401-on-mount crash. Both have been removed — gating the chat behind
`isAuthenticated` means it never mounts with bad creds, so the boundary
has no purpose.
Backend route uses `createCopilotRuntimeHandler` from
@copilotkit/runtime/v2 directly because the Next.js adapter does not
forward `hooks`. The `onRequest` hook validates the bearer token and
throws a Response(401) on missing/wrong tokens.
Agent Config — typed knobs (tone / expertise / responseLength) that
change the agent's behavior per turn. Pivoted to `useAgentContext` from
the original `<CopilotKit properties={...}>` transport, which silently
dropped the values in @ag-ui/langgraph 0.0.31 — those payloads landed
at the top level of the LangGraph stream and weren't routed into
RunnableConfig["configurable"]. A prior workaround that repacked them
there triggered LangGraph 0.6's "cannot specify both configurable and
context" 400.
useAgentContext is the supported LangGraph 0.6+ path for "frontend →
agent runtime context." A small ConfigContextRelay component sits inside
the provider and publishes the live toggles. The Python graph collapses
to a single static system prompt with three rulebooks; CopilotKitMiddleware
injects the context entry into the model's prompt automatically.
Four state-flow demos plus the multi-agent demo, all sharing the
page-as-entry-point convention with extracted suggestions.
- shared-state-streaming (Shared State: Streaming) —
StateStreamingMiddleware(state_key="document", tool="write_document",
tool_argument="document"). The argument name MUST match the state_key
for the partial-JSON streamer to index correctly. Fixed in this pass
(previous version had a name mismatch). Frontend renders `LIVE` badge
+ char counter so per-token streaming is visible.
- shared-state-read-write (Shared State: Read + Write) — bidirectional.
UI writes preferences via `agent.setState`; agent writes notes via a
`set_notes` tool that returns Command(update={...}). PreferencesInjector
middleware reads the state on every turn and injects it as a system
message. CopilotPopup layout, 2-col card UI, "Agent Scratch pad"
copy.
- shared-state-read (deprecated route stub) — kept for back-compat with
any external links; the canonical demo is shared-state-read-write.
- readonly-state-agent-context (Frontend Context Sharing) — frontend
publishes read-only context via useAgentContext (the LangGraph 0.6+
idiom). Backend has tools=[] and only CopilotKitMiddleware; read-only
is enforced by the absence of any state-write tool, not a flag.
- subagents (Sub-Agents) — supervisor + research / writer / critic
sub-agents. Per-tool useRenderTool registrations surface delegation
events to the chat. State has a delegations[] log; the Python side
only writes status="completed" so the type was tightened (dropped
unused "running" / "failed" legs from both Python TypedDict and the
TypeScript shape). Frontend infers active sub-agent from in-flight
tool calls via a defensive structural probe over agent.messages.
A single commit for the "agent-authored UI" cluster — five distinct
strategies, all sharing a common shape (declare a catalog, let the
agent pick + populate components):
- declarative-gen-ui (Declarative UI: A2UI) — A2UI dynamic schema. The
agent calls `generate_a2ui` (not the runtime's auto-injected
`render_a2ui`) which secondary-binds an internal render tool with
forced tool_choice, then returns operations via `a2ui.render(...)`.
Custom catalog (Card / StatusBadge / Metric / InfoRow / PrimaryButton
/ PieChart / BarChart) wired via `a2ui.catalog` on the provider.
- a2ui-fixed-schema (Declarative UI: A2UI Fixed Schema) — fixed
server-side schema. The "Book flight" button is an inert label; the
earlier draft tried a schema swap to a booked-confirmation but the
SDK doesn't yet expose `action_handlers` from Python. Removed
BOOKED_SCHEMA + booked_schema.json since they were dead weight.
Cleaned 8 (props as Record<string, any>) casts down to a single
shared `s()` helper.
- mcp-apps — MCP server-driven UI via activity renderers. The runtime's
`mcpApps.servers` config wires Excalidraw; agent has tools=[] and
the middleware emits activity events that the built-in
MCPAppsActivityRenderer auto-mounts as a sandboxed iframe.
- byoc-hashbrown (Declarative UI: Hashbrown) — streaming structured
output via @hashbrownai/react. Agent prompt locks output to JSON via
`response_format: json_object` with a `{ ui: [{ tag: { props } }] }`
contract. Custom slot override on messageView.assistantMessage parses
the streaming JSON.
- byoc-json-render (Declarative UI: json-render) — streaming hierarchical
JSON UI spec via @json-render/react with a Zod-validated catalog.
Catalog (defineCatalog) + registry (defineRegistry) split keeps the
schema as the single source of truth.
- open-gen-ui (Open Generative UI: Default) — runtime's
`openGenerativeUI` config injects a sandboxed UI tool; design-skill
override steers the agent toward educational visualizations. Built-in
OpenGenerativeUIActivityRenderer auto-mounts.
- open-gen-ui-advanced (Open Generative UI: Advanced) — adds frontend
sandboxFunctions registered on the provider; each Zod-typed handler
is exposed to the iframe via the host bridge. Suggestion titles read
as normal user prompts (no iframe-restriction LLM-prompt copy bleed).
Backends sit at src/agents/{a2ui_fixed,byoc_hashbrown_agent,
byoc_json_render_agent}.py and the MCP runtime at
src/app/api/copilotkit-byoc-hashbrown/route.ts.
Five demos exercising the per-tool / catch-all / agent-state rendering
patterns. The three tool-rendering cells share the tool_rendering_agent
graph; they differ only in how the frontend renders the same tool
calls.
- tool-rendering (Tool Rendering - Specific) — per-tool useRenderTool
for get_weather + search_flights, plus a useDefaultRenderTool wildcard
for everything else.
- tool-rendering-default-catchall (Tool Rendering - Default) — single
shadcn-styled wildcard via useDefaultRenderTool. Without registering
*some* renderer the runtime has no `*` entry and tool calls render
invisibly; this demo shows the minimum-viable shape.
- tool-rendering-custom-catchall (Tool Rendering - Custom Default) —
same single-wildcard shape, branded with a custom card.
Backend system prompt (src/agents/tool_rendering_agent.py) defaults to
ONE tool per user question. Chaining is opt-in via a "Chain tools"
suggestion that triggers an explicit-ask exception in the prompt — the
previous default-on-chaining generated extra unsolicited tool-call
cards on every turn.
- gen-ui-tool-based (Generative UI: useComponent) — useComponent for
render_bar_chart + render_pie_chart with Zod schemas; backend has
tools=[] and the runtime injects the tools.
- gen-ui-agent (Generative UI: Agent State) — agent-state-driven step
list. The Python graph plans steps via a `set_steps` tool that
returns Command(update={"steps": …}); the frontend reads via
useAgent({updates: [OnStateChanged]}) + a custom MessageList that
renders steps inside CopilotChat's messageView.children slot.
Removed: src/app/demos/{tool-rendering,gen-ui-agent}/agent.py — TODO
stubs; real graphs live in src/agents/.
Frontend Tools (in-app + async) demonstrate the spectrum of agent →
client tool calls:
- frontend-tools — useFrontendTool with a synchronous handler that
mutates page state. The agent calls `change_background` with any CSS
background value and the canvas re-paints. <CopilotSidebar /> layout;
default background is solid indigo so the canvas reads as a clean
start.
- frontend-tools-async — useFrontendTool with an async handler. The
agent calls `query_notes`, the handler awaits a 500ms simulated DB
query, and the agent uses the returned notes in its reply. Pure
frontend tool — backend has tools=[].
HITL family — three patterns for human-in-the-loop, all keyed on the
useHumanInTheLoop / useInterrupt primitives:
- hitl — step-feedback variant rendering inside the chat via
useHumanInTheLoop + useInterrupt (the v2 replacement for
useLangGraphInterrupt, which is not exported in v2).
- hitl-in-chat — time-slot picker variant. Backend graph (hitl_in_chat)
calls `interrupt({slots, …})` and resumes when the user picks. This
is the canonical "in-chat HITL" demo; the manifest entry points here.
- hitl-in-app — async useFrontendTool with an app-LEVEL approval modal
(rendered via createPortal OUTSIDE the chat). The completion callback
resolves the pending tool Promise with the user's decision. This is
HITL where the human surface is your app's UI, not the chat.
- gen-ui-interrupt — the lower-level useInterrupt primitive. Backend
(src/agents/interrupt_agent.py) has a real `schedule_meeting` tool
that emits an interrupt with topic / attendee / slots, and the
frontend renders an inline TimePickerCard.
Three "production-feel" chat demos that exercise the same convention
(page.tsx as entry point + suggestions extracted) and add their own
specialized hooks:
- multimodal — image + PDF uploads via CopilotChat attachments. Includes
a LegacyConverterShim (until @ag-ui/langgraph ships an updated
converter), magic-byte + LFS-pointer guard for safe content sniffing,
and sample-attachment-buttons that inject test images via DataTransfer
+ dispatch `change` event so screenshots / Playwright reproduce.
- voice — speech-to-text via @copilotkit/voice. Uses the V2 runtime
directly with [[...slug]] catch-all because `transcriptionService` is
V2-only. A guarded sample-audio-button injects deterministic sample
text via the textarea's native value setter (CopilotChat has no
controlled-input prop today). useSingleEndpoint={false} opts into the
V2 multi-endpoint protocol.
- beautiful-chat — flagship polished starter chat with brand fonts,
theme tokens, suggestion pills, generative-UI charts, and
enableAppMode / enableChatMode tools. Backend
(src/agents/beautiful_chat.py) wires query_data, manage_todos,
search_flights, and an A2UI dynamic generator (generate_a2ui) that
hits a secondary LLM for schema design. Model: gpt-5-mini.
The convention pass extracted suggestions into separate files for each
demo and slimmed page.tsx down to imports + provider + render.
Three demos showing the prebuilt component formats. All three share the
neutral assistant graph and follow the page-as-entry-point convention:
each page.tsx slimmed to imports + provider + the suggestions hook
mount + JSX, with `useConfigureSuggestions` extracted to its own file.
- agentic-chat (Prebuilt: CopilotChat) — full-page CopilotChat. Plain
text suggestions (joke / fun fact / limerick) — earlier drafts had a
"Weather in Paris" prompt but the agent has no weather tool; trimmed
to non-tool prompts so suggestions actually work.
- prebuilt-sidebar (Pre-Built: Sidebar) — <CopilotSidebar /> docked to
the edge of the viewport. Page content centered in mx-auto max-w-2xl
column with icon + heading + paragraph. The sidebar genuinely PUSHES
the page now — see the body width fix in src/app/globals.css from the
scaffolding commit.
- prebuilt-popup (Pre-Built: Popup) — <CopilotPopup /> with a floating
launcher. Same centered content shape as the sidebar demo.
Removed: src/app/demos/agentic-chat/agent.py — TODO stub with a
misleading docstring; the real graph is at src/agents/agentic_chat.py.
A pair of demos that exercise the same backend reasoning graph but
differ only in whether the frontend overrides the
`messageView.reasoningMessage` slot.
Backend (src/agents/reasoning_agent.py): uses a reasoning-capable OpenAI
model (gpt-5-mini by default, override via OPENAI_REASONING_MODEL) routed
through the Responses API so the model's chain-of-thought streams as
AG-UI REASONING_MESSAGE_* events with `role: "reasoning"`. The prompt
asks for a concrete physics answer, which reliably triggers reasoning;
meta-prompts like "show your reasoning step by step" produce no
reasoning summary because the model recognizes those as a request to
reveal chain-of-thought (which it refuses).
Frontend:
- reasoning-default/ — no slot override; built-in
CopilotChatReasoningMessage renders the "Thinking… / Thought for X"
header with an expandable content region.
- reasoning-custom/ — overrides `messageView.reasoningMessage` with a
ReasoningBlock (amber banner with `data-testid="reasoning-block"`).
The label flips from "Thinking…" while streaming to "Agent reasoning"
once the stream settles.
Suggestions live in their own files (per the page-as-entry-point
convention). Both demos share `agent="reasoning-default"` /
`agent="reasoning-custom"` against the same `reasoning_agent` graph,
registered in api/copilotkit/route.ts.
Removed:
- src/app/demos/agentic-chat-reasoning/ — replaced by reasoning-custom/
for naming clarity.
- src/app/demos/reasoning-default-render/ — earlier draft of the Default
demo with a slightly different page name.
- tests/e2e/agentic-chat-reasoning.spec.ts — replaced by
reasoning-custom.spec.ts.
Two paired demos showing the spectrum of "change the look" without
rewriting components:
CSS theming (chat-customization-css/) — HALCYON, a warm-paper editorial
brand. Two layers do the work:
1. v2 token overrides on `[data-copilotkit]` recolor every Tailwind
utility (cpk:bg-muted, cpk:text-foreground, …) the runtime renders.
2. Class-targeted styling on .copilotKitChat, .copilotKitMessage*,
.copilotKitInput, suggestions, scrollbar, welcome screen for the
editorial details that CSS variables alone can't express.
Aesthetic: cream parchment surface, sharp 90° corners, copper-ember
accents, italic display serif (Instrument Serif) + Fraunces body +
JetBrains Mono dispatch, paper-grain noise via inline SVG, mono masthead
pinned under the top edge. All selectors namespaced under
`.chat-css-demo-scope` — no leakage.
Slot atlas (chat-slots/) — every overrideable slot wrapped in a
dashed-outline marker. Markers nest correctly: each shows ONLY its own
label on hover via `:has(.slot-marker:hover)` rather than lighting up
every nested label as the cursor enters the outermost one. Each label is
a click-to-copy button (✓ flash on success) that copies the slot's
PascalCase component path (`Input.TextArea`,
`MessageView.AssistantMessage`, …) so a developer can paste straight
into IDE search. SuggestionPill, ScrollToBottomButton, and Feather slots
are all wired. CustomFeather has its own `FeatherCopyLabel` because the
default Feather uses position:absolute and can't share SlotMarker.
Both demos use the neutral assistant graph (chat-customization-css and
chat-slots are entries in the route.ts neutralAssistantCells list).
Full headless surface — a hand-rolled CopilotChat replacement that wires
every render hook on top of shadcn/ui primitives. Visual chrome matches
Headless: Simple so the two read as a paired sibling demo.
Architecture is progressive-disclosure: the entry file is a 30-line
HeadlessCompleteRoot that enumerates capabilities, each registered via
a focused hook module:
page.tsx
hooks/
use-tool-renderers.tsx — useRenderTool x3, useDefaultRenderTool
use-frontend-components.ts — useComponent (highlight_note)
use-headless-suggestions.ts — useConfigureSuggestions
chat/
chat.tsx, header.tsx, empty-state.tsx, composer.tsx,
suggestion-bar.tsx, message-list.tsx, message-user.tsx,
message-assistant.tsx, message-activity.tsx, typing-indicator.tsx
attachments/use-attachments-config.ts + attachment-preview.tsx
tools/weather-card.tsx, stock-card.tsx, chart-card.tsx,
generic-tool-card.tsx, highlight-note.tsx
Backend (src/agents/headless_complete.py): get_weather, get_stock_price,
get_revenue_chart tools; the chart tool replaces the previous Excalidraw
"Sketch a diagram" suggestion (MCP capability stays wired).
Bug fixes folded in:
- Tool-call cards stuck "running" forever — message-list.tsx indexes
role:"tool" messages by toolCallId and passes the matching ToolMessage
to renderToolCall so cards advance to "complete".
- Empty state was hugging the top of the viewport — Radix ScrollArea
wraps content in a `display: table` div that breaks h-full propagation.
Empty state now renders OUTSIDE the ScrollArea.
- SuggestionBar duplicated the empty-state prompts on first paint.
Hidden until the conversation starts.
Minimum-viable headless chat that wires only `useAgent` + `useCopilotKit`,
dressed in shadcn/ui primitives. Five small single-purpose files so a
reader can grok the surface in under a minute:
page.tsx — provider + <Chat />, ~10 lines
chat.tsx — useAgent + useCopilotKit + send loop
composer.tsx — Textarea + send button
empty-state.tsx — sparkles + sample prompts
message-bubble.tsx + typing-indicator.tsx — render pieces
Wires runtimeUrl="/api/copilotkit" + agent="headless-simple" against
the neutral assistant graph registered in route.ts.
Also adds the v2 catch-all route at copilotkit-mcp-apps/[[...slug]]/route.ts
(used by Headless: Complete in the next commit). v2 hooks POST to subpaths
like /v2/agent/run; the previous flat route 404'd, leaving headless demos
stuck on "Thinking…".
Foundational layer that the per-demo work in subsequent commits builds on.
- Manifest-driven landing page (src/app/page.tsx) — auto-generated grid
of demo cards from manifest.yaml, grouped by tag with explicit ordering
for chat-ui / interactivity / generative-ui / agent-state / multi-agent
/ headless / platform.
- Per-demo titles (src/middleware.ts + src/app/demos/layout.tsx).
- Diagnostic console gated to NODE_ENV=production in app/layout.tsx so
deployed showcases surface uncaught errors and iframe context.
- src/app/globals.css — Tailwind v4 @theme inline block that maps
showcase CSS variables into Tailwind theme tokens (without it, shadcn
utilities like bg-muted / text-foreground compile to nothing). body
intentionally NOT given width:100% so <CopilotSidebar /> can shrink
the document via marginInlineEnd.
- shadcn primitives under src/components/ui/ + src/lib/utils.ts.
- tsconfig.json — @/* path alias rooted at src/.
Removed:
- src/app/copilotkit-overrides.css (global override layer, superseded
by per-demo theming)
- src/app/api/copilotkit-mcp-apps/route.ts (replaced with
[[...slug]]/route.ts so v2 subpath POSTs like /v2/agent/run resolve)
Switch CLI command to `npx copilotkit@latest create --framework <id>` on all 8
framework quickstarts. Bypasses the unfiltered 18-framework picker and skips
the EIP prompt (which is mutually exclusive with --framework and today
scaffolds langgraph-python-threads regardless of which framework page the
user came from).
For LangGraph: keep an EIP callout since EIP=Yes does scaffold a LangGraph-
Python project today; note that threads support for other frameworks is
coming. For Microsoft Agent Framework and LangGraph (multi-variant): show
both --framework <variant> commands.
Apply the canonical V2 form:
- \`<CopilotKit>\` from \`@copilotkit/react-core\` (root, not /v2).
- styles from \`@copilotkit/react-core/styles.css\` (not react-ui/v2).
- drop \`@copilotkit/react-ui\` from npm install commands.
Add sample-audio-button region markers around the SampleAudioButton
component in the built-in-agent voice demo so the
<Snippet cell="voice" region="sample-audio-button" /> reference in
shell-docs/voice.mdx resolves to real code instead of a missing-snippet
warning.
Comment-only change; no runtime behavior change. Mirrors the canonical
in-place region pattern already used by langgraph-typescript, mastra,
ms-agent-python, claude-sdk-typescript, llamaindex, spring-ai,
pydantic-ai, claude-sdk-python, and crewai-crews per the Mastra Round
Pattern Decisions playbook.
## Summary
- The dynamic shields.io license badge in the top-of-README badge row
sometimes renders as **invalid** on github.com (I suspect some caching
or something but not gonna spend the time digging in).
- Downloaded the rendered SVG once and vendored it at
`assets/license-badge.svg`
## Summary
Three small pre-cutover cleanup fixes batched into one PR (consolidation
of the prior #4680, #4681, #4682 — same content, fewer review queues).
- `b3ec38720` — Add `<WhenFrameworkHas absent>` fallback to
`programmatic-control.mdx` for the 7 frameworks without
`interrupt_pattern` (ag2, agno, built-in-agent, crewai-crews,
google-adk, mastra, spring-ai), mirroring the canonical pattern from PR
#4496.
- `c080ca062` — Retarget `/migrate/1.10.X` redirect destination from
`/migrate` (which 404s) to `/migrate/v2`. `permanent: false` preserved.
- `e61e8c36d` — Add `mcp-server-setup.mdx` exclusion to docs sync
script. Shell-docs version is intentionally ahead of upstream (HTTP/SSE
Tabs + `mcp-remote` + Tadata callout); without exclusion the next sync
would clobber it.
Supersedes #4680, #4681, #4682.
## Test plan
- [ ] `nx run shell-docs:dev` and visit `/programmatic-control` while
switching the framework selector to non-native fws — verify fallback
callout renders and links to `/human-in-the-loop`.
- [ ] Visit `/migrate/1.10.X` — should redirect to `/migrate/v2` and
render the V2 migration page.
- [ ] Inspect `showcase/scripts/sync-docs-from-main.ts` PATH_EXCLUSIONS
for the `mcp-server-setup` regex.
## Summary
- Extract `CopilotKitContext` and `useCopilotKit` into standalone
`context.ts` in react-core, enabling cross-platform reuse without web
dependencies
- Add new `@copilotkit/react-native` package with lightweight provider,
polyfills, and streaming fetch
- All hooks (`useAgent`, `useFrontendTool`, `useHumanInTheLoop`, etc.)
are re-exported directly from react-core — no reimplementation
## Motivation
CopilotKit's React hooks are platform-agnostic, but the barrel import in
`@copilotkit/react-core` pulls in web-only dependencies (Radix UI, Lit,
A2UI renderer, react-dom, CSS). This makes the package unusable in React
Native without extensive Metro shimming.
By extracting the React context into a standalone entry point
(`@copilotkit/react-core/v2/context`), the new
`@copilotkit/react-native` package can provide its own lightweight
provider while reusing all existing hooks.
## What's in `@copilotkit/react-native`
| Export | Description |
|--------|-------------|
| `CopilotKitProvider` | Lightweight provider — no DOM, CSS, Radix, Lit,
or A2UI deps |
| `installStreamingFetch()` | XHR-based streaming fetch for
`response.body.getReader()` support |
| `@copilotkit/react-native/polyfills` | All polyfills at once
(ReadableStream, TextEncoder, crypto, DOMException, window.location) |
| `@copilotkit/react-native/polyfills/*` | Granular per-polyfill imports
(`/streams`, `/encoding`, `/crypto`, `/dom`, `/location`) for users who
need to avoid overriding their own shims |
| `useAgent`, `useFrontendTool`, etc. | Re-exported from react-core
(shared context) |
## Usage
```tsx
// index.js (entry point, before other imports)
import "@copilotkit/react-native/polyfills";
import { installStreamingFetch } from "@copilotkit/react-native";
installStreamingFetch();
// App.tsx
import { CopilotKitProvider, useAgent, useCopilotKit } from "@copilotkit/react-native";
function App() {
return (
<CopilotKitProvider runtimeUrl="https://your-server/api/copilotkit">
<ChatScreen />
</CopilotKitProvider>
);
}
```
## Test plan
- [x] `nx run react-core:build` passes
- [x] `nx run @copilotkit/react-native:build` passes
- [x] `nx run react-core:test` — all 1153 tests pass
- [x] Manual test in React Native app (tested during development with
bare RN 0.84 project)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add to monorepo scope in release.config.json. Set version to 1.56.5,
correct ESM extensions in exports map, add check-types/publint/attw
scripts, align tsdown to ^0.20.3. Add react-native example glob to
pnpm-workspace.yaml. Regenerate lockfile preserving zod@3 and
langchain dependency versions.
## Summary
- Fix oxfmt formatting violation in
`deep-agents-finance-erp/use-request-approval.tsx` (failing `static /
quality`)
- Add missing `lucide-react` dependency to
`showcase/shell-docs/package.json` (failing `Showcase: Build & Push` for
shell-docs)
- Regenerate `langgraph-typescript` lockfile after
`@langchain/langgraph` bump to 1.3.0 (failing `Showcase: Build & Push`
for langgraph-typescript)
- Guard all Slack notification steps in `showcase_docs-sync`,
`test_smoke-starter`, and `showcase_qa-sync` workflows with
`env.SLACK_WEBHOOK != ''` so they skip gracefully when
`SLACK_WEBHOOK_OSS_ALERTS` is not set (failing `Showcase: Docs Sync` and
smoke tests)
## Test plan
- [x] `oxfmt --check` passes locally on the formatted file
- [x] `lucide-react` resolves via `npm ls` in shell-docs
- [x] `npm ci --dry-run` passes for langgraph-typescript with
regenerated lockfile
- [x] Pre-commit hooks (lint, test, publint, attw) pass locally
- [x] CI green on prior push (all 24 checks passed)