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>
The earlier commits in this PR taught `createCopilotEndpoint` paired with
`handle` from `hono/vercel`, and added `hono` to 20 install commands with a
callout explaining why readers must install it. Both were wrong, and the second
was a consequence of the first.
`createCopilotEndpoint` is a **deprecated alias**. This repo's own handler table
says so — `docs/backend/runtime-endpoints.mdx`:
| Deprecated | Use instead |
| `createCopilotEndpoint` | `createCopilotHonoHandler` |
| `createCopilotEndpointSingleRoute` | ... with mode: "single-route" |
`createCopilotRuntimeHandler` serves the same multi-route mode (it is the
default), returns a plain fetch handler, is not deprecated, and needs **no hono
at all**. So the route collapses to:
const handler = createCopilotRuntimeHandler({
runtime,
basePath: "/api/copilotkit",
});
export const GET = handler;
export const POST = handler;
`hono` was therefore an artifact of the shape, not a requirement of the library.
The install lines and the callout are reverted; nothing tells readers to install
it any more.
## Verified with hono deleted, not merely absent from package.json
`examples/shadcn` converted to this shape, `hono` removed from its
`package.json`, and `node_modules/hono` deleted outright so a hoisted copy could
not mask the result:
GET /api/copilotkit/info -> 200
POST /api/copilotkit/agent/default/run -> 200, chat turn rendered
tsc --noEmit / eslint / next build -> clean
next build route -> ƒ /api/copilotkit/[[...slug]]
The doctest sidecar drops `hono` too, so the CI gate now typechecks the
canonical snippet against `@copilotkit/runtime` alone — proof by construction
that the snippet needs nothing else.
pnpm tsx scripts/doc-tests/run.ts -> 2 passed, 0 failed
showcase/shell-docs: typecheck -> exit 0
showcase/shell-docs: build -> exit 0
structural audit: 31/31 mdx files, fence + JSX identical to HEAD
## Also corrected
`docs/backend/custom-agent.mdx` repeated the same incorrect transport claim the
earlier commit fixed in four other places ("Both `<CopilotKit>` and
`<CopilotKitProvider>` negotiate the transport when the prop is omitted").
Corrected to match released behaviour.
## Left alone deliberately
`snippets/shared/backend/custom-agent.mdx` and `docs/backend/custom-agent.mdx`
still call `createCopilotEndpoint` in three fences each, as
`export default copilotEndpoint` — the Hono-app deployment pattern rather than a
Next.js route handler. That predates this PR, the documented replacement is
`createCopilotHonoHandler`, and I have not run that shape. Recorded as follow-up
rather than guessed at. (The two files have also drifted from each other, which
is a separate problem.)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seven fences already imported from `@copilotkit/runtime/v2` but were still
titled `app/api/copilotkit/route.ts`. That is the same title/body mismatch this
sweep exists to fix, seen from the other side: a reader follows the title,
creates a plain route file for a runtime that needs the catch-all path, and gets
no `/info`.
Titles only — no bodies changed.
Two categories are deliberately left on the plain path, because there it is
correct:
- fences mentioning `createCopilotEndpointSingleRoute`. Single-route mode is
served from a plain `route.ts` and is POST-only by design; retitling one would
destroy what it demonstrates.
- fences still on the v1 entrypoint. Those are separate migrations, blocked for
the reasons recorded in the PR description.
Verified:
pnpm tsx scripts/doc-tests/run.ts -> 2 passed, 0 failed
showcase/shell-docs: pnpm build -> exit 0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Finishes the tractable remainder of the v1 -> v2 runtime sweep, and fixes a
docs claim that the previous commit's `useSingleEndpoint={false}` edits exposed
as wrong.
## The pairing guidance described unreleased behaviour
`backend/runtime-endpoints.mdx` is the authoritative page for provider/handler
pairs, and it said omitting `useSingleEndpoint` is safe on either provider
because the client negotiates from `/info` — with `auth.mdx` and two quickstart
callouts repeating it. That is true on `main` and false in every published
release: the compat `<CopilotKit>` wrapper still ships
useSingleEndpoint={props.useSingleEndpoint ?? true}
(verified in the published `@copilotkit/react-core` 1.68.3 bundle), so omitting
the prop selects the single-route transport and 404s against a multi-route
Runtime. The Runtime's own error body says so. `<CopilotKitProvider>` does
negotiate; only the wrapper pins — and every docs snippet uses the wrapper.
So the pairing table now splits the two providers instead of grouping them,
states that the pin exists in released versions and is removed on `main`, and
says plainly that passing `{false}` is the forward-compatible choice. The
"pinning the wrong mode 404s silently" warning now covers omitting the prop on
`<CopilotKit>`, which is the same failure by a different route. Same correction
applied to `auth.mdx` and to the two "Which provider goes with which handler?"
callouts, which additionally still named `copilotRuntimeNextJSAppRouterEndpoint`
as the route above them after that route became `createCopilotEndpoint`.
## Remaining migrations
- `self-hosting-remote-endpoints.mdx` — three LangGraph fragments moved to
`@copilotkit/runtime/v2` for `CopilotRuntime` and
`@copilotkit/runtime/langgraph` for the agents, splitting what was a single
v1 root import.
- `copilot-runtime.mdx` — the transport callout rewritten to match the
authoritative page and link to it, rather than asserting the default itself.
## Verified
pnpm tsx scripts/doc-tests/run.ts -> 2 passed, 0 failed
showcase/shell-docs: pnpm typecheck -> exit 0
showcase/shell-docs: pnpm build -> exit 0
structural audit: 6/6 mdx files, fence + JSX structure identical to HEAD
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Migrates the Next.js App Router runtime fences across the docs from the v1
entrypoint to the v2 multi-route shape proved in `examples/shadcn`: catch-all
path, `createCopilotEndpoint`, a runner, and both verbs exported. 38 fences
across 33 pages.
Only the boilerplate is rewritten. Each page's agent wiring — `MastraAgent`,
`LangGraphAgent`, `HttpAgent`, `BuiltInAgent`, middleware `.use(...)` calls —
is left byte-identical, because that part is not what was broken.
Three co-changes travel with every migrated page, since the shape does not work
without them:
- `hono` added to the page's install command (20 lines). It is a dependency of
`@copilotkit/runtime`, not a peer, so `hono/vercel` resolves under npm's flat
layout but not under pnpm.
- `useSingleEndpoint={false}` on `<CopilotKit>` (27 provider tags). The
provider defaults to the single-route transport, which posts to the bare
`runtimeUrl`; a multi-route runtime answers with 404. Only tags carrying a
`runtimeUrl` are touched — a provider using `agents__unsafe_dev_only` has no
runtime to match. Angular's `provideCopilotKit` defaults its transport to
`"auto"` and needs no equivalent, so those snippets are unchanged.
- fence titles retitled to the catch-all path, plus the prose that introduces
them, so no snippet claims a path its body contradicts.
`LangGraphAgent` moves from the v1 root entrypoint to
`@copilotkit/runtime/langgraph` on one page. Both spellings resolve, but the
subpath is the one that survives the v1 entrypoint; verified by typechecking
`LangGraphAgent` + v2 `CopilotRuntime` + `createCopilotEndpoint` together
against the published 1.68.3.
## Two mistakes worth recording, since both were caught by a check rather than by reading
A block regex scoped to the fence's opening indentation corrupted five
quickstart pages: their fences open and close at *different* indentation, so
the match ran past the closing backticks and re-indented the following
`</Step>` / `</Tab>` boundary into the code block. The five pages were reverted
and redone with a line-oriented pass that never re-indents anything and
re-emits the original closing line verbatim.
Every modified page is now checked structurally — fence-marker count and the
full set of JSX structural lines, indentation included, must be identical to
`HEAD`. All 33 pass. That check is what found the corruption; a diff review had
already missed it on the first pass.
## Verified
pnpm tsx scripts/doc-tests/extract.ts -> 2 snippets
pnpm tsx scripts/doc-tests/run.ts -> 2 passed, 0 failed
showcase/shell-docs: pnpm typecheck -> exit 0
showcase/shell-docs: pnpm lint -> exit 0 (pre-existing warnings only)
showcase/shell-docs: pnpm build -> exit 0
structural audit: 33/33 pages, fence + JSX structure identical to HEAD
Note this validates that the pages still build and that the one doctested
snippet compiles. It does not execute the other 37 fences. Their correctness
rests on Stage 0: the boilerplate they now contain is the text that was run in
`examples/shadcn`, and their agent wiring is untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`snippets/copilot-runtime.mdx` calls itself "the recommended way to use
CopilotKit" and taught the v1 plain-POST route. A reader following it got an
endpoint that answers 405 on `GET /api/copilotkit` and does not route
`GET /api/copilotkit/info` at all, so nothing could discover the runtime.
The route fence is now the shape proved in `examples/shadcn`: catch-all path,
`createCopilotEndpoint`, a runner, and both verbs exported. The three other
fences on the page that were titled with the plain route path are retitled to
the catch-all path, so no snippet claims a path its body contradicts.
Also documents the two things the shape actually requires, both of which were
found by running it:
- `npm install @copilotkit/runtime hono` — `hono` is a dependency of the
runtime rather than a peer, so `hono/vercel` resolves under npm's flat
layout but not under pnpm.
- `useSingleEndpoint={false}` on `<CopilotKit>`. The provider defaults it to
`true` (single-route transport), which posts to the bare `runtimeUrl`; a
multi-route runtime answers that with 404. The Angular provider defaults its
transport to `"auto"` and needs no equivalent change, so that snippet is
unchanged.
## The snippet is now gated in CI
`scripts/doc-tests` already extracts fences tagged `doctest=` and, for
`component`, runs `tsc --noEmit` against real npm-installed dependencies — but
it could not handle a fence whose title is a path, which is exactly what a
Next.js route handler's title is. Two defects blocked it, both fixed here:
- `extract.ts` wrote the title as a path without creating intermediate
directories, so a titled route fence died on ENOENT.
- `run.ts` derived the npm package name from the snippet directory, and a
catch-all leaf directory is literally `[[...slug]]`, which npm rejects as an
invalid name. It also looked for `doctest.json` only in the snippet's own
directory, while the sidecar is copied once per page — so a nested snippet
silently installed no dependencies and failed with "Cannot find module".
With those fixed, the canonical route snippet is tagged `doctest="component"`
and typechecked in CI against the published `@copilotkit/runtime` 1.68.3 and
`hono`. This is the gate the docs did not have: snippet correctness no longer
rests on review alone.
Verified:
pnpm tsx scripts/doc-tests/extract.ts -> 2 snippets extracted
pnpm tsx scripts/doc-tests/run.ts -> 2 passed, 0 failed
mutation check: restoring the v1 import in the fence turns the run red
(1 passed, 1 failed), so the gate fails on the regression it exists to catch
vitest scripts/doc-tests/__tests__/extract.test.ts -> 10 passed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Swapping the create_agent factory for create_react_agent (langgraph.prebuilt)
does not work: create_react_agent has no middleware= or system_prompt=
parameter and rejects state_schema=CopilotKitState, so following the comment
raises TypeError. It is also deprecated in favour of langchain.agents.create_agent.
Replace the misleading inline comment with an accurate note at all 7 sites
(supersedes the deprecated factory; accepts neither middleware= nor
system_prompt=), and fix the TypeScript snippets to reference createReactAgent
instead of the Python snake_case name.
Closes CopilotKit#6607
## What does this PR do?
Adds documentation explaining that `useFrontendTool` may require
explicit `system_prompt` guidance in LangGraph agents to be reliably
called. Includes a working code example showing both a well-described
`useFrontendTool` registration and the matching system prompt
instruction. Addresses the confusion reported in #4950 where users
implement tools with only a `description` and find the agent doesn't
call them.
Changes:
- `docs/integrations/langgraph/frontend-tools.mdx` — new section
"Ensuring your agent reliably calls frontend tools" with a `Callout`,
Python+TypeScript code examples, and a decision table (description vs.
system_prompt)
- `reference/hooks/useFrontendTool.mdx` — added "LangGraph agents:
description vs. system_prompt" subsection linking to the full example
- `docs/troubleshooting/common-issues.mdx` — expanded the "tool listed
but agent never calls it" bullet to cross-link the new guide
## Related PRs and Issues
- Closes#4950
## 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
The Anthropic extended-thinking examples were stale in three ways. The AI SDK
snippet passed thinking options as a second argument to `anthropic()`, which
takes only a model id — so it was a TypeScript error and thinking was never
enabled. The TanStack snippet used a model id the current adapter no longer
accepts, plus `budgetTokens` where that package spells it `budget_tokens`. And
all of them showed `{ type: "enabled", budgetTokens }`, the form deprecated
from Claude 4.6 and rejected outright on 4.7+.
Move the AI SDK options into `providerOptions.anthropic`, switch to
`{ type: "adaptive" }` with `effort`, and pin models to `claude-sonnet-4-6`.
Sonnet 4.6 is deliberate rather than a newer model: `@ai-sdk/anthropic` does
not expose thinking `display`, and from Opus 4.7 onward Anthropic defaults it
to "omitted" — so a newer model would emit reasoning events with no reasoning
text, defeating the point of the example. A callout explains that trap.
Also cross-links the BuiltInAgent `providerOptions` page from the custom-agent
reasoning section, which is where reporters looking for a BuiltInAgent thinking
example were failing to find one.
Refs #2191
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## Summary
React v2 feedback callbacks receive an assistant message without the
trace metadata carried by the direct AG-UI event that created it. This
slice exposes that metadata to thumbs callbacks without changing
canonical messages or future run inputs.
## Root cause
AG-UI keeps `rawEvent` on events while reducer-created assistant
messages remain protocol-clean. `StateManager` sees the direct start
event but previously discarded its correlation before
`CopilotChatMessageView` forwarded the message to feedback callbacks.
## Changes
- Store defined direct `TEXT_MESSAGE_START.rawEvent` metadata by agent,
thread, and message.
- Replace repeated scoped entries and prune them with message removal
and lifecycle cleanup.
- Return a cloned sidecar value through
`CopilotKitCore.getRawEventForMessage`.
- Enrich only thumbs-up and thumbs-down callback arguments at click time
across flat and virtualized rendering.
- Add production-path regressions and document the callback-only type.
## Out of scope
Canonical messages, future `RunAgentInput.messages`, render props,
message identity, stream ordering, snapshots, transformed chunks,
persistence, GraphQL, legacy React, Vue, Angular, and standardized trace
semantics remain outside this slice.
## Related PRs and Issues
Addresses #3039.
The callback-only scope follows
https://github.com/CopilotKit/CopilotKit/issues/3039#issuecomment-5086936452.
Related trace-correlation contract: #4634.
## Test plan
- [x] StateManager sidecar tests, 10 passed. Covers direct capture,
falsey values, replacement, scope isolation, cleanup, snapshots, and
chunks.
- [x] React v2 feedback tests, 4 passed. Covers real callback routing,
canonical and outbound cleanliness, render identity, and flat/virtual
paths.
- [x] Full package suites, 625 core tests, 1,475 React Core tests, and 2
script tests passed.
- [x] Typecheck, formatting, lint, and whitespace validation passed;
lint reported five pre-existing warnings.
- [ ] CI green (`static / quality`, `test / unit` on Node 20/22/24).
## Notes
The clean-base behavioral half of the reproduction remains unproved
because temporary worktree setup hung behind unrelated Git processes.
The PR makes no base execution claim for that half.
Refs [OSS-888](https://linear.app/copilotkit/issue/OSS-888).
## The failure
A correctly assembled v2 integration 404s on its first browser request
while every static check passes and `GET /info` returns 200.
`packages/react-core/src/v2/index.ts:28` re-exports the **v1-compat**
`CopilotKit` wrapper, so it is the provider most integrations reach for.
That wrapper pinned:
```tsx
useSingleEndpoint={props.useSingleEndpoint ?? true}
```
which overrode the core's `"auto"` negotiation and forced single-route
transport. But **every** v2 handler defaults to `mode: "multi-route"`
(`endpoints/hono.ts:95`; `createCopilotEndpoint` is an alias at `:90`).
Nothing serves the single-route envelope the client sends, so the
runtime 404s while the provider looks connected.
## What this is *not*
The library defaults do not actually disagree. `CopilotKitProvider` (the
real v2 provider) leaves the flag undefined → `"auto"`, which probes
`GET /info` and falls back to the single-route envelope
(`core/agent-registry.ts` `fetchRuntimeInfoAutoDetect`) — it works
against **either** handler mode. Only the compat wrapper defeated that.
So this is one line of override, not a defaults mismatch needing a
direction chosen.
## Why four onboarding runs hit it, not one
The library bug alone doesn't explain a 100% failure rate. The shipped
`react-core` skill does:
`packages/react-core/skills/react-core/references/provider-setup.md` —
bundled in the npm tarball (`files: ["dist","skills"]`) — **mandated**
the compat wrapper, **forbade** `CopilotKitProvider` as "a subset of the
functionality", and mentioned `useSingleEndpoint` **zero times** across
~10 code samples. An agent following it wrote the 404 configuration
every time.
Meanwhile `skills/copilotkit-setup/SKILL.md` got it right, so the two
shipped skills contradicted each other and nothing gated either against
the code.
## The change
**Commit 1 — the library fix.** The prop already arrives through
`v2Props`, so dropping the override lets it stay `undefined` and inherit
`"auto"`. An explicit `useSingleEndpoint` still wins in both directions.
**Commit 2 — the docs and skills.** Correcting the default made ~15
pages' explanations false. Code samples that pass `{false}` stay valid
(they pin what negotiation would find anyway), so this corrects the
*explanations* rather than the samples — keeping every page true both
before and after release. Includes dropping the now-false causal claim
from the single-route-envelope diagnostic added in #6579.
## Compatibility
Safe for existing v1 apps. A v1 app on a single-route-only handler
(`copilotRuntimeNextJSAppRouterEndpoint` and friends) now does one `GET
/info` that 404s, then falls back to single-route and works. Cost is one
extra request on connect.
One edge case worth a reviewer's eye: if a deployment's `runtimeUrl` +
`/info` returns 200 from something that is *not* a multi-route
CopilotKit runtime (a catch-all proxy serving HTML, say), `"auto"` would
resolve to `rest`. Setting `useSingleEndpoint` explicitly remains the
escape hatch.
Conventional-commit note: this lands as `fix`, but it *does* change a
public default. Flag if you'd rather it carried a minor bump.
## Tests
- New `copilotkit-transport-default.test.tsx` — omitted → `"auto"`,
`{true}` → `"single"`, `{false}` → `"rest"`. Confirmed RED first
(`expected 'single' to be 'auto'`).
- `CopilotChat.readinessGate.test.tsx` depended on the old default to
avoid a REST probe. Single-route transport is a **precondition of that
fixture**, not the behaviour under test, so it now pins the flag
explicitly and its stale comments are corrected. Its coverage (readiness
gate across the real SSE boundary) is unchanged.
- `react-core` 1512 passed · `runtime` 2073 passed · `core` 668 passed.
- `pnpm check:plugin-skills` in sync (`skills/react-core/` is the
generated mirror).
`showcase/shell-docs`'s own vitest suite fails to load 35 files with
`Cannot find package 'react/jsx-dev-runtime'` — reproduced identically
on unmodified `origin/main`, so it is environmental in this checkout and
unrelated. All 183 tests that do run pass.
## Not addressed here
Nothing gates a shipped skill against the code it documents, which is
why `provider-setup.md` could contradict both the library and the
sibling skill indefinitely. Worth its own ticket.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- add an independently runnable Claude Managed Agents finance-assistant
example
- add a cookbook recipe that explains the CopilotKit runtime,
managed-session mapping, and tool rendering flow
- add the recipe to cookbook navigation, the overview grid, sidebar icon
mapping, and render coverage
- use the real Claude vector mark for the cookbook instead of the
text-placeholder SDK asset
- register the example's Vite configuration and managed-agent model with
the repository CI allowlists
- include a compact architecture diagram and links to the relevant
rendering and CopilotKit Intelligence documentation
- disable Claude's complete built-in toolset and expose only the scoped
`show_growth_projection` runtime tool
- make the provisioning model configurable through `ANTHROPIC_MODEL`,
defaulting to `claude-fable-5`
- bound CopilotKit request bodies to 256 KB and managed-agent turns to
90 seconds, while relying on the adapter's per-thread serialization
- cap public run traffic at 20 provider-like attempts per client IP per
minute and 2,000 successful starts per process per 24-hour window
- restrict browser runtime requests with an exact Origin allowlist that
supports same-origin or separately hosted frontends, and restrict iframe
parents with CSP `frame-ancestors`
- validate persisted managed-agent IDs at startup so malformed local
configuration fails immediately
- publish the interactive example on Railway and embed the live
deployment in the cookbook
- align the demo with the existing cookbook chat styling and show the
`Project monthly investing` starter on first load
## Demo

## Why
This gives developers a focused example of connecting CopilotKit to
Anthropic Claude Managed Agents without the extra surface area of a
larger analyst application. The recipe follows the existing cookbook
structure and keeps the live demo compact enough for the standard
cookbook pane. Its managed environment has no outbound network or
package-manager access, and its agent cannot use bash, filesystem,
search, or fetch tools.
The request, turn, per-IP, and process-wide limits bound public demo
traffic without adding authentication or user friction. The traffic
counters are intentionally in memory, reset on process restart, and are
not shared across replicas, so the dedicated Anthropic workspace spend
limit remains the durable cost backstop. The exact-Origin browser check
reduces drive-by use but is explicitly documented as a control rather
than authentication. The model override allows operators to select a
lower-cost supported model during provisioning without editing source
code.
## Validation
- scoped formatting: passed
- scoped lint: 0 warnings, 0 errors
- shell-docs typecheck: passed
- standalone example typecheck: passed
- docs render tests: 26/26 passed
- standalone example tests: 23/23 passed
- shell-docs tests: 375/375 passed
- shell-docs production build: passed (222/222 pages)
- standalone example production build: passed
- standalone npm lockfile validation: passed
- build-config allowlist validator: passed
- docs model-name validator: passed
- exact-Origin regression coverage for run requests plus headerless
same-origin runtime discovery: passed
- malformed persisted agent-ID regression coverage: passed
- live Railway root and iframe CSP: passed
- live Railway runtime discovery, exact welcome copy, and first-load
starter pill: passed
- live three-turn AG-UI managed-agent run with `show_growth_projection`:
passed
- cookbook verified in the browser at desktop and narrow widths with no
console errors or horizontal overflow
## What does this PR do?
Closes the naming and documentation half of
[OSS-881](https://linear.app/copilotkit/issue/OSS-881). Paired with
CopilotKit/Intelligence#890, which adds `copilotkit verify` and tightens
the evaluation rubric.
### 1. One name for the Intelligence key
**Three** names for one value were live in CopilotKit's own
documentation, and following the wrong one with a CLI-provisioned
project yields an undefined key:
| Name | Where | Code readers |
| --- | --- | --- |
| `INTELLIGENCE_API_KEY` | what `copilotkit project select` writes; all
34 integration examples; the docs site | 34 |
| `COPILOTKIT_INTELLIGENCE_API_KEY` | 7 Channels package READMEs +
packaged skills | **0** |
| `COPILOTKIT_API_KEY` | `examples/slack`, `examples/teams`, and the
TSDoc on `CopilotKitIntelligence` itself | 2 |
`INTELLIGENCE_API_KEY` wins — it is the name the CLI provisions, and
changing it would break every scaffolded project in the wild.
- `COPILOTKIT_INTELLIGENCE_API_KEY` is **retired outright**. Nothing
ever read it, so there is nothing to keep compatible.
- `COPILOTKIT_API_KEY` stays **readable as a deprecated alias** in the
two examples that consume it, so an existing `.env` keeps working, and
is documented as deprecated everywhere it appears.
The third name was the worst placed: it was in the TSDoc on
`CopilotKitIntelligence`, which is what an IDE shows on hover.
This was not only untidy. The CLI's own `channels-preflight` accepts
`INTELLIGENCE_API_KEY` or `COPILOTKIT_API_KEY` — **not**
`COPILOTKIT_INTELLIGENCE_API_KEY`, the name the Channels READMEs told
people to set. So following a Channels README verbatim made `copilotkit
channels` warn that no runtime API key was present while the key sat
visibly in `.env`. After this PR the documented name is one preflight
accepts.
> [!NOTE]
> `NEXT_PUBLIC_COPILOTKIT_API_KEY` is a **different value** — the legacy
Copilot Cloud public key — and is deliberately left alone.
### 2. A real defect, not just naming skew
`skills/runtime/references/intelligence-mode.md` documented
`organizationId` as a `CopilotKitIntelligence` option, sourced from two
further env names (`COPILOTKIT_INTELLIGENCE_ORG_ID`,
`COPILOTKIT_ORG_ID`).
`CopilotKitIntelligenceConfig` has no such field — the copy-pasteable
sample it appeared in **would not compile**. Removed from the samples,
and the prose telling readers to fetch a value for it corrected. That
file is the only place those two names ever existed, which is very
likely why the failing validation run reported that "the runtime reads
`COPILOTKIT_INTELLIGENCE_API_KEY` and `COPILOTKIT_INTELLIGENCE_ORG_ID`".
### 3. Publish the Intelligence wiring
The wiring instructions existed only inside
`node_modules/@copilotkit/runtime/skills/`, and the only docs pages
mentioning `CopilotKitIntelligence` at all were the two Channels
frontends — so a developer on the plain web path had no page to reach it
from.
Adds **`/premium/connect-your-runtime`**: the wiring itself, how to
confirm the credential is actually consumed, the self-hosted
both-URLs-or-neither rule, and a troubleshooting table. Linked into both
navs, and the skills reference now points at the published page.
### 4. A guard so it cannot drift back
`scripts/validate-intelligence-env-names.ts` (`pnpm
check:intelligence-env-names`), wired to lefthook and a new workflow.
The workflow is **intentionally unfiltered**. The two workflows that
would otherwise cover this both filter: `plugin-skills-check` by
`paths:`, and `static/quality` by `paths-ignore: examples/**` — which is
exactly where the deprecated alias lives. Scoping the job would re-open
the hole it exists to close. Legitimate alias sites live in
`ALIAS_ALLOWLIST`.
## Related PRs and Issues
- [OSS-881](https://linear.app/copilotkit/issue/OSS-881) — needs
**both** PRs; neither closes it alone
- CopilotKit/Intelligence#890 — items 1 and 4 (`copilotkit verify` +
rubric contract 1.3.0)
## Verification
- Full lefthook pre-commit ran green: `check-plugin-skills`, `lint-fix`,
the new `check-intelligence-env-names`, and `test`/`publint`/`attw`
across **25 projects**.
- `examples/slack` `managed.test.ts` extended to cover **both** the
canonical name and the alias fallback, and proven non-vacuous — removing
the fallback turns the new test red.
- The drift guard proven non-vacuous the same way: reintroducing a
retired name fails it, exit 1.
- `oxfmt` and `oxlint` clean on every file touched (0 errors).
## 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
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The compat `<CopilotKit>` wrapper no longer pins `useSingleEndpoint` to `true`,
so every statement that it "defaults to single-route" or that a multi-route
backend "needs `{false}`" is now wrong. Code samples that pass `{false}`
explicitly stay valid — they pin what negotiation would find anyway — so this
corrects the explanations rather than the samples, keeping the pages true both
before and after the release.
The shipped `react-core` skill is the load-bearing one. `provider-setup.md`
mandated the wrapper, forbade `CopilotKitProvider` as "a subset of the
functionality", and never mentioned `useSingleEndpoint` across ~10 samples — so
an agent following it wrote the 404 configuration every time. It now documents
the transport and stops steering readers off the negotiating provider.
Also drops the false causal claim from the runtime's single-route-envelope
diagnostic (added in #6579), which named the wrapper's old default as the cause.
`skills/react-core/` is the generated mirror of `packages/react-core/skills/`,
synced with `pnpm sync:plugin-skills`.
Refs OSS-888.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The page told the reader to run `npx copilotkit verify` and said it "reports
whether the runtime is wired for Intelligence at all". Neither half holds yet:
`verify` is not in the published CLI — `latest` is 4.8.3 and the command landed
after that tag — and the Intelligence-consumption check it referred to is still
in review, so even on `main` the command does not report that.
Publishing it would have documented a seam that does not exist, which is the
class of defect this change set exists to remove.
The dashboard check works today and needs no CLI at all, so it becomes the
instruction: send a message and confirm a thread appears. A runtime in SSE mode
produces none, whatever the browser showed. The `verify` route can be documented
once the command ships with the check in it.
Closes
[OSS-882](https://linear.app/copilotkit/issue/OSS-882/add-to-existing-journeys-reach-for-the-v1-compat-copilotkit-wrapper).
## The failure
The v1-compatible `<CopilotKit>` provider pins `useSingleEndpoint` to
`true`
([`copilotkit.tsx:108`](https://github.com/CopilotKit/CopilotKit/blob/main/packages/react-core/src/components/copilot-provider/copilotkit.tsx#L108)),
so its startup handshake POSTs `{ method: "info" }` at the base path. A
multi-route runtime — the default — matches no route for that path and
answered a bare `{"error":"Not found"}`, indistinguishable from a wrong
`basePath` or an unmounted handler.
Two independent onboarding validation runs hit this on their first
browser attempt and each had to guess the cause. Both were
*add-to-existing-app* journeys; the greenfield one reached for
`CopilotKitProvider` and never saw it.
## What changed
**The runtime says what happened.** `detectSingleRouteEnvelope`
recognises a POST whose JSON body carries a `method` the single-route
endpoint accepts, and the multi-route handler uses it at the one point
routing gives up. The 404 now carries a `code` and a message naming the
prop, plus a `logger.warn` so it lands in the dev-server terminal too.
Deliberately conservative — wrong verb, non-JSON, unknown method, or a
JSON POST that isn't an envelope all stay ordinary 404s, unchanged in
status and shape.
**The client stops discarding it.** All four `/info` callers (two in
`agent-registry.ts`, two in `agent.ts`) threw away the response body and
reported only the status, so a server-side diagnosis reached nobody.
They now go through `runtimeInfoError`, which folds a string `message`
from the body into the thrown error. Any future server-side diagnosis
reaches the developer for free.
**Docs.** Five pages paired a v2 multi-route handler with `<CopilotKit>`
and never mentioned the prop. Rather than a warning under a snippet that
is still wrong to copy, the snippets themselves now pass
`useSingleEndpoint={false}`, with a short callout linking to the
provider/handler mapping.
Two pages were deliberately left alone: `backend/runtime-endpoints.mdx`
already documents the pairing in full, and `cookbook/arcade.mdx` uses
`mode: "single-route"` on purpose and already explains it.
`backend/copilot-runtime.mdx` keeps its snippet as-is — it pairs with
the v1 endpoint, where the default is correct — and gains the caveat
only on its "switch to v2 handlers" note.
Option 3 in the issue (reconsidering the compat default) is **not** in
this PR.
## Testing
### Both halves connect, end to end
Real `createCopilotRuntimeHandler` + real `CopilotKitCore` configured
the way the v1 wrapper configures it — no mocks on either side:
```
code : runtime_info_fetch_failed
message: Runtime info request failed with status 404: Received a single-route
request envelope ({ method: "..." }) but this runtime is mounted in
multi-route mode, so the request matched no route. If the frontend uses
<CopilotKit> from @copilotkit/react-core/v2, pass useSingleEndpoint={false}
— that provider defaults it to true. Otherwise mount the runtime with
mode: "single-route" to serve this envelope.
PASS — the diagnostic reached the client
```
The server-side `logger.warn` fired in the same run, carrying `{ url,
path, method: 'info' }`.
### Unit tests
`packages/runtime` — `single-route-envelope-diagnostic.test.ts` (2
positive, 5 control):
```
✓ src/v2/runtime/__tests__/single-route-envelope-diagnostic.test.ts (7 tests) 26ms
Tests 7 passed (7)
```
`packages/core` — `runtime-info-error-detail.test.ts` (2 positive, 5
control):
```
✓ src/__tests__/runtime-info-error-detail.test.ts (7 tests) 267ms
Tests 7 passed (7)
```
### Mutation checks
Every new test was verified to fail when its mechanism is broken, in
both directions.
Detector forced to `return null` — the two positives die, the four
controls hold:
```
× names useSingleEndpoint when the envelope is an info call
× diagnoses every method the single-route envelope accepts
✓ leaves an ordinary unmatched route as a plain 404
✓ leaves a JSON POST that is not an envelope as a plain 404
✓ leaves an unrecognized method name as a plain 404
✓ does not diagnose a non-JSON POST
```
Detector forced to `return "info"` — the controls die instead, proving
they are not vacuous:
```
✓ names useSingleEndpoint when the envelope is an info call
✓ diagnoses every method the single-route envelope accepts
× leaves an ordinary unmatched route as a plain 404
× leaves a JSON POST that is not an envelope as a plain 404
× leaves an unrecognized method name as a plain 404
× does not diagnose a non-JSON POST
```
`runtimeInfoError` with the detail dropped, then with the `typeof
message === "string"` guard removed — each kills a different pair:
```
mutation: detail dropped → 2 failed | 5 passed
mutation: accept any message field → 2 failed | 5 passed
restored → 7 passed
```
### Full suites, builds, docs
| Check | Result |
|---|---|
| `packages/core` full suite | `Test Files 60 passed (60)` / `Tests 662
passed (662)` |
| `packages/runtime` full suite | `Test Files 142 passed (142)` / `Tests
2067 passed (2067)` |
| `packages/core` `tsc --noEmit` | clean |
| `packages/runtime` `tsdown` | `416 files` — build complete |
| MDX compile, 5 edited pages | all `OK` |
| pre-commit `nx run-many -t test,publint,attw` | passed across affected
projects |
| CI on `f94d1ab0` | 72 pass, 3 skipping, 0 fail |
Both suites are fully green. An earlier revision of this description
reported 6
runtime failures as pre-existing on `main`; they were not. They were
artifacts
of a worktree whose `node_modules` had been assembled by hand, and a
proper
`pnpm install` cleared all of them along with the inspector-metadata
failures
from a stale `@copilotkit/shared` dist. `main` is clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Two pages document both transport modes and carry a single "point your
frontend at it" snippet serving every front door on the page. Baking
`useSingleEndpoint={false}` into those snippets traded one silent mismatch for
its mirror image: correct for the multi-route majority, wrong for anyone who
followed the `mode: "single-route"` example.
Both now state the rule conditionally next to the snippet instead of asserting
one side of it. Pages with a single handler mode (auth, custom-agent) are
unambiguous and keep the prop inline.
Also pins the one path where the diagnostic could have cost more than it gives:
`clone()` throws once a before-request middleware has drained the body, so the
detector must return null and let the plain 404 stand rather than surfacing a
500. The guard existed; nothing held it in place.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>