5522 Commits

Author SHA1 Message Date
Ben Taylor b0077511bd docs(built-in-agent): mention Novita in OpenAI-compatible providers list (#6502)
## What does this PR do?

Adds Novita to the list of OpenAI-compatible providers documented for
the built-in agent's model selection, alongside OpenRouter, Ollama,
Together, and Groq. Novita exposes an OpenAI-compatible `/openai/v1`
endpoint, so it works through the existing `createOpenAI({ baseURL })`
pattern already documented for those providers.

A follow-up commit adds a callout clarifying that Novita only implements
the Chat Completions endpoint, not Responses — so readers should call
`provider.chat(model)` rather than the bare `provider(model)` form shown
in the adjacent OpenRouter example, which routes through Responses and
would error on Novita's endpoint.

## Related PRs and Issues

- None

## Verification

- `npm run typecheck` — pass
- `npm run test` — 55/55 files, 374/374 tests pass
- `npm run build` — Next.js production build succeeded, 222/222 static
pages generated
- Live verification: called Novita's OpenAI-compatible endpoint via
`createOpenAI({ baseURL }).chat(model)` with model
`deepseek/deepseek-v4-pro-0813` — HTTP 200, finish reason `stop`, usage
populated

## 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
- [ ] "Allow edits by maintainers" is checked
2026-08-30 15:06:48 -05:00
Ben Taylor 2fd9cf72c1 docs(shell-docs): fix broken Action Handlers link in a2ui fixed-schema page (#6764)
The "Advanced — Action Handlers" link pointed to
`./advanced#action-handlers`, but there is no `advanced.mdx` page in
`docs/generative-ui/a2ui/`. The "Action handlers (reference)" section
lives in this same file, so the link now points to it directly with
`#action-handlers-reference`.
2026-08-29 21:15:33 -05:00
Ben Taylor a68fd0b253 fix(showcase/harness): re-auth on 403 from an expired PocketBase token (#6466)
## Root cause

The harness's PocketBase client
(`showcase/harness/src/storage/pb-client.ts`) re-authenticated its
superuser token **only on HTTP 401**. But when the superuser/admin auth
token's ~14-day TTL expires, PocketBase does **not** return 401 — it
treats the request as an unauthenticated *guest* and returns:

```
HTTP 403 {"code":403,"message":"Only admins can perform this action.","data":{}}
```

on every write. Because 403 was never treated as an auth-expiry signal,
the expired token was never refreshed, so **all `status` writes failed
permanently** until the process restarted. `classifyWriterError` maps
403 → `pb_permission` (a terminal reason), so the failure looked like a
permission problem rather than an expired session. This is what blanked
the dashboard for ~46h.

## The fix

In `request()`, treat a 403 as the same stale-session signal as a 401 —
**but only when the request actually carried an `Authorization` header**
(`sentAuth`). A 403 on a request that sent no token is a genuine
guest-forbidden result that re-auth cannot fix, so it is left to
surface.

- The retry stays bounded by `MAX_AUTH_RETRIES` (1). A 403 that
**persists after a fresh, successful re-auth** is a real permission
error and falls through to the caller (still classified `pb_permission`)
— never an infinite re-auth loop.
- No change to the 401 path, the retry envelope, or any other status
class.

```
(res.status === 401 || (res.status === 403 && sentAuth)) &&
authRetries < MAX_AUTH_RETRIES && attempts < maxAttempts
```

## Local red-green proof (real PocketBase, real client — not a fake)

Stood up a live **PocketBase v0.22.21** (the pinned version) locally,
created an admin + a superuser-gated `status` collection, and set
`adminAuthToken.duration = 5` (5s — the server's minimum). A temporary
driver drove the **real `createPbClient`** against it: write #1 caches a
token, sleep 6.5s so the cached token **genuinely expires**, then write
#2.

First confirmed the raw failure surface — an expired admin token on a
write:

```
EXPIRED-token write status + body:
{"code":403,"message":"Only admins can perform this action.","data":{}}
HTTP 403
```

### RED (unmodified code)

```
[driver] write#1 OK id=setjh0ca1s09s14 — token now cached
[driver] sleeping 6.5s for the cached admin token to expire...
CVDIAG component=pb-client:create:status ... status=error error=status=403 {"code":403,"message":"Only admins can perform this action.","data":{}}
[driver] RED: write#2 FAILED after expiry: Error: pb create failed: 403 {"code":403,"message":"Only admins can perform this action.","data":{}}
EXIT=1
```

The expired token 403s, **no re-auth occurs**, the write stays failed.

### GREEN (with this fix)

```
[driver] write#1 OK id=tkl59dt5d3xt11g — token now cached
[driver] sleeping 6.5s for the cached admin token to expire...
[driver] GREEN: write#2 SUCCEEDED after expiry id=uns9y2dgysynpwz
EXIT=0
```

Same repro, same expired token: the 403 now triggers re-auth, the write
is retried once and **succeeds**.

## Regression tests

Added three tests to `pb-client.test.ts`:

1. `re-auths on 403 (expired superuser token treated as guest) then
retries the write` — 403-with-token → re-auth → retry succeeds (2 auths,
2 writes).
2. `caps 403 re-auth at 1 — a 403 that persists after a fresh auth
surfaces (no infinite loop)` — bounded; the persistent 403 surfaces (2
auths, 2 writes, then throws).
3. `does NOT re-auth on 403 when no credentials were sent (genuine
guest-forbidden)` — no token → no re-auth, no retry (0 auths, 1 write).

**Mutation check:** reverting the fix (403 branch removed) makes tests 1
and 2 fail while test 3 still passes — the tests are structurally able
to detect the fix.

## Code-review hardening (Tier-3 cr-loop)

A full-breadth review of the re-auth branch surfaced two additional
load-bearing issues in the exact code this PR modifies; both fixed here
with their own red-green + individual mutation checks:

- **Drain the response body on the re-auth path.** The 401/403 re-auth
branch did `continue` without draining the prior failed response —
unlike the 429/5xx branches, which call `drainBody()` — leaking a
half-consumed socket on every token refresh (F2.3 socket-reuse
discipline). `drainBody` was hoisted above the branch and invoked before
the retry.
- RED: `failed401.bodyUsed` = `false` (undrained). GREEN: body drained
after the fix.
- **Bound the re-auth gate by `attempts < maxAttempts`.** The re-auth
gate checked only `authRetries`, not `attempts` (the 429/5xx gates check
both), so a token expiring on the final attempt could fire a 4th
`fetchImpl`, exceeding the documented `maxAttempts = 3` envelope. Added
the guard for consistency.
- RED: `expected 4 to be 3` (4th fetch fired). GREEN: `writeCount ===
3`.

Full `pb-client.test.ts` suite: **35 passed**. CI green.

## Follow-ups (out of scope for this PR — pre-existing, tracked
separately)

The review confirmed the fix is sound and found no defect in it, but
flagged pre-existing issues in the same file that predate this change
and belong in their own PRs:

- **Observability regression (HF13-B1):** `create()`'s CVDIAG "every
record write failure is greppable" log is unreachable for
retry-exhausted 429/5xx writes, because `request()` now throws
`PbHttpError` before `create()`'s `!res.ok` block runs. (403 writes are
unaffected — they reach the log.)
- **Auth re-auth stampede:** `ensureAuth()` has no single-flight guard,
so at token expiry every concurrent writer re-auths independently.
Fixing this (coalesce concurrent re-auths behind one shared in-flight
promise) benefits both the 401 and 403 paths.
- **401 `sentAuth` symmetry (trivial):** the 401 re-auth path lacks the
`sentAuth` guard the new 403 path has, wasting one bounded attempt when
no credentials are configured.
- **`deleteByFilter` off-by-one:** the iteration cap throws on a
fully-successful delete of exactly a multiple-of-200 ≥ 20000 rows.
- **Inert `RETRY_AFTER_MAX_MS` cap + its mutation-blind test.**
2026-08-29 16:08:16 -05:00
Benjamin Taylor 0b021ba32e docs(langgraph): fix crossed hook names in coagent troubleshooting accordions
The two "agent name" accordions on the LangGraph troubleshooting page each
carried the other one's hook name, so a reader debugging "agent not found"
got contradictory guidance:

- The accordion titled `useCoAgent` showed a `useAgent({ agentId })` sample.
- The accordion titled `useCoAgentStateRender` told the reader to check
  "the `useAgent` hook" while showing a `useCoAgentStateRender({ name })`
  sample.

Align each accordion's title and prose with the hook its code sample actually
uses, and name the specific prop to match — `agentId` for `useAgent`, `name`
for `useCoAgentStateRender` — since the differing prop name is the actual
gotcha. Also fixes the "the that" and "use n" typos on those two lines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 16:07:15 -05:00
Ben Taylor 415aa9af74 docs: fix typo in coagent troubleshooting (#6787)
Fix duplicate the/typo n -> in.
2026-08-29 16:05:43 -05:00
一片一片 3555b4a48e Merge branch 'main' into docs/fix-a2ui-action-handlers-link 2026-08-29 18:43:17 +08:00
deepshekhardas 6ff101e7c0 docs: fix typo in coagent troubleshooting 2026-08-29 11:29:05 +05:30
deepshekhardas 93248cf95f docs: fix GitHub branding and hyphenation in troubleshooting 2026-08-29 11:28:28 +05:30
Ben Taylor db6d885021 docs(shell-docs): fix broken Fixed Schema (Streaming) link (#6733)
The A2UI overview pages for both the DeepAgents and LangGraph
integrations link to ./fixed-schema-streaming, but that file does not
exist (only dvanced, dynamic-schema, ixed-schema, index, styling
exist). Point both links to the existing ./fixed-schema page.
2026-08-28 22:12:45 -05:00
gdut4140 1ef61717b8 docs(shell-docs): point Action Handlers link at the LangGraph advanced page 2026-08-29 11:06:54 +08:00
Mike Ryan 64181a34b9 feat(docs): add Intelligence onboarding prompts (#6779)
## Summary

- replace the homepage Channels activation block with an Intelligence
onboarding prompt focused on Learning
- place the same onboarding prompt across framework quickstarts, with
feature-specific copy for Learning and Rich Threads
- generate the CLI run ID only when the prompt is copied and record
successful copies in PostHog
- use existing local Lucide icons with no additional package or external
font dependency

## Experiment

The CTA uses one canonical agentic onboarding prompt everywhere while
changing the product promise by surface. Learning placements explain
Rich Threads, Learning, and support for new or existing agents. Threads
placements focus on persistent conversations.

Successful copies emit `docs.intelligence_onboarding_prompt_copied` with
`feature`, `from_path`, `run_id`, and `surface`. The same `run_id` is
embedded in the copied CLI command.

## Validation

- `pnpm exec oxfmt --check` on changed TypeScript files
- `npm run lint` in `showcase/shell-docs` (no errors; existing warnings
remain)
- `npm run typecheck` in `showcase/shell-docs`
- `vitest run src/lib/__tests__/inspector-docs.test.ts --maxWorkers=1`
(10/10 passed)
- memory-capped `npm run build` in `showcase/shell-docs`
- manual desktop, mobile, light-mode, and dark-mode checks on `/`,
`/threads`, and a framework quickstart

The full Shell Docs test command currently also reports failures
unrelated to this change, including unhydrated Git LFS image fixtures
and generated-doc baselines on current `main`. The affected Inspector
docs test passes independently.
2026-08-28 15:21:19 -07:00
Ben Taylor c8ffcd5353 docs(vue): document threads and the threads drawer for Vue (#6775)
Vue ships CopilotThreadsDrawer and useThreads but no page documents
them, so an integration guide that needs to name a Vue threads page has
nothing to cite. Adds the guide, modelled on the Angular one.

Needed by CopilotKit/Intelligence OSS-1033, whose conversion leg cites
this URL.

## Notes

Corrected against the source while writing this
(`packages/vue/src/v2/components/chat/CopilotThreadsDrawer.vue`,
`packages/vue/src/v2/hooks/use-threads.ts`):
- The "drawer + chat as bare siblings" example in the draft would not
actually sync selection to the chat — `CopilotThreadsDrawer` only calls
`config.value?.setActiveThreadId(...)` when a
`CopilotChatConfigurationProvider` ancestor exists; a sibling
`CopilotChat` provides its own config internally, which a sibling drawer
can't see. Wrapped both in a shared `CopilotChatConfigurationProvider`,
matching how the Angular guide documents the same pattern.
- `Thread.name` is `string | null`, not `title`; fixed the headless
example to use `name` with a fallback for `null`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-28 17:19:06 -05:00
Sam Julien 59a9279cdf fix(docs): balance Intelligence CTA columns 2026-08-28 14:24:23 -07:00
Sam Julien b10f6e7299 feat(docs): add Intelligence onboarding prompts 2026-08-28 14:19:10 -07:00
Ben Taylor 3409035d5a docs(vue): teach useComponent in the generative-UI guide (closes OSS-1037) (#6776)
## Correcting the ticket first

OSS-1037 was filed on a wrong diagnosis, mine. It said the Vue
generative-UI guide was unreachable because of a routing defect. It is
not:

```
docs.staging.copilotkit.ai/vue/guides/generative-ui.md   200
docs.copilotkit.ai/vue/guides/generative-ui.md           404
```

The page is merged, built, and live on staging. `showcase_promote.yml`
is `workflow_dispatch` only — *"Humans trigger. No automatic prod
promotes."* — so prod is simply behind. The same is true of
`pydantic-ai/agent-app-context.md` (added 08-28, also 404 on prod, 200
on staging), while pages from 08-24 are live. Nothing about Vue is
broken, and there is nothing here to "publish".

So this PR does the one thing that *was* actually wrong with the guide.

## What was wrong

`@copilotkit/vue/v2` exports its own `useComponent` — a Vue-native
composable, not the React one — and the guide never named it. Not in the
path table, not in the body, not in the closing reference list.

Its path table sent "your components" to `useRenderTool`, or
`useFrontendTool` with a `render`. Both work, and both ask the reader
for more than the display-only case needs: the agent shows a component
and nothing else runs. It is also the case the onboarding graph now
tells a Vue run to reach for, so a developer arriving at this guide
afterwards would not find the hook they had just been told to use.

## What changed

- A path-table row for the case: **A component the agent shows** →
`useComponent`. The existing row is re-scoped to what it is actually for
— the agent already owns the tool and you draw its call.
- A **Let the agent display a component** section, placed before the
server-side section because it is the shorter path. Vue SFC component
plus registration, with the schema arriving as props.
- A callout answering the question a reader will have — `useComponent`
or `useRenderTool`? The give-away is where the tool lives: if removing
the component would remove the tool from the agent's list, it is a
`useComponent`.
- The grounding warning. The model fills these props from what it knows,
so a card rendered over records the application does not hold looks
identical in a browser, a screenshot and a video to a correct one.
Points at `useAgentContext`.
- `useComponent` added to **Next steps**.

Every URL the new section cites was probed and returns 200:
`reference/vue/hooks/useComponent`,
`reference/vue/hooks/useAgentContext`,
`reference/vue/hooks/useRenderTool`.

## Testing

New `vue-generative-ui-docs.test.ts`, written first and confirmed red
(`expected '---\ntitle: Generative UI in Vue…' to contain
'useComponent'`). It asserts against the raw source, the loaded doc, and
the rendered llm-text, following `deepagents-interrupt-docs.test.ts`,
and separately asserts that a **path-table row** names the composable —
naming it only in prose would leave the table still recommending the
longer route for the simpler job.

`showcase/shell-docs`: 68/70 files, 487 tests pass. The 2 failures are
pre-existing on `main` and read files this branch does not touch — a
shared inspector snippet that says "Playground", and mastra
tool-rendering content.

Closes OSS-1037

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-28 15:39:13 -05:00
Ben Taylor 7f651dc62f docs(showcase): state the frontend-tool requirement per framework (refs OSS-1036) (#6777)
## Why

OSS-1034 makes `/<framework>/generative-ui/tool-based.md` the terminal
page every onboarding run fetches, on all 19 framework routes. That
page's `## How it works in code` section is a bundled
`frontend-tools-setup` concept, and only **5 of 19** frameworks shipped
one.

Where the concept is unbundled, `FrameworkSetup` returns `null` and the
section renders nothing. Absence encoded two different facts and nothing
separated them:

- this framework needs no agent-side wiring, or
- it needs some and nobody wrote it down.

For the 5 that had a snippet, the requirement is substantial and
load-bearing — ADK's `AGUIToolset()` in the `tools=` list, LangGraph's
`CopilotKitMiddleware` / `CopilotKitStateAnnotation`, Claude SDK's
Messages-API tool conversion. So "nobody wrote it down" was a live
possibility for the other 14, not a theoretical one.

## Coverage: 6 → 10 of 19

Four frameworks whose own `gen-ui-tool-based` demo agent settles the
question. I used the demo agents as the evidence rather than the docs,
because the demos are the thing that actually runs.

**Nothing to wire** — `pydantic-ai`, `llamaindex`, `ms-agent-python`.
Their demo agents declare no tools at all and say why in as many words:

> *"CopilotKit's runtime injects those tool definitions into the agent
request at runtime, so the agent does not need to declare them locally —
PydanticAI's AG-UI bridge surfaces frontend-registered tools to the
model on each run."*
> — `showcase/integrations/pydantic-ai/src/agents/gen_ui_tool_based.py`

Their snippets say that, and then say the half that is easy to miss:
**the tool arriving is not the same as the model calling it.** Every one
of those demo agents carries a `SYSTEM_PROMPT` naming the tool. Omit it
and the agent answers in prose while the component never renders — which
looks like a broken integration and is not one.

**Real wiring** — `crewai-crews`. The opposite case, and the one the
silence was hiding. A Flow owns its own model call, so the forwarded
tools do not reach the model unless the Flow passes them: read
`state.copilotkit.actions`, hand them over as `tools=`, wrap in
`copilotkit_stream` so the call reaches the browser as it streams, and
drive `tool_choice`. Its own demo comments on why:

> *"Force the chart on the user's turn. Once the browser has returned
the render result the follow-up is plain narration, so leaving this on
'auto' is what ends the run."*

I did **not** write snippets for the nine I could not establish from
source. Guessing "nothing is required" into the docs is worse than the
silence it replaces.

## A compile failure is no longer silent

```ts
// before — both states returned null
if (source === null) return null;          // nobody bundled it: deliberate
} catch (err) { console.error(...); return null; }  // bundled and broken: a defect
```

A snippet that fails to compile shipped looking exactly like a framework
with no requirement, and the only trace was a `console.error` nobody
reads in production. Absence stays quiet; a broken snippet now throws.
This is the shape `llm-text.ts` already refuses for
`channels-agent-setup`.

## The remaining nine are named, not silent

`frontend-tools-setup-coverage.test.ts` holds
`REQUIREMENT_NOT_ESTABLISHED` — `ag2`, `agno`, `built-in-agent`,
`deepagents`, `mastra`, `ms-agent-dotnet`, `ms-agent-harness-dotnet`,
`strands`, `strands-typescript`. Two tests bind it in both directions: a
framework serving the page with no snippet and no listing fails, and a
listed framework that has since been documented fails until its name is
removed. So a new framework cannot join the gap quietly, and closing one
is a deletion.

That test earned its keep immediately — it caught that I had written
`aws-strands` (the docs folder) where the registry slug is `strands`.

A third test asserts the two snippet shapes stay distinguishable, so a
future edit cannot quietly turn the CrewAI wiring into a "nothing
required" note.

## Testing

- `setup-concept.test.ts` — 2 new tests, the compile-failure one
confirmed red before the fix.
- `frontend-tools-setup-coverage.test.ts` — 3 new tests.
- `showcase/shell-docs`: 487 tests pass. The 2 failures are pre-existing
on `main` and read files this branch does not touch.
- Formatting: my files pass `oxfmt`. The two `claude-sdk-*` snippets it
also flags are pre-existing and untouched here.

## Not done

The nine frameworks above. Each needs its AG-UI adapter and demo agent
read, then a snippet — including where the honest content is "nothing is
required". Left on OSS-1036.

Refs OSS-1036

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-28 15:35:01 -05:00
Benjamin Taylor fb2162f286 docs(showcase): state the frontend-tool requirement per framework
`generative-ui/tool-based` is now the terminal page every onboarding run fetches
(OSS-1034), and its "How it works in code" section is a bundled
`frontend-tools-setup` concept. Only 5 of 19 frameworks shipped one, so for the
rest the section rendered nothing and absence encoded two different facts: this
framework needs no agent-side wiring, or it needs some and nobody wrote it down.

Four frameworks whose own gen-ui-tool-based demo agent settles the question get
a snippet. pydantic-ai, llamaindex and ms-agent-python declare no tools at all --
the AG-UI request forwards them and their demo agents say so in as many words --
so their snippet states that, and then states the half that is easy to miss: a
model with no instruction about the tool answers in prose and the component never
renders. CrewAI is the opposite case. A Flow owns its own model call, so it has
to read `state.copilotkit.actions` and pass them itself, wrap the call in
`copilotkit_stream`, and drive `tool_choice`.

A compile failure in a bundled snippet no longer returns null. It shared that
return with "nobody bundled this", so a rendering defect shipped looking exactly
like a deliberate omission, traceable only through a console.error nobody reads
in production. Absence stays quiet; a broken snippet throws.

The nine frameworks still undetermined are named in a list a test reads, so a new
framework cannot join the gap silently and closing one means deleting a name.

Refs OSS-1036

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 15:25:12 -05:00
Benjamin Taylor c2b6078666 docs(vue): teach useComponent in the generative-UI guide
`@copilotkit/vue/v2` exports its own `useComponent`, and the guide never named
it. Its path table sent the display-only case -- the agent shows a component and
nothing else runs -- to `useRenderTool` or `useFrontendTool` with a `render`,
both of which ask the reader for more than that case needs, and neither of which
is what the onboarding graph now tells a Vue run to reach for.

The guide gains a row for the case, a section that teaches the composable, and
the distinction that decides between the two: `useComponent` declares the tool
from the frontend, `useRenderTool` draws a tool the agent already owns. It also
carries the grounding warning, because a card rendered over records the
application does not hold looks the same in a browser as a correct one.

Refs OSS-1037

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 15:23:07 -05:00
Benjamin Taylor 9f4487ac39 docs(vue): describe the threads drawer's license gate accurately 2026-08-28 15:16:03 -05:00
Benjamin Taylor c0efad9207 docs(vue): document threads and the threads drawer for Vue 2026-08-28 15:08:26 -05:00
Benjamin Taylor b92821a03c feat(angular): add registerComponent so a component can be a tool the agent calls
Angular had no counterpart to `useComponent` in react-core and vue, so the only
way to let an agent display one of your components was `registerFrontendTool`
with a handler the component does not need, or `registerRenderToolCall`, which
requires the tool to already exist in the agent.

`FrontendToolConfig.handler` becomes optional, and `#bindClientTool` returns the
config unwrapped when it is absent. Core already has the render-only path: a tool
declaring no handler gets an empty tool result and completes the turn. Binding a
wrapper regardless called `undefined` on the first tool call, and a stub handler
would write a fabricated result into the thread instead.

`registerComponent` is that shape with the model-facing description built for it,
identical to the one react-core and vue build, so the tool reads the same to the
model whichever frontend registered the component. The component stays an
ordinary `ToolRenderer` reading `toolCall().args`.

The tool is declared by the frontend and forwarded over AG-UI, so a display-only
component needs nothing added to the agent, on any framework.

Refs OSS-1034

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 15:05:08 -05:00
copilotkit-qa-bot ed9da2e369 fix(showcase): restore AIMessage runtime import 2026-08-28 12:50:05 -07:00
github-actions[bot] 4574e7ea03 style: auto-fix formatting 2026-08-28 19:17:14 +00:00
copilotkit-qa-bot 2238c9d56d Keep LangGraph TypeScript docs on public model APIs 2026-08-28 12:14:47 -07:00
Aswin Kumar 99d349c6cd Merge branch 'main' into fix/angular-hitl-result-envelope 2026-08-29 00:41:13 +05:30
Ben Taylor d692f25852 feat(runtime): expose Learning Container selector (#6767)
## What does this PR do?

Adds `getLearningContainerId` to `CopilotKitIntelligence` so developers
can assign Intelligence Threads to Learning Containers without a
theta-prefixed Runtime option.

The selector receives:

- The resolved application `user`.
- The parsed AG-UI `input` for the run.
- The `agentId` and the `web` or `channel` surface.

Web runs pass the exact parsed `RunAgentInput`. Channel runs build the
same canonical input that the AgentRunner receives. Channels also carry
the resolved application user through the core and Intelligence adapter
boundaries.

The Runtime validates the selected stable ID and sends only that ID with
the existing Thread create or lock call. Intelligence stays responsible
for project scope, entitlements, Container lookup, and the one-time
Thread binding. Persisted AG-UI events remain the source for Learning
snapshots.

The old `ɵlearning` Runtime option remains as a deprecated fallback. The
Runtime rejects configurations that set both APIs.

## Why?

Learning Container assignment is an Intelligence SDK concern. Developers
also need the resolved user and complete run input to select a Container
from application data without reading raw transport details.

## Related PRs and Issues

- Refs
[ENT-1149](https://linear.app/copilotkit/issue/ENT-1149/enable-projects-to-learn-from-agent-runs-and-publish-reusable-skills)
- Related design: #6746

## Validation

- GitHub CI: 53 passed, 3 skipped
- `pnpm nx run-many -t test,check-types,build -p @copilotkit/runtime
@copilotkit/channels-core @copilotkit/channels-intelligence`
- `pnpm nx run-many -t publint,attw,check-dts -p @copilotkit/runtime
@copilotkit/channels-core @copilotkit/channels-intelligence`
- `pnpm lint` (0 errors; existing warnings remain)
- `npm run typecheck` and `npm run build` in `showcase/shell-docs`
- `npm test` in `showcase/shell-docs` has one pre-existing failure at
`inspector-docs.test.ts:141`: the tracked Threads callout contains
`Playground`.

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] Maintainer edits are available because this PR uses a branch in
the main repository
2026-08-28 13:02:10 -05:00
Ben Taylor 28c5208596 docs: document reading AG-UI context in a Pydantic AI agent (#6768)
## Problem

Pydantic AI's AG-UI adapter reads `messages`, `tools`, `state`,
`thread_id` and `resume` off `RunAgentInput`, and nothing else.
`context` — the field `useAgentContext` travels on — is never passed to
the agent.

Nothing errors when it is dropped. There is no warning and no console
message, so an agent that received none of the page's entries still
answers confidently about them. A developer who wires `useAgentContext`
against a Pydantic AI agent gets a well-formed answer about data the
agent never had.

Verified against `pydantic-ai-slim` 2.33.0 and current upstream `main`:
zero references to `run_input.context` across all nine modules in
`pydantic_ai/ui/ag_ui/`.

## Why there was no page

The omission is deliberate upstream, not a bug.
[pydantic/pydantic-ai#7105](https://github.com/pydantic/pydantic-ai/issues/7105)
was closed as completed by
[#7106](https://github.com/pydantic/pydantic-ai/pull/7106): `run_input`
is public, so `adapter.run_input.context` has always worked, and
auto-injecting client-submitted text into `instructions` would let a
prompt injection inherit operator authority. Upstream documented the
route instead of adding API.

What was missing was a CopilotKit page saying any of this.
`useAgentContext`'s reference page documents the frontend hook only, and
the four existing `agent-app-context` pages cover built-in-agent,
langgraph, mastra and microsoft-agent-framework.

## What's here

`pydantic-ai/agent-app-context.mdx`, the fifth such page, wired into the
integration's App Control nav after `shared-state`.

Two details the page pins down, both verified against a running agent
rather than adapted from a sibling page:

- **`value` is a string, not your object.** `useAgentContext` calls
`JSON.stringify` before the run leaves the browser, and AG-UI types
`Context.value` as a string on both ends. `json.loads` is required, and
a shape check like `isinstance(entry.value, list)` can never pass. A
failed check is indistinguishable from context never being sent, which
is what makes this one expensive.
- **`from_request`, not `dispatch_request`.** The one-line
`AGUIAdapter.dispatch_request(request, agent=agent)` used elsewhere in
these docs parses the request internally, leaving no `run_input` to
build `deps` from. The context route needs the two-step form.

The page also carries upstream's trust rule: entries reach the model as
tool output, never as `instructions`, and facts the *server* established
are what belong in instructions.

## Verification

The documented `agent.py`, served over real HTTP with AG-UI request
bodies shaped exactly as the runtime sends them:

| Case | Result |
|---|---|
| Asks about the shared entries | Answers from them, all three
colleagues |
| Asks about someone never sent | Declines, and names exactly the three
the page did send |
| `context` arrives empty | Reports an empty list rather than inventing
one |

Suite: **480 passed / 2 failed**. Both failures (`inspector-docs`,
`llm-text` mastra tool-rendering) reproduce identically on pristine
`origin/main` content — confirmed by reverting both files and
re-running.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-28 12:52:57 -05:00
Benjamin Taylor 9acc242f34 docs: document reading AG-UI context in a Pydantic AI agent
Pydantic AI's AG-UI adapter reads `messages`, `tools`, `state`, `thread_id`
and `resume` off `RunAgentInput`, and nothing else. `context` -- the field
`useAgentContext` travels on -- is never passed to the agent, and nothing
errors when it is dropped, so an agent that received none of the page's
entries still answers confidently about them.

That omission is deliberate upstream (pydantic/pydantic-ai#7105, closed by
#7106): entries are client-submitted, so the adapter leaves it to the
application to decide what to trust, and `run_input` is public for exactly
this purpose. What was missing on our side was a CopilotKit page saying so.

Add `pydantic-ai/agent-app-context.mdx`, the fifth such page, alongside
built-in-agent, langgraph, mastra and microsoft-agent-framework, and wire it
into the integration's App Control nav.

Two details the page pins down, both verified against a running agent rather
than adapted from a sibling page:

- `useAgentContext` JSON-stringifies `value` and AG-UI types
  `Context.value` as a string on both ends, so `json.loads` is required and
  a shape check like `isinstance(entry.value, list)` can never pass.
- The one-line `AGUIAdapter.dispatch_request(request, agent=agent)` used
  elsewhere in these docs parses the request internally, leaving no
  `run_input` to build `deps` from. The page uses the two-step
  `from_request` form instead.

The page also carries upstream's trust rule: entries reach the model as tool
output, never as `instructions`, so a prompt injection cannot inherit
operator authority.

Verified: the documented `agent.py` served over HTTP answers from the shared
entries, names exactly what the page did send when asked about a colleague it
did not, and reports an empty list when `context` arrives empty. Suite is
480 passed / 2 failed, both failures identical on pristine origin/main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 12:27:36 -05:00
Ben Taylor 4ccae6fe20 fix(react-native): keep the polyfill imports in the built barrel (closes OSS-1002) (#6744)
## The bug

`src/polyfills.ts` is five side-effect-only imports plus
`installStreamingFetch()`. The published barrel was 195 bytes:

```js
// node_modules/@copilotkit/react-native/dist/polyfills.mjs — 1.69.2
import { t as installStreamingFetch } from "./streaming-fetch-BnQh3vBz.mjs";
installStreamingFetch();
export {  };
```

Every React Native app following the documented setup died on its first
runtime call:

```
E ReactNativeJS: '[CopilotKit] Error (runtime_info_fetch_failed):',
  [ReferenceError: Property 'ReadableStream' doesn't exist]
```

## Root cause

The `sideEffects` field, but not in the way it first looks. It is
correct for *consumers* and wrong for *this package's own build*:

```json
"sideEffects": ["./dist/index.*", "./dist/headless.*", "./dist/polyfills.*", "./dist/polyfills/**/*"]
```

tsdown/rolldown reads the package's own `sideEffects` while bundling and
matches it against **source** paths. `src/polyfills/streams.ts` matches
none of those `dist` globs, so it is declared side-effect-free — a hard
assertion that lets rolldown drop the import without analysing the
`globalThis` assignments inside.

Reproduced in isolation at the pinned tsdown (0.20.3):

| `sideEffects` | built barrel |
|---|---|
| `["./dist/polyfills.*", "./dist/polyfills/**/*"]` | `export { };` —
empty |
| same + `["./src/polyfills.*", "./src/polyfills/**/*"]` | `import
"./polyfills/streams.mjs";` |
| field absent | `import "./polyfills/streams.mjs";` |

**Wider than the ticket recorded:** `dist/index.mjs` and
`dist/headless.mjs` also had zero polyfill code, so the package's
advertised auto-install on first import did not happen either. Not
RN-specific in principle — but I surveyed every package at `origin/main`
and this is the only one exposed. The other `sideEffects` arrays
(`react-core`, `react-ui`, `react-textarea`) are `["**/*.css"]`, which
matches source and works.

## The fix

Add matching `./src/**` globs. Barrel goes 195B → 362B with all five
imports; `headless.mjs` now leads with `import "./polyfills.mjs"`.

## The test, and why the existing one didn't catch this

`src/__tests__/polyfills.test.ts` has ~20 assertions covering all five
groups and was green the whole time — it imports `"../polyfills"`, the
TypeScript **source**, which vitest transpiles without bundling and
therefore without tree-shaking. It exercises a graph the published
package does not contain.

So the new check runs against `dist/`. Two things it has to get right to
be honest:

- **Node ships these globals natively.** Asserting `ReadableStream` is
"defined" after import passes on an empty barrel. The probe clears all
nine first, emulating Hermes.
- **The two formats need different treatment.** CJS is executed for real
in a child realm. ESM is checked structurally — it cannot be executed
here because `encoding.mjs` takes a named import from CommonJS
`text-encoding`, which Metro rewrites to a `require()` but bare Node ESM
rejects.

It is wired into `build`, so a dead barrel fails the build rather than
reaching npm — which matters, because this shipped through a fully green
suite.

## Docs

Added the `Property 'ReadableStream' doesn't exist` symptom to
troubleshooting, which previously covered only the inverse case (a
polyfill *conflict*).

I deliberately left the reference docs' "auto-installs on first import"
claims and the crypto import-order callout alone: both become **true**
once the build is fixed, and I verified the auto-install behaviourally.

## Verification

- **Red/green proven, not assumed:** reverted the `sideEffects` change,
rebuilt → 5/5 groups FAIL in both formats. Restored → 5/5 PASS. There is
also a test for a *single* group regressing, which a whole-barrel
assertion would wave through.
- **Packed tarball** (`pnpm pack`) verified behaviourally: all nine
globals install.
- 289 vitest + 26 script tests pass; `check-types` clean; `attw` green;
`publint` clean apart from a pre-existing `repository.url` suggestion;
oxfmt/oxlint clean.
- Added `{projectRoot}/scripts/**` to the package's `test` inputs and
confirmed cache invalidation (19/19 cached → 18/19 after touching the
verifier); without it, editing the verifier alone would restore a cached
pass.

**Not verified:** the on-device round trip — no emulator in this
environment. The bare-realm equivalent passes on the packed tarball.

## Follow-up worth its own ticket

`dist/polyfills/encoding.mjs` uses a named import from CommonJS
`text-encoding`. Metro handles it; a true-ESM consumer would not.
Pre-existing and not RN-facing, so left out of this change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-28 12:24:39 -05:00
gdut4140 7a2d0bd257 docs(shell-docs): fix broken Action Handlers link in a2ui fixed-schema page 2026-08-29 01:19:04 +08:00
Mike Ryan 9e27e10830 feat(runtime): expose Learning Container selector 2026-08-28 10:17:27 -07:00
Ran Shem Tov 95240cba4a fix(showcase): return raw Agent so the endpoint applies recovery a2ui_config (review)
Review caught a real bug: the endpoint only applies `a2ui_config` while wrapping a
RAW agent. The recovery factory returned an already-wrapped `AgentFrameworkAgent`,
so its `a2ui_config` was dropped and recovery silently ran on toolkit defaults
instead of the configured `maxAttempts: 3`.

- recovery_agent.py: `create_agent` now returns a raw `Agent`; the /a2ui_recovery
  endpoint wraps it and applies `A2UI_RECOVERY_CONFIG` (verified: the wrapper carries
  the config). D6 green with the config actually applied.
- Refresh the remaining old-path descriptions to the auto-inject + a2ui_config wording:
  manifest.yaml, the demo page.tsx header, the e2e spec contract, and the fixture _note.
2026-08-28 18:56:36 +02:00
Benjamin Taylor f346e94f96 docs(inspector): state the browser requirement plainly, drop the VS Code extension pointer 2026-08-28 11:48:57 -05:00
copilotkit-qa-bot[bot] 67945e2641 Merge remote-tracking branch 'origin/main' into codex/fac-74-tool-lifecycle 2026-08-28 09:34:37 -07:00
copilotkit-qa-bot[bot] 61d232ec63 docs: complete predictive-state tool lifecycle 2026-08-28 09:33:58 -07:00
Benjamin Taylor 465abb0239 docs: correct four pages that contradict shipped code, and document verify
Five onboarding-sweep defects that share one shape: a page states something the
library stopped doing, or never said something the library requires.

Mastra `resourceId` (OSS-936) — `getLocalAgents({ mastra })` does not typecheck
against `@ag-ui/mastra`; `resourceId` is required. It is Mastra's memory-scoping
key, required identically on the local, single-agent and remote option types, so
the snippets were wrong rather than the type over-strict. Fixed at all six doc
sites, including the tracing example that #6663 left behind.

Angular Inspector (OSS-948) — `@copilotkit/angular@0.4.0` ships the auto-mount
with a pinned `@copilotkit/web-inspector`. The Angular Inspector page still
taught a hand-written mount whose unconditional `DestroyRef.onDestroy` tears out
the element the framework now owns. Rewritten as a thin migration page that
points at `/inspector` instead of restating it, and the Angular Open Inspector
snippet — which asserted "Angular does not mount Inspector by default" — is
deleted in favour of the shared one every other web frontend already uses.

Angular runtime port (OSS-950) — say plainly that the runtime is its own
process, and name `PORT` as the way to move it off 8200. `COPILOT_RUNTIME_PORT`
appears nowhere in either repo and is not the mechanism.

`copilotkit verify` (OSS-953) — documented nowhere in the product docs. Added to
the shared CLI snippet, stating what `--round-trip` cannot prove: it records the
answer's character count and tool-call names, never its text, and proves an
agent answered under the declared id, not which deployment. React Native now
links that section rather than restating it, and its claim that the CLI defaults
to `:8200` is corrected to the real default, `:3000`.

A2UI flight example (OSS-944, part) — mark the domain illustrative on the page
the onboarding graph is mandated to fetch. The domain swap itself is not here:
it is 106 files across 21 showcase cells and wants the post-OSS-942 re-run
first.

Also fixes a shipped skill that taught `import { CopilotKitWebInspector }`, an
export that does not exist (OSS-891's failure mode, found in passing).

Two new tests guard the Angular claims, both mutation-checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 10:58:22 -05:00
Alem Tuzlak 8469e72b30 feat(web-inspector): copy stored threads into Playground from Threads (#6642)
Inspector Threads now has **Try from here**. One click copies a stored
thread into a Playground scratch session. The stored thread does not
change.

If the copy fails, Inspector stays on Threads and keeps the current
Playground scratch. Example tour threads and locked Threads do not show
the button.

## What does this PR do?

Adds **Try from here** on a real stored thread in Inspector Threads. One
click copies messages and thread state into a Playground scratch
session. The stored thread does not change.

If the copy fails, Inspector stays on Threads and keeps the current
Playground scratch. Example tour threads and locked Threads do not show
the button.

## Related PRs and Issues

- Linear: OSS-873
- Playground base: https://github.com/CopilotKit/CopilotKit/pull/6580
(merged)

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked

## Testing

**Commands run**

1. Rebased `feat/oss-873-try-from-here` onto `origin/main` and resolved
6 conflict files.
2. `npx nx run @copilotkit/web-inspector:test` — 626 tests passed (after
the stale-result guard).
3. `npx nx run @copilotkit/web-inspector:check-types` — passed.

**Manual test**

1. Open Inspector on localhost with Intelligence on, so a real stored
thread exists.
2. Open that thread. Confirm **Try from here** is in the thread header.
3. Click **Try from here**. Confirm Inspector opens Playground with the
copied messages and the stored thread is unchanged.
4. Open an example tour thread. Confirm **Try from here** is not shown.
5. Force a copy failure (disconnect runtime). Confirm Inspector stays on
Threads and the prior Playground scratch is unchanged.

**How this PR makes testing easy**

- `packages/web-inspector/src/__tests__/inspector-navigation.spec.ts`
covers the button, copy path, failure path, and a stale click that must
not overwrite Playground.
- `packages/web-inspector/src/lib/__tests__/telemetry.test.ts` covers
`oss.inspector.threads_try_from_here_clicked`.

## Risk / rollback

Risk is limited to Inspector Threads and Playground. A revert of this PR
removes the button and the new telemetry event. No runtime protocol
change.

## Public API change

New Inspector telemetry export and event name:

**Before**

```ts
trackThreadsTabClicked(props);
```

**After**

```ts
trackThreadsTabClicked(props);
trackThreadsTryFromHereClicked({ ...props, outcome: "success" });
```

`CpkThreadInspector` also emits a `tryFromHere` custom event when the
user clicks the button.
2026-08-28 16:10:06 +02:00
Alem Tuzlak 95285be33b feat(web-inspector): copy stored threads into Playground from Threads 2026-08-28 14:24:05 +02:00
Alem Tuzlak 5686a0669e Merge branch 'main' into lukas/oss-904-runtime-connection-status 2026-08-28 14:06:40 +02:00
Alem Tuzlak 1dfc5cdafa refactor(core): remove OSS-904 design comments 2026-08-28 13:27:37 +02:00
Alem Tuzlak a7191e2a12 fix(core): bound recovery /info hang and tighten OSS-904 comments 2026-08-28 13:08:44 +02:00
Ran Shem Tov b4adf37664 fix(showcase): recovery demo uses MAF auto-injection + a2ui_config (review)
Address review: switch the a2ui-recovery demo from an explicit enable_a2ui() wrap
to MAF's auto-injection path, matching the other MAF A2UI demos and MAF's upstream
recovery example.

- recovery_agent.py: now a plain Agent (no enable_a2ui, no tool). The recovery cap
  + catalog live in A2UI_RECOVERY_CONFIG.
- agent_server.py: the /a2ui_recovery endpoint passes a2ui_config=A2UI_RECOVERY_CONFIG
  ({"recovery": {"maxAttempts": 3}, "default_catalog_id": "declarative-gen-ui-catalog"}).
- route.ts: injectA2UITool false -> true (auto-inject, same as declarative-gen-ui).
- docs: dynamic-schema "backend recovery policy" section now shows the a2ui_config
  path instead of enable_a2ui.

Verified: the agent constructs as a plain Agent; plan_a2ui_injection fires from the
forwarded injectA2UITool flag and reads recovery{maxAttempts:3} + catalog from
a2ui_config, producing the same A2UIAgent recovery engine (no separate subagent
client / attempt callback / flag-independent injection needed, so enable_a2ui was
not required).
2026-08-28 13:07:06 +02:00
copilotkit-qa-bot[bot] a1c7146739 docs: persist Deep Agents interrupt names 2026-08-27 13:50:49 -07:00
Ben Taylor b8492e2b70 docs(vue): document the generative-UI path and publish it in the Vue sidebar (closes OSS-1005) (#6743)
## Problem

Vue 3 is a documented frontend and generative UI is the capability that
turns a chat box into the product — every completing showcase cell's
proof is a *card*, not a paragraph. But no page described how a tool
result becomes a rendered surface in Vue.

A showcase run pairing AWS Strands with Vue reached exactly that point,
correctly refused to invent a rendering path, and said so:

> "The official Vue documentation also does not document Strands
generative-UI rendering, so none was invented or claimed."

It shipped a text answer. Vue has 2 recorded runs against Next.js's 42 —
the least-covered frontend is also the one where the most valuable
capability was undocumented, and those reinforce each other.

## The capability was never missing

`packages/vue` already ships the whole surface: `useRenderTool`,
`useDefaultRenderTool`, `A2UIMessageRenderer`,
`A2UISurfaceActivityRenderer`, `OpenGenerativeUIRenderer`,
`MCPAppsActivityRenderer`, a full `src/v2/components/a2ui/` catalog and
adapter, e2e coverage, and two working demo pages under
`examples/v2/vue/demo/`. Notably it is React-free *by design* — the A2UI
code carries comments explaining it duplicates small helpers
specifically to avoid pulling `@copilotkit/a2ui-renderer`'s React
dependencies.

So this is a docs task, not an SDK one.

## But the gap was structural, not editorial

This is the part worth reviewing carefully, because it's why a guide
file alone would not have fixed anything.

**Sidebar.** `getFrontendQuickstartNavTree()` gated its guides branch on
`id === "angular"`. Angular gets its 8 guides; every other frontend got
an empty array plus a "Guides coming soon" placeholder. The new test's
red-check shows Vue's entire sidebar:

```
AssertionError: expected [ '/vue', …(2) ] to include '/vue/guides/generative-ui'
```

Three URLs.

**Routing.** `resolveFrontendDocPage()` serves `/<frontend>/<slug>` only
from a `frontends/<frontend>/<slug>` variant file, or from a doc whose
nearest `meta.json` declares `frontend: universal`.
`generative-ui/meta.json` declares no policy at all, so
`/vue/generative-ui/*` resolves **not-found**. Those pages weren't
merely React-flavored for a Vue reader — they were unreachable in the
Vue namespace.

The irony: `concepts/meta.json` **is** universal, and it holds
`generative-ui-overview`. A Vue developer could reach the page
explaining *what* generative UI is, and no page showing *how*.

## Changes

| File | Change |
| --- | --- |
| `docs/frontends/vue/guides/generative-ui.mdx` | New. The guide. |
| `lib/frontend-page-content.ts` | `VUE_GUIDE_PAGES` + a
`FRONTEND_GUIDE_PAGES` lookup replacing the `id === "angular"` branch,
so a frontend's guides are data rather than a conditional. Angular's
tree is unchanged. |
| `docs/frontends/vue.mdx` | The missing "Where to go next" pointer. |
| `lib/__tests__/frontend-options.test.ts` | Three tests. |

The guide covers `useRenderTool`, `useDefaultRenderTool`,
`useFrontendTool` with a renderer, A2UI (provider-level and
catalog-on-provider), Open Generative UI, and MCP Apps — written from
`packages/vue` source and the in-repo demos, not translated from the
React docs.

Two things it states deliberately:

- **It does not depend on the agent framework.** The reporting run read
the absence as Strands-specific. Generative UI reads AG-UI tool calls;
nothing changes when you swap the agent. The guide says so up front.
- **`useRenderTool` and `useFrontendTool` do not hand their renderers
the same props.** The former normalizes to `parameters` + a string-union
status; the latter passes through to core with `args` + the
`ToolCallStatus` enum. A renderer written for one silently draws nothing
in the other. Verified in source, not inferred.

### One note on the link form

The quickstart links the guide as `/vue/guides/generative-ui`, not the
relative `guides/generative-ui` that `angular.mdx` uses.
`resolveDocsHref` returns any non-root-relative href untouched, and
`next.config.ts` sets no `trailingSlash` — so the relative form would
resolve against `/vue` and land on `/guides/generative-ui`, which
doesn't exist. A test pins the authored href and asserts it both
survives rewriting and resolves. (`angular.mdx:241` uses the relative
form and looks like it has the same problem; not touched here.)

## Verification

- `frontend-options.test.ts` — 25/25. **Red-checked twice**: commenting
out the single nav wiring line fails the sidebar test; reverting the
href to the relative form fails the link test. Both can actually fail.
- Full `shell-docs` suite — 475/476. The one failure
(`llm-text.test.ts`, mastra tool-rendering) **reproduces on unmodified
`origin/main`** with these changes reverted. Pre-existing, unrelated.
- `tsc --noEmit` clean. `oxfmt --check` and `oxlint` clean.
- Search index regenerated: the page parses and is indexed at `href:
"/vue/guides/generative-ui"`, section "Frontends".

## Deliberately out of scope

1. **No Vue redirect map.** Angular's `ANGULAR_DOC_REDIRECTS` maps ~20
`generative-ui/*` slugs onto its guides, so
`/angular/generative-ui/tool-rendering` lands somewhere useful.
`/vue/generative-ui/tool-rendering` still 404s. That's a policy decision
about how much React IA to mirror into Vue.

2. **Backend-scoped variant.** On `/vue/<backend>`, `resolveDocsHref`
rewrites cross-section links — `/generative-ui/a2ui`,
`/generative-ui/mcp-apps`, `/inspector` — into that prefix, where they
resolve not-found. This follows from those sections having no
`frontend:` policy, is the same for every non-Angular frontend page
today, and is not introduced here. The sidebar link to the guide is
correct in both contexts.

3. **`FRONTEND_REFERENCE_SLUGS.vue` left alone — but please look at
it.** Vue's sidebar "Reference docs" link points at `"reference"`, the
**React** reference, despite a complete 25-page `/reference/vue` tree
existing and registered in `reference-items.ts`. It's pinned by an
assertion at `frontend-options.test.ts:538`, so it looks deliberate. If
it's an oversight it compounds this exact bug — a Vue developer sent to
the React reference cannot find `useRenderTool`'s Vue signature.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-27 13:04:11 -05:00
Benjamin Taylor a768047532 docs(vue): document the generative-UI path and publish it in the Vue sidebar (closes OSS-1005)
Vue 3 is a documented frontend and generative UI is the capability that turns a chat box
into the product, but no page described how a tool result becomes a rendered surface in
Vue. A run pairing AWS Strands with Vue reached that point, correctly refused to invent a
rendering path, and shipped a text answer instead.

The capability was never missing. packages/vue ships useRenderTool, useDefaultRenderTool,
A2UIMessageRenderer, A2UISurfaceActivityRenderer, OpenGenerativeUIRenderer, a full a2ui/
catalog and adapter, e2e coverage, and two working demo pages. Only the docs were absent.

They were absent structurally, not editorially. getFrontendQuickstartNavTree gated its
guides branch on `id === "angular"`, so every other frontend got an empty list plus a
"Guides coming soon" placeholder -- Vue's whole sidebar was three URLs. Routing matched:
resolveFrontendDocPage serves /<frontend>/<slug> only from a frontends/<frontend>/ variant
or a section marked `frontend: universal`, and generative-ui/meta.json declares no policy,
so /vue/generative-ui/* resolved not-found. concepts/meta.json IS universal, so a Vue
reader could reach the page explaining what generative UI is and no page showing how.

Add the guide, and replace the Angular identity check with a FRONTEND_GUIDE_PAGES lookup
so a frontend's guides are data rather than a branch. Angular's tree is unchanged.

The guide is written from packages/vue source and the in-repo demos rather than translated
from React, states up front that none of this depends on the agent framework, and documents
that useRenderTool and useFrontendTool do not hand their renderers the same props --
`parameters` plus a string-union status versus `args` plus the ToolCallStatus enum -- so a
renderer written for one silently draws nothing in the other.

The quickstart's link to the guide is the fully-qualified /vue/guides/generative-ui rather
than the relative form angular.mdx uses. resolveDocsHref returns non-root-relative hrefs
untouched and next.config sets no trailingSlash, so `guides/generative-ui` would resolve
against /vue and land on /guides/generative-ui. A test pins the authored href and asserts
it both survives rewriting and resolves.

Not addressed here: Vue has no equivalent of ANGULAR_DOC_REDIRECTS, so /vue/generative-ui/*
still 404s rather than landing on this guide, and on the backend-scoped variant of the page
(/vue/<backend>) resolveDocsHref rewrites cross-section links like /generative-ui/a2ui and
/inspector into that prefix, where they do not resolve. Both follow from the missing
`frontend:` policy rather than from this guide. Separately, FRONTEND_REFERENCE_SLUGS.vue
points at the React reference despite a complete /reference/vue tree; it is pinned by a
test assertion, so it is left alone here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 12:25:11 -05:00
Benjamin Taylor 84dea7bfbb fix(react-native): keep the polyfill imports in the built barrel (closes OSS-1002)
`src/polyfills.ts` is five side-effect-only imports. The `sideEffects` globs only matched
`./dist/**`, and rolldown matches that field against SOURCE paths while bundling, so every
`src/polyfills/*.ts` was declared pure and dropped. Every published version through 1.69.2
shipped a 195-byte barrel installing nothing but streaming fetch, so an app following the
documented setup died on its first runtime call with `Property 'ReadableStream' doesn't exist`.

`dist/index.mjs` and `dist/headless.mjs` lost the same imports, so the package's advertised
auto-install on first import did not happen either.

Add matching `./src/**` globs. The barrel goes 195B to 362B with all five imports, and
`headless.mjs` now leads with `import "./polyfills.mjs"`.

`src/__tests__/polyfills.test.ts` stayed green throughout this, because it imports the source,
which is never bundled and so is never tree-shaken. Add `scripts/verify-polyfill-barrel.mjs`,
which checks `dist/` instead. It clears the nine globals first (Node ships them natively and
Hermes does not, so asserting they are merely "defined" would pass on an empty barrel), then
executes the CJS barrel in a child realm and checks the ESM barrel structurally. ESM cannot be
executed here: the encoding polyfill takes a named import from CommonJS `text-encoding`, which
Metro rewrites to a require() but bare Node ESM rejects.

The check runs from `build`, so a dead barrel fails the build rather than reaching npm.

Also document the `ReadableStream doesn't exist` symptom in troubleshooting, where only the
inverse case (a polyfill *conflict*) was covered before.

Verified: reverting the sideEffects change and rebuilding turns the check red in both formats,
5 of 5 groups; restoring it turns it green. A behavioural check on the packed tarball installs
all nine globals. 289 vitest + 26 script tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 12:22:02 -05:00
Benjamin Taylor b18f7054af docs(react-core): state that an agent receives useAgentContext value as a JSON string (closes OSS-1003)
useAgentContext stringifies any non-string value before it leaves the
browser, and the AG-UI protocol types Context.value as a string on both
ends. An agent therefore always reads a JSON string, never the object or
array that was registered. None of the four reference pages said so; they
stopped at "serialized automatically", which reads as "the framework
handles it".

An author who believes that writes an agent that reads the object. When
the resulting shape check fails, the agent cannot distinguish "context
arrived JSON-encoded" from "no context was sent" -- the two are
identical -- so it refuses every request while the browser is registering
context correctly. That is what happened on the both-oss
langgraph-python conversion journey, where the agent's
isinstance(value, list) guard could never pass and the journey was dead
on arrival.

Each page now carries a "What the agent receives" section: the wire shape
as literal JSON, json.loads and JSON.parse examples, and a callout naming
the shape check as the trap. The value parameter description and the
Serialization behavior bullet now name the consequence for the agent
author instead of stopping at the browser half.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 12:18:14 -05:00
Ran Shem Tov 0738e10188 docs(showcase): follow the langgraph a2ui pages verbatim, drop the paraphrase
Replace the paraphrased MAF a2ui pages with langgraph's a2ui tree copied
verbatim, changing only genuinely framework-specific bits:

- styling.mdx, advanced.mdx: byte-identical to langgraph (frontend, framework-agnostic).
- index.mdx: only the framework name, the copilotkit.a2ui SDK snippet (MAF has no
  such SDK — shown as the raw a2ui_operations container it emits), and dropping the
  "Fixed Schema (Streaming)" bullet/row (langgraph links it but it 404s in prod, and
  MAF has no streaming demo).
- fixed-schema.mdx: the Python code swapped to MAF's real display_flight (hand-built
  ops); prose/structure verbatim.
- dynamic-schema.mdx: the two backend sections swapped to MAF's paths — auto-inject
  (plain Agent + injectA2UITool) and owning the tool (enable_a2ui + recovery); prose verbatim.

No added notes, no restructuring. Zero dead links; essential-content status matches
langgraph's a2ui pages exactly.
2026-08-27 18:37:47 +02:00
Mike Ryan 593fe0bc0b fix(docs): address Agent Framework review 2026-08-27 09:21:37 -07:00
Mike Ryan 6943ca8232 fix(docs): replace retired GitHub Models setup 2026-08-27 09:21:37 -07:00