## Problem
After #6106 merged, **staging showed every built-in-agent cell capped at
D3** with the backend red:
```
Failure: empty assistant response (level: chat)
Backend: https://showcase-built-in-agent-staging.up.railway.app
```
The D4 chat probe hits the main agent (`agentic_chat` / generic
`createBuiltInAgent`), which used **`gpt-5.5`** → the real OpenAI call
returns empty → the whole D-ladder gates → all cells stuck at D3.
## Root cause
- `gpt-5.5` is **unique to built-in-agent** (introduced in #6106). Every
other integration — including the **LGP reference that works on
staging** — uses **`gpt-5.4`** (38× across the repo).
- Staging's OpenAI account doesn't serve `gpt-5.5`, so every real call
came back empty.
- **aimock ignores the model id**, so this was invisible in local D6
(which is why it passed locally but broke on staging).
- The other factories also still had leftover `gpt-4o` / `gpt-4o-mini`
(a2ui, byoc, mcp-apps, ogui, subagents).
## Fix
Switch **all** `built-in-agent` `openaiText()` calls to **`gpt-5.4`**
(matches LGP, served on staging). `reasoning-factory` keeps `gpt-5.2`
(reasoning-capable; those demos are NSF-quarantined). 10 factory files,
model-string-only changes.
> Note: this deviates from the general "always gpt-5.5" preference
because this is an **LGP-parity** integration and staging only serves
`gpt-5.4` — parity + a working staging both require it.
## Verify
Once merged + redeployed, staging D4 chat should return real text and
the cells should climb past D3. (Can't be verified in local D6 since
aimock ignores the model.)
Staging D4 chat probe returned 'empty assistant response' for every cell,
capping all cells at D3. Root cause: the factories used gpt-5.5 (agentic-chat +
generic createBuiltInAgent) and leftover gpt-4o/gpt-4o-mini (a2ui, byoc, mcp-apps,
ogui, subagents). gpt-5.5 is unique to built-in-agent; every other integration —
including the LGP reference that works on staging — uses gpt-5.4, which staging's
OpenAI account serves. aimock ignores the model id, so this was invisible locally.
Switch all built-in-agent openaiText() calls to gpt-5.4 (matches LGP, unblocks
staging). reasoning-factory keeps gpt-5.2 (reasoning-capable, its demos are
NSF-quarantined). Note: deviates from the general gpt-5.5 house rule because this
is an LGP-parity integration and staging only serves gpt-5.4.
Adversarial-review finding: ready() awaits all channels' startup; an adapter whose
start() hangs would block readiness forever. Both examples now pass timeoutMs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial-review finding: ɵruntime.start() swallowed every adapter start failure
and resolved, so the runtime reported status "online" on a dead channel (revoked
token, port-in-use). Now: if a channel has adapters and NONE started, start() rejects
so ChannelManager surfaces "error" (a partial start, >=1 adapter live, still counts as
started). Adds a channel-manager failStart regression test + updates the telemetry test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The activation path reads the top-level channel.provider; the ɵruntime.provider
copy was never consumed. Keeps the real top-level accessor.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## What & why
Brings the **built-in-agent** showcase integration to parity with the
**LangGraph-Python (LGP)** reference: byte-identical demo frontends + a
named-agent backend registry (BuiltInAgent + TanStack AI), so every demo
climbs the D0–D6 ladder against the LGP gold standard.
## Changes (4 commits)
1. **P0 pattern** — `agentic-chat` byte-identical + named agent
(`agentic_chat`); proven D6-green locally. Fixed `gpt-4o` → `gpt-5.5` in
the shared factory.
2. **Frontend migration (all demos)** — every LGP `src/app/demos/*`
copied verbatim (`diff -r` clean), plus shared `components/ui` (25
shadcn primitives) + `lib/utils`, byte-identical. Added the 5 demos BIA
lacked (`a2ui-recovery`, `declarative-hashbrown`,
`declarative-json-render`, `shared-state-read`,
`threadid-frontend-tool-roundtrip`); added the frontend deps the copied
UI needs (radix-ui, cmdk, embla-carousel-react, react-markdown,
remark-gfm, yaml, …).
3. **Named-agent backend** — `/api/copilotkit` registers 22 named agents
(generic all-tools, fixture-driven; reasoning trio via the reasoning
adapter). 8 dedicated routes re-keyed `default` → LGP agent id;
`mcp-apps` also serves `headless-complete`; `ogui` serves both
open-gen-ui ids; `byoc-*` routes renamed to `declarative-*`; new
`a2ui-recovery` + `beautiful-chat` routes reuse existing agents. Dropped
BIA-only extras (`byoc-*`, `hitl-in-chat-booking`).
4. **Reconcile** — `manifest.yaml` (37 features / 40 demos;
`generate-registry` + `validate-parity` pass) + `PARITY_NOTES.md`.
> **Note on "byte-identical":** frontends are verbatim LGP **modulo
BIA's `consistent-type-imports` ESLint rule** (type imports split into
`import type {}`) — required for a green lint/PR, semantically & DOM
identical.
## D6 status (local sweep)
- **~33/40 demos GREEN** on the first sweep — byte-identical frontends +
named agents + existing fixtures work broadly.
- **4 RED locally are an aimock-infra issue, not this integration:** the
deployed `ghcr.io/copilotkit/aimock:latest` has no
`context`/`--context-field` fixture scoping, so cross-slug `userMessage`
collisions let earlier-loaded (`ag2`/`d4`) fixtures shadow BIA's own.
BIA's fixtures are **correct** and converge under a context-aware aimock
(present on aimock `origin/main`). Affects
`tool-rendering-custom-catchall`, `headless-complete`, `gen-ui-agent`,
`frontend-tools`. **Action for infra: redeploy aimock from a
context-aware build.** Details in `PARITY_NOTES.md`.
- **2 downstream-host RED (kept as features, informational — mirrors
LGP):** `declarative-gen-ui` (A2UI renderer host) and `mcp-apps` (MCP
iframe host).
- Quarantined NSF unchanged: `gen-ui-interrupt`, `interrupt-headless`,
`shared-state-streaming`, reasoning-trio.
D6 is informational/weekly (not a merge gate); these are documented for
parity tracking.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## What
Widens the optional `@anthropic-ai/sdk` peer dependency of
`@copilotkit/runtime` from `^0.57.0` to `>=0.57.0`.
## Why
An outside contributor reported that `@copilotkit/runtime` still
declares an optional peer of `@anthropic-ai/sdk@^0.57.0`, which
conflicts with current SDK versions (e.g. `0.109`) and forces consumers
to install with `--legacy-peer-deps`.
The `^0.57.0` caret pins the range within `0.57.x` (since it's a `0.x`
version), so any newer minor trips the peer-conflict warning even though
the SDK works fine at runtime.
## Safety
The anthropic adapter only relies on stable `@anthropic-ai/sdk` APIs —
client construction (`new Anthropic({})`), `messages.create`, and
ephemeral `cache_control` — which have been stable across `0.x`
releases. The reporter confirms `0.109` works at runtime today; this
only removes the false install-time peer conflict.
## Change
One line in `packages/runtime/package.json`:
```diff
- "@anthropic-ai/sdk": "^0.57.0",
+ "@anthropic-ai/sdk": ">=0.57.0",
```
Both run their Channel through an Intelligence runtime that owns lifecycle:
new CopilotRuntime({ intelligence, identifyUser, channels: [bot] }) + handler.channels.ready()/stop(),
no bot.start(). Direct adapters retained (multi-platform slack now runs under Intelligence). Env + example READMEs note the required Intelligence key (free tier).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Channels require an Intelligence connection (API key, free tier); run via
CopilotRuntime({ intelligence, channels }) + handler.channels.ready()/stop();
no channel.start(), no standalone/DIY path. Adapters keep their credentials.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The ChannelManager (only constructed for an Intelligence runtime) now STARTS
direct-adapter channels via channel.ɵruntime.start() instead of recording them
"unmanaged" and skipping — so every channel runs only because Intelligence is
configured; there is no standalone path. Removed the now-dead "unmanaged" status;
direct channels reuse the bounded/idempotent teardown via a synthetic handle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Channels run only through the Intelligence runtime now; there is no public
lifecycle to call. The internal channel.ɵruntime.{start,stop,addAdapter} seam is
retained and is what the runtime drives. Internal callers + guard strings migrated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
Fixes#4819.
`processAgentResult` recurses into `runAgent` whenever `needsFollowUp`
is true, with **no depth limit, no circuit breaker, no duplicate
detection**. Any scenario that keeps `needsFollowUp = true` loops
forever:
- The LLM repeatedly calling the same tool
- The backend returning a `RunError` after receiving tool results
(#2416)
- Input processors reprocessing tool messages (#3044)
This silently consumes API quota and can DOS the backend. The only
existing workaround — setting `followUp: false` on a tool — is too blunt
and breaks legitimate multi-step workflows.
## Change
- Add an absolute safety cap `MAX_FOLLOW_UP_DEPTH = 100`, reusing the
existing `_runDepth` counter (incremented in `runAgent`, decremented in
its `finally`).
- In `processAgentResult`, when the depth cap is reached: stop
recursing, emit a `logger.warn` (for debuggability), and return the
current result normally (already-inserted tool messages are preserved).
- The cap is deliberately high so legitimate multi-step workflows
(search → fill form → confirm → update → send email) are never affected;
it only trips on runaway recursion.
This protects against **all** infinite-loop scenarios in the issue, not
just specific triggers, without requiring users to set `followUp:
false`.
## Test
- Added `core-full.test.ts` TEST 9b: an agent that always returns a
fresh tool call (so `needsFollowUp` stays true). Asserts the run
terminates, `runAgent` is capped at ≤100 calls, and a warning is
emitted.
- `nx run @copilotkit/core:test` → 40 files / 431 tests pass.
- `nx run @copilotkit/core:build` → success.
Move start/stop/addAdapter/provider bodies onto channel.ɵruntime.*; the public
methods become thin delegators (behavior identical). Lets a runner drive the
lifecycle without the public API. Pure relocation — tsc + 156 tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The vi.fn mock factories were 0-arg but invoked with the provider options in
the vi.mock adapters, tripping tsc (TS2554). vitest transpiles without type-
checking, so it passed vitest locally but failed the check-types job.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_def.typeName isn't on ZodTypeDef's public type (TS2339 in check-types);
instanceof is the type-safe equivalent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A frontend/client tool (`useFrontendTool`) whose Zod `parameters` use
`z.discriminatedUnion(...)` — or any schema that serializes to a JSON-schema
`anyOf`/`oneOf` node — silently lost the union-typed field when calling OpenAI.
The tool call arrived with that field missing or empty.
Root cause: the runtime has two JSON-Schema -> Zod converters. The shared one
(`@copilotkit/shared`) already handles `anyOf`/`oneOf` as `z.union`, but the
local copy in `packages/runtime/src/agent/index.ts` — used by the classic
`BuiltInAgent` / AI SDK path via `convertToolsToVercelAITools` — never did.
A union node carries no top-level `type`, so it hit the empty-schema guard and
collapsed to `z.object({})`. The reconstructed tool schema therefore dropped
the union entirely (most visibly for a union nested inside array `items`), so
the model was never offered those fields and could not emit them.
Fix: handle `anyOf`/`oneOf` as `z.union` before the empty-schema guard,
mirroring the shared converter. A single-variant union unwraps to that variant.
Backward compatible: only previously-broken union nodes change behavior
(empty object -> real union). Empty `{}` schemas, typed nodes, and the
`isJsonSchema` gate are untouched.
Repro: a `useFrontendTool` with `parameters: z.object({ blocks: z.array(
z.discriminatedUnion("type", [...])) })` against OpenAI — before, `blocks`
items arrived empty; after, both variants survive into the model call.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `@copilotkit/react-native` barrel statically re-exports the prebuilt chat
UI (CopilotChat / CopilotModal / CopilotSidebar / CopilotPopup, which import
`@gorhom/bottom-sheet`) and `useAttachments` (which imports
`expo-document-picker` + `expo-file-system`). Those are optional peer deps, but
a static re-export still forces Metro to resolve them at bundle time. A headless
consumer that uses only `CopilotKitProvider` + `useAgent` + `useFrontendTool`
(a fully custom UI) had to install every chat/attachment native dep or stub them
in `metro.config.js`, or the release bundle fails with
`Unable to resolve module expo-document-picker`.
Add a lean `@copilotkit/react-native/headless` entry that re-exports only the
provider, the platform-agnostic hooks, the render-tool registry, and the
core/AG-UI types — none of the chat UI or `useAttachments` — so those native
deps never enter the bundle graph and the metro-stub workaround is retired.
Mirrors `@copilotkit/react-core/v2/headless` (#5883): a standalone entry file,
wired into the tsdown entry list, the package.json `exports` map, and
`sideEffects` (it side-effect-imports the polyfills). The default barrel now
does `export * from "./headless"` and layers the chat UI on top, so it stays
fully backward compatible. Adds a static import-graph regression test asserting
the headless graph never reaches the chat/attachment modules or their native
peer deps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UseAgentProps had no `threadId`, yet the shipped V2 React Native demo
calls `useAgent({ agentId: "default", threadId })`. Because the prop
didn't exist, it was silently dropped: the demo's thread state (and its
"New Chat" reset) never reached the agent, which ran under its own
auto-minted UUID. threadId was only ever sourced from a surrounding
`CopilotChatConfigurationProvider`, which the headless RN demo has none.
Accept an optional `threadId` on UseAgentProps and honor it. Resolution
precedence: an explicit `threadId` prop wins; otherwise fall back to the
chat configuration's threadId (gated on hasExplicitThreadId, as before).
When the prop is omitted, behavior is unchanged — fully backward
compatible. This makes the RN demo's existing usage work and unblocks
headless callers that have no chat-configuration provider in the tree.
Extends the threadId-propagation contract test with coverage for the
prop path (no provider, prop-over-config precedence, prop re-sync).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
resolveModel() built each provider with only an apiKey, so a string model
spec (e.g. "openai/gpt-4o-mini") could not target an OpenAI-compatible
endpoint — OPENAI_BASE_URL was silently ignored, and the only workaround was
to construct the LanguageModel yourself and pass the instance. Same gap for
Anthropic and Google.
Now resolveModel passes baseURL from the standard env var
(OPENAI_BASE_URL / ANTHROPIC_BASE_URL / GOOGLE_GENERATIVE_AI_BASE_URL). It is
undefined when unset, so the provider falls back to its default endpoint —
fully backward compatible.
Tests: adds resolve-model-baseurl.test.ts (4 cases). Existing resolveModel
tests unchanged (118 runtime tests pass locally).
Discovered while building an OpenAI-compatible agent on the V2 runtime +
@copilotkit/react-native.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## What & why
`@copilotkit/react-core`'s `/v2` entry (and the root entry) re-exports
from a
single **monolithic shared chunk**, so importing *any* symbol — even one
hook —
pulls the built-in chat-message rendering stack (`streamdown` → shiki,
`mermaid`,
`cytoscape`, `katex`) into the consumer's bundle: **~3 MB gzip / ~15 MB
raw**,
with no way to tree-shake it. Consumers who build a fully custom chat UI
and only
use hooks pay the full cost. (Issue #4893.)
A separate lean build entry — `@copilotkit/react-core/v2/headless` —
already
ships those hooks in their own small chunk **without** that stack (it's
how
`@copilotkit/react-native` mounts CopilotKit). This PR makes it usable
for a
custom web UI.
Measured with esbuild (react/react-dom external):
| import | bundled JS |
|---|---|
| hooks from `@copilotkit/react-core/v2` | **~2.96 MB** gzip (≈
importing full `CopilotChat`) |
| same hooks from `@copilotkit/react-core/v2/headless` | **~0.03 MB**
gzip |
> Note on the report: `@copilotkit/a2ui-renderer` doesn't bundle the
rich-text
> stack (its deps are `@a2ui/web_core`, `lit`, `clsx`, `zod`). The
weight is
> entirely `streamdown` (shiki/mermaid/cytoscape) + `katex`, pulled by
the
> built-in `CopilotChat*` message components.
## Changes
- **`headless.ts`** — export `useCopilotKit` + `useRenderToolCall` (both
DOM-free
and rendering-stack-free); fix `UseAgentUpdate` (a runtime `enum`) being
re-exported via `export type`, which stripped its runtime value under
`isolatedModules` (so `useAgent`'s `updates` option was unusable from
headless
— a bug `tsc` can't catch). `useDefaultRenderTool` /
`useRenderCustomMessages`
/ `useRenderActivityMessage` stay in `/v2` (web-only markup or
`a2ui-renderer`).
- **Remove a `tailwind-merge` leak** — extract the tailwind-free ref
helpers
(`shallowEqual` / `useShallowStableRef`) into
`lib/shallow-stable-ref.ts` so the
headless graph no longer pulls `tailwind-merge` via
`CopilotChatConfigurationProvider`.
- **Test** — a small vitest export-surface test guarding the hook
surface and the
`UseAgentUpdate` runtime value.
## Verification
`react-core` typecheck + vitest (1427) and `react-native` typecheck
pass. Shipped
`dist/v2/headless.mjs` imports only `react`, `@ag-ui/client`,
`@copilotkit/core`,
`@copilotkit/shared`, `@copilotkit/react-core/v2/context`, `zod` — no
rendering
stack.
## Notes / follow-ups
- Headless hooks read a **different React context** than the prebuilt
`/v2`
`<CopilotKitProvider>`, so the two can't be mixed — mount a lean
provider over
`/v2/context` (as `@copilotkit/react-native` does). Making the `/v2`
provider
reuse the standalone `/v2/context` singleton would remove that sharp
edge and
is the natural follow-up.
- Existing bundle-size CI (`compressed-size-action`) already tracks
`headless.mjs`,
so no new size tooling is added here.
Addresses #4893.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Fixes#5966. Follow-up to #5812 / #5885.
## Problem
After #5885 stopped the post-terminal `TEXT_MESSAGE_END` crash, pressing
**Stop** no longer breaks the chat — but for an agent that emits a
terminal `RUN_ERROR` (code `abort`) as its cancellation signal (e.g.
pydantic-ai's `AGUIAdapter`), the client still surfaces that as an
**error banner** ("This operation was aborted"). A user-initiated stop
is expected cancellation, not a failure.
Traced path (no abort suppression at any hop):
`RUN_ERROR(code:"abort")` → `RunHandler.onRunErrorEvent`
(`run-handler.ts`) → `emitAgentError(AGENT_RUN_ERROR_EVENT)` → `onError`
→ CopilotChat/react-ui `triggerChatError` → banner. The only existing
abort suppression is for the *local* fetch-abort rejection
(`run-handler.ts:318`), a different path.
## Fix
Suppress the error emission in `onRunErrorEvent` when the run was
user-aborted — mirroring the local-abort suppression already on the
`runAgent`/`connectAgent` paths:
```ts
const runWasAborted = this._runAbortController?.signal.aborted === true;
if (runWasAborted || event?.code === "abort") {
return;
}
```
Prefers the client's own `_runAbortController.signal.aborted` (robust —
the agent-supplied `code` isn't standardized across agents; the
`code:"abort"` in the repro comes from the agent, not CopilotKit) with
`code === "abort"` as a secondary signal. Normal `RUN_ERROR`s are
unaffected.
## Testing
- **TDD** (`core-error-handling.test.ts`): two new tests fail pre-fix
and pass after —
- agent emits `RUN_ERROR` code `"abort"` → no `AGENT_RUN_ERROR_EVENT`
surfaced.
- run user-aborted mid-stream (via `agent.abortRun()`, which RunHandler
intercepts to abort the controller) → a subsequent `RUN_ERROR` with a
*non-abort* code is still suppressed (exercises the `signal.aborted`
path).
- The pre-existing test — normal `RUN_ERROR` (code `"bad_request"`)
still emits `AGENT_RUN_ERROR_EVENT` — continues to pass (control against
over-suppression).
- Full `@copilotkit/core` suite green: **578/578**. `tsc` 0 errors;
`oxlint` 0.
Note: this is a UX/product call (a user Stop shouldn't render as an
error). Suppressing in core fixes it for both the default chat banner
and app-level `onError` handlers; the run lifecycle still reflects the
termination.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- folds CopilotKit App Context into `ModelRequest.system_message` during
LangGraph model calls
- stops injecting App Context as a separate `SystemMessage` from
`before_agent`, avoiding non-consecutive system messages after LangGraph
reducers run
- updates middleware regression tests for state context, runtime
context, forwarded-header filtering, and message-history no-op behavior
## Root cause
`before_agent` inserted a new App Context `SystemMessage` into
`state["messages"]`, but the LangGraph message reducer can append new
message IDs rather than preserving positional insertion. With an
existing system prompt and prior conversation turns, this can produce
multiple non-consecutive system messages, which `langchain-anthropic`
rejects.
Fixes#5610.
## Validation
- `uv run pytest -q`
## What does this PR do?
Pins `opentelemetry-resourcedetector-gcp==1.12.0a0` in the ADK starter.
`google-adk` accepts prerelease resource-detector versions, but `uv`
skips transitive prereleases by default. The only stable candidate,
`1.13.0`, was yanked because it breaks imports. That left the ADK
starter with no valid dependency set.
The direct pin selects the last working release without allowing
prereleases for every dependency. The ADK starter image can build again.
## Related PRs and Issues
- Failing job:
https://github.com/CopilotKit/CopilotKit/actions/runs/30027772426/job/89285780349
## Validation
- RED: `docker build --progress=plain -f
examples/integrations/adk/Dockerfile examples/integrations/adk` failed
at `uv pip install --system -e .` because the requirements were
unsatisfiable.
- GREEN: the same command resolved 124 Python packages, installed the
pinned detector, built the Next.js app, and exported the image.
- `pnpm nx affected -t lint,check-types,test,build --base=origin/main
--head=HEAD` found no affected Nx tasks because this starter is built
outside the Nx project graph.
- `oxfmt --check examples/integrations/adk/agent/pyproject.toml` passed.
## Checklist
- [x] I have read the Contribution Guide.
- [x] No documentation change is needed; this restores the existing
starter build.
- [x] Allow edits by maintainers is enabled.
This PR contains the following updates:
| Package | Type | Update | Change |
|---|---|---|---|
| [docker/login-action](https://redirect.github.com/docker/login-action)
| action | minor | `v4.4.0` → `v4.5.0` |
---
> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/592) for more information.
---
### Release Notes
<details>
<summary>docker/login-action (docker/login-action)</summary>
###
[`v4.5.0`](https://redirect.github.com/docker/login-action/compare/v4.4.0...v4.5.0)
[Compare
Source](https://redirect.github.com/docker/login-action/compare/v4.4.0...v4.5.0)
</details>
---
### Configuration
📅 **Schedule**: (in timezone America/Los_Angeles)
- Branch creation
- "before 9am every weekday"
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Enabled.
♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box
---
This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/CopilotKit/CopilotKit).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
The optional peer dependency on @anthropic-ai/sdk was pinned to
^0.57.0, which conflicts with current SDK versions (e.g. 0.109) and
forces consumers to install @copilotkit/runtime with --legacy-peer-deps.
The anthropic adapter only relies on stable @anthropic-ai/sdk APIs
(client construction, messages.create, ephemeral cache_control), so
loosen the range to >=0.57.0 to remove the false peer conflict.
pnpm auto-installs this optional peer, so its specifier is mirrored in
the lockfile; update that specifier line to match. The resolved version
(0.57.0) still satisfies the range, so resolution is otherwise unchanged
and `pnpm install --frozen-lockfile` passes.
Reported by an outside contributor.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
`CopilotChatInput`'s `AddMenuButton` renders its trigger as nested Radix
`asChild` slots:
```tsx
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>{button}</DropdownMenuTrigger>
</TooltipTrigger>
```
Radix `asChild` slots forward a ref to their child.
`DropdownMenuTrigger` and `TooltipTrigger` were plain function
components, so under React 18.3 the forwarded ref triggers this warning
on every render (reported in #5744):
```
Warning: Function components cannot be given refs. Attempts to access this ref will fail.
Did you mean to use React.forwardRef()?
```
## Change
Wrap `DropdownMenuTrigger` and `TooltipTrigger` in `React.forwardRef`,
forwarding the ref to the underlying Radix primitive — mirroring
`forwardRef` usage already present in this package (e.g. `Button`,
`CopilotChatInput.TextArea`). No behavior change; the ref now reaches a
DOM node and the warning is gone.
## Scope
Limited to the two primitives in the reported warning path. The other
shadcn/ui primitives in `react-core` follow the same React-19
(no-`forwardRef`) style and would warn identically when used as
`asChild` children under React 18.3 — happy to extend this to the rest
if you'd prefer full React 18.3 coverage.
## Verification
- `nx build @copilotkit/react-core` succeeds (compiles source +
generates type declarations).
- Pre-commit `test-and-check-packages` passes.
Fixes#5744
Restoring frontend parity re-added the @region[custom-bubbles] markers in both
message-assistant.tsx and message-user.tsx (matching the langgraph reference and
every other integration). Add the ms-agent-dotnet::headless-complete::custom-bubbles
key to the multi-file-region allowlist so the demo-content bundler accepts it.
## What changed
- Build the canonical Angular browser bundle once when an integration
image needs it.
- Download and materialize that bundle inside each integration Docker
context.
- Generate the per-integration same-origin runtime config before Depot
builds the image.
- Run the same artifact path in the pre-merge build check.
- Rebuild integration images when the Angular host or its workspace
dependencies change.
## Why
The deployment workflow copied `public/angular` as a symlink whose
target sat outside each integration Docker context. The resulting images
had no `/angular/index.html`, so deployed Angular deep links returned
404.
Staging deploys the GHCR images built here. Production promotion pins
the same tested image digest, so the fix applies to both environments.
## Validation
- RED: `pnpm nx test @copilotkit/showcase-scripts -- --run
__tests__/angular-integration-hosting.test.ts` — 2 new workflow
assertions failed before the fix.
- GREEN: the same focused command — 46 tests passed.
- `pnpm nx test @copilotkit/showcase-scripts` — 2,322 tests passed.
- `pnpm nx build @copilotkit/showcase-angular-host` — passed, including
browser artifact audit and bundle budget.
- Staged the built artifact for `langgraph-python`, `mastra`, and `ag2`;
each contained `index.html` and the correct runtime config.
- `actionlint` passed for both changed workflows after ignoring existing
custom-runner and unrelated shellcheck notices.
- `git diff --check` passed.
## Known check
`pnpm nx exec -p @copilotkit/showcase-scripts -- tsc --noEmit -p
tsconfig.json` still reports six existing errors in
`equivalence-gate.ts`, `generate-search-index.ts`, and
`verify-prod-resweep.ts`. This change does not touch those files.
## What does this PR do?
- Preserve non-tool `AIMessage` fields when frontend tool calls are
intercepted in `afterModel` and restored in `afterAgent`, including
`additional_kwargs`, `response_metadata`, `usage_metadata`,
`invalid_tool_calls`, `id`, and `name`.
- Use a shared rebuild helper with `tool_calls` as the source of truth.
For LangChain v1 content blocks, remove stale `tool_call` and
`tool_call_chunk` blocks before reconstructing the message.
- Add regression coverage for the `reasoning + backend/frontend tool
calls -> afterModel -> afterAgent` flow, including metadata preservation
and v1 content block synchronization.
## Related PRs and Issues
- Closes#6087
- Related to #4759 and #5308
## Checklist
- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] Documentation is not required because this is an internal
middleware bug fix with no public API changes
- [x] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly — faster turnaround for everyone)
The stale-file cleanup removed chat-slots/custom-welcome-screen.tsx, the
top-level headless-complete/{message-list,use-rendered-messages}.tsx, and the
top-level gen-ui-interrupt/time-picker-card.tsx, but their manifest highlight
entries still pointed at them, failing the registry bundler (shell/shell-docs/
shell-dojo builds). Repoint to the real files (slot-wrappers, chat/chat,
hooks/use-tool-renderers, _components/time-picker-card).
## Release angular v0.3.0
**Scope:** `angular` | **Bump:** `minor`
---
### How this release process works
1. **This PR was created automatically** by the "release / create-pr"
workflow.
It bumped the `angular` packages to `0.3.0`
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 `angular` packages to npm at version `0.3.0`
- Creates git tag `angular/v0.3.0`
- 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.
Restore the root shell (globals.css theme+brand, manifest-driven index, layout,
middleware x-pathname, tsconfig), the declarative-gen-ui demo subtree, doc-snippet
region markers, import-style, and subagents to match the langgraph-python reference;
remove stale orphaned files. Load-bearing .NET adaptations (parse-json 3-layer
unwrap, multimodal shim, tool-based hitl, agent-config properties) are preserved.
Add the per-token createSharedStateStreamingAgent route shim, register the
threadid-frontend-tool-roundtrip agent (frontend_tools passthrough) and its demo,
drop shared-state-streaming from not_supported_features, and add the a2ui-recovery
feature + demo entry to the manifest.
Implement the render/validate/retry recovery loop with a2ui_recovery_exhausted
hard-fail as a raw-SSE endpoint (RecoveryAgent.cs, mounted in Program.cs), add
the demo frontend + API route, the deterministic aimock fixture, and the unique
per-slug PROMPTS entry in the shared d5-a2ui-recovery probe.
Replace the final-snapshot-only shared-state-streaming behavior with a
write_document tool whose document arg streams; per-token state.document
emission is bridged on the copilotkit route (see the routing commit).
## Release monorepo v1.63.2
**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.63.2`
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.63.2`
- Creates git tag `monorepo/v1.63.2`
- 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.
harness-control-plane and harness-pool-worker both declared a build: block
AND the same image: showcase-harness:local. Under the parallel docker buildx
bake path (default in recent Docker Compose) both targets build and race to
tag the identical image, failing the whole 'bin/showcase up' with
'image "...showcase-harness:local": already exists'. It only surfaces on a
cold parallel bake build (Colima/Homebrew, fresh clone), which is why it is
intermittent across toolchains.
Give the image a single build owner: harness-pool-worker now reuses the
image built by harness-control-plane (worker vs control-plane role is chosen
at runtime via HARNESS_ROLE) instead of declaring its own build:.
## Summary
Adds first-class Angular Showcase support and the public
`@copilotkit/angular`
package.
- Freezes 41 supported Angular features and keeps runnable cells as
frontend
support intersected with backend support.
- Builds one Angular artifact and stages it into all 20 existing
integration
images at same-origin `/angular/{feature}` routes.
- Keeps React `/demos/{feature}` routes unchanged and adds no Angular
service,
proxy, image, deployment environment, or production activation.
- Matches the React SDK's MCP Apps inline sandbox, permissions, and
resource-domain CSP semantics.
- Removes the temporary broad Angular proof workflow after it produced
the
merge evidence below.
## Evidence
- [Angular proof run
29966964494](https://github.com/CopilotKit/CopilotKit/actions/runs/29966964494):
all 48 jobs passed.
- Final report: 1,296 exact cells, 660 frontend comparisons, 636 Angular
pairs,
and 41 registry-supported Angular features.
- Pairwise policy: zero Angular regressions, zero React regressions,
zero
unowned failures, zero identity mismatches, and zero missing results.
- Chromium, Firefox, and WebKit each passed 16 browser checks and ten
cold
readiness samples. Maximum readiness was 250 ms, 163 ms, and 166 ms
against
the 2,000 ms limit.
- All 20 existing integration images passed Angular hosting checks.
- Angular 20, 21, and 22 packed consumers passed.
- PR #6095 remains linked as prior implementation evidence. This branch
ports
proven work without merging or resetting the old branch.
## Commits
- [x] Checkpoint 1 — baseline and registry (`873cbb8b6`)
- [x] MCP Apps activity renderer (`b3de484be`, Manfred Steyer)
- [x] Checkpoint 2 — core and package (`fec70d086`)
- [x] Checkpoint 3 — shared build and proof pair (`637845bb7`)
- [x] Checkpoint 4 — all supported features and docs (`4d32d941e`)
- [x] Checkpoint 5 — hardening and final exposure (`7ccd34a05`)
- [x] Review fixes (`cd0b5b406`)
- [x] Angular docs (`06df1ea15`, `1c0c76956`)
- [x] Remove the broad proof workflow (`c4919f9f7`)
- [x] Match React MCP Apps sandbox semantics (`053b00e84`)
## Delivery
- Rebased on `main` at `9855a8107`.
- Preserves both Angular docs commits.
- Uses one canonical Angular artifact across every existing integration
image.
- Preserves React routes and frozen-base comparison.
- Keeps accepted baseline failures owned and linked to issues.
- Excludes CLI scaffolding and Hashbrown work.