Commit Graph

15971 Commits

Author SHA1 Message Date
David McKay be12b0b198 docs(intelligence): correct the memory-vector access rule
Three review findings, all valid.

The secret-column callout claimed memory vectors are 'withheld at the
database grant, so no combination of scopes returns them', and the exports
section says an export returns them with memory:content. Both cannot be
true, and the callout was the wrong one: the embedding is not in the
model's neverProject list and migration 039 withholds columns only on
api_keys, query_api_keys, organization_oidc_connections,
managed_intelligence_sessions and channel_adapter_credentials.

That mattered beyond tidiness. It told a customer their vectors were
unreachable when an export is the documented way to take them, which is the
opposite of the point of exporting them at all. The callout now separates
credentials, which really are unreachable, from the vector, which is the
customer's own data withheld inline and available on export.

Also: 'Both have to allow the read' followed a list of three scope
families, so it named the scope and the licence without saying so. And the
success and error envelopes key their correlation ids differently,
meta.request_id versus a top-level requestId, which a client logging ids
for every response needs to know.
2026-09-08 12:54:34 -07:00
David McKay 0d34392510 docs(intelligence): document the full MCP tool set
Lists all nine tools rather than the original four, and explains that
memory recall searches by meaning across every user in the project, since
the key is an organization credential that already lists those same rows.
2026-09-06 08:34:05 -07:00
David McKay 30329ec0bd docs(intelligence): document expanding related rows
Adds expand to the parameter table and a section covering the shape rules,
that an empty result is an empty array rather than an absent key, and that
each side is fetched separately so the expanded resource is gated by its own
scopes.
2026-09-05 21:54:57 -07:00
David McKay 51801dcd55 docs(intelligence): document how to get a key
The page explained how to use a key and never how to obtain one, which made
the first step of every workflow the undocumented one.

Adds the CLI commands, the fact that the token is shown once and is not
recoverable, and that omitting --scopes gives every scope.
2026-09-05 21:41:41 -07:00
David McKay eb5f7f1ed2 docs(intelligence): document skill sections and usage
Adds the two learning resources that now carry data: skills split into
heading-path sections at publish time, and a record of which skill revision
reached an agent in which thread.

States the instrumentation caveat plainly: a zero-usage answer for a period
before the instrumentation existed is indistinguishable from a skill nobody
used, so the earliest occurred_at is worth checking before concluding a
skill was never loaded.
2026-09-05 21:08:34 -07:00
David McKay 19f44c0473 docs(intelligence): document exports and SQL scope enforcement
Adds the exports section: the three formats, the job lifecycle, the quota,
and why the memory vector is available there and nowhere else.

Also states that scopes apply on the SQL surface, which they now do:
a statement selecting a gated column with a key that lacks its scope is
refused before it runs, whether the column is named directly, reached
through SELECT *, used in a WHERE clause, or read inside a CTE.
2026-09-05 20:16:00 -07:00
David McKay 0b1b07ac64 docs(intelligence): document the query time window
Adds start and end to the list parameters, and states that a parameter the
API does not implement is refused by name rather than accepted and ignored,
so a request that returns rows is a request that did what was asked.
2026-09-05 16:33:32 -07:00
David McKay 417aa15cae docs(intelligence): document the Query API
Explains how to read every piece of your own Intelligence data from a
script, a notebook, or an agent, without a browser session: the resource
catalog, the scope model and what :read and :content each unlock, list and
filter syntax, keyset paging, declarative aggregation, arbitrary read-only
SQL with frozen-result paging, and the four MCP tools.

States the things that are easy to get wrong and expensive to discover
late: that a measure's filter scopes to that measure alone rather than
narrowing the whole query, that the organization is never a parameter you
can pass so a SQL statement with no WHERE clause still reads one tenant,
that a field omitted for scope is named in the response while a field named
in `fields` that does not exist is an error, and that secret columns are
unreachable at any scope.

Every route, parameter, operator, aggregate, error code and header on this
page was exercised against a running deployment rather than read out of the
source.
2026-09-05 16:25:00 -07:00
Tyler Slaton 25ba706399 Make docs search trustworthy and surface Intelligence for capability searches (#6887)
Closes OSS-1079.

Docs search was not trustworthy. Showcase rows competed with docs rows
and some of them were dead links, abandoned pages answered as
confidently as maintained ones, and the result order fell back on
whatever order the index happened to be built in. On top of that, a
reader who types the word for a capability — "analytics", "learning",
"persistence" — had no way to learn that the capability is called
Intelligence.

Three changes, plus a PRD at
`prds/oss-1079-docs-search-and-intelligence-ctas.md` that records the
decisions and the measurements behind them.

## Showcase rows leave the docs search

The modal loaded the showcase registry and pushed integration and
feature rows into the result list. Every feature row was emitted with
`href: "/"`, so a query like "chat" produced fifteen differently-titled
rows that all navigated to the docs home page ("tools" six, "state"
five). Both loops are gone. The registry is still loaded — the framework
scope picker is built from it.

The generator now writes a different payload per target: the showcase
home, the integrations explorer and the feature matrix stay in the index
the showcase app consumes and leave the one the docs app consumes. Two
hand-written entries that duplicated real pages ("Home", "API
Reference") are removed outright.

## The index follows what a reader can actually reach

The docs portion of the index was a walk over every `.mdx` file on disk.
It now derives from navigation: a page is indexed when it appears in a
navigation surface, or when a page that appears in one links to it.

Navigation is not one tree. The union covers the root tree, one surface
per non-hidden integration — using the same builder the app picks for
that integration's `docs_mode` — and the sixteen `"root": true`
sub-trees the root walk deliberately skips. Group nodes contribute their
own slug, because a folder with an index page renders as an expandable
parent. Entries whose destination is off-site contribute nothing, so no
result promises a docs page that does not exist. Channel pages bypass
the filter entirely; they are re-routed onto the Slack and Teams
surfaces at runtime and filtering them against the docs navigation would
delete live, linked pages.

A page's inlined snippets count as part of that page. Many pages here
are thin wrappers around shared snippets — the Intelligence overview's
whole body is one include — so a scan that reads only the page file sees
almost nothing: 868 link targets before resolving includes, 1964 after.
Resolution reuses the docs renderer's own inlining rather than a second
resolver.

`search: false` forces a reachable page out and `search: true` forces an
unreachable one in. As shipped no page needs either, and a test asserts
the forced-in set is empty so reaching for the override stays a
deliberate act.

Route-group segments are stripped from destinations, so results no
longer take a redirect hop. Titles come from navigation where the two
disagree, with guards so auto-derived group titles and `nav_title:
Overview` do not leak into a flat result list. A coverage floor fails
the build if the docs portion collapses.

## Order is deterministic, and Intelligence keywords get one
recommendation

The old scoring rewarded a query that matched the *start* of a title,
which is why "threads" put the threads-drawer component above the
canonical Threads guide. That slot is now a whole-word test at the same
weight, and everything still tied is settled by shorter-title-first and
then alphabetically. Nothing depends on index construction order any
more. No content family gets a bonus — deliberately, including
Intelligence.

A curated keyword table drives a single recommendation block above the
result list. Five entries today: threads, self-hosting, learning,
analytics, and intelligence as the catch-all. Triggering is whole-word,
or a typed prefix of at least four characters, never a plain substring.
Specificity is declared, so "intelligence threads" resolves to the
threads entry, and exactly one block ever renders. Every destination is
an internal docs route.

`learning` and `analytics` point at the Intelligence overview because no
docs page describes either capability yet — they are rows on that
overview which link out for the detail. The overview is also the right
landing for someone already running Intelligence, for whom a
connect-in-five-minutes quickstart would be useless. Retargeting when
those pages ship is a one-line edit.

The block reuses the in-page Intelligence CTA visual language (accent
stripe, kite, theme tokens), is a labelled group rather than a
fourteenth listbox option, participates in the existing arrow-key
selection, and reports its surface and matched keyword through the same
attribution helpers the other docs CTAs use.

## Numbers

| | before | after |
|---|---|---|
| docs-search index entries | 950 | 851 |
| of which docs pages | 678 | 583 |
| destinations with more than one entry | 2 | 0 |
| destinations taking a redirect hop | 36 | 0 |

Of the 583 docs entries, 637 slugs come from navigation, 9 more from an
inbound prose link, and 94 entries left search as unreachable.

## Follow-ups this PR deliberately does not take

Two groups inside those 94 are substantive content, not leftovers, and
both want a content decision rather than a search fix. The two
step-by-step tutorial series (24 entries) form a closed link island: no
navigation lists them and nothing reachable links in, so even unlimited
transitive reachability would not find them. And 28 LangGraph pages
under `advanced`, `troubleshooting` and `your-components` have zero
inbound links anywhere, because the LangGraph navigation file references
neither subtree. Adopt, redirect or delete — each is its own call.

Also untouched: content work on the What's New pages (the roll-up page
leaves search and stays on disk), the near-duplicate search modal in the
showcase app, the sitemap, and the matching engine itself.

## Verification

`npm test` 783 passing in `showcase/shell-docs`. Six failures remain and
are pre-existing — verified by running the same files against a clean
checkout of `origin/main`, where they fail identically: three
`public-assets` PNG checks against unmaterialized LFS pointers, two
`angular-docs-content` content checks, one `llm-text` mastra example.
Typecheck clean, lint clean, production build green.

Checked in the browser against a local dev server: "threads" now leads
with the Threads guide, "intelligence" leads with the Intelligence
landing page, "chat" returns only real docs destinations, "learning"
shows the recommendation, and the console is clean.

---

# Follow-up round, from testing the branch in a browser

Seven further changes after the first pass was tried by hand.

## The AG-UI "What's New" page is unlinked from search and nav

`/ag-ui/development/updates` is titled "What's New", holds a single
entry dated April 2025, and throws on render because it uses an
`<Update>` component this app does not provide — a Mintlify component
from the upstream AG-UI docs. It is almost certainly the page the
ticket's second complaint is about.

Our reachability rule did not catch it: the AG-UI section keeps its own
hand-maintained published-slug list, which this PR deliberately does not
reinterpret, and the page is listed in the AG-UI sidebar. So it is
removed from both by hand, with a test and a floor assertion so a typo
in that hand-maintained list cannot silently empty the AG-UI portion of
the index.

The MDX itself is untouched. AG-UI docs are canonical upstream in
`ag-ui-protocol/ag-ui` and this tree is a downstream mirror, so the page
is unlinked here rather than edited.

### Open question for reviewers: should the AG-UI mirror be in these
docs at all?

While tracking that page down, the mirror turned out to be an orphaned
island:

- The site chrome has Docs, Reference and Cookbook. There is no AG-UI
entry, in the desktop nav, the mobile nav or the footer.
- Nothing outside `/ag-ui/*` links into it. The only inbound links come
from the section's own pages.
- Where our prose does reference AG-UI it uses `/ag-ui-protocol`, which
redirects to `/agentic-protocols/ag-ui` in the main docs — not into the
mirror. Ten other places link straight out to `docs.ag-ui.com`.
- `docs.ag-ui.com` is live and canonical, and the mirror is still being
synced (last touched three days ago).

So 96 pages are maintained, served, and unreachable by anyone reading
the docs, while search offers 42 of them. By the rule this PR
introduces, the whole island fails the reachability test; it survives
only because AG-UI is exempted.

Three ways forward, none taken here: keep it and give it a nav entry,
which makes it legitimate in one move; drop the whole mirror from search
while leaving the pages served; or retire the mirror and redirect
`/ag-ui/*` to `docs.ag-ui.com`. The last is the real cleanup but has SEO
consequences and spans two repos. Deliberately left as a product
decision rather than folded into a search PR.

## Ranking: the reader's own frontend first, V1 last

Searching "chat" returned 78 matches, roughly 38 of them belonging to
frontends the reader is not using — 13 Angular feature pages, 10 Vue, 9
Angular reference, 6 React Native — plus 5 from the deprecated V1
reference. A React reader got a screen of Angular.

Entries carrying another frontend are now demoted, never filtered:
someone who wants Angular from a React page still finds it by typing
"angular chat", and because both words then match, those rows come
straight back to the top. Filtering would have hidden them outright,
which is the failure this deliberately avoids. The penalty is waived as
soon as the query names the frontend.

The deprecated V1 reference always sorts last, as a separate tier rather
than a weight another bonus could out-argue, and those rows now carry a
muted "Deprecated" tag.

## Matching survives punctuation and camelCase

`whats new` found nothing though the announcement pages exist, and `use
Copilot kit` found nothing though `useCopilotKit` does. Punctuation —
apostrophes, hyphens, dots, slashes — is now ignored on both sides of
the comparison, and camelCase identifiers are split into words on the
index side, so `use Copilot kit` reaches `useCopilotKit` and `ag ui`
reaches `AG-UI`. Both forms feed the title tiers of the score as well,
otherwise the page matches but never ranks. The haystack keeps the
unsplit form too, so `copilotruntime` still finds `CopilotRuntime`.

The CTA keyword matcher is untouched: it stays
whole-word-or-four-character-prefix, so loosening the result matching
cannot make the recommendation block fire on unrelated queries.

## Keyboard, mouse and the recommendation block

- Arrowing past the sixth result used to move the selection out of sight
— the list has a fixed height and nothing ever scrolled it. It now
follows the keyboard, minimally, and only for keyboard moves: hover
still selects but must not slide the list out from under the pointer.
The selection stays on the last item rather than wrapping.
- The arrow icon at the end of a row lit up one row too low whenever the
recommendation block was visible; the row background accounted for the
block's selection slot and the icon did not.
- The whole recommendation block is clickable now, not just its primary
link, via a card-link overlay so the two or three secondary links keep
their own destinations. Nested anchors would have been invalid markup;
the cost is that text inside the block is no longer selectable.
- Buttons in the modal — result rows, framework picker, close, CTA links
— get a pointer cursor back, which Tailwind 4 dropped.

## Verification of this round

Browser-checked on a local dev server: keyboard scrolling follows
selection while hover does not scroll, selection clamps at the last row,
the arrow accent tracks the selected row, a click on the block's body
lands on the Threads guide while a click on "Connect Intelligence" lands
on the Intelligence quickstart, the V1 row sorts last with its tag,
`what's new` and `whats new` both return the announcement pages, `use
Copilot kit` surfaces `useCopilotKit`, "chat" is free of
foreign-frontend rows and "angular chat" brings them back.

`npm test` 806 passing with the same 6 pre-existing failures. Lint and
typecheck clean.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved documentation search relevance with predictable ranking,
frontend-aware results, and better keyboard navigation.
* Added curated Intelligence recommendations with accessible links and
conversion tracking.
* **Bug Fixes**
* Excluded broken, outdated, duplicate, and incorrect documentation
links from results.
* Improved handling of punctuation, camelCase terms, redirects, and
canonical URLs.
* Removed showcase destinations and the unlinked AG-UI “What’s New” page
from docs search.
* **Documentation**
  * Updated navigation and search coverage for AG-UI documentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-05 03:12:47 +02:00
Tyler Slaton 9173ab479c fix(docs): address search accessibility and indexing review findings
Announce recommendation selection without invalid active descendants, omit
missing controlled elements, and cover empty-result and result-slot behavior.
Report snippet expansion failures and reject partially staged content roots
before either search index is overwritten.

Validation: 829 tests pass; three Angular/Mastra content failures already
reported in PR #6887 remain. Typecheck and lint pass (existing lint warnings).
Browser-verified local search, keyboard selection, and recommendation navigation.
2026-09-05 03:05:49 +02:00
Lukas Moschitz 45ac1b482b feat(docs): improve search ranking and recommend Intelligence guides 2026-09-05 03:05:49 +02:00
Lukas Moschitz c1086fe5fa fix(docs): index reachable pages across docs build contexts 2026-09-05 03:05:49 +02:00
Tyler Slaton d20f55ca88 feat(inspector): add Learning view (#6875)
## Summary

This PR adds Learning to Web Inspector.

Learning guides users from setup to Skills and Insights from their
Threads.

## User flows

### Start Learning

1. The user opens Learning in Inspector.
2. The user copies the setup prompt and gives it to the coding agent.
3. Inspector shows progress while it waits for Threads.
4. Inspector shows a link to the web app when Threads are ready for
analysis.
5. A setup error links the user back to the setup prompt.

### Review Skills and Insights

1. Inspector shows Skills first because Skills are the main result of
Learning.
2. Each Skill shows its description and full `SKILL.md`.
3. An Insight that supports a Skill appears inside that Skill.
4. Other Insights appear below the Skills.
5. Insights remain available when Learning has not created a Skill.
6. Separate page controls let the user browse Skills and Insights.

### Analyze new Threads

1. Inspector shows when new Threads are ready for analysis.
2. Existing Skills and Insights remain visible.
3. The user opens the web app to analyze the new Threads.

### Review candidate Skills

1. Inspector shows the number of candidate Skills.
2. The user opens the web app to review the candidates.

### Inspect supporting evidence

1. Each Insight shows the number of supporting Threads.
2. The user opens the evidence to review the related Thread and message.
3. Inspector shows unavailable evidence without information from the
removed Thread.

### Recover from incomplete states

1. Inspector shows clear states for loading, unsupported Runtime
versions, missing selections, data errors, and empty results.
2. Existing results remain visible when a refresh error occurs.
3. Retryable errors give the user a clear next action.

## Related PR

The Intelligence data source is in
[CopilotKit/Intelligence#1139](https://github.com/CopilotKit/Intelligence/pull/1139).

## Screenshots

### Start Learning

#### Learning page

![Learning page in Web
Inspector](https://github.com/user-attachments/assets/ae128a6a-b012-402f-bab7-07d7d0bcc5f5)

#### Setup prompt

![Learning setup prompt in Web
Inspector](https://github.com/user-attachments/assets/992addcd-32e8-4cda-882f-8035f7e96106)

#### Setup prompt copy error

![Setup prompt copy error in Web
Inspector](https://github.com/user-attachments/assets/a8314e81-ed59-41c9-9453-6a7edb9fbc8d)

#### Waiting for the first Thread

![Learning waits for the first Thread in Web
Inspector](https://github.com/user-attachments/assets/8e05c844-e894-4a83-9494-05bf2fae3c78)

#### Threads ready for analysis

![Threads ready for analysis in Web
Inspector](https://github.com/user-attachments/assets/4925928e-88fb-4368-8402-11ac11208b44)

#### First analysis in progress

![First Learning analysis in progress in Web
Inspector](https://github.com/user-attachments/assets/487c5959-aec4-4479-9c03-f869ed453470)

#### Setup error

![Learning setup error in Web
Inspector](https://github.com/user-attachments/assets/fe4098b2-e65d-4440-a1c6-1302b340bd54)

### Review Learning results

#### Skills and Insights

![Skills and Insights in Web
Inspector](https://github.com/user-attachments/assets/f6174d8f-e795-4fa1-a89f-abee211240c6)

#### Insights before the first Skill

![Insights before the first Skill in Web
Inspector](https://github.com/user-attachments/assets/79f05d13-be71-4dec-837c-1c0dbdd20b9f)

#### Multiple Skills

![Multiple Skills in Web
Inspector](https://github.com/user-attachments/assets/ed16a8a3-c1f4-43a5-aa99-0631208c10f4)

#### New Threads with existing results

![New Threads with existing Learning results in Web
Inspector](https://github.com/user-attachments/assets/3604ca04-2464-407e-97a0-481605b2a32d)

#### Candidate Skills

![Candidate Skills in Web
Inspector](https://github.com/user-attachments/assets/dfa81e63-255b-4652-8515-53a9e91aaa30)

#### No new results

![No new Learning results in Web
Inspector](https://github.com/user-attachments/assets/67195d73-f353-485a-b3ca-1ca6b81b8b74)

### Inspect supporting evidence

#### Evidence details

![Supporting evidence details in Web
Inspector](https://github.com/user-attachments/assets/522d98f4-547c-4407-8b20-a5791da093f5)

#### Evidence unavailable

![Unavailable supporting evidence in Web
Inspector](https://github.com/user-attachments/assets/27717c36-dcc0-4429-8ee2-92d0c7097cb6)

### System and recovery states

#### Unsupported Runtime

![Unsupported Runtime state in Web
Inspector](https://github.com/user-attachments/assets/2f8370b6-9208-42f7-a83e-70520328f2dc)

#### Loading

![Learning loading state in Web
Inspector](https://github.com/user-attachments/assets/8c91d840-1971-4dfc-a647-d4b57e9f9d66)

#### Data error

![Learning data error in Web
Inspector](https://github.com/user-attachments/assets/9bf74b30-8c1c-4ea5-b5aa-9ae06837f21a)

#### Agent selection required

![Agent selection required in Web
Inspector](https://github.com/user-attachments/assets/5e7ab17d-4580-402c-814b-dcae4afe605e)

#### Results refresh error

![Learning results refresh error in Web
Inspector](https://github.com/user-attachments/assets/ae3aae29-6503-484b-addb-005b84aa394c)

### Narrow layout

#### Waiting for the first Thread

![Learning waits for the first Thread in the narrow
layout](https://github.com/user-attachments/assets/c0b4b086-fbe5-47d5-866c-fb7ea8db14c8)

#### Threads ready for analysis

![Threads ready for analysis in the narrow
layout](https://github.com/user-attachments/assets/8b7b12db-9864-46f8-8ed2-49ca299e7d55)

#### Skills and Insights

![Skills and Insights in the narrow
layout](https://github.com/user-attachments/assets/fd385ed4-42ed-494d-9543-f0209a86845a)

#### Insights before the first Skill

![Insights before the first Skill in the narrow
layout](https://github.com/user-attachments/assets/dd5929d8-4fa5-45d1-acba-a4f2e6387357)

#### Multiple Skills

![Multiple Skills in the narrow
layout](https://github.com/user-attachments/assets/13dd3c3a-95eb-491d-afcb-fdd72c9aab38)

#### New Threads with existing results

![New Threads with existing Learning results in the narrow
layout](https://github.com/user-attachments/assets/aab292c4-6feb-46df-9740-f6fb4dfd3189)

#### No new results

![No new Learning results in the narrow
layout](https://github.com/user-attachments/assets/87b43562-8d55-49e2-8130-38ac015d5e86)

#### Setup error

![Learning setup error in the narrow
layout](https://github.com/user-attachments/assets/a7a6ea51-22c5-4e22-99f3-3c681db0aef0)

## Verification

All current GitHub checks pass.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a Learning pane to the Web Inspector for published Skills,
supporting Insights, and related Thread evidence.
* Added setup guidance, progress tracking, loading and error states,
evidence navigation, skill expansion, Intelligence web app links, and
independent pagination.
* Learning availability is negotiated with eligible debug-enabled
runtimes across supported transports, with setup progress preserved
across reloads.
  * Added optional Inspector Learning support for runtime integrations.

* **Documentation**
* Updated Inspector documentation to describe Learning content and
workflows.

* **Tests**
* Added coverage for Learning states, pagination, setup flows,
validation, persistence, and browser behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-05 02:44:02 +02:00
Martha Kelly Schumann 1fdca1dc9e fix(inspector): harden Learning review flows 2026-09-04 17:30:44 -07:00
Martha Kelly Schumann cfc4fd8e26 fix(inspector): refine Learning onboarding flow 2026-09-04 17:12:34 -07:00
Martha Kelly Schumann c70502b137 feat(inspector): add Learning view and workbench 2026-09-04 17:11:59 -07:00
Martha Kelly Schumann 05fc4e05a4 feat(runtime): expose Learning snapshots to Inspector 2026-09-04 17:11:42 -07:00
Ben Taylor 428fcbd60d fix(core): send the whole RunAgentInput in the Intelligence run body (#6890)
Fixes OSS-1132

## Problem

`IntelligenceAgent` hand-built its REST run body by naming fields, and
`resume` was not one of them:

```ts
body: JSON.stringify({ threadId, runId, messages, tools, context, state, forwardedProps })
```

`HttpAgent` posts the whole `RunAgentInput`, so the self-hosted and SSE
paths carry `resume` correctly. Only the Intelligence transport dropped
it.

The two interrupt paths carry their resume payload in different fields:

| Path | Trigger | Resume travels as | Survived the Intelligence body |
| -- | -- | -- | -- |
| Legacy | `on_interrupt` CUSTOM event | `forwardedProps.command.resume`
| Yes |
| Standard | `RUN_FINISHED` with `outcome: "interrupt"` | top-level
`resume[]` | **No** |

So resuming a standard interrupt against an Intelligence runtime failed
silently: no error, no console output, and the graph simply re-entered
its gate. The server side was already correct — `RunAgentInputSchema`
declares `resume` and `parseRunRequest` parses with that schema.

Nothing the CLI scaffolds hits this combination today (it needs the
built-in agent plus Intelligence mode plus HITL), which is why it stayed
quiet.

## Change

Spread the input instead of naming fields, so a future protocol field
cannot be lost the same way:

```ts
body: JSON.stringify({ ...input, ...(mode === "connect" ? { lastSeenEventId } : {}) })
```

## Testing

Verified in a worktree with its own full `pnpm install` and freshly
built workspace `dist` output. The baseline is the same command with the
two changed files checked out from `origin/main`.

### Two new tests in
`packages/core/src/__tests__/intelligence-agent.test.ts`

- `carries the AG-UI resume array in the run body`
- `posts every RunAgentInput field, so no protocol field is dropped` —
iterates the input's own keys, so it fails on any future omission

### Whole-package suite

| | Test files | Tests |
| -- | -- | -- |
| Baseline (`origin/main`) | 69 passed | 830 passed |
| With this change | 69 passed | **832 passed** |

+2, exactly the new tests. No failures either side.

### Mutation check

Reverted the source fix to the hand-built field list and re-ran the
file:

```
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯
      Tests  2 failed | 59 passed (61)
```

Both new tests fail without the fix, so neither is self-fulfilling.

### Typecheck, lint, format

- `tsc --noEmit -p packages/core/tsconfig.json`: **0 errors**.
- `oxlint` on both files: 0 errors (2 pre-existing
`consistent-function-scoping` warnings in the test file, unchanged).
- Formatted with `oxfmt`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed agent run requests so all provided run input fields are
transmitted correctly.
  * Preserved resume information when starting an agent run.
  * Ensured no supported protocol fields are omitted from requests.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 18:46:57 -05:00
Tyler Slaton e9ff66ce72 docs(integrations): state the JSON-string context contract on every agent-app-context page (#6893)
Closes OSS-1134.

## Problem

`useAgentContext` calls `JSON.stringify` on any non-string `value`
before the run leaves the browser
([`use-agent-context.tsx:29-34`](https://github.com/CopilotKit/CopilotKit/blob/main/packages/react-core/src/v2/hooks/use-agent-context.tsx#L29-L34)),
because the AG-UI protocol types `Context.value` as `z.string()` on both
ends. The Python SDK only calls `model_dump()`, so the value reaches
`state["copilotkit"]["context"]` as a JSON string with no parsing
anywhere in between.

The four reference pages have said so since b18f7054af (OSS-1003). The
**integration guides** — the pages a reader actually follows — did not,
and they walked the reader straight into the trap:

- register `colleagues`, an array of objects
- read `.get("value")` and interpolate it into an f-string

An f-string hides the type completely, because a JSON string formats
without complaint. A reader who wants `colleagues[0]["name"]` gets `'['`
instead, and the failure reads as "the frontend sent nothing" —
indistinguishable from an empty context.

## What changed

Documentation only. The wire format does not change: the string is the
protocol.

**One shared callout, eight pages.** New snippet
`snippets/shared/basics/agent-context-json-string.mdx`, imported by
every `agent-app-context` variant before its first code sample, so the
wording cannot drift. Three pages (`adk`, `crewai-flows`, `pydantic-ai`)
already stated the contract, but only *after* their first code sample,
where a reader skimming to the code misses it.

**Four examples were wrong, not just undocumented:**

| Page | Defect | Fix |
|---|---|---|
| langgraph (Python) | interpolated the raw string | `json.loads`, then
reads `c["name"]` so the reason to parse is visible |
| langgraph (TypeScript) | `find` predicate was `'The current user\'s
colleagues"'` — a stray quote that could never match | predicate
corrected, then `JSON.parse` |
| mastra | `JSON.stringify(item?.value)` on an already-encoded value →
double encoding | parses instead |
| ag2 | returned the raw string at three sites, one annotated `->
list[dict]` | all three parse |

The langgraph TypeScript predicate bug meant that example could not have
worked as printed, independently of the JSON issue.

Reference pages are untouched — all four already cover this correctly.

## Testing

**Acceptance criteria, checked mechanically against the final content:**

```
=== AC1: callout precedes the first code fence, all 8 variants
  PASS adk        PASS ag2          PASS built-in-agent   PASS crewai-flows
  PASS langgraph  PASS mastra       PASS ms-agent-fwk     PASS pydantic-ai
=== AC2: no context value interpolated without a parse
  PASS (all 8; every ag2 extraction assigns to `raw`, then json.loads(raw))
=== AC3: nothing stringifies an already-string value
  PASS (swept every .mdx under docs/ and snippets/)
```

**The edited code actually runs.** Executed the Python and TypeScript
fragments as printed:

```
compiles: langgraph / ag2 get_readable / ag2 list_colleagues
round trip OK; None default still absorbed by the call site's `or []`
chat_node   -> 'John Doe (Developer), Jane Smith (Designer)'
mastra      -> 'John Doe (Developer), Jane Smith (Designer)'
pre-fix colleagues[0] was '[' (a single character)
pre-fix mastra output: "[{\"id\":1,\"name\":\"John Doe\",\"role\":\"D...   (double encoded)
pre-fix langgraph TS find predicate matched: false (was always undefined)
```

The last three lines reproduce the reported failure and both latent
bugs, then show them fixed.

**MDX renders.** All 9 files compiled through the real pipeline
(`inlineSnippets` → `convertTablesInJSX` → `@mdx-js/mdx`), with zero
snippet-resolution warnings:

```
PASS × 9   snippet warnings: (none)
```

**Test suite — failure-set diff, not a bare pass.** This environment has
a known install-staleness gap (`@clerk/nextjs`), so I compared against a
pristine-content baseline in the same worktree rather than against zero:

```
baseline (pristine main content):  Test Files  14 failed | 68 passed (82)   Tests 35 failed
with this change:                  Test Files  14 failed | 68 passed (82)   Tests 35 failed
FAILURE-SET DIFF: IDENTICAL — this change introduces no new failure
```

For reference, the same content passes cleanly where the install is
complete: 51 files / 351 tests, matching its own baseline exactly.

**Mutation-checked the probes** rather than trusting a green light:
breaking the snippet import path fails 1 page, and deleting the callout
text fails all 6 dependents — confirming the snippet is genuinely shared
and the checks can actually fail.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added guidance across integration guides clarifying that agent context
values arrive as JSON strings.
* Added parsing examples for Python and TypeScript, including
colleague-list formatting.
* Added warnings about avoiding raw access and double-encoding context
values.
* Updated AG2, LangGraph, and Mastra examples to parse context values
before use.


<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-05 01:39:23 +02:00
Tyler Slaton 69d60cf90f feat(docs): clarify onboarding and Intelligence journey (#6912)
## Summary

- Rework the quickstart around a framework-agnostic, product-first setup
path.
- Refine the docs sidebar hierarchy and derive breadcrumbs from that
navigation structure.
- Surface Automatic Learning, User Memories, Rich Threads, and
Intelligence more clearly.
- Improve copy-prompt discoverability, guidance, placement, and
responsive behavior.
- Center and widen documentation reading layouts while fixing the mobile
table of contents.

## Why

The existing entry points assumed too much agent-framework context,
obscured key Intelligence capabilities, and made high-value prompt
actions easy to miss. This gives new users a clearer route from first
setup through production features without implying that CopilotKit
requires a particular framework or React meta-framework.

## How

- Update root navigation metadata and breadcrumb derivation across
authored docs.
- Add optional coding-agent setup prompts for Automatic Learning and a
post-quickstart Intelligence CTA.
- Align Intelligence labels and overview content across framework
integrations.
- Add a stronger, explained copy-prompt action with responsive placement
and accessible hover behavior.
- Adjust shared docs layout and mobile TOC styles with focused
regression coverage.

## Verification

- 10 focused test files passed, covering 26 tests.
- Shell docs TypeScript typecheck passed.
- Visually verified the restored homepage and affected docs layouts in
the in-app browser.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Added User Memories to Intelligence documentation and navigation.
- Added a Quickstart call-to-action for persistent conversations and
Intelligence.
- Added an optional coding-agent prompt to help configure Automatic
Learning.
  - Added accessible tooltip support to the “Copy prompt” action.
- **Improvements**
  - Updated documentation breadcrumbs and sidebar organization.
- Refined mobile layouts, table-of-contents behavior, and page-action
styling.
- Improved the docs quickstart with current provider guidance and
simplified setup.
- **Documentation**
- Expanded Intelligence descriptions to include memory and durable
cross-conversation context.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-05 01:32:54 +02:00
Tyler Slaton 97d1379ae8 feat(docs): improve page prompt actions 2026-09-05 01:24:50 +02:00
Tyler Slaton 282e8f1c11 feat(docs): make quickstart and learning product first 2026-09-05 01:24:50 +02:00
Tyler Slaton 79c683bb2c feat(docs): refine navigation and Intelligence hierarchy 2026-09-05 01:24:50 +02:00
Tyler Slaton 21ac18fba6 fix(docs): center reading layout and mobile toc 2026-09-05 01:24:50 +02:00
Ben Taylor 8c629c147b docs(showcase): document frontend-driven activity cards (refs #3388) (#6904)
## What

Issue #3388 asked for a way to put a card into the chat transcript from
frontend code, without a tool call and without adding to the
conversation the model reads.

**That already ships.** A message with `role: "activity"` renders
standalone in the transcript, and `AbstractAgent.prepareRunAgentInput`
strips every activity message from the run payload:

```js
prepareRunAgentInput(e) {
  let t = structuredClone_(this.messages).filter(e => e.role !== `activity`);
  ...
}
```

The gap was documentation. `renderActivityMessages` is only documented
for **backend-emitted** activities (mastra background-tasks, a2a,
mcp-apps), so the frontend-driven path was undiscoverable.

This PR adds the missing guide page and a test that pins the behavior.

## Changes

| File | Why |
| --- | --- |
| `showcase/shell-docs/.../generative-ui/frontend-cards.mdx` | New
"Frontend-Driven Cards" guide |
| `showcase/shell-docs/.../generative-ui/meta.json` | Sidebar entry
(6-line insertion) |
| `packages/react-core/.../CopilotChatFrontendActivityCard.e2e.test.tsx`
| Pins both halves of the contract |

No source changes. Behavior is unchanged; this documents and locks what
already works.

## The non-obvious part

The card must be added via the agent returned by `useAgent()`. An agent
instance constructed and held outside React is **not** the instance the
chat renders, so messages added to it silently never appear. This cost
me a debugging round while verifying, and it is called out as a warning
callout in the docs.

## Testing

**1. New test passes against clean `origin/main`** (run in a worktree at
`96cf7aa55f`, with `@copilotkit/shared` and `@copilotkit/core` rebuilt
from the worktree so the test is not reading a stale dist):

```
✓ src/v2/components/chat/__tests__/CopilotChatFrontendActivityCard.e2e.test.tsx (2 tests) 72ms

 Test Files  1 passed (1)
      Tests  2 passed (2)
```

**2. Mutation-checked, so neither assertion is self-fulfilling.**

Drop the renderer registration → the render test fails:
```
× renders a card added from frontend code, with no tool call 1068ms
      Tests  1 failed | 1 passed (2)
```

Swap the card from `role: "activity"` to `role: "assistant"` → it
reappears in the payload, so the exclusion is real and specific to
`activity`:
```
AssertionError: expected [ 'user', 'assistant' ] to deeply equal [ 'user' ]
```

**3. Neighboring test unaffected on the same base:**

```
✓ src/v2/components/chat/__tests__/CopilotChatMessageView.test.tsx (16 tests) 53ms
      Tests  16 passed (16)
```

**4. Independent probe of the filter** against the pinned
`@ag-ui/client` 0.0.57:

```
agent.messages roles: [ 'user', 'activity' ]
run input roles     : [ 'user' ]
```

**5. `tsc --noEmit`** — zero errors in the new file. Remaining errors in
this workspace are in files this PR does not touch
(`MCPAppsActivityRenderer.tsx`, `CopilotKitInspector.tsx`) and are
artifacts of a hand-assembled local `node_modules`; CI has the real
install.

**6. `oxfmt --check`** — clean.

**7. Docs checks** — `meta.json` validated as JSON; internal link uses
the house `/generative-ui/...` form (no `/docs` prefix); `Callout
type="warn"` matches the dominant existing usage; import paths verified
against the real `@copilotkit/react-core/v2` barrel exports.

## Follow-up

Leaving #3388 open until this lands, then closing it with a pointer to
the new page.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added support for frontend-driven activity cards that render in chat
transcripts without being sent to the agent or language model.
- Added documentation covering activity card renderers, schemas,
registration, payload filtering, snapshots, and limitations.
- Added a new “Frontend-Driven” section to the Generative UI
documentation navigation.

- **Tests**
- Added end-to-end coverage for activity card rendering and payload
exclusion.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 17:32:15 -05:00
Ben Taylor 1b028f484c fix(mastra): stop thread-scoped working memory aborting the first turn (closes OSS-1122) (#6870)
## Problem

A starter scaffolded with `copilotkit init --framework mastra` and
connected to managed Intelligence starts, accepts a chat message, and
never answers. `POST /api/copilotkit/agent/default/run` still returns
200, so the abort is only visible in the server log:

```
Agent execution failed: Error: Thread c883919e-… not found
```

## Root cause

`@ag-ui/mastra`'s `syncInputStateToWorkingMemory` writes the UI's shared
state into Mastra working memory **before** it streams a turn. That
write is unguarded and never creates the thread, because it assumes the
resource-scoped store, which upserts. Its own comment says so, and its
*remote* branch handles the opposite case explicitly ("requires the
thread to exist… create the thread and retry once").

This starter was the one Mastra agent in the repo that set
`workingMemory.scope: "thread"`. Thread scope routes the same write to
thread metadata, and `@mastra/memory` throws `Thread <id> not found`
when the thread row does not exist. On the first turn of a conversation
it never does, so the run dies before the model is called.

Managed Intelligence made that certain rather than likely:
`handlers/intelligence/run.ts` replaces the client thread id with a
platform-canonical one from `ɵacquireThreadLock`, which the Mastra store
has never seen. That also explains the two different thread ids in the
same failure.

## Evidence

Verified by running, against the starter's exact pins (`@mastra/core`
1.41.0, `@mastra/memory` 1.0.1-alpha.1, `@ag-ui/mastra` 1.1.2):

| Configuration | First-turn state sync |
| --- | --- |
| `scope: "thread"` (as shipped) | throws `Thread <id> not found`, run
aborts |
| `scope: "resource"` | writes, reads back, reaches the agent's system
message |

Resource scope keeps working memory **per conversation** here, because
the bridge derives the resource id from the thread id when no explicit
resource id is configured. Confirmed: a second thread id reads back
`null`, and schema merge semantics still work on turn 2.

## Change

- `examples/integrations/mastra` uses `scope: "resource"`, matching
every other Mastra agent in this repo, with a comment explaining why.
- A new contract test in
`scripts/__tests__/integration-intelligence-migration.test.ts` fails if
any integration starter configures thread-scoped Mastra working memory.
It asserts the mastra starter is in scope, so it cannot pass vacuously,
and it ships with five helper cases including a decoy
(`observationalMemory.scope: "thread"`, which is unrelated and must not
trip it).

This also fixes the Channel host, which drives the same agent.

## Verification

- `vitest run
scripts/__tests__/integration-intelligence-migration.test.ts` — 159
passed, and the new test is red on the unfixed starter (`expected [
'mastra/src/mastra/agents/index.ts' ] to deeply equal []`).
- `parity:check` passes, `oxlint` and `oxfmt --check` clean.

## Left undone, deliberately

The adapter's local branch is still unguarded, so a developer who
chooses thread scope hits the same abort in their own code. The fix
belongs in `@ag-ui/mastra` and mirrors what its remote branch already
does. That needs an ag-ui PR plus a release, so it is not in this
change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Updated the weather agent’s working-memory scope to support shared UI
state during the first turn of a conversation.
* Prevented conversation initialization issues caused by thread-scoped
memory.

* **Tests**
* Added validation to ensure integrations use compatible working-memory
scopes.
* Added coverage for direct, nested, resource-scoped, omitted, and
unrelated configuration cases.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:46:49 -05:00
Ben Taylor a4adf38683 fix(shared): keep Node-only telemetry out of browser build graphs (#6846)
## What does this PR do?

`@copilotkit/shared` re-exported `telemetry/telemetry-client.ts` from
its root entry. That module imports `@segment/analytics-node`, which
imports `node-fetch`, which imports the Node built-ins `stream`, `http`,
`https` and `zlib`. Browser bundlers resolve the whole static module
graph before they tree-shake, so every browser build of a dependent
package printed `Module ... has been externalized for browser
compatibility` warnings, even when the consumer never touched telemetry.

This PR keeps that edge out of the browser-facing entry:

- `isTelemetryDisabled` moves into
`src/telemetry/telemetry-disabled.ts`, so the root entry can keep
exporting it without reaching the client.
- The root entry keeps `isTelemetryDisabled`, the `lambdaClient`
surface, the sampling helpers, and the `TelemetryCapture` /
`TelemetryIdentity` types. The types are exported with `export type`, so
they are erased and add no runtime edge.
- `TelemetryClient` is now reachable at `@copilotkit/shared/telemetry`,
a new export subpath.
- A new test walks the value-level import graph from `src/index.ts` and
fails if it reaches a Node-only package.

Deferring the import does not fix this, which is what PR #5482
attempted. A dynamic import defers evaluation but keeps the graph edge,
so `vite:resolve` still reaches `node-fetch`. The measurement is in
https://github.com/CopilotKit/CopilotKit/pull/5482#issuecomment-5509823707.

## Export surface change

`TelemetryClient` is no longer on the `@copilotkit/shared` root entry,
or on the `CopilotKitShared` UMD global. It is reachable at
`@copilotkit/shared/telemetry`.

```diff
- import { TelemetryClient } from "@copilotkit/shared";
+ import { TelemetryClient } from "@copilotkit/shared/telemetry";
```

This is a public export in the packaging sense only. `TelemetryClient`
is our internal metrics client, so no application code is expected to
import it, and nothing that works today is expected to stop working.
`packages/runtime/src/v1-deprecated/lib/telemetry-client.ts` is the only
in-repo consumer and is updated here. There is no root shim on purpose:
a runtime re-export would reintroduce the graph edge and the bug.

`typesVersions` carries the subpath for `moduleResolution: "node"`
(node10) consumers, which `packages/runtime` still uses. Without it,
`tsc` cannot see the subpath's types.

`scripts/release/public-api/manifest.v1.json` is regenerated for the new
entry point. The manifest tracks entry points rather than symbols, so
the change there is the added `./telemetry` record.

## Related PRs and Issues

- Fixes #4151
- Supersedes #5482

## Testing

### The reported symptom, before and after

Vite 7.3.2, minimal app whose entry imports only browser-safe symbols
from `@copilotkit/shared`, pointed at a real tsdown build of the
package.

| | `vite build` warnings | modules transformed |
| --- | --- | --- |
| `main` | 4 (`stream`, `http`, `https`, `zlib`) | 663 |
| this branch | **0** | 451 |

After, verbatim:

```
vite v7.3.2 building client environment for production...
transforming...
✓ 451 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html                0.12 kB │ gzip: 0.12 kB
dist/assets/index-EEiKsU3u.js  2.43 kB │ gzip: 1.29 kB
✓ built in 267ms
```

The dev-server dependency scanner is fixed too. `vite optimize --force`
before this change pre-bundled `@ag-ui/client, @segment/analytics-node,
chalk, graphql, partial-json, uuid, zod`; after it pre-bundles
`@ag-ui/client, graphql, partial-json, uuid, zod`.

### The new export surface, exercised in Node

```
=== CJS require of subpath ===
TelemetryClient: function
isTelemetryDisabled: function true
lambdaClient: object
segment instantiated: Analytics
=== ESM import of subpath ===
esm TelemetryClient: function disabled: true
=== root entry ===
root TelemetryClient: undefined
root isTelemetryDisabled: function
root lambdaClient: object
root computeSamplingMeta: function
root firstNonBlankTelemetryId: function
```

### Subpath type resolution, both resolution modes

```
### moduleResolution node10 (what packages/runtime uses) ###
(clean)
### moduleResolution node16 ###
(clean)
```

Before adding `typesVersions`, node10 failed as expected, which is why
the field is there:

```
probe.ts(1,33): error TS2307: Cannot find module '@copilotkit/shared/telemetry' or its
corresponding type declarations.
  There are types at '.../dist/telemetry/index.d.mts', but this result could not be
  resolved under your current 'moduleResolution' setting.
```

### The regression guard is not self-fulfilling

Mutation-checked both ways. Restoring `export * from "./telemetry"` on
the root entry:

```
× root entry browser safety (#4151) > does not reach Node-only packages through value imports
  → expected [ '@segment/analytics-node' ] to deeply equal []
```

Turning the type-only re-export into a value re-export fails it as well,
and restoring the file makes both tests pass again.

### The gate that went red on the first push

`scripts/release/lib/public-api-manifest.test.ts` compares the committed
public API manifest to a freshly generated one, and a new export subpath
has to be recorded there. Regenerated with `pnpm
generate:public-api-manifest`; the failing test and its whole suite now
pass:

```
scripts/release/generate-public-api-manifest.ts --check
  scripts/release/public-api/manifest.v1.json is current

vitest run scripts/release
  Test Files  14 passed (14)
       Tests  162 passed (162)
```

### Package gates

```
@copilotkit/shared: tsc --noEmit          clean
@copilotkit/shared: vitest run            18 files, 404 tests passed
@copilotkit/shared: tsdown                Build complete
@copilotkit/shared: verify-cjs-exports    exit 0
@copilotkit/shared: es-check es2022       55 files, ES13 compatible
@copilotkit/shared: es-check es2018 (umd) 1 file, ES9 compatible
@copilotkit/shared: publint               only the pre-existing repository.url suggestion
@copilotkit/shared: attw --profile node16 all green, including "@copilotkit/shared/telemetry"
```

### Not run locally

`@copilotkit/runtime:build` and the workspace-wide pre-commit gate. My
local install is missing `type-graphql@2.0.0-rc.1` from the pnpm store,
so the runtime build fails on `Cannot find module 'type-graphql'` on
`main` as well, with or without this change. The runtime change here is
one import line, and I verified that it resolves under both node10 and
node16. CI runs the real gate. This commit was made with `--no-verify`
for that reason.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added a dedicated `@copilotkit/shared/telemetry` entry point for
server-side telemetry functionality.
- Added support for disabling telemetry when
`COPILOTKIT_TELEMETRY_DISABLED` or `DO_NOT_TRACK` is set to `true` or
`1`.

- **Improvements**
- Improved browser compatibility by preventing Node-only telemetry
dependencies from being included in browser bundles.
- Existing browser-safe telemetry utilities remain available from the
main shared package entry point.
- Full telemetry client functionality is now accessed through the
dedicated telemetry entry point.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:42:53 -05:00
Ben Taylor 5fd08a824e feat(react-core): controlled open/onOpenChange props for CopilotSidebar and CopilotPopup (#6905)
Closes #3334 (OSS-524).

## Problem

v1 `<CopilotSidebar>` exposed `open` and `onSetOpen`. Those props let a
host open and close the chat from its own UI. v2 shipped only
`defaultOpen`. The reporter wanted a button in their own nav bar to
close the sidebar.

The reporter's stated root cause is now stale. `shouldCreateModalState`
no longer exists. Since CPK-7152 the provider syncs both directions:
`setAndSync` upward, and an effect downward. A host that wraps its
layout in `<CopilotChatConfigurationProvider>` and calls `setModalOpen`
therefore does drive the sidebar on current `main`. I verified that
before writing any code.

Two things are genuinely missing. The first is the ergonomic API that v1
had. The second is documentation for the outer-provider pattern that
already works.

Two earlier community attempts (#3729, #6418) were closed unmerged.

## What changed

`open` and `onOpenChange` on `<CopilotSidebar>` and `<CopilotPopup>`:

- `open` pins what the surface renders, from the first frame.
- `onOpenChange` reports every request to open or close: the toggle
button, click-outside, Escape, and the drawer's mobile mutual-exclusion.
It fires with or without `open`, so it also works as a plain
notification on the uncontrolled path.
- `defaultOpen` is unchanged. If both are passed, `open` wins.

Two design choices are worth review.

**1. A context-overriding scope, not a fourth mode in the provider.**
`ControlledModalOpenScope` replaces `isModalOpen` and `setModalOpen` for
the subtree below the provider that owns the state. The resolution chain
inside `CopilotChatConfigurationProvider` stays untouched: own state,
parent sync, drawer mutual-exclusion, and the `ɵregisterModalCloser`
stack. The scope's setter still calls the underlying one, so those side
effects keep running. It also registers itself as the modal closer, so
the drawer's mobile exclusion reaches the host instead of flipping state
that nothing displays. The alternative was a controlled branch threaded
through `resolvedIsModalOpen`, `setAndSync`, and the sync effect. That
adds a fourth interacting mode to the code CPK-7152 just stabilized.

**2. The props reach the views by context, not as props.**
`<CopilotSidebar>` hands its view to `<CopilotChat>` as a memoized
`chatView` component. Adding `open` to that memo's deps mints a new
element type per toggle, and React then remounts the whole chat subtree.
That is the same class of bug #6173 fixed for popup resize. There is a
regression test for it.

Scope note: I included `<CopilotPopup>` because it shares the mechanism
and the same docs page. The issue named only the sidebar.

## Testing

**New suite, 15 tests** (`CopilotSidebar.controlledOpen.test.tsx`). It
covers the controlled contract, the unchanged uncontrolled path, and the
remount guard.

```
✓ src/v2/components/chat/__tests__/CopilotSidebar.controlledOpen.test.tsx (15 tests) 155ms
  Test Files  1 passed (1)
       Tests  15 passed (15)
```

**Mutation-checked.** I broke each mechanism to confirm that the tests
really fail.

| Mutation | Result |
| --- | --- |
| Drop `ControlledModalOpenScope`, keep only the seeded default | 5
failed: both `onOpenChange` reports, both host-driven open/close cases,
the popup report |
| Implement through the memoized override instead (add `open` to the
`useMemo` deps) | 1 failed: the remount guard, `expected 4 to be 1`, one
extra mount per flip |
| Drop the `open ?? defaultOpen` seeding | 1 failed: "stays put when the
host stops controlling open" |

I also mutation-checked the pre-existing two-way sync before I started.
That confirmed the outer-provider workaround really works on `main`,
instead of only appearing to.

**Full `@copilotkit/react-core` suite.** No regressions.

```
Test Files  141 passed | 1 skipped (142)
     Tests  1604 passed | 2 skipped (1606)
EXIT=0
```

**Adjacent suites re-run explicitly**: sidebar position, sidebar and
popup slots, popup resize-remount, drawer launcher, and the provider's
own 43 tests.

```
Test Files  6 passed (6)
     Tests  117 passed (117)
```

**Typecheck.** `tsc --noEmit` in `packages/react-core` gave `exit=0`
with no output. The tsconfig includes `src/**/*`, so the new test file
is typechecked too.

**Format and lint.** `oxfmt --check packages/react-core/src/v2` reported
"All matched files use the correct format." `oxlint` on the touched
files reported 0 errors.

**Pre-commit hooks.** They ran for real on both commits.

```
NX   Successfully ran targets test, publint, attw for 2 projects and 20 tasks they depend on
✔️ test-and-check-packages (15.33 seconds)
```

## Docs

- `prebuilt-components/chat-controls.mdx` now leads with the controlled
pair. Its example drives the sidebar from a nav button outside it, which
is the shape #3334 asked about. The `useCopilotChatConfiguration` route
stays, reframed as the option for callers who prefer not to lift the
state.
- `reference/components/CopilotSidebar.mdx` and `CopilotPopup.mdx` gain
`open` and `onOpenChange`. Both pages documented `defaultOpen` as
`false`, but both surfaces mount open, so I corrected that. A new test
per surface pins the real default.

## Not in this PR

- Vue and Angular parity for the same props.
- The `width` prop of `<CopilotSidebar>` still sits in the memo deps of
the `chatView` override. A live-resized sidebar therefore remounts the
chat subtree, the way the popup did before #6173. That is pre-existing
and out of scope here.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added controlled open-state support for chat popups and sidebars
through `open` and `onOpenChange`.
- Preserved uncontrolled usage with `defaultOpen`, while allowing
externally managed visibility and toggle requests.
  - Improved coordination between modal and mobile drawer behavior.

- **Documentation**
- Added usage guidance and reference details for controlled and
uncontrolled open-state management.

- **Tests**
- Added coverage for initial visibility, toggle callbacks, controlled
updates, default behavior, and preserving the chat subtree.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:39:28 -05:00
Ben Taylor 603bc16cf3 fix(react-core): restore code block line breaks in packaged CSS (#3330) (#6902)
## What does this PR do?

Fixes #3330 — fenced markdown code blocks render as one collapsed line
in the packaged v2 React UI.

### Root cause

streamdown renders one `<span>` per source line inside
`pre[data-streamdown="code-block-body"] > code`, and leaves **no newline
characters** in the text. The line break comes entirely from the raw
Tailwind utility `block` on that span:

```js
// streamdown 1.6.11, dist/code-block-*.js
var v = cn("block", "before:content-[counter(line)]", ...);
```

CopilotKit builds Tailwind with `@import "tailwindcss" prefix(cpk)`, so
`.block` is never emitted into `dist/v2/index.css` — only `.cpk\:block`
is. Every line therefore renders inline and the block collapses onto one
row.

The line spans carry no `data-streamdown` attribute, so the rule has to
be scoped structurally, the same way the table action controls were in
#5944:

```css
[data-copilotkit] [data-streamdown="code-block-body"] > code > span {
  @apply cpk:block;
}
```

### Why the earlier attempts did not work

Three previous PRs (#3441, #3615, #5387) added `whitespace-pre` to the
`<pre>`. That is a no-op: the UA stylesheet already applies
`white-space: pre` to `<pre>`, nothing in the packaged CSS overrides it,
and there are no newlines in the text for it to preserve.

### Knowingly not fixed here

- **Line-number gutter.** streamdown's `before:content-[counter(line)]
before:w-4 before:mr-4 …` utilities are unprefixed too, so the gutter
never renders. That is cosmetic, and the repo's existing scoped rules do
not port it either.
- **The pre-highlight loading skeleton** (`space-y-4`, `divide-y`,
`animate-spin`) is unprefixed as well — a brief flash of unstyled
skeleton before shiki resolves.
- **The broader class of bug.** Every unprefixed streamdown utility has
to be hand-ported like this. streamdown 2.x adds a `prefix` prop that
would fix the whole surface at once, and #5147 proposes removing the
bundled renderer entirely. Both are larger calls than this bug fix.

## Testing

**1. Live browser verification.** Built `dist/v2/index.css` from
`origin/main` and from this branch, rendered streamdown 1.6.11's actual
code-block DOM against each, and measured layout in Chromium:

| | `white-space` on `<pre>` | line-span `display` | distinct rendered
rows | `<pre>` height |
|---|---|---|---|---|
| main | `pre` | `inline` | **1** | 52px |
| this PR | `pre` | `block` | **5** | 112px |

Indentation is preserved after the fix (`spans[1].textContent` starts
with two spaces).


**2. Compiled CSS.** `tailwindcss -i src/v2/styles/globals.css -o … -m`
emits exactly:

```css
[data-copilotkit] [data-streamdown=code-block-body]>code>span{display:block}
```

**3. Tests** — `pnpm -C packages/react-core exec vitest run
src/v2/styles`

```
 ✓ src/v2/styles/__tests__/streamdown-styles.test.ts (3 tests) 2ms
 ✓ src/v2/styles/__tests__/streamdown-table-controls.test.tsx (1 test) 37ms
 ✓ src/v2/styles/__tests__/streamdown-code-block-lines.test.tsx (1 test) 430ms

 Test Files  3 passed (3)
      Tests  5 passed (5)
```

Two tests, following the split established by #5944 — a source-string
test that the selector exists, and a DOM test that streamdown still
renders the structure that selector assumes (so a streamdown markup
change fails loudly instead of silently un-fixing this).

**4. Mutation-checked both tests.** Removing the CSS rule fails the
string test:

```
   × Streamdown styles > ships a scoped display rule for code block lines (#3330) 3ms
      Tests  1 failed | 2 passed (3)
```

Pointing the DOM test at a selector streamdown does not render fails it:

```
   × Streamdown code block lines DOM (#3330) > renders one line span per source line 428ms
      Tests  1 failed (1)
```

**5. Formatting** — `oxfmt --check` clean on all three files; `git diff
--check` clean.

`tsc --noEmit` in this worktree reports 58 pre-existing errors, all from
a stale cross-package `@copilotkit/core` dist; none are in the changed
files (which are CSS plus tests).

## Related PRs and Issues

Fixes #3330
Supersedes #3441, #3615, #5387, #5996 (all added a no-op
`whitespace-pre`)

## 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 (not applicable: scoped visual bug fix)
- [x] "Allow edits by maintainers" is checked


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Fixed fenced code blocks collapsing into a single line in the packaged
UI.
- Code lines now render vertically as separate rows with the correct
layout styling.

- **Tests**
- Added regression coverage to verify code-line rendering and scoped
styles for code blocks.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:38:59 -05:00
Ben Taylor dc737a80f1 fix(react-textarea): stop Cmd+K insert from deleting adjacent text (#6900)
Closes #2192

## Problem

`CopilotTextarea`'s Cmd+K hovering editor destroys text when the user
clicks **Insert**. `HoveringToolbar` deleted the selection and then
reused the same `selection` range for the insert:

```ts
Transforms.delete(editor, { at: selection });
Transforms.insertText(editor, insertedText, { at: selection });
```

Two separate defects come out of those two lines:

1. **Expanded selection.** The range is stale after the delete, and
`Transforms.insertText` already deletes an expanded range before
inserting. The delete inside `insertText` therefore runs a second time,
at the same offsets in the now-shorter document, and eats the characters
that followed the insertion point.
2. **Collapsed caret** (plain insert, no selection). `Transforms.delete`
resolves a collapsed range to a point and deletes one character
*forward*, so inserting at the caret always destroyed the next
character.

The reporter described it as "Insert did not fill in the content". What
actually happens is that the insert lands but neighbouring text
disappears with it, which is data loss in the user's document.

`@copilotkit/react-textarea` is a deprecated v1 package with **no 1:1 v2
replacement**, so affected users have nowhere to migrate. That is why
this is worth a one-line fix rather than a won't-fix.

## Change

Drop the `Transforms.delete` call. `Transforms.insertText` is correct
for both cases on its own: it deletes an expanded range through point
refs and inserts at its start (`slate@0.94.1`,
`TextTransforms.insertText`), and it inserts in place when the range is
collapsed.

The two `import type` lines in the diff are the pre-commit `oxlint
--fix` hook's own autofix on the touched file, not a hand edit.

No new API surface, no runtime dependency change, no test-harness added
to a deprecated package.

## Testing

The package has no component/slate test setup (only two trivial unit
test files), so verification is behavioural, against a standalone Vite +
React 18 app that mounts `BaseCopilotTextarea` with a stub
`insertionOrEditingFunction` that streams the literal
`HELLO_FROM_SUGGESTION` (no LLM in the loop). Each run: set the
selection, Cmd+K, type a prompt, generate, click **Insert**, then read
back both the editor DOM text and the controlled `value` mirrored
outside the component.

**Before** — `@copilotkit/react-textarea@1.70.1` from npm (identical to
`main`):

| Case | Start | Result |
| --- | --- | --- |
| select `bravo` | `alpha bravo charlie delta echo` | `alpha
HELLO_FROM_SUGGESTIONlie delta echo` — ate ` char` |
| caret at offset 6, no selection | `alpha bravo charlie delta echo` |
`alpha HELLO_FROM_SUGGESTIONravo charlie delta echo` — ate `b` |

**After** — `packages/react-textarea/dist` built from this branch (`nx
run @copilotkit/react-textarea:build`) and swapped into the same app:

| Case | Start | Result |
| --- | --- | --- |
| select `bravo` | `alpha bravo charlie delta echo` | `alpha
HELLO_FROM_SUGGESTION charlie delta echo`  |
| caret at offset 6, no selection | `alpha bravo charlie delta echo` |
`alpha HELLO_FROM_SUGGESTIONbravo charlie delta echo`  |
| select last word `echo` | `alpha bravo charlie delta echo` | `alpha
bravo charlie delta HELLO_FROM_SUGGESTION`  |
| select all (3 lines) | `one alpha\ntwo bravo\nthree charlie` |
`HELLO_FROM_SUGGESTION`  |
| select `alpha\ntwo bravo` (mid, spans lines) | `one alpha\ntwo
bravo\nthree charlie` | `one HELLO_FROM_SUGGESTION\nthree charlie`  |

The last three cases were already correct before the change (the stale
range clamps at the document end), and they stay correct — the fix does
not regress them.

Repo checks, in the worktree at `origin/main`:

```
$ pnpm nx run-many -t test,publint,attw --projects=@copilotkit/react-textarea
 ✓ src/lib/utils.test.ts (1 test) 1ms
 ✓ src/esm-compat.test.ts (1 test) 1ms
 Test Files  2 passed (2)
      Tests  2 passed (2)
NX   Successfully ran targets test, publint, attw for project @copilotkit/react-textarea and 19 tasks it depends on

$ pnpm exec tsc --noEmit        # in packages/react-textarea
exit: 0

$ pnpm exec oxlint packages/.../hovering-toolbar.tsx
Found 5 warnings and 0 errors.   # all pre-existing `import type` warnings elsewhere in the file
```

`nx run @copilotkit/react-textarea:check-types` also builds the
dependency project `@copilotkit/runtime-client-gql`, which fails locally
on missing generated GraphQL modules (`../graphql/@generated/graphql`).
That is a pre-existing local codegen gap in an untouched package, not
from this change; the direct `tsc --noEmit` above covers this package.

Pre-commit hooks ran on the commit (`check-binaries`, `lint-fix`,
`test-and-check-packages`, `check-intelligence-env-names`, `commitlint`)
and all passed.

## Not in scope

The screenshot on #2192 also shows the Cmd+K popup rendered far from the
selection (bottom-left of the viewport). That is a separate positioning
bug; PR #3679 attempted it and was closed. Not touched here.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved text insertion behavior in the hovering toolbar, including
replacement of selected text and insertion at the current caret
position.
* Prevented issues caused by outdated selection ranges during insertion.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:38:36 -05:00
Ben Taylor 41a31b99b0 fix(runtime): build the logger without pino redact so edge runtimes work (#6899)
Closes #2355 (OSS-547).

## The bug

`@copilotkit/runtime` cannot build its logger on Cloudflare Workers. The
deployed worker throws:

```
⨯ Error: pino – redact paths array contains an invalid path (pid)
```

## The cause, which is not what earlier triage said

The support-bot answer on the issue said `pid` is rejected because
Workers have no process ID, and suggested dropping `pid` from the array.
That is wrong, and the reporter said it did not help.

pino 9 hands `redact.paths` to `fast-redact`, whose validator checks
each path by **calling `Function(...)`**:

```js
// fast-redact/lib/validator.js
try {
  ...
  Function(`
      'use strict'
      const o = new Proxy({}, ...);
      o${expr}
      ...`)()
} catch (e) {
  throw Error(ERR_INVALID_PATH(s))   // <- swallows the real EvalError
}
```

Cloudflare Workers forbid code generation from strings, so the
`Function(...)` call throws an `EvalError`. The `catch` swallows it and
reports the **first path in the array**, which happens to be `pid`.
Every path fails, not just `pid` — removing `pid` only moves the error
to `hostname`.

## The fix

Use pino's own `base` switch, which is what the `redact` block was
emulating. It omits `pid` and `hostname`, produces identical output, and
needs no code generation.

```diff
-      redact: {
-        paths: ["pid", "hostname"],
-        remove: true,
-      },
+      base: null,
```

The file lives under `v1-deprecated/`, but v2 still reaches into it:
`v2/runtime/core/runtime.ts` and
`v2/runtime/handlers/shared/sse-response.ts` both call `createLogger`
when `debug.enabled`. So this fixes both major versions. In v1 the call
is at module scope (`v1-deprecated/lib/integrations/shared.ts:90`), so
the import throws unconditionally, which is why the reporter hit it on
v1.

## Testing

**1. Reproduced the exact reported error.** `node
--disallow-code-generation-from-strings` applies the same restriction
Workers apply. Run against pino 9.2.0 + pino-pretty 11.2.1 with the
pre-fix logger options:

```
$ node --disallow-code-generation-from-strings current.js
Error: pino – redact paths array contains an invalid path (pid)
    at .../fast-redact/lib/validator.js:29:15
    at Array.forEach (<anonymous>)
    at validate (.../fast-redact/lib/validator.js:12:11)
    at handle (.../pino/lib/redaction.js:113:3)
    at redaction (.../pino/lib/redaction.js:16:29)
    at pino (.../pino/pino.js:129:33)
```

**2. Confirmed `pid` is not special.** Same flag, other paths:

```
hostname-only FAILED: pino – redact paths array contains an invalid path (hostname)
unrelated path FAILED: pino – redact paths array contains an invalid path (req.headers.authorization)
```

**3. Confirmed the fix builds the logger under the same restriction**,
with the post-fix `createLogger` verbatim (both the plain and the
`component` child path):

```
$ node --disallow-code-generation-from-strings final.js
[13:18:27.986] DEBUG: debug line
    component: "copilotkit-debug"
[13:18:27.988] ERROR: error line
OK: createLogger works with code generation disabled
exit=0
```

**4. Confirmed output parity.** `base: null` emits exactly what the
`redact` block emitted:

```
--- redact variant ---          {"level":30,"time":1788545869311,"msg":"x"}
--- base:null variant ---       {"level":30,"time":1788545869311,"msg":"x"}
--- child component ---         {"level":30,"time":...,"component":"copilotkit-debug","msg":"y"}
```

**5. Confirmed the fix is safe on pino 10** (which this monorepo pins
via a pnpm override), same flag:

```
{"level":50,"time":1788545913844,"msg":"p10 base:null ok"}
```

**6. New unit test, mutation-checked.**
`packages/runtime/src/v1-deprecated/lib/__tests__/logger.test.ts`.
Passing:

```
 ✓ src/v1-deprecated/lib/__tests__/logger.test.ts (4 tests) 2ms
 Test Files  1 passed (1)
      Tests  4 passed (4)
```

Restoring the `redact` block fails it, so it is not self-fulfilling:

```
 FAIL  ... > createLogger > suppresses pid and hostname with base instead
AssertionError: expected undefined to be null
 Test Files  1 failed (1)
      Tests  2 failed | 2 passed (4)
```

**7. Full `@copilotkit/runtime` suite:**

```
 Test Files  1 failed | 153 passed (154)
      Tests  3 failed | 2273 passed (2276)
```

The one failing file is
`v1-deprecated/service-adapters/google/google-genai-adapter.test.ts`. It
fails identically on pristine `origin/main` with this change reverted
(`Test Files 1 failed (1) / Tests 3 failed (3)`), so it is pre-existing
and unrelated.

**8. Pre-commit hook green** — `check-binaries`, `lint-fix` (0 warnings,
0 errors), `check-intelligence-env-names`, and `test-and-check-packages`
(`test`, `publint`, `attw` across 7 projects) all passed on the commit.

`tsc --noEmit --strict` on the changed file exits 0. `oxfmt --write`
produced no changes.

## What this does not claim

This removes one proven blocker, not "Cloudflare support". I did not
deploy to workerd end to end, so `pino-pretty` and other Node
dependencies in the runtime may block separately.

## Separate observation, not fixed here

`packages/runtime/package.json` declares `"pino": "^9.2.0"`, but the
root `pnpm.overrides` pins `pino@<=10.1.1: 10.1.1`. pino 10 swapped
`fast-redact` for `@pinojs/redact`, which uses no code generation. So
this class of bug is invisible to local dev and CI here and only appears
in published installs. Worth closing that gap, but it is a major-version
bump for a published package and does not belong in this fix.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved logger compatibility in edge runtimes by preventing startup
failures caused by logger configuration.
* Preserved existing log output while suppressing process-specific
details such as process ID and hostname.
* Maintained default and environment-configured log levels, including
component-specific child loggers.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:38:19 -05:00
Ben Taylor 4da2d7e34e fix(core): hydrate self-hosted threads whose /connect replay contains an errored run (#6528)
Hydrating an existing thread through `/connect` fails on a
**self-hosted** runtime whenever that thread's history contains a run
that ended in `RUN_ERROR`.

## The defect

A `/connect` response is a *replay* of a thread's history, so it can
legitimately carry several past runs back to back — including an errored
run followed by a later `RUN_STARTED`. The base `AbstractAgent` connect
pipeline pushes that stream through `verifyEvents`, which enforces
AG-UI's **single run** lifecycle rules and rejects the sequence
outright:

```
Cannot send event type 'RUN_STARTED': The run has already errored with 'RUN_ERROR'. No further events can be sent.
```

The user-visible effect is the one reported in #4943:
`agent_connect_failed` on reload, and the existing thread never hydrates
its prior messages.

`IntelligenceAgent` already omitted `verifyEvents` from its connect
pipeline for exactly this reason (its JSDoc spells it out). But
`ProxiedCopilotRuntimeAgent.connectAgent` only takes that path in
`RUNTIME_MODE_INTELLIGENCE` — self-hosted (`RUNTIME_MODE_SSE`) fell
through to `super.connectAgent()` and inherited the single-run
verification. So the managed product was fine and self-hosting was not.

## The fix

`ɵconnectWithoutEventVerification`
(`packages/core/src/utils/connect-replay.ts`) holds the
verifyEvents-free pipeline, and **both** paths now use it.
`transformChunks` is still applied — message reassembly is needed either
way.

This is a de-duplication rather than a third copy:
`IntelligenceAgent.connectAgent` drops ~100 lines of hand-replicated
base pipeline (including its private-field `any` escape hatch) and keeps
only its canonical-run-id handling before delegating. Net
`intelligence-agent.ts` change is −101 lines.

### Fidelity to the base implementation

The helper was diffed statement-by-statement against the **real**
`AbstractAgent.connectAgent` in `@ag-ui/client@0.0.57` (recovered from
the shipped source map), not just against `IntelligenceAgent`'s replica.
`verifyEvents` is the only intended difference.

That diff caught a defect in the first push: the base special-cases
`AGUIConnectNotImplementedError` (swallow → `EMPTY`) and the replica did
not. `IntelligenceAgent` never needed it — it always implements
`connect()` — so the gap was invisible there, but on the SSE path it is
load-bearing: `run-handler.ts:447-450` documents that `await
agent.detachActiveRun()` only stopped deadlocking because that error
path still reaches the pipeline's finalize block. Routing it through
`onError` would also fire run-failure callbacks on every subscriber for
a benign condition. Restored, with a regression test.

Also confirmed that dropping `verifyEvents` cannot alter a well-formed
replay: it is a pure gate — 18 `return of(event)` pass-throughs, 42
error paths, and zero `endWith` / `startWith` / `tap` side effects. It
only removes the single-run rejection.

The existing upstream TODO still stands and is carried over:
`@ag-ui/client@0.0.57`'s `connectAgent(parameters?, subscriber?)` takes
no option to skip verification, so this override is still the only way
to express "this stream is a replay, not a run."

## On the second half of #4943

The issue also reports that the legacy chat path doesn't copy the
resolved `threadId` onto the agent before connect/run. **That half is
already fixed on `main`** — the #5041/#4739 fix put `agent.threadId =
resolvedThreadId` in v2 `useAgent`, and `useCopilotChatInternal`
delegates to that same hook. Nothing more was needed.

It was untested, though, and untestable from the suite that looked like
it covered it: `use-copilot-chat-internal-connect.test.tsx` mocks
`useAgent` wholesale, so it cannot observe threadId propagation at all.
This PR adds `legacy-chat-explicit-threadid.test.tsx`, which drives the
legacy hook through the **real** `useAgent` under a real `<CopilotKit>`,
covering both the explicit-threadId case and the "don't adopt a
non-explicit placeholder UUID" case.

It reads the agent off `useCopilotChatInternal()`'s own return value
rather than calling `useAgent` in the probe. That distinction matters:
the first version of this test did call `useAgent`, so the probe itself
performed the assignment under test and the test passed **even with
`useCopilotChatInternal()` removed entirely**. The current version is
mutation-checked — disabling the assignment in v2 `useAgent` fails it
(`expected 'dc051f13-…' to be 'cookie-backed-thread'`).

Contributor PR #4969 proposed a manual assignment for this half; it is
now redundant.

## Testing

Worktree caveat, stated up front: this worktree symlinks the primary
checkout's `node_modules`, so `@copilotkit/shared` and
`@copilotkit/core` resolve to that checkout's **stale `dist`**. That
produces failures unrelated to this change; each is baselined against
clean `main` in the same environment below. CI installs fresh and is the
authoritative gate.

**1. Reproduces the reported failure before the fix.** The new core
test, run on unmodified `origin/main`, fails with the exact error from
the issue:

```
FAIL  src/__tests__/proxied-connect-replay-multi-run.test.ts > hydrates a thread whose replayed history contains an errored run
AssertionError: promise rejected "Error: Cannot send event type 'RUN_STARTE…" instead of resolving
Caused by: Error: Cannot send event type 'RUN_STARTED': The run has already errored with 'RUN_ERROR'. No further events can be sent.
```

**2. Passes after the fix**, hydrating both runs' messages (`["msg-1",
"msg-2"]`):

```
✓ src/__tests__/proxied-connect-replay-multi-run.test.ts (1 test) 11ms
Test Files  1 passed (1)
```

**3. Connect-not-implemented guard, fail-first.** With the guard
removed, the new second test fails exactly as the base contract
predicts:

```
× swallows AGUIConnectNotImplementedError instead of failing the run
AssertionError: promise rejected "Error: Connect not implemented. This meth…" instead of resolving
```

**4. Full `@copilotkit/core` suite** — this is the evidence the
`IntelligenceAgent` extraction is behavior-identical, since
`intelligence-agent.test.ts` exercises that path heavily:

```
Test Files  59 passed (59)
      Tests  635 passed (635)
```

(excludes `core-inspector-metadata.test.ts`; its 20 failures are the
stale-`shared`-dist artifact — verified identical on clean `main`: `20
failed | 2 passed`, missing export `InspectorMetadataV1`)

**5. `@copilotkit/react-core` — new + adjacent existing suites:**

```
✓ src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx (7 tests)
✓ src/hooks/__tests__/legacy-chat-explicit-threadid.test.tsx (2 tests)
✓ src/components/copilot-provider/__tests__/v1-explicit-threadid-bridge.test.tsx (5 tests)
Test Files  3 passed (3)
      Tests  14 passed (14)
```

Full react-core suite: `8 failed | 1492 passed (1500)`. All 8 are in
`use-interrupt` / `use-pin-to-send` / `CopilotChatView.pinToSend` — none
touch connect replay or threadId, and clean `main` in this worktree
fails the identical 8 (`8 failed | 37 passed (45)` for those three files
alone).

**6. `@copilotkit/vue`** (affected via core): `100 passed (100)` files,
`1072 passed (1072)` tests.

**7. Types, lint, format:**

```
tsc -p packages/core/tsconfig.json --noEmit   → no errors in any changed file
oxlint  <5 changed files>                     → Found 0 warnings and 0 errors
oxfmt --check <5 changed files>               → All matched files use the correct format
```

The only remaining `tsc` errors are 4 pre-existing stale-dist ones in
`agent-registry.ts` / `types.ts` (`InspectorMetadataV1`), untouched by
this PR.

Fixes #4943


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved thread hydration when reconnecting to histories containing
multiple runs, including runs that previously ended in error.
* Prevented unsupported connection errors from being reported as run
failures.
* Ensured connection state is properly finalized after replaying a
thread.
* Legacy chat components now correctly reuse an explicitly provided
thread ID while preserving generated IDs when none is provided.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 15:37:42 -05:00
Benjamin Taylor 28a19ddfa2 docs: document controlling the chat open state from your own UI
Leads the "Open, close, and feedback" page with the `open` /
`onOpenChange` pair and an example driving the sidebar from a nav button
outside it, which is the case #3334 asked about. The existing
`useCopilotChatConfiguration` route stays, now framed as the option for
callers who would rather not lift the state.

Also corrects `defaultOpen` on the CopilotSidebar and CopilotPopup
reference pages: both documented `false`, but both surfaces mount open.
2026-09-04 15:12:11 -05:00
Benjamin Taylor 91abd959f7 feat(react-core): controlled open/onOpenChange props for sidebar and popup
v1 exposed `open` + `onSetOpen`, so a host could open and close the chat
from its own UI. v2 shipped only `defaultOpen`, leaving the open state
reachable exclusively from inside the chat subtree. Restores the
controlled pair on `<CopilotSidebar>` and `<CopilotPopup>`:

- `open` pins what the surface renders, from the first frame.
- `onOpenChange` reports every request to open or close (toggle button,
  click-outside, Escape, the drawer's mobile mutual-exclusion). It fires
  with or without `open`, so it also works as a plain notification.

Implemented as `ControlledModalOpenScope`, which overrides the chat
configuration context for the subtree, rather than as a fourth mode
inside CopilotChatConfigurationProvider's modal-state resolution. The
provider's own state, parent sync, drawer mutual-exclusion and
modal-closer registry are untouched: the wrapped setter still calls the
underlying one, so those side effects keep running, and it registers
itself as the modal closer so the drawer reaches the host.

The props travel to the views by context, not through the memoized
`chatView` override. Threading a changing `open` through that override
would mint a new element type per toggle and remount the whole chat
subtree, which is the class of bug already fixed for popup resize.

Closes #3334
2026-09-04 15:11:41 -05:00
Benjamin Taylor 3672d007ae docs(showcase): document frontend-driven activity cards, lock the behavior with a test
Activity messages (role: "activity") already render standalone in the
transcript and are stripped from the run payload by
AbstractAgent.prepareRunAgentInput, so frontend code can put a card in the
chat without a tool call and without polluting the conversation. That was
only ever documented for backend-emitted activities, so the frontend-driven
path was undiscoverable — issue #3388 asked for a feature that already ships.

Adds a Generative UI guide page for the pattern and a react-core test that
pins both halves of the contract: the card renders, and it never reaches the
agent.

The non-obvious part, and the reason this needs documenting rather than a
one-line answer: the card must be added via the agent from useAgent(). An
agent instance constructed and held outside React is not the instance the
chat renders, so messages added to it silently never appear.

Refs #3388

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 15:05:30 -05:00
Benjamin Taylor b5a6d05ae9 fix(react-core): restore code block line breaks in packaged CSS (#3330)
Fenced code blocks rendered as a single collapsed line in the packaged v2
UI. streamdown emits one <span> per source line inside
`pre[data-streamdown="code-block-body"] > code` and leaves no newline in
the text, so the line break comes entirely from the raw Tailwind utility
`block` on that span. CopilotKit builds Tailwind with `prefix(cpk)`, so
`.block` never reaches `dist/v2/index.css` and every line ran inline.

Scope the display rule structurally, because the line spans carry no
`data-streamdown` attribute of their own.

Adding `whitespace-pre` to the <pre>, as earlier attempts did, changes
nothing: the UA stylesheet already sets `white-space: pre` there and
there are no newlines left to preserve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 14:57:50 -05:00
Murat Sari 96cf7aa55f Angular demo and Storybook fixes (#6901)
Gets the Angular demo and Storybook running again. Both were broken on
`main`.

Also makes `provideCopilotKit(config = {})` optional — widening only.

## Verification

Both boot clean, previously failing stories render with an empty
console.
`check-types` passes, Angular tests.

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] "Allow edits by maintainers" is checked

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Angular integrations can now be initialized without providing
configuration options.
- Added reusable chat-state behavior for Angular Storybook examples,
including input handling and message submission.

- **Improvements**
- Updated Angular Storybook examples with streamlined application
configuration and more consistent chat component setup.
- Refined TypeScript project scope for the Storybook preview
configuration.

- **Examples**
- Added web-inspector support to the Angular demo and Storybook
environments.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 21:55:08 +02:00
Murat Sari 51f1f0f09a chore(examples): declare the web-inspector dependency in the angular demo and storybook fixes 2026-09-04 21:48:27 +02:00
Benjamin Taylor 9dea76ca81 fix(runtime): type the pino mock so the logger test typechecks
`tsc --noEmit` rejected reading `calls[0]` off an untyped `vi.fn()`,
whose call tuple is empty: TS2493. Give the mock pino's own
(options, stream) signature so the tuple carries real element types,
and drop the cast that was hiding it.
2026-09-04 13:58:46 -05:00
Benjamin Taylor cb8814c7ce fix(react-textarea): stop Cmd+K insert from deleting adjacent text
The Cmd+K hovering editor deleted the selection and then reused the same
`selection` range to insert:

    Transforms.delete(editor, { at: selection });
    Transforms.insertText(editor, insertedText, { at: selection });

The range is stale after the delete, and `Transforms.insertText` deletes
an expanded range itself before inserting, so the second delete ran at
the same offsets in the already-shortened document and ate the
characters that followed the insertion point. With a collapsed caret it
was worse: `Transforms.delete` resolves a collapsed range to a point and
deletes one character forward, so a plain insert always destroyed the
character after the cursor.

`Transforms.insertText` alone is correct for both cases. It deletes an
expanded range through point refs and inserts at its start, and it
inserts in place when the range is collapsed.

Closes #2192
2026-09-04 13:51:08 -05:00
Benjamin Taylor 1ad6b6fc79 fix(runtime): build the logger without pino redact so edge runtimes work
pino 9 validates every `redact.paths` entry by calling `Function(...)`
through fast-redact. Cloudflare Workers and other edge runtimes forbid
code generation from strings, so the runtime threw while building its
logger. The validator swallows the real EvalError and blames the first
path in the array, which made the failure read as "redact paths array
contains an invalid path (pid)" and sent earlier triage after `pid`
itself. Every path fails, not just `pid`.

`base: null` is pino's own switch for omitting `pid` and `hostname`, it
produces identical output, and it needs no code generation.

Closes #2355

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 13:47:53 -05:00
Mike Ryan 37703eb083 Support Intelligence over the single Runtime route (#6896)
## Summary

- carry Intelligence thread, memory, and annotation requests through the
single Runtime endpoint
- advertise the bridge through an optional Runtime info capability
- reuse the existing REST route matcher, handlers, method checks, hooks,
and memory gate
- route Core memory and React annotation calls through the negotiated
Runtime fetch
- make single-route the documented Intelligence quickstart while keeping
multi-route supported

## Compatibility

- Multi-route behavior does not change.
- A new client uses the bridge only when a single-route Runtime
advertises it.
- An old client ignores the new optional capability.
- A new client keeps the old behavior with a Runtime that does not
advertise the capability.

## Validation

- `pnpm nx run-many -t check-types,build
--projects=@copilotkit/shared,@copilotkit/core,@copilotkit/runtime,@copilotkit/react-core`
- package pre-commit gate: tests, `publint`, and `attw` passed for all
affected packages
- Runtime focused suite: 102 tests passed
- Core focused suite: 108 tests passed
- React focused suite: 53 tests passed
- React full suite: 1,591 Vitest tests and 47 script tests passed
- Angular and React memory tests: 18 tests passed
- docs type-check and production build passed
- changed docs contract tests: 33 tests passed

## Local baseline notes

The full docs test command also reads Git LFS images and generated
cross-framework fixtures. It has six unrelated failures in this
checkout: three image-pointer checks, two Angular content checks, and
one Mastra content check. The changed docs tests pass, and the docs
production build passes.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added single-route support for thread, memory, and annotation
operations.
- Runtime capability discovery now advertises single-route resource
support.
- Resource requests preserve paths, query parameters, headers, methods,
and request bodies.
- Memory and annotation operations consistently use the configured
runtime transport.

- **Documentation**
- Updated setup guides for single-route configuration, capability
negotiation, and compatibility.
  - Added guidance for single-route LangGraph deployments.

- **Tests**
- Added coverage for transport behavior, validation, resource
operations, and error handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 11:33:44 -07:00
Tyler Slaton ecf4cfe873 docs: document Intelligence Learning (#6897)
## Summary

- Adds a comprehensive Learning guide under Agent capabilities.
- Embeds the product walkthrough and documents setup, review, and Skill
publishing.
- Makes Learning discoverable from the Intelligence overview and docs
navigation.

## Why

Learning needs a clear, human-readable guide that explains how real
Threads become reviewed, reusable Skills without mixing in the separate
Memory workflow.

## How

- Explains the Learning lifecycle in plain language.
- Walks through connecting Intelligence, creating a container, routing
Threads, collecting examples, reviewing results, and downloading
published Skills.
- Keeps Memory documentation separate; that work is tracked in [Memory
documentation PR
#6854](https://github.com/CopilotKit/CopilotKit/pull/6854).
- Adds navigation, Intelligence landing-page coverage, and regression
tests.
- Verified with the shell-docs build and typecheck, 37 focused tests,
and local visual QA.
2026-09-04 20:09:21 +02:00
Tyler Slaton e1a6225afc docs: streamline Learning workflow explanation 2026-09-04 20:09:01 +02:00
Tyler Slaton b0035f2b78 docs: simplify Intelligence Learning guide 2026-09-04 20:09:01 +02:00
Tyler Slaton ff3dbd2922 docs: clarify Intelligence Learning guide 2026-09-04 20:09:01 +02:00
Tyler Slaton f08ff8e926 docs: document Intelligence Learning 2026-09-04 20:09:01 +02:00
Tyler Slaton df104edff4 docs(intelligence): document Memories and recall (#6854)
## Why

Memories ships and is entitlement-gated, but has no conceptual or
activation
documentation on the public site.

The only existing coverage is the Angular headless guide, which shows
`injectMemories` without explaining what a memory is, and the Angular
public API
reference. There is nothing for React, nothing on the three kinds or the
scope
model, and nothing on what a deployment needs before the memory surfaces
exist
at all.

That last gap is the expensive one. A self-hosted operator reasonably
looks for
a `memory.enabled` value or a `MEMORY_ENABLED` variable, finds neither,
and has
no way to discover that access is granted by entitlement and that the
embedder
must be configured separately at startup. This is an initial pass at
closing
that, offered ahead of the planned docs work rather than instead of it.

## What the page covers

An explanation page at `/intelligence/memories`, following the structure
and
voice of `threads-explained.mdx`:

- What a memory is, and how it differs from a thread in lifetime and
purpose
- The three kinds (`topical`, `episodic`, `operational`), and that dedup
and
  supersession are same-kind operations, so the kind is not cosmetic
- `user` and `project` scope, with `user` as the platform default
- That saving a near-duplicate absorbs it into the existing memory
rather than
  creating a second one
- That update is a supersede and a **full replacement**, including that
omitting
  `sourceThreadIds` resets rather than preserves them
- That removal retires rather than erases
- Activation: entitlement for self-hosted and managed, the four embedder
variables, the fail-loud startup behaviour, the pgvector requirement,
the
  bundled in-cluster embedder and the external-provider switch
- That changing the embedding model changes the vector space, so it is a
  migration rather than a config change
- The React (`useMemories`), REST, and MCP surfaces

## Validation

Every claim is taken from the implementation, not from intent. Notably:

- Activation is resolved through the license/entitlement checker,
fail-closed,
  and `memory` ships in the enterprise plan
- The embedder variables, the mandatory 1024 dimensions, and app-api's
refusal
  to start without valid configuration
- Route list, request limits (`content` 8192 chars, `sourceThreadIds`
100
entries, recall `limit` default 5 capped at 20), strict rejection of
unknown
fields, and the exact response shape (`id`, `kind`, `scope`, `content`,
`sourceThreadIds`, plus `score` on recall and `invalidatedAt` on the
list)
- `useMemories` semantics for `isAvailable` and `realtimeStatus`, and
the
supersede and retire behaviour, which match what the Angular guide
already
  documents

Checks run:

- `npm run pretypecheck` in `showcase/shell-docs`; the page indexes as
  "Memories & Recall" under the Intelligence section at
  `/docs/intelligence/memories`
- Pre-commit `check-intelligence-env-names` passes, which independently
confirms
  the documented environment variable names are canonical
- All in-page links point at paths already used elsewhere in the docs. I
deliberately did not link a generated `injectMemories` reference URL,
since no
such page exists in content; the Angular guide and public API reference
are
  linked instead

## Notes for review

- I used `feature="learning"` on `IntelligenceOnboardingPrompt`, because
the
component's feature union is `"learning" | "threads"` and adding a third
value
felt out of scope for a docs change. Happy to add `"memories"` if you
would
  rather it read that way.
- The Inspector memory surface is deliberately not described, only
referenced,
  since that UX is changing.
- Nothing in the existing Angular guide is contradicted; where we
overlap, the
  wording agrees.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Added documentation for the Memories & Recall feature, including
memory types, scopes, recall behavior, updates, and removal.
* Documented activation requirements and configuration for managed and
self-hosted deployments.
* Added guidance for using memories with React, Angular, REST, and MCP
integrations.
* Added the Memories page to the Intelligence documentation navigation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-04 20:08:38 +02:00
Mike Ryan c34f7abfc1 fix(runtime): retain resource context on method errors 2026-09-04 10:49:22 -07:00
Mike Ryan c276befc13 fix(runtime): harden single-route resource requests 2026-09-04 10:39:10 -07:00