Upgrade the Angular library, demo, and Storybook setup to Angular 22, including the Angular CLI, compiler, CDK, TypeScript, and related build tooling.
Apply the Angular 22 migrations, retain strict template checking, adopt the migrated change-detection defaults, remove obsolete safe-navigation wrappers and empty imports, and update the icon integration from lucide-angular to @lucide/angular while retaining the core lucide package required by the inspector.
Update the documented support policy and package metadata to Angular 22. The published library is compiled and tested against Angular 22.0 to protect the minimum supported version, including installation, SSR, hydration, and zoneless browser verification through a packed consumer.
Retires the v1 runtime adapter from `showcase/integrations/`. After
this, **no code under `showcase/integrations/` calls
`copilotRuntimeNextJSAppRouterEndpoint`** — 239 routes across 20
integrations.
This is the cheap path we discussed: single-route mode, which is a
genuine drop-in. **No demo page changes, no route path changes, no `GET`
exports, no new dependencies.**
## The shape
```ts
const copilotHandler = createCopilotRuntimeHandler({
runtime,
basePath: "/api/copilotkit-x",
mode: "single-route",
});
...
return await copilotHandler(req);
```
**Why single-route:** these demos' frontends are `<CopilotKit
runtimeUrl="/api/copilotkit-x">` with no transport prop, and every
released provider pins the single-route transport. So single-route mode
is what the v1 adapter was already serving. Migrating to multi-route
instead would have meant editing every demo page in lockstep, for no
functional gain — nothing in the showcase probes `/info`.
**Why `createCopilotRuntimeHandler`** rather than
`createCopilotEndpointSingleRoute`: that helper is itself deprecated in
favour of the `mode` option (per the deprecated-aliases table in
`docs/backend/runtime-endpoints.mdx`), and the fetch handler needs no
`hono` dependency and composes directly with the wrappers these routes
already have.
The statement is rewritten **in place**, inside whatever wrapper it
already sat in, so `withForwardedHeaders`, the try/catch envelopes,
`wrapStreamingResponse` and `withCvdiagBackend` are untouched. 75 of
these routes construct the runtime inline in the call; rewriting in
place preserves that per-request construction exactly as v1 did. No
`runner` is added — it's optional and none of these routes passed one.
13 `copilotkit-auth/[[...slug]]` routes already use the v2 fetch handler
and are left alone; they only name v1 in comments.
## Verified
The shape was proved end-to-end **before** the rollout, in a real
running app with an untouched provider (aimock as the model backend):
`POST /api/copilotkit` → 200 twice, chat turn rendered in the browser.
It also typechecks against the exact version these integrations pin
(1.68.2).
`mastra` is the integration installed and exercised locally — 19 routes,
the `withCvdiagBackend` main route, and the only vitest suites that
touch routes. Measured against `origin/main` **in the same tree**:
| | baseline (`origin/main`) | after |
| --- | --- | --- |
| `tsc --noEmit` | errors in 10 files | errors in **9** |
| `vitest run` | 2 files / 13 tests failed, 21 passed | 2 files / 13
tests failed, 21 passed |
- **New type errors introduced: none.**
- **Fixed:** `src/app/api/copilotkit-mcp-apps/route.ts`, whose
`@ts-expect-error` was *already* unused on `main`.
- **Test-neutral:** those 13 failures are pre-existing on `main` (mostly
`extractXHeaders` dereferencing `req.headers` on a `{}` fake request).
Structural audit over all 239 routes, re-run after the pre-commit
formatter: none still imports the v1 root, calls the v1 adapter,
references `ExperimentalEmptyAdapter` or `handleRequest` in code, or is
missing `createCopilotRuntimeHandler` / `basePath` / `mode:
"single-route"`.
**CI has now built all 21 integrations green** — `showcase_build_check`
Docker-builds each changed integration and `next build` typechecks
inside it. That covers the ones I could not stand up locally, including
the non-JS backends (`spring-ai`, `ms-agent-dotnet`, `ms-agent-python`,
`ms-agent-harness-dotnet`, `langroid`, `strands`). Full run: 41 pass / 3
skip / 0 fail.
To be precise about what each gate proves: CI proves these 21 apps still
**build and typecheck**. It does not exercise a chat turn per
integration — that came from the pre-rollout live proof of the shape
itself, plus mastra's local test suite.
## Runtime verification on real cells
Docker is not running on my machine, and `bin/showcase test --d6
--direct` requires it
(`--direct` only swaps the in-process driver for the fleet
control-plane; the containers are
not optional). **So the sanctioned Iron Rule 4 probe has NOT been run**
— that gap is real and
a reviewer should weigh it. What I did instead was run a real
integration directly.
`showcase/integrations/mastra` on this branch, `npm run dev`, aimock as
the model backend.
Probing eight migrated routes with the exact envelope the released
provider sends
(`POST {basePath}` with `{"method":"info"}`) — all **200** with real
runtime payloads:
copilotkit-multimodal 200 agents: multimodal-demo
copilotkit-mcp-apps 200 agents: headless-complete
copilotkit-a2ui-fixed-schema 200 agents: a2ui-fixed-schema
copilotkit-beautiful-chat 200 agents: beautiful-chat
copilotkit-agent-config 200 agents: agent-config-demo
copilotkit-ogui 200 agents: open-gen-ui
copilotkit-declarative-gen-ui 200 agents: declarative-gen-ui
copilotkit-background-agents 200 agents: background-agents
Then three real demo cells driven in a browser, each rendering and
completing a chat turn
through its migrated route (two POSTs, both 200, assistant message
rendered):
/demos/beautiful-chat -> POST /api/copilotkit-beautiful-chat 200, 200
/demos/a2ui-fixed-schema -> POST /api/copilotkit-a2ui-fixed-schema 200,
200
/demos/multimodal -> POST /api/copilotkit-multimodal 200, 200
Deliberately spread across different route configs — plain, `a2ui`, and
a dedicated
vision-model route — rather than three variations of the same one.
### One route is 500, and it is pre-existing
`POST /api/copilotkit` (mastra's main route) returns 500 in dev:
`module-not-found` on
`./schema.js` from `src/cvdiag/cvdiag-emitter.ts`. `schema.ts` **is**
tracked and present —
Turbopack in dev just does not resolve the ESM-style `.js` specifier to
it. Proven
pre-existing by restoring **only** that file to `origin/main` and
re-probing: same 500 on the
v1 code. Its Docker build passes, which is why CI is green.
### A mistake in my own verification, recorded
My first pass at the above ran against the wrong branch — I was still on
the docs branch,
where these routes are v1, so the first six 200s I collected were the
**v1** routes. Caught it,
switched to this branch, and re-ran everything above against the
migrated code. The accidental
run was not wasted: it independently confirms the premise of this PR,
that the v1 adapter and
v2 single-route mode answer the same envelope the same way.
## Judgement call worth reviewing
27 `@ts-expect-error` directives guarded the **v1** `CopilotRuntime`
agents type ("wraps `Record` in `MaybePromise<NonEmptyRecord<...>>`").
Under `/v2` that hole is gone, which makes the directive *unused* — a
hard compile error.
I demoted them to `@ts-ignore`, which compiles whether or not the
mismatch survives in a given integration. The honest reason at the time:
19 of these apps can't be built locally, so I couldn't prove per-file
which still need a suppression, and `@ts-ignore` is what 190 sibling
files already use.
Now that CI has built all 21 green, that constraint is gone — the ~220
now-stale suppressions (all of which cite a **v1** type hole that no
longer applies) can be removed and verified by the same 21 builds. I've
left them in place here to keep this PR mechanical and reviewable; say
the word and I'll do it as a second pass.
## Two pre-existing problems found on the way
- **`npm ci` fails in `showcase/integrations/mastra`**: `Missing:
@types/http-errors@2.0.5 from lock file`. The Dockerfile uses `npm ci
--legacy-peer-deps`, which *does* succeed, so the image still builds —
but a plain `npm ci` doesn't. No manifest or lockfile is in this diff.
- **`mastra`'s vitest suite is red on `main`** — 13 failures, as tabled
above.
## What's left of the v1 entrypoint
| Surface | Before | After |
| --- | --- | --- |
| `showcase/integrations/**` | 239 | **0** |
| `examples/v1/**` | 12 | 12 (deliberately v1, never in scope) |
| everything else in `examples/` | ~61 | ~61 (not in this PR) |
Stacks cleanly with #6617 (docs) — no file overlap. It also **unblocks
the two Claude SDK quickstart pages** I had to revert there:
single-route keeps the starter file at the plain `route.ts` path, so
those pages' prose claims and `verify-shell-docs.ts` starter-path checks
stay valid, and only the fence body needs updating.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- mark CrewAI Conversational Flows `deployed: true` now that its
production Railway instance is provisioned, SSOT-tracked, promoted, and
healthy
- update the parity note so it reflects the live production deployment
- retain `docs_mode: hidden`; Conversational Flows remain documented
within the existing CrewAI Flows docs rather than as a separate
framework
## Production verification
- `GET
https://showcase-crewai-conversational-flows-production.up.railway.app/api/health`
returns HTTP 200 with `status: ok`
- post-promotion D5 run `frun_mt2lnj48_t8zh0h_1`, job `o8rkn6b0igh4rxd`:
40/40 cells passed, 0 failed
## Local verification
- `nx run @copilotkit/showcase-scripts:validate-manifests`
- `nx run @copilotkit/showcase-scripts:generate-registry`
- `validate-constraints.ts crewai-conversational-flows`
- formatter check and `git diff --check`
- Nx affected lint, test, and build resolved no affected targets for
this manifest/Markdown-only change
## What does this PR do?
The Agent tab Current Messages list used `whitespace-pre-wrap` around
the message text.
The Lit template also had extra spaces and newlines around that value.
As a result, a short message such as `test` rendered with a large empty
block.
This change puts the message text on the same line as the opening tag,
so only the real message text is shown.
Verified in the browser: the user row is now the exact string `test`
(one line, 16px high).
Inspector tests: 485 passed, including a new regression test.
## Related PRs and Issues
None. Found while testing Playground on the react-router example.
## 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
## Summary
- add an isolated Playground tab for chatting with the selected agent
- fork saved thread history into a fresh Inspector-owned conversation
- show the ephemeral-thread Intelligence CTA only for non-Intelligence
runtimes
## Why
OSS-869 needs a small, local-first surface for testing agents without
changing the host application chat or its stored thread history.
## How
- clone the active runtime agent and stream runs through the existing
Core
- reuse Inspector thread endpoints to seed scratch conversations
- mirror the default CopilotKit chat treatment, including run/stop
states and motion
- cover navigation, input, saved-thread isolation, and Intelligence CTA
behavior
Verified with `pnpm nx run @copilotkit/web-inspector:test`, `build`, and
`check-types`, plus a live React v2 demo run.
## Summary
- complete the tool-only HITL approval leg when the app-level approval
modal mounts
- retain the shared runner's finished-run/new-assistant-bubble gates and
the existing approval/follow-up assertions
- add a contract test that pins the modal completion selector to the
first turn
## Why
Unhandled tool calls intentionally render no default chat card. The HITL
fixture's first leg therefore produces an empty assistant bubble plus
the approval modal, so text-stability completion cannot converge even
though the app and fixture are healthy.
## Verification
- focused red/green contract: 8 tests passed after failing on missing
`completeOnMount`
- showcase harness: 177 test files / 3,722 tests passed; typecheck and
build passed
- isolated fleet-control-plane D5 cells passed for LangGraph Python,
CrewAI Conversational Flows, and Mastra
## Deployment scope
This changes only the shared showcase harness image. Promote the harness
control-plane and harness pool-worker roles together; no integration
service image changes are required for this fix.
## Summary
Redesigns the Web Inspector around Home, What's New, System Health,
Intelligence, and a clearer responsive sidebar. It also keeps live
Threads scoped to the matching agent so All Agents does not show
duplicates.
## Why
The Inspector needed a faster at-a-glance health view, coherent light
and dark themes, explicit Intelligence states, and a notification flow
that fits the new animated launcher without showing a floating banner
over the host application.
## How
- adds Alem Tuzlak's Home briefing, live sidebar, and matching-agent
thread filtering
- integrates the latest launcher halo, pulse, and unread dot from main
- opens unread launcher notifications on Home with a What's New preview
and sidebar ping
- marks the announcement read only after its What's New content is
visible
- adds responsive System Health, Intelligence, features, Learning,
Settings, and What's New surfaces
- expands the deterministic local test bench, including disconnected
Intelligence and RUN_ERROR states
- preserves Alem's original authored commits and keeps the follow-up
polish in one Tyler-authored commit
## Verification
- pnpm nx test web-inspector --skip-nx-cache (481 tests)
- pnpm nx build web-inspector --skip-nx-cache
- full pre-commit affected package test, publint, and attw checks
- interactive launcher-to-dismissal walkthrough in the local Inspector
lab
## Related
- Linear: OSS-866
- Linear: OSS-868
REST /threads is agent-scoped. The Phoenix user_meta channel is not. Drop live upserts whose agentId does not match the store so Inspector All Agents does not show the same thread twice.
After the first chat, web quickstarts now tell the reader to open
Inspector and confirm three things: the agent is listed, AG-UI Events
are moving, and Threads is unlocked or shows Enable Intelligence.
## What does this PR do?
- Add a shared Open Inspector step after the first chat in every web
integration quickstart, plus Vue and Angular.
- Angular links the [Inspector for Angular](/angular/inspector) install
page first. Vue sets `show-dev-console="auto"` so the overlay appears on
localhost.
- Add a short Callout on feature pages that map to a shipped pane:
Threads, Frontend Tools, State, Context, Learning, and HITL tools.
- Add the `inspector-docs` skill so a new Inspector pane gets a docs
pointer, or `no page yet`.
- Keep the Intelligence signup copy that names Inspector. Skip React
Native and Channels.
## Related PRs and Issues
- Linear: https://linear.app/copilotkit/issue/OSS-885
## Checklist
- [ ] 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 (lets us help iterate on
your PR directly — faster turnaround for everyone)
## Testing
Commands run:
1. File contract check against the shared step, 17 integration
quickstarts, Vue, Angular, feature Callouts, and non-web skip. Passed.
2. `node --experimental-strip-types scripts/sync-plugin-skills.ts
--check`. Passed (`plugin skill mirror in sync`).
3. Did not run `pnpm test` or shell-docs `vitest`. This worktree has no
`node_modules`.
Manual test:
1. Follow a React quickstart on localhost. After the first chat, open
Inspector. Agents lists the agent. AG-UI Events move. Threads is
unlocked or shows Enable Intelligence.
2. Repeat with Intelligence set to No. The Open Inspector step is still
there. Threads shows Enable Intelligence.
3. Follow the Angular frontend guide. The step links the Angular
Inspector install page first.
4. Open Threads, frontend tools, shared state, and agent-readonly. Each
has a Callout that names the matching pane.
How this PR makes testing easy:
`showcase/shell-docs/src/lib/__tests__/inspector-docs.test.ts` fails if
a web quickstart drops the step, if a mapped feature page drops its
Callout, or if Callouts name Playground or Fork.
## Risk / rollback
Docs-only plus a repo skill. Revert the PR to undo. No runtime API
change.
## Summary
- register the provisioned `showcase-crewai-conversational-flows`
production Railway service instance, domain, health path, and probe in
the Railway SSOT
- regenerate the promotion closure and workflow service selector so the
integration can be promoted through the standard runbook path
- update SSOT, image-reference, generator, and environment-aware
redeploy tests for dual-environment coverage
- recast the staging-only runbook reference as a completed
staging-to-production example
This deliberately does not mark the integration manifest as deployed or
perform another Railway mutation. It only reconciles the already-running
production instance into source control.
## Live verification
- production `/api/health` returns HTTP 200
- production and staging run the same image digest:
`sha256:e6f38a9454f8ae9410239bb3cc75d21b0d2ccecbbbfe789b25a9f2d9f03139b4`
- all 84 environment-scoped Railway image refs verified
- `autoUpdates` verified disabled across all 84 service/environment
checks
- promotion dry-run resolves the production target to the pinned digest
above
## Local verification
- `pnpm exec tsc --noEmit -p showcase/scripts/tsconfig.json`
- uncached Nx test run: 77 files, 2,519 tests passed
- Railway Ruby suite: 188 runs, 723 assertions passed
- `pnpm lint` (0 errors)
- `actionlint .github/workflows/showcase_promote.yml`
- `pnpm exec tsx showcase/scripts/emit-railway-envs-json.ts --check`
- `pnpm exec tsx showcase/scripts/sync-promote-service-options.ts
--check`
## Summary
Replace the Inspector announcement banner with a non-blocking unread
signal on the launcher and a persistent **What's new** destination
inside the Inspector. The launcher now uses the approved responsive Kite
treatment: an internal wash plus two visible, staggered water-ripple
rings.
This follow-up also trims the implementation to the one signal that
exists today, adds a local replay control, and records when the launcher
notification is actually presented.
## Why
The old banner covered the host application and duplicated the
announcement inside every Inspector tab. The initial signal
implementation also carried speculative registry machinery for future
error notifications, could consume its only pulse while the launcher was
hidden, and counted ordinary announcement-content clicks as CTA
interactions.
The notification funnel also had no exposure event, and announcement
telemetry could run before the runtime handshake revealed that telemetry
was disabled.
## How
- Adds **What's new** as the first primary navigation destination and
removes the host-app overlay.
- Uses direct news-signal state instead of a generic one-entry registry.
- Defers the one-beat pulse until the launcher and browser tab are
visible, and persists read state only after announcement content
renders.
- Adds `oss.inspector.whats_new_signal_viewed`, emitted once per
announcement presentation with `banner_id`, `surface: "launcher"`, and
`presentation: "animated" | "reduced_motion"`.
- Holds notification views and attribution behind the runtime `/info`
handshake, preventing events or `posthog_distinct_id` link parameters
when telemetry is disabled.
- Tracks announcement clicks only when a link is activated.
- Scales the launcher from 51.84 px on compact screens to a 62.208 px
desktop cap, with an internal wash, two staggered outward ripples, a
resting unread dot, and a reduced-motion fallback.
- Preserves the Kite artwork and pins its crop/path invariant in tests.
- Adds a one-shot **Replay notification** workbench control that
preserves Inspector layout and clears only the local read/pulse mirrors
needed for replay.
- Keeps the launcher pointer cursor at rest and the grabbing cursor only
while dragging.
Verified with 463 Web Inspector tests plus Nx type-check and build
targets. The full pre-commit test, package-quality, publint, and `attw`
gate passes; lint reports zero errors.
Related: OSS-860, OSS-864, OSS-865
- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] Relevant documentation is updated
- [x] Allow edits by maintainers is enabled
Replace speculative signal machinery with direct state and defer hidden pulses.
Limit click telemetry to real links and add the replay workbench control.
Restore the pointer cursor and record visible launcher presentations.
Add host-scoped read state and the persistent What’s new destination.
Include the responsive Kite treatment, renamed announcement telemetry, and complete behavior tests.
Refs OSS-860, OSS-864, OSS-865
Moves all 239 showcase integration routes off
`copilotRuntimeNextJSAppRouterEndpoint`, the deprecated v1 Next.js adapter, so
the v1 entrypoint has no remaining code-level users under
`showcase/integrations/`.
const copilotHandler = createCopilotRuntimeHandler({
runtime,
basePath: "/api/copilotkit-x",
mode: "single-route",
});
...
return await copilotHandler(req);
## Why single-route, and why this handler
**Single-route** because these demos' frontends are
`<CopilotKit runtimeUrl="/api/copilotkit-x">` with no transport prop, and every
released provider pins the single-route transport. Single-route mode is
therefore a drop-in for the v1 adapter: no frontend change, no path change, no
`GET` export, and nothing here probes `/info`. Migrating to multi-route instead
would have required editing every demo page in lockstep for no functional gain.
**`createCopilotRuntimeHandler`** rather than `createCopilotEndpointSingleRoute`
because that helper is itself deprecated in favour of the `mode` option (see the
deprecated-aliases table in `docs/backend/runtime-endpoints.mdx`), and because
the fetch handler needs no `hono` dependency and composes directly with the
wrappers these routes already have.
The statement is rewritten in place, inside whatever wrapper it already sat in,
so `withForwardedHeaders`, the try/catch envelopes, `wrapStreamingResponse` and
`withCvdiagBackend` are all untouched. 75 of these routes construct the runtime
inline in the call; rewriting in place preserves that per-request construction
exactly as v1 did. No `runner` is added — it is optional, and none of these
routes passed one before.
13 `copilotkit-auth/[[...slug]]` routes already use the v2 fetch handler and are
left alone; they only mention the v1 name in explanatory comments.
## Collateral
- `mastra`'s main route declared a module-level
`const serviceAdapter = new ExperimentalEmptyAdapter()` plus a startup log
about the adapter choice. V2 has no service adapters, so both are gone and the
comment now explains that there is nothing to configure.
- The three `mastra` vitest suites mocked `@copilotkit/runtime` and the v1
`{ handleRequest }` return shape; they now mock `@copilotkit/runtime/v2` and
`createCopilotRuntimeHandler`, which returns the handler directly.
- 27 `@ts-expect-error` directives guarded the **v1** `CopilotRuntime` agents
type ("wraps Record in MaybePromise<NonEmptyRecord<...>>"). Under `/v2` that
hole is gone, which makes the directive unused — a hard error. They are
demoted to `@ts-ignore`, which compiles whether or not the mismatch survives
in a given integration, because 19 of these apps cannot be built locally to
prove it either way. Removing all ~220 now-stale suppressions is left as
follow-up once CI has built every integration green.
## Verified
`mastra` is the one integration installed and exercised locally (19 routes, the
`withCvdiagBackend` main route, and the only vitest suites that touch routes).
Measured against `origin/main` in the same tree:
tsc --noEmit baseline: errors in 10 files
after: errors in 9 files
new errors introduced: NONE
fixed: src/app/api/copilotkit-mcp-apps/route.ts, whose
@ts-expect-error was ALREADY unused on main
vitest run baseline: 2 files failed, 13 tests failed, 21 passed
after: 2 files failed, 13 tests failed, 21 passed
→ test-neutral; those 13 failures are pre-existing on main
Structural audit over all 239 routes: none still imports the v1 root, uses the
v1 adapter, references `ExperimentalEmptyAdapter` or `handleRequest` in code, or
is missing `createCopilotRuntimeHandler` / `basePath` / `mode: "single-route"`.
The shape itself was proved end-to-end before the rollout, in a real running
app with an untouched provider (aimock as the model backend):
`POST /api/copilotkit` -> 200 twice, chat turn rendered.
## Two pre-existing problems found on the way
- `npm ci` fails in `showcase/integrations/mastra`: `Missing:
@types/http-errors@2.0.5 from lock file`. Its Dockerfile uses
`npm ci --legacy-peer-deps`, which does succeed, so the image still builds —
but a plain `npm ci` does not. Untouched here; no manifest or lockfile is in
this diff.
- `mastra`'s vitest suite is red on `main` (13 failures, mostly
`extractXHeaders` dereferencing `req.headers` on a `{}` fake request).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## Summary
- replace the configuration-context update in the assistant slot-prop
stability test with an unrelated message-view prop update
- preserve coverage that the raw-event feedback adapter does not churn
ordinary assistant render props
- leave production behavior and the callback-only raw-event boundary
unchanged
## Root cause
The test changed chatInputPlaceholder, which changes the memoized
chat-configuration context value. CopilotChatAssistantMessage consumes
that context, so React correctly rerenders it independently of the
message-view memo comparator. The configuration update was therefore not
an unrelated proxy for feedback-adapter churn.
## Test plan
- [x] reproduce the original expected 1 / received 2 failure
- [x] prove the corrected test fails when className is temporarily added
to the feedback adapter memo dependencies
- [x] raw-event feedback test file
- [x] React-core memoization/performance tests
- [x] complete React-core suite on React 19
- [x] complete React-core suite on React 18 compatibility overrides
- [x] React-core build and normal typecheck
- [x] changed-file format and lint checks