## What does this PR do?
Corrects `faciliate` to `facilitate` in the Mastra shared state
documentation.
## Related PRs and Issues
- None.
## Validation
- `codespell
showcase/shell-docs/src/content/docs/integrations/mastra/shared-state/index.mdx`
- `git diff --check`
## Checklist
- [x] I have read the [Contribution
Guide](https://github.com/CopilotKit/CopilotKit/blob/main/CONTRIBUTING.md).
- [x] The relevant documentation is updated by this PR.
- [x] "Allow edits by maintainers" is enabled.
## Why
The React Native page covers building the integration thoroughly and
never says how to
establish that it **works**. `verify` appeared zero times in its 646
lines, and the only
verification content was a reactive troubleshooting entry ("no response
from the runtime →
check `/info`").
That gap is sharper here than on the web frontends. There, "open it and
look" is an
unstated fallback that genuinely works. On React Native there is no
browser, so a reader
who follows this page to the end has no proof step at all — and the
obvious substitutes
each prove less than they appear to.
## What this adds
A **Proving it works** section with three checks, explicit that none is
sufficient alone:
1. **`copilotkit verify --round-trip`** — proves an agent answered, with
no browser and no
device. Its limits are stated rather than left to be discovered: it
sends a *fixed*
prompt and records the answer's length, never its text, so it cannot
tell you what came
back; and it proves an agent answered under the declared id, not *which*
deployment
answered.
2. **A device capture** — `adb exec-out screencap -p`, plus `adb logcat`
for an unresolved
redbox. iOS has no `adb` equivalent short of full Xcode, and the Command
Line Tools do
not ship `simctl`, so the section says so instead of implying parity.
3. **Checking the answer against the records the app holds** — the only
step that separates
a correct answer from a fluent one about records that do not exist. That
failure is
invisible in a screenshot, in a video, and to any reviewer unfamiliar
with the data.
Two smaller fixes on the same page:
- **`useAgentContext` is now a callout, not a list entry.** It sat in
the shared-hooks list
described as behaving "the same as on the web", which undersells the one
hook whose
absence fails *silently*. Rendering a list puts it in the view tree, not
in the agent's
context — separate steps. An agent missing the second still answers
plausibly, the tool UI
paints, and nothing errors. React Native has no browser console to
notice it in.
- **`@react-native-community/cli` is now a prerequisite.** React Native
0.87 no longer
bundles it, so an *upgraded* app needs it in `devDependencies` or
`react-native bundle`
and `react-native start` refuse to run. A freshly `init`ed app already
has it, which is
why the quickstart path never surfaced this.
## Notes for review
- **Docs-only.** One `.mdx` file, +78 lines, no code or config touched.
- The three anchor links used (`#connecting-from-a-device-or-bench`,
`#which-hooks-are-shared-and-which-arent`, `#known-limitations`) all
resolve to existing
headings, and match the anchor style the page already uses elsewhere.
- Prose is unwrapped to single-line paragraphs and callout bodies are
2-space indented, to
match the file's existing convention.
- `npm run lint` in `docs/` exits 0 with no new warnings. `vitest run`
gives 188 passed / 29
failed-to-load — **identical to a pristine `origin/main` worktree**,
which I ran to confirm;
those failures are a local module-resolution issue, not this change.
- Deliberately **not** included: documenting `copilotkit verify`
generally. It is currently
undocumented across the whole docs tree (Angular and Vue score zero on
"verif" too), which
wants its own change and probably a shared page rather than a
per-frontend section.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Closes the docs half of OSS-938. The Intelligence half (graph node flip,
`frontend/plan.md`, fixture conversion, replacement unsupported cell)
lands as a separate PR in `CopilotKit/Intelligence` — it cannot share a
PR across the repo boundary.
## Why
React SPA was the only frontend the onboarding graph could not route to
a validated outcome, and the gap was exactly one step: **where Copilot
Runtime lives.** Every framework quickstart hosts the runtime in a
Next.js route handler and sets a relative
`runtimeUrl="/api/copilotkit"`. That path resolves only because Next.js
serves the app and the runtime from one origin. A Vite or CRA app has
neither a server nor a shared origin, so the instruction had nowhere to
land.
The rest of the React tree already works unchanged in a SPA —
`/frontend-tools`, `/generative-ui`, `/human-in-the-loop`, `/headless`,
`/prebuilt-components` and `/reference/v2` contain no Next.js-specific
steps. So this adds one page for the one difference and links out for
everything else, rather than forking a parallel React tree.
## What's here
**1. `docs/frontends/react-spa.mdx`** — the standalone Node runtime
server (the `angular.mdx` / `vue.mdx` shape), the absolute `runtimeUrl`
it requires, `cors: true`, the two-dev-server port story, and links back
out to the root React pages.
**2. `react-spa` registered in
`showcase/shared/frontend-registry.json`** — required, not cosmetic.
Frontend route resolution is gated on `isFrontendId`
(`src/app/[framework]/[[...slug]]/page.tsx:96`, and the `/frontends/x` →
`/x` flattening at line 133), and `isFrontendId` reads the registry. An
unregistered MDX file 404s. Vue and React Native are the precedent —
both registered, both a single page, neither with a namespaced subtree —
so this does **not** create the `/react-spa/**` mirror tree OSS-938
rules out. `feature_support_required: false` matches them, so no
feature-support matrix entries are needed.
**3. The `runtimeUrl` sweep — 13 quickstarts**, each getting a callout
on its provider step noting that the relative path assumes a
Next.js-served origin.
## Two things worth a reviewer's attention
**`cors: true` is load-bearing and easy to omit.** `resolveCorsConfig`
(`packages/runtime/src/v2/runtime/core/fetch-handler.ts:784`) is `if
(!cors) return null`, and `createCopilotNodeListener` passes options
straight through to `createCopilotRuntimeHandler`. So CORS is **off by
default** on exactly the adapter a standalone SPA runtime uses — while
Express (`endpoints/express.ts:126`, `cors: corsOption = true`) and Hono
(`endpoints/hono.ts:105`) default permissive. Since the SPA's app and
runtime are on different origins, omitting it fails every request on
preflight. The page calls this out twice.
**The sweep callouts deliberately contain no root-relative links.** My
first attempt linked `/react-spa`, `/vue` and `/react-native`, which
broke `angular-docs-content.test.ts` → "keeps every rendered
backend-specific Angular link in context" with 45 leaks. That test is
right and the links were wrong: `resolveAngularDoc` falls back to
`frameworkContentSlug`, so the Angular surface **reuses these same
integration quickstarts**, and its link contract deliberately keeps
readers inside `/angular/**`. Enumerating three other frontends was also
wrong content for an Angular reader. The callout now names the guide
paths as inline code instead.
The cost is that the sweep no longer hands the reader a clickable link —
discoverability for React SPA comes from the frontend selector entry
instead. Doing both properly needs a frontend-conditional content
component (the `WhenAngularBackend` pattern, but keyed on frontend),
which is more than this sub-task should carry. Worth a follow-up.
## Corrections to the issue found while implementing
- **There is no doctest harness.** OSS-938 says the snippets are
doctest-gated. `shell-docs` runs vitest over `src/**/*.test.{ts,tsx}`
only — MDX code blocks are never executed. The real gates are that suite
plus `tsc --noEmit`.
- **The docs do have a frontend selector**, backed by the registry (6
entries before this change). The issue's "no frontend selector anywhere"
is true only of MDX *tab groups*.
- **The sweep is 13 source files, not 18 pages.** The langgraph,
microsoft-agent-framework and aws-strands variants are tab groups inside
one page each, so `langgraph-fastapi`/`-python`/`-typescript` collapse
to one file, the three `ms-agent-*` to one, and
`strands`/`strands-typescript` to one.
- **The root `/quickstart` needs nothing.** It is a 17-line routing shim
that 308-redirects to `/` and carries no runtime step at all. The issue
counts it among the 18.
- **The issue's page list misses `built-in-agent` and the root-level
`agent-spec/quickstart.mdx`**, both of which do carry the relative
`runtimeUrl`. Both are swept here.
- **Vue and React Native are already done**, in both repos — both ship
the absolute-`runtimeUrl` recipe and both already route to
`credentials/finalize-plan`. The issue defers them as out of scope, but
that also means the sweep fixes the mis-route for one frontend, not
three.
## Testing
Run in the worktree against `origin/main` (`0943c5196e`).
**`tsc --noEmit` — no new errors.** Baselined by setting my changes
aside on a pristine checkout: 8 pre-existing errors, all from
`@clerk/nextjs` / `@testing-library/react` / `jsdom` being undeclared
and uninstalled in `showcase/shell-docs/package.json` (verified absent
in `main` too, so this is repo state, not this branch). With the changes
applied: the same 8, zero added.
The type widening surfaced one real error, now fixed —
`FRONTEND_REFERENCE_SLUGS` in `frontend-page-content.ts` is `satisfies
Record<FrontendPageId, string>` and needed a `react-spa` entry. It maps
to `"reference"`, the root React reference, same as Vue.
**Test suite — no new failures.**
```
$ npx vitest run src/lib src/app
Test Files 1 failed | 41 passed (42)
Tests 1 failed | 380 passed (381)
× renders one dependency-complete canonical tool-rendering example for mastra
```
That mastra failure is pre-existing — reproduced on a pristine
`origin/main` checkout with every change of mine removed:
```
$ git checkout -- <changed files> && mv react-spa.mdx aside
$ npx vitest run src/lib/__tests__/llm-text.test.ts
Tests 1 failed | 39 passed (40)
× renders one dependency-complete canonical tool-rendering example for mastra
```
**The new page is covered by an existing registry-driven guard, and the
coverage is real.** `frontend-options.test.ts` → "maps every non-React
frontend to an MDX guide page" iterates `FRONTEND_PAGE_IDS` and asserts
`loadDoc(getFrontendContentSlug(id))?.fm.title`. Mutation-checked rather
than assumed — removing the page fails it, restoring it passes:
```
$ mv src/content/docs/frontends/react-spa.mdx /tmp/ && npx vitest run frontend-options.test.ts
× maps every non-React frontend to an MDX guide page
Tests 1 failed | 21 passed (22)
$ mv /tmp/react-spa.mdx src/content/docs/frontends/ && npx vitest run frontend-options.test.ts
Tests 22 passed (22)
```
**Sweep coverage checked programmatically, not by eye.** For each of the
13 files, asserted exactly one `runtimeUrl="/api/copilotkit"`
occurrence, the callout inserted immediately after that code block's
closing fence, and the `runtimeUrl` line exactly 9 lines above it. Then
re-derived the target set from the tree to confirm nothing was missed —
the only quickstart still carrying an un-annotated relative `runtimeUrl`
is `aws-strands`, which is excluded on purpose.
**Route wiring confirmed live.** `GET /frontends/react-spa` → `301` on
the local dev server, which is the registry-gated flattening redirect
firing for a registered id. Full HTML render could not be verified
locally: the dev server 500s on `@clerk/nextjs` for *every* page
(`/vue.md` fails identically), because that dep is undeclared and
uninstalled — pre-existing and not specific to this branch.
**Every outbound link on the new page resolves** — probed
`/frontend-tools`, `/generative-ui`, `/human-in-the-loop`, `/headless`,
`/prebuilt-components`, `/reference/v2`, `/model-selection`,
`/backend/runtime-endpoints`: all 200 or 301-to-canonical.
**Fixed a stale mock while here.**
`src/app/llms-mdx/[[...slug]]/route.test.ts` hard-codes the frontend
list instead of reading the registry, so it silently omitted
`react-spa`. Added it to both lists; suite passes (15/15). The
hard-coding is still a latent divergence worth a follow-up.
## Not done here
- **`aws-strands/quickstart.mdx` is excluded from the sweep**, per the
standing hands-off arrangement while Mark leads the Strands
rejuvenation. That leaves `strands` and `strands-typescript` carrying
the un-annotated Next.js step.
- **A clickable cross-link in the sweep callouts**, per the
Angular-contract finding above.
- The Intelligence-side changes, as noted at the top.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## What
`MastraAgent.getRemoteAgents` appeared **nowhere** in this repo — not in
shell-docs, not in an example, not in a snippet. The only wiring the
Mastra docs taught was `getLocalAgents({ mastra })` behind `import {
mastra } from "@/mastra"`.
That was on the **"Use an existing agent"** branch of the quickstart —
the branch for readers who already have a Mastra service. Two steps
earlier the same branch tells you to `npx create-next-app
my-copilot-app`, a *separate* directory. `@/mastra` cannot resolve
across that boundary, and the shape it teaches moves a running Mastra
service into the frontend, deleting the process the reader was trying to
preserve.
All four cells of the 2026-08-21 Mastra × Next.js sweep reached the
agent over HTTP, and all four derived how on their own. `both` filed
"the remote-Mastra API is entirely undocumented" as its largest
friction; `empty` filed it as its worst papercut at ~10 minutes.
## Changes
**`mastra/quickstart.mdx`** (existing-agent branch)
- Route wired with `getRemoteAgents` over a `MastraClient`, so the agent
keeps running as its own process. Passed as a **factory**, so the agent
list is fetched per request — see the note below on why the promise form
is unsafe.
- `MASTRA_BASE_URL` convention, as `.env.local` in the frontend beside
the route that reads it: `process.env.MASTRA_BASE_URL ??
"http://127.0.0.1:4111"`.
- A **"Start your agent"** step, which the branch never had. Its
liveness check is `/api/agents`, not `GET /` — Mastra serves its console
on the agent port and answers 200 whether or not an agent is registered
(straight from the `empty` cell's evidence).
- A warning that `next dev` rewrites the `tsconfig.json` at its own root
— forcing `esModuleInterop`, `isolatedModules`, `resolveJsonModule` and
`jsx`, setting `noEmit: true`, and replacing `include`/`exclude`.
`noEmit` is the sharp one for an agent project that compiles with `tsc`.
A sibling package is why this path goes over HTTP. `agent-only` derived
this independently.
**`mastra/copilot-runtime.mdx`** — a new **"Local vs remote agents"**
section that decides between the two by *where the agent runs*, not by
preference, plus:
- the full `GetRemoteAgentsOptions` contract (`mastraClient`,
`resourceId`, `observationalMemory`, `tracingOptions`);
- why the factory form is the one to use — `agents` does accept the
promise itself, but that starts the HTTP call at module load with
nothing awaiting it, so an agent server that is not up yet produces an
unhandled rejection and **Node terminates the process**. The factory has
no such window: a failure is a 500 and the next request retries, so a
route that started first recovers on its own. Cost is one `listAgents()`
per request;
- the local-only options (`requestContext`, `untilIdle`) — so a run that
needs background tasks has to be embedded.
**CI gating** — the new route fence carries `doctest="component"` with a
mastra `doctest.json`. The old fence could never have been gated:
`@/mastra` does not resolve. Mastra now has its first typechecked route
snippet, 21 gated fences → 22.
## Verified
```
shipped fence, agent down -> up -> 500, then 200; process survived, no restart needed
promise form, agent down -> node terminated on an unhandled rejection
next build, NodeNext tsconfig -> 13 keys written; module/moduleResolution NOT touched
mastra CLI -> serverPort 4111, getPort over 4111..4131, apiPrefix /api
doc-test extraction -> 21 -> 22 fences; mastra sidecar selected, not the root one
extracted fence, runner config -> tsc exit 0 (runtime 1.68.3; @ag-ui/mastra 1.1.1 and 1.1.2)
mutation: drop resourceId -> tsc exit 1, TS2741 (the gate is live)
previously documented local shape-> tsc exit 2, resourceId missing
MDX compile, both files -> OK (mutation-checked: unclosed tag -> FAIL)
validate-intelligence-env-names -> exit 0
```
The behavioural checks drove the **extracted fence itself** against a
stub agent server, not a paraphrase of it — including confirming it
calls `/api/agents` (the same path the quickstart gives as the liveness
check) and that it honours `MASTRA_BASE_URL`.
The extracted fence was byte-compared against the file that typechecked
green.
**Not run:** the shell-docs vitest suite. No test reads either file,
there are no snapshots, and no page was added or moved — nav, sitemap
and `llms.txt` are unchanged. Lefthook could not run in the worktree
(`tsx: command not found`, no `node_modules`); its one non-skipped gate,
`check:intelligence-env-names`, was run manually against this tree and
passes, and the commit message passes commitlint.
## Second commit
The first commit shipped the promise form and named `moduleResolution:
"NodeNext"` as what `next dev` clobbers. Self-review caught both: the
promise form crashes the process, and `nodenext` is in Next's *accepted*
set for `module` and `moduleResolution`, so it is never rewritten.
`7f068c6` corrects both plus the `MASTRA_BASE_URL` shell, each against a
real run rather than a source read.
## Found along the way, not fixed here
`getLocalAgents({ mastra })` — no `resourceId` — **does not typecheck**
against current `@ag-ui/mastra`; `resourceId` is required in
`GetLocalAgentsOptions`. That shape still ships on four other pages
(`shared-state/` ×3, `background-tasks.mdx`), and
`examples/integrations/mastra/src/agent.ts` carries a `//
@ts-expect-error - ignore for now, typing error` over exactly this call.
Left alone to keep this PR focused; happy to file it or fix it in a
follow-up.
Refs OSS-925.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Resolves the Mastra quickstart runtime step, where this branch's remote-agent
wiring and main's Intelligence wiring landed on the same lines. Kept both: the
per-request `getRemoteAgents` factory now sits alongside `intelligence` and
`identifyUser`, `runner: new InMemoryAgentRunner()` is gone (main dropped it
with the runner), and `resourceId` is derived from the same request header as
`identifyUser` rather than left hardcoded to "user-1", which would have scoped
Mastra's memory and CopilotKit's threads to different users. Both env blocks
and both callouts are preserved.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The page tells you how to build the integration and never how to establish that it
works. `verify` appeared zero times in 646 lines, and the only verification content
was a reactive troubleshooting entry. That gap is sharper here than on the web
frontends: there, "open it and look" is an unstated fallback that actually works. On
React Native there is no browser, so a reader following this page to the end has no
proof step at all.
Adds a "Proving it works" section with three checks, and is explicit that none of them
is sufficient alone, because each one looks more conclusive than it is:
- `copilotkit verify --round-trip` proves an agent answered with no browser and no
device. It sends a fixed prompt and records the answer's length, never its text, so
it cannot tell you what came back -- and it proves an agent answered under the
declared id, not which deployment answered.
- A device capture proves the tool UI rendered. Android gets `adb exec-out screencap`;
iOS has no equivalent short of full Xcode, and the Command Line Tools do not ship
`simctl`, so that is stated rather than left to be discovered.
- Checking the answer against the records the app holds is the only step that
separates a correct answer from a fluent one about records that do not exist. That
failure is invisible in a screenshot, in a video, and to any reviewer unfamiliar
with the data.
Also on this page:
- `useAgentContext` was listed in the shared-hooks list as behaving "the same as on
the web", which undersells the one whose absence fails silently. Rendering a list
puts it in the view tree, not in the agent's context. An agent missing it still
answers plausibly and nothing errors -- and React Native has no browser console to
notice it in. Now a callout.
- React Native 0.87 no longer bundles `@react-native-community/cli`, so an upgraded
app needs it in devDependencies or `bundle` and `start` refuse to run. A freshly
`init`ed app already has it, which is why the quickstart path never hit this. Now a
prerequisite.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## What does this PR do?
Lets a developer open a saved Inspector thread in the live official
chat.
- New header action: **View in your app**
- Official React and Vue chat switch to that thread
- A pinned `threadId` does not block the switch
- **Stop viewing** or an app thread change restores the previous thread
- Example threads have no action
- Production builds hide the action
- Same agent only. No matching official chat shows an error in the
Inspector
Core owns a two-way EventClient bridge
(`@tanstack/devtools-event-client`). The root import is a no-op in
production.
Docs: Inspector guide, section **View a thread in your app**.
## Related PRs and Issues
-
https://linear.app/copilotkit/issue/OSS-871/new-features-add-a-new-view-thread-in-your-app-feature
## Checklist
- [x] I have read the Contribution Guide
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] Allow edits by maintainers is checked
Three claims the code refuses, and one source missing.
- "The failed tool call is highlighted" covered both tool cases, but
`TOOL_NOT_FOUND` is emitted with `toolName` and `agentId` and no
`toolCallId` -- a tool that was never found has no call to point at.
- "The failed `RUN_ERROR` event is highlighted" holds only when such an
event is in the buffer; several codes reach the run source without one.
- "A red launcher pill names the failure. Click it" reads as unconditional,
but the pill is suppressed where there is no room beside the launcher,
leaving a red dot and nothing to click.
- Learning is the fifth source and appeared in neither page. Documented
with the constraint that makes it different: the memory store is created
on first visit, so nothing is reported before that.
Closes#6607.
Verified against the pinned `langgraph_prebuilt` (1.1.0):
`create_react_agent` has neither `middleware` nor `system_prompt`
parameters, rejects `state_schema=CopilotKitState`, and is deprecated in
favour of `langchain.agents.create_agent`. Readers following the comment
hit an immediate `TypeError`.
All 7 occurrences on `main` are updated (4 sites noted in the issue plus
the 3 that landed with #5469):
-
`showcase/shell-docs/src/content/docs/integrations/langgraph/agent-app-context.mdx`
(Python + TypeScript)
-
`showcase/shell-docs/src/content/docs/integrations/langgraph/frontend-tools.mdx`
(Python + TypeScript)
-
`showcase/shell-docs/src/content/snippets/integrations/langgraph/frontend-tools.mdx`
(Python + TypeScript)
- `showcase/shell-docs/src/content/reference/hooks/useFrontendTool.mdx`
(Python)
Each comment is replaced with an accurate note (”`create_agent`
supersedes the deprecated `create_react_agent`, which accepts neither
`middleware=` nor `system_prompt=`”), and the TypeScript snippets now
reference `createReactAgent` (camelCase) instead of the Python
`create_react_agent` name — the second, smaller problem noted in the
issue.
Open Inspector Event Snippets on localhost. You can compile, save, and
replay AG-UI events in chat. Chat shows a bookmark icon next to a tool
call, an A2UI block, or generative UI. Click the icon to save that turn
as a snippet.
## What does this PR do?
This PR adds the Inspector Event Snippets pane.
You can:
- Compile a snippet from a recipe (tool-call, reasoning, text, activity,
raw)
- Save snippets in origin-scoped localStorage
(`cpk:inspector:event-snippets`)
- Import and export snippets from the pane header
- Replay a snippet into live chat through Inspector-only Core inject
Each Run remints `messageId`, `parentMessageId`, `toolCallId`, and
`runId`. The second Run of the same snippet is a new turn.
On localhost, chat shows a bookmark icon beside a tool call, A2UI block,
or generative UI. The icon is absolutely positioned. It hangs to the
right when there is room. Otherwise it hangs to the left. The card stays
full chat width.
The React demo adds `sayHello`, `getTime`, `addNumbers`, and a **Call 3
tools** suggestion.
## Related PRs and Issues
- Linear
[OSS-874](https://linear.app/copilotkit/issue/OSS-874/new-features-also-allow-users-to-emit-specific-events-from-the)
## 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 (lets us help iterate on
your PR directly — faster turnaround for everyone)
## Testing
### Commands run
1. Lefthook pre-commit ran `nx` targets `test`, `publint`, and `attw`
for 27 affected projects. All passed.
2. I did not run `pnpm test:pr` (full repo). Lefthook ran the affected
package matrix only.
### Manual test
1. Run `pnpm demo:react` from the repo root.
2. Open http://localhost:3000
3. Open Inspector and select Event Snippets.
4. In chat, click **Call 3 tools**. Confirm three tool cards at full
chat width, with the bookmark hanging outside the card.
5. Click a bookmark, then click Run twice. Chat shows a second turn with
new IDs.
### How this PR makes testing easy
- `packages/web-inspector/src/lib/__tests__/event-snippets.test.ts`
- `packages/core/src/__tests__/inspect-inject.test.ts` (covers two
injects)
- React demo: `examples/v2/react/demo/src/app/page.tsx`
## Linked issues
Linear
[OSS-874](https://linear.app/copilotkit/issue/OSS-874/new-features-also-allow-users-to-emit-specific-events-from-the)
## Risk / rollback
- If ID remint is wrong, a second Run can no-op or duplicate a turn.
- The save icon shows on localhost Inspector (or when `showDevConsole`
is `true`).
- Rollback: revert this PR.
## Public API change
**Before**
Angular has no Inspector service.
```ts
// no CopilotInspector export from @copilotkit/angular
```
**After**
```ts
import { CopilotInspector } from "@copilotkit/angular";
const inspector = inject(CopilotInspector);
inspector.openInspector({
messageId: "msg-1",
menu: "event-snippets",
});
```
React and Vue apps that already mount Inspector on localhost need no new
caller code. Chat wires the bookmark through Inspector context.
`@copilotkit/core` exports `ɵinjectInspectorEvents` for Inspector only.
App code must not call it. There is no public Core emit API.
Every framework quickstart sets runtimeUrl="/api/copilotkit". That resolves
only because Next.js serves the app and the runtime from one origin, and
nothing on the page said so -- so a reader on a client-only frontend followed
a step that could not work for them.
Annotate the provider step in all 13 quickstarts that carry it, pointing at
the per-frontend guides that show a standalone runtime server and an absolute
runtimeUrl.
The callout deliberately uses no root-relative links. The Angular surface
reuses these same integration quickstarts via resolveAngularDoc's fallback to
frameworkContentSlug, and its link contract keeps readers inside /angular/**;
linking three other frontends' pages both broke that contract and was wrong
content for an Angular reader.
aws-strands is left un-annotated while the Strands rejuvenation is underway.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A React single-page app is the one frontend the docs could not get to a
working runtime. Every framework quickstart hosts the runtime in a Next.js
route handler and uses a relative runtimeUrl of /api/copilotkit, which only
resolves because Next.js serves the app and the runtime from one origin. A
Vite or CRA app has neither a server nor a shared origin, so that step had
nowhere to land.
Add a React SPA page covering only that difference: a standalone Node runtime
server, the absolute runtimeUrl it requires, and cors: true -- which is off by
default on createCopilotNodeListener, unlike the Express and Hono adapters.
Everything else links back to the root React docs rather than restating them.
Registering react-spa in the frontend registry is what makes /react-spa
resolve; route resolution is gated on isFrontendId, so an unregistered page
404s. Vue and React Native are the precedent: registered, single-page, no
namespaced subtree. The existing registry-driven guard in frontend-options
already covers the new page.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## What does this PR do?
Twelve integration quickstarts opened by telling the reader to create a
free account and get a license key, then — seven steps later — showed a
runtime constructed like this:
```ts
const runtime = new CopilotRuntime({
agents: { ... },
runner: new InMemoryAgentRunner(),
});
```
`runner` and `intelligence` are mutually exclusive by construction
(`CopilotSseRuntimeOptions` declares `intelligence?: undefined`), so the
key provisioned in step 1 could not be consumed. Threads read "locked",
and nothing on the page indicated a choice had been made. Worse, **none
of the twelve pages ever named `INTELLIGENCE_API_KEY`** — after step 1
the key was never mentioned again.
Each page now:
1. Constructs the runtime with `intelligence: new
CopilotKitIntelligence({ apiKey: process.env.INTELLIGENCE_API_KEY! })`
and `identifyUser`.
2. Names `INTELLIGENCE_API_KEY` in a `.env.local` fence at the point the
route reads it.
3. Links `/premium/connect-your-runtime` — a good page that had **zero**
inbound links from any quickstart — from a callout that also documents
the in-memory opt-out.
The in-memory runner stays available and is labelled as the opt-out. It
was already the default (`super(options, options.runner ?? new
InMemoryAgentRunner())`), so passing it explicitly only ever added the
steer.
Also adds the required `name` field to the `identifyUser` snippets in
`connect-your-runtime.mdx` and the runtime skill's `agent-runners.md`.
Both omitted it, so copying either was a type error:
```
Property 'name' is missing in type '{ id: string; }' but required in type 'CopilotRuntimeUser'
```
### Scope
Not "every page mentioning `InMemoryAgentRunner`" — that is 37 files,
and most are legitimate (`backend/agent-runner.mdx` is *about* runners;
an AgentCore host is a Lambda and cannot host the Intelligence socket at
all). The scope is **pages that provision a license key and then show a
runtime that cannot consume it**, which partitions those 37 cleanly into
12 in-scope and 25 untouched.
Note that includes `docs/agent-spec/quickstart.mdx`, which is
byte-identical to `docs/integrations/agent-spec/quickstart.mdx`. Both
are fixed here; retiring the duplication is filed separately.
## Verification
Nine of the twelve runtime fences are `doctest="component"` gated, so
they are really compiled in CI against a pinned
`@copilotkit/runtime@1.68.3`. The new constructor was proven there
before being applied to twelve files.
- Extracted the docs tree with `scripts/doc-tests/extract.ts` → 16
snippets. **All 15 `component` snippets typecheck clean**, covering 9 of
the 12 edited pages plus 6 untouched pages (so it also rules out
collateral damage).
- Confirmed the gate can go red: removing `name` from an edited snippet
reproduces exactly the error above, so the pass above is meaningful.
- The 3 ungated fences (mastra ×1, langgraph ×2) were typechecked by
hand, since CI will not.
- `src/lib/__tests__/intelligence-wiring-docs.test.ts` passes 3/3. That
suite guards this defect class, and **this change brings these pages
into its coverage for the first time — 8 → 20 pages**, because a page
only enters the suite once it actually configures `intelligence`.
- `pnpm check:intelligence-env-names` passes. `pnpm check:plugin-skills`
initially failed (`packages/runtime/skills/**` is mirrored to
`skills/**`); synced, both copies included.
## Related PRs and Issues
- Closes OSS-932
- Part of the OSS-923 split, alongside OSS-933 (runtime silently drops
`runner` alongside `intelligence`)
- OSS-935 — the byte-identical agent-spec duplication
- OSS-936 — the Mastra fence's `getLocalAgents({ mastra })` does not
compile against `@ag-ui/mastra@1.1.2`. **Pre-existing on
`origin/main`**, reproduced on the unmodified snippet, not addressed
here
Worth noting for reviewers: the Mastra runtime fence cannot be
doctest-gated as written (it imports the `@/mastra` path alias, which
does not resolve in the extracted directory), and `@ag-ui/mastra` is in
no `doctest.json`. It is the least-verified page in the set on two
independent axes, and it accumulated two unrelated defects. That may
explain why only the Mastra evaluation cell surfaced this.
## Checklist
- [x] I have read the Contribution Guide
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Resolves conflicts in the two custom-agent docs copies. Main's "docs: update
Anthropic model references to Opus 4.8" (518feae6cd) independently bumped the
Anthropic thinking snippets to `claude-sonnet-4-6` -- the same model id this
branch picked -- so the overlap was textual, not a disagreement.
Kept this branch's side in both files: it already carries that model id and
additionally moves the AI SDK options into `providerOptions.anthropic` and
switches to `{ type: "adaptive" }` with `effort`. Main's bumps on the
surrounding property-forwarding examples merge in unchanged.
Twelve quickstarts provisioned a license key in step 1 and then showed a
runtime constructed with `runner: new InMemoryAgentRunner()` — an option
that is mutually exclusive with `intelligence`, so the key was never read.
Threads showed "locked" and nothing indicated a choice had been made.
Each of those pages now constructs the runtime with `intelligence` and
`identifyUser`, names `INTELLIGENCE_API_KEY` where the route reads it, and
links /premium/connect-your-runtime — which had no inbound link from any
quickstart. The in-memory runner stays available as a labelled opt-out;
it was already the default, so passing it explicitly only added the steer.
Also adds the required `name` field to the `identifyUser` snippets in
connect-your-runtime.mdx and the runtime skill's agent-runners reference.
Both omitted it, so copying either was a type error.
Scope is every page that provisions a key and then shows a runtime that
cannot consume it. Pages that legitimately document the in-memory runner
(backend/agent-runner, deploy/agentcore) are unchanged.
Verified: all 15 doctest `component` snippets typecheck against the pinned
@copilotkit/runtime@1.68.3, and the gate goes red when `name` is removed.
Add chat phrases and lab buttons that fail a frontend tool or emit RUN_ERROR.
Clear the Break threads cookie on load so a refresh does not keep a fake
thread-list failure.
Self-review of the previous commit found three defects, two of them factual
errors I asserted without checking.
1. The promise form can kill the process. I documented
`agents: MastraAgent.getRemoteAgents({ ... })` and described its failure mode
as "the rejection is cached and every later request fails". That understated
it: the call starts at module load with nothing awaiting it, so an agent
server that is not up yet produces an *unhandled* rejection and Node
terminates. Both files now lead with the factory form, which has no such
window — nothing runs until a request arrives, a failure is a 500, and the
next request retries.
2. The tsconfig warning named the wrong key. `next dev` does not overwrite
`moduleResolution: "NodeNext"` — `nodenext` is in Next's accepted set for
both `module` and `moduleResolution`. What it actually does at its own root
is force `esModuleInterop`, `isolatedModules`, `resolveJsonModule` and `jsx`,
set `noEmit: true`, and replace `include`/`exclude`. `noEmit` is the sharp
one for an agent project that compiles with `tsc`. The advice stands; the
mechanism is now the verified one.
3. `MASTRA_BASE_URL` was set in the wrong shell. It was exported in the agent's
terminal, where the frontend cannot see it. It now appears as `.env.local` in
the Next app, next to the route that reads it. The port note moved to the
step that starts the agent, and says what `mastra dev` really does: 4111 when
free, walking up to 4131 when not.
Verified:
shipped fence, agent down -> up -> 500, then 200; process survived, no restart
promise form, agent down -> node terminated on unhandled rejection
next build, NodeNext tsconfig -> 13 keys written; module/moduleResolution untouched
mastra CLI -> serverPort 4111, getPort over 4111..4131, apiPrefix /api
extracted fence, runner config -> tsc exit 0; mutation (drop resourceId) -> TS2741
MDX compile, both files -> OK
The behavioural checks drove the extracted fence itself, not a paraphrase of it.
Refs OSS-925.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`MastraAgent.getRemoteAgents` appeared nowhere in this repo — not in
shell-docs, not in an example. The only wiring the Mastra quickstart taught was
`getLocalAgents({ mastra })` behind `import { mastra } from "@/mastra"`,
including on the "Use an existing agent" branch, which two steps earlier tells
you to `create-next-app` a *separate* directory. That import cannot resolve, and
the shape it teaches moves a running Mastra service into the frontend, deleting
the process the reader was trying to keep.
All four cells of the 2026-08-21 Mastra x Next.js sweep reached the agent over
HTTP, and all four derived how on their own; `both` filed it as its largest
friction and `empty` as its worst papercut at ~10 minutes.
- Quickstart, existing-agent branch: wire the route with `getRemoteAgents` over
a `MastraClient`, add the `MASTRA_BASE_URL` convention, and add the missing
step that starts the agent server. `/api/agents` is the liveness check; a
bare `GET /` answers 200 from Mastra's console whether an agent is registered
or not.
- Warn that `next dev` rewrites the `tsconfig.json` at its own root, so the
frontend belongs in a sibling package — the reason this path goes over HTTP.
- copilot-runtime.mdx: a "Local vs remote agents" section that decides between
them by where the agent runs, with the full `GetRemoteAgentsOptions` contract,
the promise-vs-factory trade-off, and the local-only options
(`requestContext`, `untilIdle`).
- Gate the new route fence in CI (`doctest="component"` plus a mastra
`doctest.json`). The old fence could never have been gated: `@/mastra` does
not resolve. Mastra now has its first typechecked route snippet.
Verified:
MDX compile, both files -> OK (mutation-checked: unclosed tag -> FAIL)
doc-test extraction -> 21 -> 22 fences; mastra sidecar selected
extracted fence, runner config -> tsc exit 0 (runtime 1.68.3; ag-ui/mastra 1.1.1, 1.1.2)
mutation: drop resourceId -> tsc exit 1, TS2741
previously documented shape -> tsc exit 2, resourceId missing
validate-intelligence-env-names -> exit 0
Not run: the shell-docs vitest suite. No test reads either file and no page was
added or moved, so nav, sitemap and llms.txt are unchanged.
Refs OSS-925.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes OSS-901.
## Problem
`/mastra/generative-ui/a2ui/fixed-schema` could not be followed. A
Mastra onboarding run on Codex stopped there rather than invent an API,
reporting that the guide "depends on unbundled showcase helpers."
That is true, and the mechanism is worse than the report. Region bodies
are assembled at bundle time, so what ships is invisible in a source
diff. The `backend-render-operations` marker sits on **line 1** of
`mastra/src/mastra/tools/index.ts` — put there by the marker-hoist sweep
in 34b6418 so snippets would carry their imports — and the closing
marker is at the bottom of the file. The page therefore published **all
432 lines** of the tools barrel: weather, stock price, dice, d20,
query-data, schedule-meeting, search-flights, the aimock
header-forwarding import, and
```ts
import { generateA2uiImpl, buildA2uiOperationsFromToolCall } from "@copilotkit/showcase-shared-tools";
```
`@copilotkit/showcase-shared-tools` is not a package. It is a tsconfig
`paths` entry (`mastra/tsconfig.json:23`) pointing at `./shared-tools`,
a symlink to `showcase/shared/typescript/tools`. There is nothing for a
reader to install.
Same defect on the strands page from the same sweep: 586 lines of a
1688-line `agents/agent.py`.
## What changed
**The two cells get a dedicated module for the A2UI tool**, so hoisting
the marker to the top of the file yields exactly the tool plus its own
imports. This is the shape of the reference cell
(`langgraph-typescript/src/agent/a2ui-fixed.ts`, which likewise builds
A2UI operations locally) and, on the Python side, of `gen_ui_agent.py` /
`a2ui_dynamic.py`.
| page | before | after |
| --- | --- | --- |
| mastra fixed-schema | 432 lines, 16.5 KB | 166 lines |
| strands fixed-schema | 586 lines | 171 lines |
Every line in the new snippets either installs from npm or is a visibly
local `./` / `@/` module carrying a comment about what a real app uses
instead. Mastra keeps a single operation builder — the beautiful-chat
flight tool now calls the same one. The strands cell also highlights
`tools/generate_a2ui.py` so the guide shows the helper the tool calls.
**A guard in the bundler**, because neither failure mode shows up in
review:
- any `@copilotkit/showcase-*` specifier in a published body fails the
build (corpus is at zero after this change, so no baseline);
- over 200 lines fails the build (median region is 28, p90 is 125; the
48 already over the line are baselined by `slug::region::file` and the
list only shrinks).
**The entrypoint half of the issue lands differently than I first read
it.** OSS-901 flagged `@copilotkit/runtime` +
`@copilotkit/react-core/v2` on the shared A2UI page as a v1/v2 trap. It
is not a broken pairing — v1's `CopilotRuntime` forwards `a2ui` (and
`mcpApps` / `openGenerativeUI`) straight to the v2 runtime
(`packages/runtime/src/lib/runtime/copilot-runtime.ts:414`). But #6618
landed while this branch was open and retired the v1 runtime adapter
across every showcase integration, so the page's v1 root import *was*
the stale half. The block also imported `ExperimentalEmptyAdapter` and
`copilotRuntimeNextJSAppRouterEndpoint` and used neither, so it was a
route a reader could not run. It now shows `createCopilotRuntimeHandler`
from `@copilotkit/runtime/v2` in the single-route form, matching the
rebased showcase route and `/runtime-server-adapter`, with a note that
the legacy form still works.
**On the systemic question.** A separate sweep counted ~50 regions whose
marker sits on line 1 with a matching close at end-of-file, and proposed
failing a region that spans >=90% of its file. That rule does not
survive contact with the published bodies: of 141 regions at >=90% span,
only **2** publish more than 200 lines, and 98 publish under 100 —
dedicated single-purpose files whose whole content *is* the intended
snippet. It would also flag this PR's own fix
(`strands/a2ui_generate.py` is 171/188 = 91%) and the langgraph
reference cells. Published size is the signal that separates the defect
from the pattern, which is what the guard here measures.
## Testing
**Guard catches the pre-fix tree** (restored HEAD sources, moved the new
modules aside, ran the bundler):
```
REAL EXIT=1
Region bodies importing repo-only modules:
mastra::agentic-chat: region "weather-tool-backend" (src/mastra/tools/index.ts) imports "@copilotkit/showcase-shared-tools", ...
mastra::agentic-chat: region "backend-render-operations" (src/mastra/tools/index.ts) imports "@copilotkit/showcase-shared-tools", ...
Region bodies over the published-snippet limit:
strands::a2ui-fixed-schema: region "backend-render-operations" (src/agents/agent.py) publishes 586 lines (limit 200) ...
```
and passes on this branch (`bundler exit=0`, 801 demos bundled).
**Guard unit tests** —
`showcase/scripts/lib/__tests__/demo-region-guard.test.ts`, 10 passed.
Mutation-checked: raising `MAX_REGION_LINES` and short-circuiting the
alias scan fails exactly 2 of them; restoring passes 10/10.
**Showcase script suites** — `demo-region-guard`, `bundle-demo-content`,
`validate-parity`, `verify-shell-docs`, `validate-shared-symlinks`:
**151 passed (5 files)**.
**Mastra vitest** — `tests/vitest/a2ui-context.test.ts`, 5 passed. The
prompt builder lives in the dependency-free `a2ui-context.ts` so this
regression test still runs without the Mastra SDK installed, as it did
before. Mutation-checked: breaking the join fails 1 of 5.
**Strands pytest** — `tests/python/test_generate_a2ui_errors.py` 11
passed (was 1 failed / 10 passed after the move, because the happy-path
test patched `agents.agent.build_a2ui_operations_from_tool_call`;
retargeted at the new module). Whole runnable suite: **40 passed**
across `test_generate_a2ui_errors`, `test_hook_injection`,
`test_sales_state_from_args`, `test_tool_call_cap`. Mutation-checked:
stubbing out the builder call fails the happy-path test.
`test_cvdiag_boundaries` / `test_instrumentor_patch` need `starlette` /
`opentelemetry-instrumentation-threading`, absent from this venv —
unrelated to this change.
**Published snippet, rendered** (`demo-content.json` after bundling):
```
mastra snippet lines: 166 | file: src/mastra/tools/a2ui-generate.ts
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { generateText, tool as aiTool } from "ai";
// In your own app this is `import { openai } from "@ai-sdk/openai"`. ...
```
**Docs verification** — `verify-shell-docs.ts` produces a byte-identical
finding set with my two MDX edits toggled on and off (empty diff), so
the edits add no new findings. `component-imports`, `essential-content`
and the rest are unchanged; the suite's pre-existing failures are
untouched.
**Lint / format** — `oxfmt` on all changed TS, `oxlint` clean on the new
and edited files.
## Follow-ups (not in this PR)
- The 48 baselined regions are the same class of defect on other pages —
`strands::supervisor-delegation-tools` publishes 795 lines,
`strands::subagent-setup` 625, `ms-agent-dotnet::weather-tool-backend`
549. Each wants the same split.
- `claude-sdk-typescript/shared-tools/` and
`langgraph-typescript/shared-tools/` are real directories where symlinks
belong — the erosion `showcase/AGENTS.md` documents. Untouched here.
- Dropping the strands commit (`14c7351`) is safe on its own; it only
requires adding
`strands::backend-render-operations::src/agents/agent.py` to the guard
baseline.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Two things this PR was missing, both now closed.
## The Claude SDK quickstarts are unblocked
#6618 put `showcase/integrations/claude-sdk-{python,typescript}` on
`createCopilotRuntimeHandler` with `mode: "single-route"`, at the **plain**
`route.ts` path. That dissolves the coupling that forced these two pages to be
reverted earlier: `verify-shell-docs.ts` asserts each page claims a starter file
at `src/app/api/copilotkit/route.ts` AND that the file exists in the extracted
starter. Single-route keeps that path, so the prose claims and
`requiredStarterFiles` are unchanged — only the fence bodies move to v2.
The two content assertions that pinned those pages to v1
(`ExperimentalEmptyAdapter`, `copilotRuntimeNextJSAppRouterEndpoint`) now
require `createCopilotRuntimeHandler`, the `/v2` entrypoint,
`mode: "single-route"` and a `POST` export. Mutation-checked: flipping the
fixture to `mode: "multi-route"` fails with
`app/api/copilotkit/route.ts missing single-route mode`.
## Snippet gating: 1 -> 20 route fences
I previously claimed the integration pages could not be doctested because of
path aliases and per-integration deps. **That was an assumption I never
checked, and it was wrong.** Of the 52 migrated route fences, 47 import nothing
project-relative; 36 are complete, self-standing routes. 27 pages were
eligible, 20 now hold a gated fence — each extracted and typechecked by
`tsc --noEmit` against real npm-installed packages in CI.
One fence per (page, title): `extract.ts` concatenates tagged blocks sharing a
title, so a second complete route on the same page would collide.
Mutation-checked on `snippets/integrations/langsmith/index.mdx`: restoring the
v1 import in the gated fence turns the run red (20 passed, 1 failed). My first
attempt at this check was a no-op — the pattern missed because the fence is
JSX-indented — and it "passed" misleadingly. The real check asserts the mutation
reached the extracted snippet before trusting the result.
### Harness changes this needed
- `extract.ts` now finds the nearest `doctest.json` by walking up to the docs
root, instead of looking only in the page's own directory. Otherwise gating
20 pages means ~20 duplicated dependency lists that then drift. A shared list
lives at `content/doctest.json`; `docs/integrations/langgraph/` keeps its own
(Python deps) and now also carries the TS deps its page needs.
- `run.ts` installs each dependency set **once**, into
`.doctest-output/.deps/<hash>`, and links it into every snippet sharing that
set. Per-snippet installs took **7:58** for 21 snippets, uncomfortably close
to the job's 15-minute timeout; shared installs take **0:45** cold. Different
dep sets still get separate stores, so this is a dedupe, not a merge.
### `@ag-ui/*` versions have to be pinned to what the runtime expects
Unpinned, the gated fences failed with `HttpAgent is not assignable to
AbstractAgent — separate declarations of a private property '_debug'`: npm
installs a newer `@ag-ui/client` than `@copilotkit/runtime` depends on, so two
`AbstractAgent` declarations collide. The sidecar pins `@ag-ui/client@0.0.57` and
`@ag-ui/core@0.0.57` to match `@copilotkit/runtime@1.68.3`.
## Seven fences are deliberately NOT gated
Un-tagged with the reason, rather than left failing or quietly dropped:
- `docs/auth.mdx`, `docs/premium/connect-your-runtime.mdx` — illustrative
fences referencing placeholders (`myAgent`, `verifyJwt`) that cannot compile
standalone by design.
- the four langgraph-family pages and
`snippets/self-hosting-copilot-runtime-langgraph-endpoint.mdx` — these hit
`LangGraphAgent is not assignable to AbstractAgent — separate declarations of
a private property '_debug'`, which pinning does not fix.
**That last one is a real pre-existing defect, not a migration regression.** I
reconstructed the v1 form of the langgraph quickstart snippet verbatim from
`origin/main` and typechecked it against the identical installed dependencies:
it fails with the same error. So these snippets have never typechecked against
published packages — worth filing separately. It is also what the ~220
`@ts-ignore` comments across `showcase/integrations` were papering over.
## Verified
doc-tests (cold, no cache) -> 21 passed, 0 failed in 0:45
mutation check (real, verified) -> 20 passed, 1 failed
vitest extract + verify-shell-docs -> 34 passed
showcase/shell-docs typecheck -> exit 0
showcase/shell-docs build -> exit 0
structural audit -> 21/21 pages, fence + JSX identical to HEAD
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four docs pages configured a CopilotRuntime with an `intelligence` option that
nothing on the page produced. A Mastra onboarding run hit this on
/mastra/threads-lifecycle and stopped rather than invent a constructor
(OSS-900). The wiring itself was published as /premium/connect-your-runtime
under OSS-881; these pages were never connected to it.
- threads-lifecycle and headless-threads now build the client inline, so the
block a reader copies is complete
- headless-threads imported CopilotRuntime from the v1 root, whose runtime has
no `intelligence` option at all, and omitted the `identifyUser` that the
Intelligence runtime requires
- auth and backend/copilot-runtime keep their focused examples and gain a
pointer to the wiring page
The test enforces the contract page-scoped rather than per-fence, which is how
backend/runtime-endpoints already satisfies it.
The A2UI setup page imported `ExperimentalEmptyAdapter` and
`copilotRuntimeNextJSAppRouterEndpoint` and then used neither, so the block
was a truncated route a reader could not run. Show a complete route — and
show the current API while doing it: #6618 retired the v1 runtime adapter
across every showcase integration, so the page now uses
`createCopilotRuntimeHandler` from `@copilotkit/runtime/v2` in the
single-route form, matching `mastra/src/app/api/copilotkit-a2ui-fixed-schema/route.ts`
and the reference in /runtime-server-adapter.
That also settles the entrypoint question OSS-901 raised. The complaint was
that the page mixes v1 `@copilotkit/runtime` with `@copilotkit/react-core/v2`
below — not a broken pairing (v1's `CopilotRuntime` forwards `a2ui` straight
to the v2 runtime), but the v1 root import was the stale half, so both halves
of the page are now v2 entry points. The legacy form is noted as still
working for readers who are on it.
On the fixed-schema page, note that the LLM-driven integrations have no
`a2ui.render(...)` equivalent, so the operation builder in the snippet is
part of what a reader copies — and that the operations are nested, since a
flat `{ type: "create_surface" }` is silently ignored.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>