## Why
An Intelligence integration lost a request-to-row correlation map
partway through a user interaction — no error, no warning. It surfaced
as "our response routing is flaky". OSS-979 filed it as
`CopilotKitProvider` remounting its children.
The provider does nothing of the kind. It renders `{children}`
unconditionally at `CopilotKitProvider.tsx:952` — unkeyed, no early
return, and there is no `Suspense` boundary anywhere in `v2`. Nothing in
the SDK silently re-points the active thread either; every mutation path
(`setActiveThreadId`, `startNewThread`, the drawer row click, the
inspector override) is caller-driven.
The remount was app-side, and it was app-side because this skill told it
to be:
- `references/threads.md:98` teaches `useThreads()` → select →
`<CopilotChat key={activeId}>`, and that recipe is only reachable once
Intelligence is wired.
- `references/switching-agents.md:123` teaches "`key={activeAgent}`
forces remount so thread state doesn't leak" without saying what else
that discards.
- `examples/showcases/reskinnable-demo/src/app/[skin]/layout.tsx:223`
models `<SubagentActivityProvider key={threadId}>` above `{children}`,
commented "Remounting is deliberate".
Follow all three and you key a layout-level provider on a thread id that
changes asynchronously after mount. Everything below it dies
mid-interaction.
Two properties made it invisible:
- Durable threads exist only in Intelligence mode, so with a plain SSE
runtime `useThreads` returns nothing, the selected thread never changes,
and the remount never fires. It appears the moment Intelligence is
wired.
- Whether state survives depends on whether the user acted before the
thread list resolved.
## What changed
Docs only — no library change. Both traps now carry their blast radius,
in the four places an agent actually reads:
| File | Change |
|---|---|
| `SKILL.md` | Two invariants in the load-once section, so they land
before any reference is opened |
| `references/threads.md` | New HIGH entry on keying above app state;
note that `activeId` in the switcher recipe settles asynchronously |
| `references/switching-agents.md` | Existing HIGH entry now states the
blast radius and cross-links the threads trap |
| `references/switching-agents-recipes.md` | Key rule amended — keep it
on `<CopilotChat>`, nowhere higher |
| `references/agent-access.md` | The second route to the same symptom:
`useAgent` swaps a provisional stand-in for the real agent when `/info`
resolves, so an effect keyed on `agent` re-runs once, mid-interaction.
Adds an `isReady` pattern and a HIGH entry |
`isReady` appeared in **zero** shipped skills before this — it was
documented only in `showcase/shell-docs/.../useAgent.mdx` and in JSDoc.
Same shape as OSS-888, where the root cause was the shipped skill rather
than the library.
Also corrects a factual error: the skill claimed `useAgent` returns `{
agent }` only. It returns `{ agent, isReady }`.
The 10-file diff is 5 source files under `packages/react-core/skills/`
plus their 5 mirrors under `skills/`, regenerated with `pnpm
sync:plugin-skills`.
## Verification
- `pnpm check:plugin-skills` — mirror in sync
- `pnpm exec vitest run scripts/__tests__/sync-plugin-skills.test.ts` —
12 passed
- `oxfmt --check` — clean over both skill trees
- Full pre-commit suite green, including `test-and-check-packages`
(`test`, `publint`, `attw` across 2 projects and 20 dependent tasks)
## Not in scope
Whether the run's app keyed on `threadId` or on `agent` is not
settleable from the repo — its source is not in any checkout, and there
is no `2026-08-25` strands run report under
`tools/one-prompt-development/evaluation/runs` on any branch. Both
variants produce the reported symptom and this covers both, so a
first-hand repro is a separate task. The `reskinnable-demo` layout is
left as-is deliberately: it is a legitimate use of the pattern, and it
is now the worked example the guidance warns about.
Scoping detail in the OSS-979 comment.
refs OSS-979
🤖 Generated with [Claude Code](https://claude.com/claude-code)
An Intelligence integration lost a request-to-row correlation map partway
through a user interaction, with no error and no warning. It surfaced as
"our response routing is flaky". OSS-979 filed it as CopilotKitProvider
remounting its children.
The provider does nothing of the kind. It renders `{children}`
unconditionally, unkeyed, with no early return and no Suspense boundary
anywhere in v2. The remount was app-side, and it was app-side because this
skill told it to be:
* `references/threads.md` teaches `useThreads()` -> select ->
`<CopilotChat key={activeId}>`, and that recipe is only reachable once
Intelligence is wired.
* `references/switching-agents.md` teaches "`key={activeAgent}` forces
remount so thread state doesn't leak" without saying what else that
discards.
* `examples/showcases/reskinnable-demo/src/app/[skin]/layout.tsx:223`
models `<SubagentActivityProvider key={threadId}>` above `{children}`,
commented "Remounting is deliberate".
Follow all three and you key a layout-level provider on a thread id that
changes asynchronously after mount. Everything below it dies
mid-interaction.
Two properties made it invisible. Durable threads exist only in
Intelligence mode, so in OSS-only development the selected thread never
changes and the remount never fires. And whether state survives depends on
whether the user acted before the thread list resolved.
Both traps now carry their blast radius, in the four places an agent
actually reads:
* `SKILL.md` -- two invariants in the load-once section, so they land
before any reference is opened.
* `references/threads.md` -- a HIGH entry on keying above app state, plus a
note that `activeId` in the switcher recipe settles asynchronously.
* `references/switching-agents.md` and `switching-agents-recipes.md` --
keep the `key` on `<CopilotChat>`, never on a wrapper or a layout
provider.
* `references/agent-access.md` -- the second route to the same symptom.
`useAgent` swaps a provisional stand-in for the real agent when `/info`
resolves, so an effect keyed on `agent` re-runs once, mid-interaction.
Adds an `isReady` pattern and a HIGH entry. `isReady` appeared in zero
shipped skills before this; it was documented only in shell-docs and in
JSDoc.
Also corrects a factual error: the skill claimed `useAgent` returns
`{ agent }` only. It returns `{ agent, isReady }`.
No library change. The provider behaves correctly; the guidance did not
describe what it costs.
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
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.
- Raw recipe: the Events JSON input now calls requestUpdate, so Run and
Save stop being permanently disabled.
- Tool args recovery: one depth scan replaces the parse-every-prefix loop.
Truncated args from a streaming tool call now fail at once, not after
seconds of blocked main thread.
- Chat bookmark: hidden while the tool arguments are incomplete, so a
partial payload cannot be captured.
- saveEventSnippet: React, Vue, and Angular wrap the body, so a compile or
storage failure is reported instead of becoming an unhandled rejection.
- Vue and Angular now gate the in-chat affordances on a dev build plus
localhost, the same as React. showDevConsole: true on a staging URL no
longer puts a bookmark into a production chat.
## 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)
## 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>