14961 Commits

Author SHA1 Message Date
Mark 7cf869766b chore: release monorepo v1.68.2 (#6583)
## Release monorepo v1.68.2

**Scope:** `monorepo` | **Bump:** `patch`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `monorepo` packages to `1.68.2`
   and generated AI-enhanced release notes.

2. **CI runs on this PR** — the full test suite (unit tests, lint, type
checks, build)
   must pass before merging. This is the review gate.

3. **Review the release notes** in `release-notes.md` in this PR.
If a Notion draft was created, you can edit the release notes there
before merging.

4. **When this PR is merged**, the `release / publish` workflow
automatically:
   - Builds all packages
   - Publishes the `monorepo` packages to npm at version `1.68.2`
   - Creates git tag `monorepo/v1.68.2`
   - Creates a GitHub Release with the final release notes

### Before merging

- [ ] CI is green (tests, lint, types, build)
- [ ] Version bumps look correct
- [ ] Release notes are accurate (edit in Notion if a draft was created)

---

> **Do not merge until CI is fully green.** The full test suite runs
automatically on this PR.
v1.68.2
2026-08-19 19:28:56 -07:00
contextablemark b0233c4eb0 chore: release monorepo v1.68.2 2026-08-20 02:19:06 +00:00
Mark bef2c440ba fix(react-core): gate CopilotChat submission on runtime readiness (empty assistant response) (#6576)
## Problem

Fleet-wide "empty assistant response": the assistant-message container
mounts but never receives text. #5801 (first released 1.63.0) deferred
the runtime `/info` call to a React effect, widening the "provisional
agent" window; 1.63.2 exposed an `isReady` signal on `useAgent` but
`CopilotChat` never consumed it. A chat submitted during the provisional
window is committed to the provisional agent and then lost when `/info`
swaps in the real agent — the user message and streamed assistant text
disappear, so the assistant bubble renders empty.

This was confirmed with a controlled SSE A/B: stock 1.68.1 does forward
`TEXT_MESSAGE_START → TEXT_MESSAGE_CONTENT → TEXT_MESSAGE_END` (the
runtime is fine — not the in-memory runner / #5837), but the `/info`
agent swap drops the rendered messages; restoring a readiness guard
makes the identical SSE render correctly.

## Fix

`CopilotChat` now consumes `isReady` from `useAgent` and withholds
`onSubmitMessage` until the runtime is ready:

```
- const { agent } = useAgent({ ... });
+ const { agent, isReady } = useAgent({ ... });
...
- onSubmitMessage: onSubmitInput,
+ onSubmitMessage: isReady ? onSubmitInput : undefined,
```

`CopilotChatInput` already derives `canSend` (and its Enter handler)
from `onSubmitMessage`, so withholding it while not-ready (a) disables
the send control and (b) makes Enter a no-op that **preserves** the
composer text — the message can't be committed to the doomed provisional
agent. No runtime/runner changes; no fixture re-recording.

## Red–green proof

New test `CopilotChat.readinessGate.test.tsx` drives the real readiness
race against the real `CopilotChat` submit path: holds the runtime in
Connecting (deferred `/info`), sends during the provisional window, then
resolves `/info` (the real status-change re-render that flips `isReady`)
and asserts the message survives to render an assistant response.

- **RED** (fix reverted): the chat body contains only chrome text — no
user message, no assistant response (the empty-container symptom).
- **GREEN** (fix applied): assistant text renders; passes 3×
consecutively (deterministic).
- Mutation-verified: reverting the fix reproduces RED.

## Verification

- react-core: **1468 tests pass** (0 regressions; 3 pre-existing
web-inspector `localStorage` jsdom-env file errors are unrelated and
present with and without this change).
- react-ui: **69 tests pass**.
- react-core typecheck (`tsc --noEmit`): **0 errors**.

## Follow-up (not in this PR)

The showcase D4 probe driver
(`showcase/harness/src/probes/drivers/d4-chat-roundtrip.ts`) should wait
for the send control to be enabled before pressing Enter (poll
`[data-testid="copilot-send-button"]` `disabled === false` after
typing). Omitted here because it can't be red-green'd without a live
showcase backend. Note this fix makes the follow-up more relevant: with
send gated, a probe that types + Enters during the provisional window
now silently no-ops.

Ref: #5801

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

https://claude.ai/code/session_017t7HsmM31NHNmUQrHF47pm
2026-08-19 19:09:31 -07:00
Jordan Ritter 88aa50ee65 fix(showcase): D4 driver guards readiness-wait budget and baselines after the wait
Two probe false-red guards around the react-core readiness gate:

- Guard the readiness waitForSelector(SEND_ENABLED) against an exhausted
  budget BEFORE issuing it. A type that drains the first-token envelope
  would otherwise issue a doomed ~1ms readiness wait that Playwright
  rejects and the outer catch mis-classifies as a generic level-error.
  Below SEND_READY_MIN_BUDGET_MS it now throws ReadinessBudgetExhausted
  (errorDesc: delayed-readiness) — an observable, specific red.

- Capture the per-attempt turn-lifecycle baseline AFTER type + the
  enabled-send wait and immediately before Enter (for both the initial
  attempt and retries). Taking it before the wait let a run completing
  DURING the wait land its edge past the snapshot, so the poll mistook it
  for THIS submitted turn finishing and false-red'd an empty container.

Adds a delayed-readiness/budget regression and a
counter-advances-during-wait regression; restructures the existing
press-guard test to drain during the readiness wait (via a new
sendEnableDelayMs fake option) so it still targets send-budget-exhausted.
2026-08-19 16:59:23 -07:00
Jordan Ritter e34bdb9fc3 fix(react-core): hide suggestion pills until ready; rework SSE test to real wrapper
Withholding onSelectSuggestion left the pill visually enabled but inert,
silently dropping a click during the provisional (!isReady) window. Hide
the pills until isReady (pass an empty suggestions list so the view's
existing hasSuggestions gate keeps them off-screen); retain the handler
gate as defense-in-depth for custom chatView slots. The suggestion-gate
test now asserts the pill is absent while provisional and appears/works
once ready.

Rework the production-shaped SSE regression to render the real public
CopilotKit wrapper (components/copilot-provider/copilotkit) with
runtimeUrl + agent="agentic_chat", advertising agentic_chat in the mocked
single-endpoint info response and relying on the wrapper's default
useSingleEndpoint=true — removing the synthetic GET /info 404 fallback so
the test exercises the same provider chain and POST info/agent-run path
as Showcase.
2026-08-19 16:52:47 -07:00
Jordan Ritter f39d5a5b97 fix(showcase): D4 driver waits for enabled send control before Enter (readiness gate)
The react-core readiness fix disables the send control and no-ops Enter
while useAgent().isReady is false (the provisional agent /info swaps out).
An early probe Enter during that window is a silent no-op, leaving an empty
assistant response that falsely reds the cell. sendTurn now waits for
[data-testid="copilot-send-button"]:not([disabled]) after typing and before
pressing Enter, so the send lands on the real bound agent. Adds a
driver-ordering test (type -> wait-for-enabled-send -> Enter) with a fake
page that models the readiness gate.
2026-08-19 15:04:24 -07:00
Tyler Slaton 0d56e704f1 feat(web-inspector): pop the Inspector into its own window (#6563)
## What
The Inspector can open in a real browser window. The same live session
stays in that window. The app page hides the Inspector until you close
the extra window.

## Why
The Inspector covers the app. Some people want it beside the app, like
Chrome DevTools or a YouTube pop-out.

## How
The existing Inspector client opens a blank named popup. It portals the
same instance into that window. There is no second app, no extra page,
and no new backend.

## Notes
- Close the extra window to put the Inspector back. It stays open in the
same float or dock mode.
- If the browser blocks the popup, allow popups for the site.
- A refresh closes the extra window. It does not reopen as a pop-out.
- Docs update for this feature is landing in a follow-up commit on this
branch.

Draft until the last docs and a manual check are done.
2026-08-19 15:01:52 -07:00
Jordan Ritter f8160e09b9 fix(react-core): gate suggestion submission on readiness + production-shaped SSE regression test 2026-08-19 14:33:25 -07:00
Tyler Slaton 9087121bd5 fix(web-inspector): preserve state across pop-out 2026-08-19 14:03:12 -07:00
Alem Tuzlak 1ef16b6789 feat(web-inspector): pop the Inspector into its own window
Keep the same live Inspector session in a named browser popup, restore it when the popup closes, and document the workflow.
2026-08-19 14:03:12 -07:00
Tyler Slaton 463f589b4c feat(react-core): add local message inspector links (#6575) 2026-08-19 13:43:46 -07:00
Jordan Ritter 9b0e3dc88a fix(react-core): gate CopilotChat submission on runtime readiness (empty assistant response) 2026-08-19 13:37:03 -07:00
Tyler Slaton f1b26e4aa8 fix(react-core): hide local inspector action in production 2026-08-19 13:28:26 -07:00
Tyler Slaton 367e7bda15 feat(react-core): add local message inspector links 2026-08-19 13:28:26 -07:00
Ben Taylor 092058b224 docs(a2ui): require a literal-or-binding union for bound props (refs OSS-857) (#6573)
Four defects were reported from a LangGraph TypeScript + Next.js
onboarding run. Two
were unverified and one was unsound as stated, so each was reproduced or
traced to
source before anything was written. Two needed a fix, one needed a fix
plus a package
re-export, and one turned out to be correct as documented.

## Per-defect findings

**Defect 1 — bound props need a literal-or-binding union schema. REAL,
and the page said the opposite.**
Confirmed, with the mechanism. `scrapeSchemaBehavior` in
`@a2ui/web_core`'s
`GenericBinder` decides whether to resolve a `{ path }` binding by
inspecting the prop's
Zod type: a `ZodUnion` containing an object with a `path` key (and no
`componentId`)
becomes `DYNAMIC`; everything else falls through to `STATIC`, whose
handler is
`case 'STATIC': return value;`. So a bound prop declared as a plain
`z.string()` is never
resolved and the raw `{ path: "/origin" }` object reaches the renderer,
where the first
thing that renders it as text throws React error #31.

The page was not merely silent about this — it asserted the opposite:

> The A2UI binder resolves those paths *before* the React renderer runs,
so renderer
> props are typed as their resolved values (plain `z.string()`, not a
path-or-literal union).

The reference cell has declared the union all along and carries a
comment naming the exact
React error, but that comment sits *outside* the
`@region[definitions-types]` marker, and
`extractRegion` returns only the lines between the markers — so it never
reaches the page.
The rule is now stated where the reader declares the prop, with the
failure mode.

**Defect 2 — `DynamicStringSchema` is not re-exported. Explanation 2:
the symbol exists in a package that had not been searched.**
It is real and it is not a wished-for helper. It lives in
`@a2ui/web_core` at
`src/v0_9/schema/common-types`, reachable on the export map as
`@a2ui/web_core/v0_9`, and
it is a three-member union (`z.string()`, `DataBindingSchema`,
`FunctionCallSchema`) —
slightly wider than the two-member `DynString` the reference cells
hand-roll. The earlier
search was correct that it appears nowhere under `packages/`; it is a
dependency symbol.

It is also genuinely unreachable for users: `@a2ui/web_core` is a plain
`dependency` of
`@copilotkit/a2ui-renderer`, so application code cannot rely on
importing it. Re-exported
from `@copilotkit/a2ui-renderer` with its numeric/boolean/list siblings
and their types,
and noted in the docs as an alternative to hand-rolling the union.

**Defect 3 — the quickstart recommended the host form that fails. REAL,
verified independently for both runtimes.**
The advice was *"try using `0.0.0.0` or `127.0.0.1` instead of
`localhost`"*, in shared prose.
For the Node runtime that is exactly backwards, and it was verified from
source and by
running it, not taken on report. Rewritten and split across the page's
existing
Python/TypeScript language tabs so neither runtime sees the other's
advice. Also corrected
the `0.0.0.0` half, which is wrong for both: it is a bind-all address
for a server, not a
target for a client URL.

**Defect 4 — `useSingleEndpoint` guidance for the compat component. NOT
A DEFECT. Nothing changed.**
The docs are right. The compat wrapper resolves its default at

`packages/react-core/src/components/copilot-provider/copilotkit.tsx:108`:

```tsx
useSingleEndpoint={props.useSingleEndpoint ?? true}
```

and the v2 provider maps `true → "single"`, `false → "rest"`, `undefined
→ "auto"`
(`CopilotKitProvider.tsx:616-620`, again at `777-781`). So omitting the
prop really does
keep a single-route default, and `useSingleEndpoint={false}` really is
what a multi-route
Runtime needs. The same `CopilotKit` component is exported from both
`@copilotkit/react-core`
and `@copilotkit/react-core/v2`, so the guidance holds for either
import. Reported as one
observation from one run rather than an established finding — it did not
survive checking.

## Two things worth flagging

**The URL is served by the root page, not the LangGraph one.** Both
`generative-ui/a2ui/fixed-schema.mdx` and
`integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx` exist, and
the resolution is the
opposite of what the directory layout suggests: all three langgraph
slugs are
`docs_mode: generated` in their manifests, and in that branch root MDX
wins
(`[framework]/[[...slug]]/page.tsx:836-841`). Confirmed live — the
LangGraph-scoped copy is a
thinner, older duplicate that is **not served at that URL for any
framework**. Left in place,
but it is a trap for the next person and probably wants deleting
separately.

**Overlap with #6569.** That PR is still open and edits both files this
one touches.
`git merge-tree` against its head merges clean, so no action needed, but
the two should be
read together.

## Testing

Worktree off `origin/main` (which already contains #6566 and #6568).

**Defect 1 — mechanism, against the locked `@a2ui/web_core@0.10.4`.**
Schema classification:

```
plain z.string()  -> {"type":"STATIC"}
literal|binding   -> {"type":"DYNAMIC"}
```

End-to-end through the real `GenericBinder`, feeding `{ path: "/origin"
}` against a data
model of `{ origin: "SFO" }`:

```
z.string()      : typeof=object value={"path":"/origin"}
literal|binding : typeof=string value="SFO"
z.string() -> renderable as a React child? NO — React throws: Objects are not valid as a
              React child (found: object with keys {path})
literal|binding -> renderable as a React child? yes
```

**Defect 2 — the re-export works from the built entry point**, and
behaves identically to the
hand-rolled union in the binder (it has a third union member, so this
needed checking):

```
DynamicStringSchema parses a literal: "SFO"
DynamicStringSchema parses a binding: {"path":"/origin"}
hand-rolled union   -> {"type":"DYNAMIC"}
DynamicStringSchema -> {"type":"DYNAMIC"}
plain z.string()    -> {"type":"STATIC"}
```

**Defect 3 — both runtimes verified from CLI source, and the Node
binding reproduced.**
`@langchain/langgraph-cli@1.4.4` `dist/cli/dev.mjs:19` defaults `--host`
to `"localhost"`
and passes it to `serve({ hostname })`; `langgraph_cli-0.4.31`
`cli.py:664-666` defaults
`--host` to `"127.0.0.1"`. Reproducing what Node does with `{ host:
"localhost" }` on this
dual-stack machine:

```
node version: v22.14.0
bound to: {"address":"::1","family":"IPv6","port":42024}
  localhost   -> CONNECTED
  127.0.0.1   -> ECONNREFUSED
  ::1         -> CONNECTED
  0.0.0.0     -> ECONNREFUSED
```

`127.0.0.1` is refused by the very server `localhost` reaches — so the
old advice broke a
working setup.

**Rendered checks (`next dev`, body-inspected — this site soft-404s, so
no status codes were trusted).**
`/langgraph-typescript/...` and
`/langgraph-python/generative-ui/a2ui/fixed-schema`: root-file
marker present, LangGraph-file marker absent, new prose and the
React-error callout present,
old wrong sentence gone. The `{path}` braces render literally inside
`<code>` and the
`#declare-the-component-definitions` anchor resolves to a real heading
id.

Quickstart troubleshooting tabs resolve per framework, so the gating is
right:

```
/langgraph-typescript/quickstart   Python selected=false   TypeScript selected=true
/langgraph-python/quickstart       Python selected=true    TypeScript selected=false
/langgraph-fastapi/quickstart      Python selected=true    TypeScript selected=false
```

The `<Tabs>` nested in a list item renders as a real `<ul><li>` with a
working tablist, not
broken MDX.

**Suites.**

| Check | Result |
| --- | --- |
| `packages/a2ui-renderer` `tsc --noEmit` | pass |
| `packages/a2ui-renderer` build (`tsdown`) | pass, 143 files |
| `packages/a2ui-renderer` `vitest run` | 4 files, 22 tests passed |
| `oxlint` on the changed source | 0 warnings, 0 errors |
| `shell-docs` `npm run typecheck` | pass (exit 0) |
| `shell-docs` `npm run lint` | pass (exit 0) |
| `shell-docs` `npm run test` | 58/59 files, 420/421 tests |

The one failing test is `channels-docs.test.ts > publishes the Channels
overview only through
provider navigation`. It is **pre-existing on `origin/main`** and
unrelated to these files —
verified by reverting all three changes to a pristine checkout and
re-running it, where it
fails identically (`1 failed | 29 passed`).

## Conventions pass

Checked the added prose against the docs tree's actual conventions
rather than by ear, which
turned up four things worth changing:

- **`Callout type="warn"`** is the house spelling (84 uses vs 11
`warning`) — already correct.
- **Code identifiers in Callout titles are backticked** (95-odd
precedents, e.g.
``title="`identifyUser` is not an authentication gate"``). Mine wasn't;
fixed. Note these
render as *literal* backticks — verified that existing titles behave
identically on `/auth`,
  so this matches the site rather than diverging from it.
- **Dropped a hand-written code fence.** The first draft illustrated the
union with a synthetic
`ts` block that (a) wasn't valid TypeScript — an orphaned object
property with no enclosing
object — and (b) duplicated the `<Snippet region="definitions-types" />`
rendered immediately
below it. Hand-copied code next to the generated snippet is exactly the
drift the snippet
architecture exists to prevent, so the prose now names `DynString` and
`Airport`'s `code` and
lets the snippet carry the code. Confirmed those two names are present
in **all 21**
integration cells that feed this page, since the root page serves every
framework.
- **Matched local line-style.** The quickstart's other troubleshooting
bullets are single
unwrapped lines, so the new bullet's prose is too; the a2ui page wraps
at ~70–80 columns and
  the new paragraphs match that.

Also tightened two things for accuracy over emphasis: the binder rule
now says "a union with a
`{ path }` member" rather than "a union containing an object with a
`path` key", which was
over-broad (a `{ componentId, path }` member is classified `STRUCTURAL`,
not `DYNAMIC`), and
the package comment was cut from nine lines to six to sit better among
that file's one-line
section labels.

Re-verified after the rewrite: `tsc` pass, `vitest` 22 passed, `oxlint`
clean, `oxfmt` clean,
shell-docs typecheck/lint pass, tests unchanged at 420/421 with the same
pre-existing channels
failure, and both pages re-rendered — anchor still resolves, tabs still
resolve per framework
(`langgraph-python` → Python, `langgraph-typescript` → TypeScript).

Out of scope and untouched: `snippets/shared/premium/inspector.mdx`. No
changeset added.
Does not close OSS-857.
2026-08-19 15:27:44 -05:00
Benjamin Taylor 4df1e3dccd docs(a2ui): require a literal-or-binding union for bound props (refs OSS-857)
Three findings from a LangGraph TypeScript onboarding run, plus the
supporting re-export.

The A2UI binder decides whether to resolve a `{ path }` binding by
inspecting the prop's Zod type: `scrapeSchemaBehavior` classifies a
`ZodUnion` containing an object with a `path` key as DYNAMIC and
everything else as STATIC, and STATIC returns the value untouched. A
bound prop declared as a plain `z.string()` therefore reaches the
renderer as the raw `{ path: "/origin" }` object, and the first thing
that renders it as text throws React error #31. The fixed-schema page
said the opposite — that renderer props are "plain z.string(), not a
path-or-literal union" — so the obvious declaration produced an opaque
crash. The reference cell already declares the union and carries a
comment explaining why, but that comment sits outside the
`definitions-types` region marker and so never reaches the page.

`DynamicStringSchema` is real; it lives in `@a2ui/web_core`, which is a
transitive dependency of `@copilotkit/a2ui-renderer` and so not
reliably importable from application code. Re-exported here with its
numeric/boolean/list siblings and their types.

The LangGraph quickstart's troubleshooting advice told everyone with a
connection problem to swap `localhost` for `0.0.0.0` or `127.0.0.1`.
That is backwards for the Node runtime: `langgraphjs dev` defaults to
`--host localhost`, which Node resolves to IPv6 and binds `::1` only,
so `127.0.0.1` is refused by the same running server. The Python CLI
defaults to `--host 127.0.0.1` and behaves the other way, so the advice
is now split across the page's existing Python/TypeScript language tabs
instead of stated once in shared prose.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 14:48:49 -05:00
Ben Taylor 68d6c5c62d docs(inspector): document mounting the Inspector in Angular (refs OSS-857) (#6572)
## What this fixes

The Inspector is `cpk-web-inspector`, a framework-agnostic web component
from
`@copilotkit/web-inspector`. `@copilotkit/angular` does not reference
that package
and does not mount the element, so an Angular application has to create
it
itself. Nothing in the docs said so.

It was worse than a missing paragraph. `ANGULAR_DOC_REDIRECTS` mapped
the
`inspector` slug onto `guides/troubleshooting`, so
`/angular/*/inspector`
**redirected away from the Inspector**, and the Angular sidebar's
"Observe & Operate" section contained a single entry — the VS Code
extension:

```
== Observe & Operate
- VS Code Extension [vs-code-extension]
```

## What I documented

New Angular-owned page, `frontends/angular/inspector.mdx`, sourced from
`examples/integrations/adk-angular/src/app/web-inspector.ts`:

- the Inspector is a web component and `@copilotkit/angular` does not
mount it
- the mount component: `afterNextRender`, reuse-or-create, append to
`document.body`
- `inspector.core = copilotKit.core` plus `auto-attach-core="false"`,
and why —
  given no core the element hunts for development globals such as
`window.__COPILOTKIT_CORE__`, so turning the search off is what
guarantees it
  observes the app's core and never a different one
- anchoring the launcher bottom-left, clear of a chat panel's close
button
- keeping it out of production builds via `@defer (when isDev)` +
`isDevMode()`
- server rendering (`afterNextRender` + the deferred import vs.
`customElements`)
- cleanup through `DestroyRef.onDestroy`

Plus: the redirect is gone so the page is reachable, and
`frontends/angular/guides/troubleshooting.mdx` links to it.

**React's Inspector content is untouched** — not edited, not moved, not
gated.

### House style

Checked against the eleven existing Angular-owned pages rather than
written to
taste, which changed four things from my first draft:

- **`## Next steps` with a bare link list.** Every Angular guide closes
that way;
  I had `## Related` with a prose gloss per link.
- **No `<video>`.** No Angular-owned page embeds media, and none uses
`<Callout>`
or `<Steps>` either — that surface is prose, tables, and fences. I had
carried
  the Inspector video over from the shared snippet.
- **Imperative task headings**, matching "Send the current session" /
  "Validate every runtime request" in `auth.mdx`: "Mount the element",
  "Supply the application's core", "Position the launcher". I had
  "Mount it yourself" and "Hand it the application's core".
- **Declarative sentences, no rhetorical fragments.** "The mount is
yours, so the
exclusion is yours as well." and a bare "`DestroyRef.onDestroy` does."
are not
  this surface's register; both are now plain statements of mechanism.

Frontmatter (`title`/`description`/`icon`/`doc_type: how-to`), h2-only
structure, ~80-column wrapping, and the `{runtimeUrl}` placeholder
convention all
follow the siblings. `<AngularSnippet region=…>` does **not** apply —
that
component pulls code extracted from the Angular Showcase at build time,
and this
mount component is not in the Showcase. Nav needs no `meta.json` entry
either:
`frontends/meta.json` carries only a title, and the Angular sidebar is
derived in
`getAngularDocsNavTree`. Verified the entry renders anyway.

### Two deviations from the brief, both deliberate

**1. Structural gating instead of `<FrontendOnly frontend="angular">` in
the
shared snippet.** The brief described
`snippets/shared/premium/inspector.mdx` as
the real Inspector content with the per-framework pages as shims onto
it. On
current `main` that is only half true: `docs/inspector.mdx` is now a
131-line
standalone page that does **not** render `<Inspector />`, and it is what
the
Angular root and every `docs_mode: generated` framework resolve to. I
built the
`FrontendOnly` version first and it forced the Angular guide to be
duplicated
into two files that had already diverged. An Angular-owned page instead
matches
how all eleven existing Angular guides work, keeps one source of truth,
and
gates by resolution rather than by branch.

The repo's own test agrees on the direction —
`angular-docs-content.test.ts`
lists `<FrontendOnly` in `REACT_ONLY_CONTENT`, i.e. it treats the tag as
something that should not reach the Angular surface.

That test also gave me a real mutation check for free. My first attempt
leaked
React's `<CopilotKit … enableInspector={false}>` into 19 Angular pages,
and the
suite caught every one:

```
× keeps the complete Angular surface free of another frontend's code
+   "inspector: <CopilotKit
+   publicLicenseKey={process.env.NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY}
+   enableInspector={false}
+ >",
× keeps every Angular and backend combination frontend-native
    expected [ …(18) ] to deeply equal []
```

**2. I document the CSS override for positioning, not
`setAttribute("anchor", …)`.**
The scaffold sets that attribute, but `cpk-web-inspector` never reads
it. Runtime
proof against the built `dist`:

```
observedAttributes: ["auto-attach-core"]
static properties keys: ["core","autoAttachCore","_capabilitiesVersion"]
'anchor' observed? -> false
```

There is no `getAttribute("anchor")` anywhere in the package, and
`defaultAnchor`
(the prop React's `CopilotKitInspector` accepts) is not consumed either.
What
actually moves the panel is the CSS in the scaffold's own `styles.css` —
as its
comment already says: "CSS in styles.css enforces this too." So the docs
describe
the mechanism that works. **The scaffold has one dead line** its owner
may want
to drop; I did not touch it (see below).

## The adk-angular dependency is discharged

`examples/integrations/adk-angular` is planned for removal, and its
`web-inspector.ts` comment was the only written record of this pattern.
That
pattern is now documented. **Whoever removes that scaffold no longer
needs to
preserve it.** I only read the scaffold — no file under
`examples/integrations/adk-angular` is modified by this PR.

## The VS Code extension claim: both halves reproduced

The report said Angular users are pointed at a VS Code extension
instead, that
its `cpk-debug-events` endpoint is documented at the wrong path, and
that it
produced no events for a real run. I verified each independently rather
than
acting on the report.

**Pointed at the extension — confirmed.** See the one-entry sidebar
above.

**Wrong path — confirmed, and fixed.** The router suffix-matches
`cpk-debug-events`, but a runtime mounted with a `basePath` rejects
anything
outside it. Against a real runtime on `basePath: "/api/copilotkit"`:

```
runtime mounted at basePath=/api/copilotkit, NODE_ENV=development
/cpk-debug-events                -> 404  application/json  {"error":"Not found"}
/api/copilotkit/cpk-debug-events -> 200  text/event-stream  ": connected\n\n"
/api/copilotkit/info             -> 200  application/json   {"version":"1.64.1",…}
```

The docs said "available at `GET /cpk-debug-events` on your CopilotKit
runtime"
and gave the panel default as the bare origin `http://localhost:4000`,
so a
reader supplying their server's origin gets a 404. Now documented as
`GET {runtimeUrl}/cpk-debug-events`, base-path-relative, with the worked
`localhost:8200` example and a `curl` check, in both
`troubleshooting/event-inspector.mdx` and `vs-code-extension.mdx`.

**No events for a real run — confirmed, cause is runtime mode.** The
debug bus is
fed from exactly one place, `handlers/shared/sse-response.ts`, reached
only by
`handlers/sse/run.ts` and `handlers/sse/connect.ts`. An
Intelligence-configured
runtime dispatches to `handlers/intelligence/run.ts` and
`handlers/intelligence/connect.ts`, which return `Response.json` and
hand the
browser a realtime connection — no AG-UI event ever passes through the
runtime's
SSE layer. Neither file mentions `debugEventBus`. So on an
Intelligence-backed
runtime the endpoint connects, emits `: connected`, and then stays
silent
forever. That is now a callout on the event-inspector page pointing
readers at
the in-app Inspector, which reads the events client-side.

I did not change runtime code for this — it is a docs-accuracy gap, and
whether
the Intelligence path *should* feed the bus is a product decision, not
mine to
make here.

## Testing

From `showcase/shell-docs`:

**`npm run test`** — 403 passed, 1 failed, and that failure is
pre-existing on
`origin/main`. Verified in a pristine `origin/main` worktree with no
changes:

```
❯ src/lib/__tests__/channels-docs.test.ts (30 tests | 1 failed)
    × publishes the Channels overview only through provider navigation
```

It asserts `channels-architecture-dark.png` in the Channels overview
source and
is unrelated to anything here. The seven `angular-docs-content.test.ts`
tests —
the ones that police frontend separation — all pass.

**`npm run typecheck`** — identical output on my branch and on a
pristine
`origin/main` worktree (5 pre-existing `@testing-library/react`
resolution
errors from my symlinked `node_modules`, all in test files I did not
touch). No
new errors.

**`npm run lint`** — exit 0, no warnings in any file I changed.

**`npx oxfmt --check`** on the one `.ts` file — "All matched files use
the
correct format."

### Render check, both namespaces

`next dev`, following redirects, checking bodies rather than status
codes since
this site soft-404s:

| URL | http | Angular mount content | React `enableInspector` |
| --- | --- | --- | --- |
| `/angular/langgraph-typescript/inspector` | 200 | yes
(`afterNextRender`, `auto-attach-core`, `cpk-web-inspector`) | **no** |
| `/langgraph-python/inspector` | 200 | **no** | yes |

Each namespace shows only its own instructions. The only `tsx` string on
the
Angular page is Next.js dev chunk filenames, not content.

Before this change `/angular/langgraph-typescript/inspector` answered
`307 -> /angular/langgraph-typescript/guides/troubleshooting`.

Also confirmed 200-with-content, no redirect, and the mount instructions
present
on `/angular/inspector`, `/angular/google-adk/inspector`, and
`/angular/mastra/inspector`; the sidebar now carries
`href="/angular/langgraph-typescript/inspector"` under "Observe &
Operate"; the
Angular troubleshooting page links to it; and the new event-inspector
callouts
render in both the React and Angular namespaces with `/inspector`
correctly
rewritten to `/angular/<backend>/inspector`.

## Notes for reviewers

- **OSS-857 stays open** — other defects on it are unresolved.
- No changeset, per this repo's release process.
- Follow-up for the adk-angular owner, not done here:
`setAttribute("anchor", "bottom-left")` in `web-inspector.ts` is a no-op
and
can be deleted; the `styles.css` rule below it is what positions the
panel.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-19 14:46:03 -05:00
Ben Taylor d77cd3815d test(sdk-python): revalidate the poetry lock and cover the partialjson parse path (#6547)
## What does this PR do?

Follow-up to #6123, which relaxed `partialjson` to `>=0.0.8,<2.0.0`
(issue #4131). Two loose ends from reviewing that change:

1. **`sdk-python/poetry.lock` was left invalid.** Any edit to the
dependency table invalidates the lock's content-hash, so on current
`main` a bare `poetry install` in `sdk-python` fails with
`pyproject.toml changed significantly since poetry.lock was last
generated`. Refreshed here.
2. **The parse path had zero test coverage.** `partialjson` has exactly
one consumer — `JSONParser().parse(...)` at `copilotkit/runloop.py:306`
— sitting inside a bare `except` that returns `None`. Every failure mode
therefore degrades to "no predicted state was emitted", which nothing
asserted. A widened range with no tripwire under it means a future
release inside `<2.0.0` could regress streaming predicted state
silently.

## Choices worth flagging

- **Refreshed the lock with Poetry 2.1.3**, the generator the lock
itself names. Poetry 2.4.x rewrites the header and adds unrelated
entries (~120 lines of churn); 2.1.3 keeps the diff to the hash.
- **Moved `partialjson` to 1.1.0 in the lock** (`poetry update
partialjson`, 7 insertions) so CI exercises the version a fresh install
now resolves, rather than the floor of the range.
- **Left `ag-ui-langgraph` at 0.0.42 on purpose.** A from-scratch
resolve (deleting the lock rather than refreshing it) pulls 0.0.43,
which fails four `test_intercepted_tool_call_events` tests on
`AttributeError: 'LangGraphAGUIAgent' object has no attribute
'emit_raw_events'`. That latent break is worth its own issue; it is not
addressed here.
- **Tests are version-agnostic about intermediate frames.** Values
mid-stream legitimately differ across the allowed range — 1.1.0
preserves trailing whitespace inside a partially streamed string where
0.0.8 dropped it — so the assertions pin what the range must keep: a
completed payload parses exactly, and a prefix yields a prefix.
- Not touched here:
`examples/integrations/langgraph-{fastapi,python}/Dockerfile:50` still
hardcode `"partialjson>=0.0.8,<0.0.9"`, a hand-copy of the old pin that
keeps those two images on 0.0.8.

## Testing

**Lock validity — the actual bug, before and after**

Pristine `main` before #6123 was consistent; #6123's one-line edit is
what broke it. Verified in a clean worktree:

```
# main + only the constraint edit
$ poetry check --lock
Error: pyproject.toml changed significantly since poetry.lock was last generated.
$ poetry install --with dev
Installing dependencies from lock file
pyproject.toml changed significantly since poetry.lock was last generated. Run `poetry lock` to fix the lock file.

# with this PR's lock
$ poetry check --lock
(no error)
```

**CI simulated exactly** (`poetry lock && poetry install --with dev`, as
in `test_unit-python-sdk.yml:54`):

```
resolved partialjson in venv: 1.1.0
locked ag-ui-langgraph: version = "0.0.42"
230 passed, 11 skipped, 18 warnings in 0.75s
```

225 were passing before; the 5 new tests are the difference.

**New tests pass on every version the range admits**

```
partialjson 0.0.8 -> 5 passed
partialjson 0.0.9 -> 5 passed
partialjson 0.1.0 -> 5 passed
partialjson 1.0.0 -> 5 passed
partialjson 1.1.0 -> 5 passed
```

**Mutation-checked, three ways** — the tests were confirmed to fail when
the mechanism is broken, not merely to pass:

| Mutation to `JSONParser.parse` | Result |
| --- | --- |
| baseline (unmodified) | 5 passed |
| `raise RuntimeError` | 4 failed, 1 passed |
| return values with strings reversed | 3 failed, 2 passed |
| always return `{}` (the realistic silent regression) | 3 failed, 2
passed |

For contrast, the same "disable `parse` entirely" mutation against the
pre-existing suite left **all 225 tests passing** — which is what
motivated this file.

The one test that survives every mutation is
`test_unterminated_escape_does_not_escape_predict_state`, by design: it
asserts that a prefix older versions reject stays contained by the bare
`except`, so a raising parser is the case it exists to tolerate.

**Behavioural evidence that 1.1.0 is safe in the lock** (from reviewing
#6123): a differential fuzz over every prefix of 9 realistic streamed
tool-call payloads, 1232 cases per version across 0.0.8 / 0.0.9 / 0.1.0
/ 1.0.0 / 1.1.0 — zero parse-to-raise regressions on any version, 75
cases improve from raise to parse, all 9 complete payloads parse
identically. Driving the real `predict_state()` at chunk sizes 1/3/7/20
gives a byte-identical final `predicted_state` on all five versions.
2026-08-19 14:38:51 -05:00
Ben Taylor 3801de3708 docs(runtime): map the provider/handler pairs and guard BuiltInAgent (refs OSS-857) (#6569)
Follow-up to #6566. Fixes **defects 5 and 9** of OSS-857, plus the half
of **defect 6** that lives on the Built-in Agent quickstart. Defects **1
and 2** are deliberately left — they land with the non-interactive
`project list`/`select` work, since the real fix is tooling that
provisions and names the key, not prose.

**Do not close OSS-857 on this PR** — 1 and 2 remain.

## The finding that reframes defect 5

The three names are **not interchangeable**. They pair up, and nobody
had written the pairing down. Traced through source, not inferred:

| Provider | `useSingleEndpoint` | Transport | Needs handler |
| --- | --- | --- | --- |
| `<CopilotKit>` (v1 wrapper) | omitted → `true` | `single` |
single-route |
| `<CopilotKit>` | `{false}` | `rest` | multi-route |
| `<CopilotKitProvider>` (v2) | omitted | `auto`, detected from `/info`
| either |
| `<CopilotKitProvider>` | `{true}` | `single` | single-route |

`copilotkit.tsx:108` is the whole story:
`useSingleEndpoint={props.useSingleEndpoint ?? true}`. The v1 wrapper
renders `<CopilotKitProvider>` internally and **pins single-route
transport unless you pass the prop.** So the LangGraph quickstart is
internally coherent — v1 provider asks for single,
`copilotRuntimeNextJSAppRouterEndpoint` serves single — which is exactly
why chat works there and Threads cannot.

### The constraint nobody had documented

I swept every v1-era wrapper:

- `copilotRuntimeNextJSAppRouterEndpoint` →
`createCopilotEndpointSingleRoute`
- `copilotRuntimeNodeHttpEndpoint` → `createCopilotEndpointSingleRoute`
- `copilotRuntimeNextJSPagesRouterEndpoint`,
`copilotRuntimeNodeExpressEndpoint`, `copilotRuntimeNestEndpoint` → all
delegate to `copilotRuntimeNodeHttpEndpoint`

**Every one builds its handler with `mode: "single-route"` and exposes
no option to change it.** There is no v1-shaped multi-route handler
anywhere in the package.

The consequence is sharper than defect 5 as filed: **Rich Threads and
the Inspector are unreachable from the wiring both quickstarts teach, at
any provider setting.** Setting `useSingleEndpoint={false}` cannot fix
it — it just points the browser at routes the wrapper will not serve.
You need a v2 `CopilotRuntime` from `@copilotkit/runtime/v2` plus
`createCopilotRuntimeHandler`. That is a server-side change, not a
provider prop, and it is the structural reason defect 3's trap exists.
Worth its own ticket.

## Why I did not converge the quickstarts on v2

That was the original plan for this PR and I abandoned it after checking
the backend half. The split matters:

- **Frontend would have been free.** Both quickstarts already import
from `@copilotkit/react-core/v2`, where `CopilotKit` is labelled in
source as a *"V1 backward-compat re-export"*. `CopilotKitProvider` ships
from that same entry, and `CopilotSidebar` already depends on
`useLicenseContext` from it. Swapping is an import change.
- **Backend would not.** The multi-route handler takes a v2
`CopilotRuntimeLike`; the quickstart's v1 `CopilotRuntime` only reaches
it via an internal `.instance` getter that lazily news up a
`CopilotRuntimeVNext`. Converging means teaching v2 runtime construction
and dropping `ExperimentalEmptyAdapter` mid-quickstart — a real v1→v2
migration for every reader of the two highest-traffic pages.

v1 is supported, so the default path stays put. The mapping documents
all pairs instead, and the Threads upgrade stays a labelled, complete
recipe on the page the quickstarts already link to.

## What changed

**`backend/runtime-endpoints.mdx`** — new "Provider and handler pairs"
section: the provider table, the handlers-by-mode table, the
deprecated-alias mapping (`createCopilotEndpoint`,
`createCopilotEndpointSingleRoute`, and the Express pair), the wrapper
constraint above, and a "read the symptom" callout (a mismatch fails at
discovery — `GET {basePath}/info` 404s, or the Runtime rejects the
envelope — never in your application code).

**Both quickstarts** — a short callout naming the pair the page uses and
linking the mapping.

**Defect 9, `integrations/built-in-agent/quickstart.mdx`** — this is
what `/quickstart` actually serves (verified: both URLs return the
identical 8175-byte body; the root `quickstart.mdx` is a 17-line routing
shim that 308-redirects to `/`). `BuiltInAgent` extends `AbstractAgent`
and calls the model directly via `streamText`, so registering it as
`default` replaces the developer's agent rather than connecting to it.
Added a caution: readers with an existing agent take the frontend steps
here and the runtime wiring from their framework's quickstart.

**Defect 6, second half** — same page installed `@copilotkit/react-ui`
and never used it, importing `CopilotKit`/`CopilotSidebar` from
`@copilotkit/react-core/v2`. Dropped, matching #6566.

## Testing

```
$ npx vitest run
Test Files  1 failed | 58 passed (59)
     Tests  1 failed | 417 passed (418)
```

The one failure is `channels-docs.test.ts > publishes the Channels
overview only through provider navigation` — pre-existing, and proven so
in #6566 by stashing on a clean tree.

**I broke two tests and fixed them, which is worth recording** because
it caught a real defect in my first draft.
`angular-docs-content.test.ts` flagged:

```
built-in-agent/backend/runtime-endpoints: @copilotkit/react
langgraph-python/backend/runtime-endpoints: @copilotkit/react
... 10 surfaces total
```

`backend/runtime-endpoints.mdx` also serves the **Angular** surface, and
my provider prose named React packages there. Correct fix, not a
suppression: the provider axis is React-only — Angular's
`provideCopilotKit` has no `useSingleEndpoint` — so the provider table
is now `<FrontendOnly frontend="react">` with an Angular branch saying
only the handler half applies. Both Angular tests pass.

### Render checks

Per surface, `.md` and HTML:

| surface | provider table | Angular note | `@copilotkit/react` |
wrapper callout |
|---|---|---|---|---|
| langgraph-python | ✅ | — | 3 | ✅ |
| langgraph-typescript | ✅ | — | 3 | ✅ |
| angular | — | ✅ | **0** | ✅ |

The wrapper-constraint callout correctly stays on all three: it is a
server-side fact that applies to Angular too.

Defect 9 / 6b on `/quickstart` and `/built-in-agent/quickstart` — both
8175 bytes, caution present, `react-ui` gone from the install line, pair
pointer present.

Every link I added was **body-verified, never by status code** (this
site soft-404s with HTTP 200):

```
/langgraph-python/quickstart                 bytes=428497  soft404=0  h1=Quickstart
/                                            bytes=248255  soft404=0  h1=CopilotKit
/backend/runtime-endpoints                   bytes=375782  soft404=0  h1=Runtime HTTP endpoints
/langgraph-python/backend/runtime-endpoints   bytes=395130  soft404=0  h1=Runtime HTTP endpoints
```

New anchors confirmed present (`id="provider-and-handler-pairs"`,
`id="which-handlers-serve-which-mode"`), and the pointer rewrites into
the reader's namespace correctly — `/langgraph-python/backend/...` from
the LangGraph page, `/backend/...` from the root surface.

## Voice pass

A third commit runs a tone/voice check over everything added for
OSS-857, measured against the corpus instead of guessed. It also
corrects the wording that already landed in #6566, so the whole ticket
reads in one voice.

**Second person stays.** It is emphatically the house voice: 22 of 29
top-level and backend pages use `you`/`your`, and the three pages
involved used it **17, 23 and 64 times** before any of these edits.
Stripping it would make the new prose stand out, not blend in.
Mid-sentence `**bold**` also stays — the corpus does that 17 times.

What genuinely drifted, and is now fixed:

| Issue | Was | Now |
|---|---|---|
| British spelling | `honours` | `serves` |
| Third person on a second-person page | `A developer adding A2UI to an
agent they already wrote…` | `If you added A2UI to an agent you already
wrote…` |
| Essay register | `That default is the one thing to remember:` | plain
statement of the fact |
| Meta phrasing | `so this is the mapping` | `so this table is the
mapping` |
| Conversational | `no provider pairing to get wrong` | `to configure` |
| Conversational | `` `uvicorn` is told to listen on `8123` `` | ``
`main.py` sets uvicorn's port to `8123` `` |
| Literary | `you may also meet these deprecated aliases` | `Older code
may use these deprecated aliases` |
| Coinage | `agent construct` | `how the agent itself is built` |
| Coinage | `without that steer` | `Without it, the model tends to…` |
| Aphoristic Callout title | `Mismatched pair? Read the symptom, not the
code` | `A mismatched pair fails at discovery` |
| Epigram | `It replaces your agent; it does not connect to one.` | `It
replaces your agent rather than connecting to it.` |
| Redundancy | `nothing supplies persistence for you` | `nothing
supplies persistence` |

Two of these were objective, not stylistic: the corpus is American
English (`behavior` 66:6, `customize` 77:4, `serialize` 18:1, `organize`
15:0) and its only `honour` was mine; and it contains exactly two
instances of `a developer`, one of which was mine on a page that
addresses the reader directly throughout.

Callout titles were checked against the house set — declarative or plain
question (`v1 behaves differently`, `Three routes are not user-scoped`,
`Using a custom backend?`) — which is why the aphorism was the one
outlier.

Re-verified after the rewording: tests back to the single pre-existing
failure, every reworded string renders on the right surface, Angular
still shows **zero** React package mentions, and the `StateGraph` step
is still gated to langgraph-python + langgraph-fastapi only.

## Coordination

Draft PR #6112 (onsclom) also touches
`integrations/built-in-agent/quickstart.mdx`, but only two prose lines —
the signup sentence and the "Already have an app?" callout. My hunks are
the install line and the runtime step, so they should merge cleanly.
Flagging rather than assuming.

## Follow-ups this surfaced

- **Threads needs a v2 server migration** from either quickstart's
starting point. No v1-shaped multi-route handler exists. Own ticket.
- **Defects 1 and 2** ride the non-interactive project-selection work.
2026-08-19 14:38:47 -05:00
Benjamin Taylor 9ffe2546ce docs(inspector): document mounting the Inspector in Angular
The Inspector is the framework-agnostic `cpk-web-inspector` web component.
`@copilotkit/angular` does not reference or mount it, so an Angular app has to
create the element itself — and nothing said so. Worse, the Angular docs mapped
the `inspector` slug onto `guides/troubleshooting`, so `/angular/*/inspector`
redirected away from the Inspector entirely and the only thing left under
"Observe & Operate" was the VS Code extension.

Add an Angular-owned Inspector page covering the mount component, the
`core` handoff with `auto-attach-core="false"`, positioning, production
exclusion, server rendering, and cleanup on destroy. Drop the redirect so the
page is reachable, and point at it from the Angular troubleshooting guide.
React's Inspector content is untouched and unmoved.

Also correct the `/cpk-debug-events` path: it is relative to the runtime's
mounted `basePath`, not the server origin, and it only carries events for a
self-hosted SSE runtime — an Intelligence-backed runtime answers runs over the
platform's realtime connection, so the stream connects and stays empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 14:37:03 -05:00
Martha Kelly Schumann 7cb5205437 feat: add AWS Strands TypeScript starter (#6555)
## Summary

- add a standalone AWS Strands TypeScript starter with shared state,
tools, A2UI, Channels, and Docker support
- register the starter in parity, migration, docs, and PR smoke coverage
- publish the canonical `aws-strands-ts` command in the shared AWS
Strands documentation
- keep the starter out of the live Railway fleet map until a service is
provisioned

## Why

FAC-126 reports that `copilotkit create` offers AWS Strands only in
Python. The maintained TypeScript integration already exists in the
showcase, but there was no standalone starter for the CLI to download.

This is part 1 of 2.
[CopilotKit/Intelligence#878](https://github.com/CopilotKit/Intelligence/pull/878)
adds the CLI catalog entry and aliases. Merge this PR first, then merge
#878.

The CLI PR is pinned to reachable commit
`20e481b749141db40fb3126ed39d73e74e8b197c`.

## Validation

- `npm run typecheck` in the starter agent
- `npx tsc --noEmit` in the starter root
- `npm run build` in the starter root
- `pnpm parity:verify --target=strands-typescript`
- focused shell-docs tests and typecheck
- slug-map and starter-mapping drift tests
- repository config allowlist check
- agent module startup and strict CSV load
- GitHub starter Docker image build
- `git diff --check`

The local Docker smoke attempt could not extract the Playwright image
because the machine ran out of disk. GitHub CI runs the same Compose
smoke stack.

Linear:
[FAC-126](https://linear.app/copilotkit/issue/FAC-126/aws-strands-typescript-starter-missing-from-copilotkit-create)
2026-08-19 11:55:37 -07:00
Benjamin Taylor 6c1a9eb4b4 docs: match the house voice in the OSS-857 prose (refs OSS-857)
A voice pass over everything added for OSS-857, measured against the
corpus rather than guessed.

Second person stays: it is emphatically the house voice — 22 of 29
top-level and backend pages use you/your, and the three pages involved
used it 17, 23 and 64 times before any of these edits. Mid-sentence
`**bold**` for emphasis also stays; the corpus does that 17 times.

What actually drifted:

- `honours` → `serves`. The corpus is American English (behavior 66:6,
  customize 77:4, serialize 18:1, organize 15:0) and the single
  `honour` in it was mine.
- `A developer adding A2UI to an agent they already wrote…` → second
  person. The corpus contains exactly two `a developer`, and one was
  mine; the page around it addresses the reader directly throughout.
- Essay register: "That default is the one thing to remember:" → a plain
  statement of the fact. "so this is the mapping" → "so this table is
  the mapping".
- Conversational: "no provider pairing to get wrong" → "to configure";
  "`uvicorn` is told to listen on 8123" → "`main.py` sets uvicorn's port
  to 8123"; "you may also meet these deprecated aliases" → "older code
  may use these deprecated aliases".
- Coinages: "agent construct" → "how the agent itself is built"; "that
  steer" → "Without it, the model tends to…".
- Aphoristic Callout title "Mismatched pair? Read the symptom, not the
  code" → "A mismatched pair fails at discovery". House titles are
  declarative or plain questions ("v1 behaves differently", "Three
  routes are not user-scoped", "Using a custom backend?").
- Epigram: "It replaces your agent; it does not connect to one." → "It
  replaces your agent rather than connecting to it."
- Redundancy: "nothing supplies persistence for you" → "nothing
  supplies persistence".

The a2ui and LangGraph quickstart wording landed in #6566; those files
are corrected here so the whole ticket reads in one voice.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 13:50:19 -05:00
copilotkit-qa-bot[bot] 90d36a62c7 Merge main into codex/fac-126-strands-ts-starter 2026-08-19 11:46:47 -07:00
Ben Taylor 1cafb58b4a ci: stop Playwright browser installs shelling out to apt (#6567)
Ports
[CopilotKit/website#529](https://github.com/CopilotKit/website/pull/529)
to this repo. CI workflow config only — six files under
`.github/workflows/`, no package or source code touched.

## The problem

Every Playwright browser install in this repo passes `--with-deps`,
which runs `apt-get update` before downloading the browser. apt on the
runners cannot always reach `azure.archive.ubuntu.com`; when it can't,
it retries for many minutes before falling back to `archive.ubuntu.com`.
In the website repo that burned ~14 of a job's 15 minute
`timeout-minutes` budget and the job was killed before it ran a single
test — and GitHub renders a `timeout-minutes` kill as "The operation was
canceled", so it shows up in the checks list looking like a test failure
rather than an infrastructure hang.

One thing is worse here than in website. Website only took the apt
branch on PRs that touched `pnpm-lock.yaml` (a cache-key interaction).
**This repo has no Playwright browser cache at all** — `grep -rn
ms-playwright .github/` returns nothing — so all six of these jobs shell
out to apt unconditionally, on every run.

## The change

```diff
-        run: pnpm exec playwright install --with-deps chromium
+        run: pnpm exec playwright install chromium
```

Chromium's system libraries are already present on the Ubuntu runner
images, and **every one of these six steps installs chromium only**, so
the browser download is all any of them needs. A comment records the
reasoning in-file at each site so the next person doesn't helpfully
restore `--with-deps`.

| Workflow | Step | Job timeout |
|---|---|---|
| `test_unit.yml` | Install Chromium for packed Angular browser smoke |
25m |
| `test_e2e-legacy-v1.yml` | Install Playwright browsers | 20m |
| `test_e2e-showcase-on-demand.yml` | Install Playwright | 15m |
| `test_showcase-frontend-matrix.yml` | Install Chromium | 45m / 15m |
| `showcase_eval.yml` | Install Playwright chromium | 45m |
| `showcase_capture-previews.yml` | Install Playwright | 30m |

## Verification

The substantive claim — "Chromium launches without `install-deps` on the
runner images" — is about the runner image and cannot be checked
locally. **This PR's own CI run is the verification, and it holds:** 23
checks pass, 2 skipped, 0 failures.

Two jobs here actually launch a browser:

- **`test / e2e / legacy-v1`** — success. All five example legs
(`chat-with-your-data`, `form-filling`, `research-canvas`,
`state-machine`, `travel`) ran their Playwright suites to completion on
`depot-ubuntu-24.04-4`.
- **`test / unit`** — success. The packed Angular browser smoke launched
Chromium on both Node 22.x legs.

Confirmed independently in ag-ui-protocol/ag-ui#2468, where all 24 `dojo
/ *` legs ran their Playwright suites green on `depot-ubuntu-24.04`
after the same change. Between the two PRs that is 31 browser-launching
jobs on Depot images with no `install-deps` anywhere.

### Measured effect

Same step, same workflow, `main` vs this branch:

| | `Install Chromium for packed Angular browser smoke` |
|---|---|
| `main` — run
[32271967199](https://github.com/CopilotKit/CopilotKit/actions/runs/32271967199)
| **86s**, **104s** |
| this PR — run
[32281720527](https://github.com/CopilotKit/CopilotKit/actions/runs/32281720527)
| **7s**, **8s** |

apt was ~92% of that step even on a run where it *wasn't* hanging. The
failure mode this PR removes is the tail, not the mean.

Static checks:

```
$ python3 -c "yaml.safe_load each touched workflow"
ok .github/workflows/test_unit.yml
ok .github/workflows/showcase_capture-previews.yml
ok .github/workflows/showcase_eval.yml
ok .github/workflows/test_e2e-showcase-on-demand.yml
ok .github/workflows/test_e2e-legacy-v1.yml
ok .github/workflows/test_showcase-frontend-matrix.yml
```

`actionlint` on the six touched files, `origin/main` vs this branch
(line:col stripped so comment insertions don't shift the comparison):

```
$ diff before.txt after.txt
before=27 after=27
IDENTICAL — no new actionlint findings
```

The 27 findings are pre-existing on `main` — `depot-ubuntu-*` runner
labels actionlint doesn't know, and shellcheck `SC2086`/`SC2129` info in
unrelated steps.

Current timings, for what the change is worth: on run
[32271967199](https://github.com/CopilotKit/CopilotKit/actions/runs/32271967199)
the `Install Chromium` step took **86s and 104s** across the two Node
22.x matrix legs. So apt is reachable from our runners *today* — this is
preventive, plus ~1–1.5 min per job, not a fix for something currently
red.

## Risk

~~Guido proved the no-`install-deps` claim on GitHub's `ubuntu-latest`.
Three of these jobs run on `depot-ubuntu-24.04-*`, and Depot mirroring
GitHub's image is the one thing this PR's CI needs to confirm.~~
**Resolved** — see Verification above; Chromium launches on the Depot
images.

The residual risk is coverage, not the claim. Four of the six workflows
are `workflow_dispatch`/`issue_comment`-gated and so do not run on this
PR: `test_e2e-showcase-on-demand`, `test_showcase-frontend-matrix`,
`showcase_eval`, `showcase_capture-previews`. Their edit is textually
identical to the two that *were* exercised and all six installed
chromium only, so this is one shared claim rather than four independent
ones — but say the word and I'll dispatch any of them against the branch
before merge.

If a library does turn out to be missing, the fallback is `timeout 300
pnpm exec playwright install-deps chromium` — bounding the hang instead
of removing it — rather than restoring the unbounded `--with-deps`.

## Notes for review

- **A companion change is needed in ag-ui.**
`apps/dojo/e2e/package.json` there has `"postinstall": "playwright
install --with-deps"`, and our `test_e2e-dojo.yml` installs that package
with `pnpm install` (scripts enabled), so our dojo job has been pulling
all three browser engines through apt while `playwright.config.ts`
declares a chromium project only. ag-ui's own workflow dodges it with
`--ignore-scripts`. Fixed in
[ag-ui-protocol/ag-ui#2468](https://github.com/ag-ui-protocol/ag-ui/pull/2468);
since e2e-dojo pulls ag-ui at floating `main`, it reaches this repo's CI
as soon as that lands.
- `showcase_capture-previews.yml` still does `sudo apt-get update &&
apt-get install -y ffmpeg` one step earlier, so that job keeps an apt
call with the same hang exposure. Left alone — separate concern, happy
to bound it in a follow-up.
- Dockerfiles under `showcase/` keep `--with-deps` deliberately: those
build on Debian/Alpine images that genuinely lack the libraries.
Local-dev docs (`examples/e2e/AGENTS.md`) are unchanged for the same
reason.
- No changeset: CI config only, nothing published.
2026-08-19 13:44:14 -05:00
Benjamin Taylor 4078a11f36 docs(runtime): map the provider/handler pairs and guard BuiltInAgent (refs OSS-857)
Fixes defects 5 and 9 from the OSS-856 phase 1 validation run, plus the
half of defect 6 that lives on the Built-in Agent quickstart. Every claim
was traced through package source.

Defect 5 — three provider/handler names presented as interchangeable.
They are not interchangeable; they pair up, and the pairing is what was
undocumented. Added a "Provider and handler pairs" section to
`backend/runtime-endpoints.mdx`:

- The v1 `<CopilotKit>` wrapper renders `<CopilotKitProvider>` internally
  and pins `useSingleEndpoint` to `true` unless the prop is passed
  (`copilotkit.tsx:108`), so it asks for single-route transport even
  against a multi-route Runtime. `<CopilotKitProvider>` with the prop
  omitted resolves to `auto` and detects from `/info`.
- A table of which handlers serve which mode, and the deprecated aliases
  (`createCopilotEndpoint`, `createCopilotEndpointSingleRoute`, and the
  Express pair) mapped to their replacements.
- The constraint nobody had written down: every `copilotRuntime*Endpoint`
  wrapper builds its handler with `mode: "single-route"` and exposes no
  option to change it. Next.js App Router and node-http call the
  single-route helper directly; pages-router, node-express and nest all
  delegate to node-http. So Rich Threads is unreachable from the wiring
  the quickstarts teach at ANY provider setting — it needs a v2
  `CopilotRuntime` plus a multi-route handler. That is the structural
  reason behind defect 3.
- Provider half is scoped to `<FrontendOnly frontend="react">` with an
  Angular branch, because this page also serves the Angular surface and
  `provideCopilotKit` has no `useSingleEndpoint`.

Both quickstarts gain a short callout naming the pair they use and
linking the mapping.

Defect 9 — the Built-in Agent quickstart (what `/quickstart` actually
serves) instantiates `new BuiltInAgent(...)` as the `default` agent with
nothing warning a reader who already has one. `BuiltInAgent` extends
`AbstractAgent` and calls the model directly via `streamText`, so
registering it replaces the developer's agent rather than connecting to
it — the `user_code_preservation` violation the ticket describes. Added a
caution telling readers with an existing agent to take the frontend steps
here and the runtime wiring from their framework's quickstart.

Defect 6, second half — the same page installed `@copilotkit/react-ui`
and never used it, importing `CopilotKit` and `CopilotSidebar` from
`@copilotkit/react-core/v2`. Dropped it, matching the LangGraph fix in
#6566.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 13:35:43 -05:00
copilotkit-qa-bot[bot] 573a614112 Merge main into codex/fac-126-strands-ts-starter 2026-08-19 11:34:30 -07:00
copilotkit-qa-bot[bot] b9d41c0e3a Merge main into codex/fac-126-strands-ts-starter 2026-08-19 11:31:21 -07:00
Mike Ryan f40e532822 docs(backend): construct the Intelligence client and name its key (refs OSS-857) (#6568)
Fixes OSS-857 defects 1 and 2, which turn out to be one root cause.

## The problem

`backend/runtime-endpoints.mdx` shows this:

```ts
const runtime = new CopilotRuntime({
  agents,
  intelligence,
  identifyUser: async (request) => { /* ... */ },
});
```

`intelligence` is a bare identifier. No import, no shape, no env source,
and no
page on the web path constructs it — so the example is not copyable.

That is also why `INTELLIGENCE_API_KEY` appeared to have no consumer,
which the
ticket called its "defect that matters most". `copilotkit project
select` writes
that key into `.env`, and `apiKey` on the Intelligence client is what
reads it.
Because no web page ever built the client, the variable looked orphaned.

## The fix

The construction was already documented correctly — but only on the
Channels
pages (`frontends/slack.mdx:120`, `frontends/teams.mdx`). This adds a
step to
the web path using that same pattern rather than inventing a second
vocabulary
for it:

```ts
import { CopilotKitIntelligence } from "@copilotkit/runtime/v2";

const intelligence = new CopilotKitIntelligence({
  apiKey: process.env.INTELLIGENCE_API_KEY!,
});
```

It also documents the paired-override rule for `apiUrl` / `wsUrl`,
because the
API and realtime planes are separate hosts and setting one alone logs a
warning.

## The Inspector page was not wrong

`NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY` is the correct variable for the
Inspector.
The defect is that a reader whose `.env` holds `INTELLIGENCE_API_KEY`
cannot tell
whether the two are the same credential. So
`snippets/shared/premium/inspector.mdx`
now disambiguates them — publishable browser key versus server-side
project key,
with a pointer to what consumes the latter — rather than substituting
one for the
other.

## Verified against source, not inferred

- `CopilotKitIntelligence` is publicly exported from
`@copilotkit/runtime/v2`
  (`intelligence-platform` → `v2/runtime/index.ts` → `v2/index.ts`)
- `apiKey` is the only required field of `CopilotKitIntelligenceConfig`
- `apiUrl` and `wsUrl` default to the managed platform, and
`warnOnPartialHostOverride` logs a warning when one is set without the
other

## What I could not verify

The site build and its vitest suite did not run: this was authored in a
fresh
worktree with no installed toolchain, and `oxlint` covers JS/TS rather
than MDX,
so it would not have exercised these edits anyway. CI is the first real
gate.

Checked instead:

- `<Step>`, `<FrontendOnly>` and code-fence balance in both files
- both new links against existing usage in the content tree —
`](/inspector)`
  appears 7 times and `](/backend/runtime-endpoints)` 10 times. The site
soft-404s on unknown paths, so a link cannot be verified by status code.

## Scope

Defects 3, 4, 6, 7, 8, 10, 11 and 12 landed in #6566. Defects 5 and 9
are being
handled separately and are untouched here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-19 11:31:04 -07:00
Benjamin Taylor 99d3f99f4c docs(backend): construct the Intelligence client and name its key (refs OSS-857)
Fixes OSS-857 defects 1 and 2, which are one root cause. No page on the web
path ever constructs `CopilotKitIntelligence`, so `intelligence` reads as an
undefined identifier in the `new CopilotRuntime({ agents, intelligence,
identifyUser })` example, and `INTELLIGENCE_API_KEY` reads as a credential
with no consumer. `apiKey` IS that consumer.

The construction was already documented correctly, but only on the Channels
pages (frontends/slack.mdx, frontends/teams.mdx). This lifts the same pattern
onto the web path rather than inventing a second vocabulary for it.

Verified against packages/runtime source rather than inferred:

- `CopilotKitIntelligence` is exported publicly from `@copilotkit/runtime/v2`
  via intelligence-platform -> v2/runtime/index.ts -> v2/index.ts
- `apiKey` is the only required field of `CopilotKitIntelligenceConfig`
- `apiUrl` and `wsUrl` default to the managed platform, and
  `warnOnPartialHostOverride` logs a warning when one is set without the other,
  which is why the docs now say to override both together

The Inspector page was NOT wrong to show `NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY` --
that is the correct variable for that purpose. The defect is that a reader whose
.env holds `INTELLIGENCE_API_KEY` cannot tell whether the two are the same
credential. So that page disambiguates rather than substitutes: publishable
browser key versus server-side project key, with a pointer to what consumes the
latter.

Not verified: the site build and its vitest suite. A fresh worktree has no
installed toolchain (oxlint is absent), and oxlint covers JS/TS rather than MDX,
so it would not have exercised these edits. What was checked instead: <Step>,
<FrontendOnly> and code-fence balance in both files, and both new links against
existing usage -- `](/inspector)` appears 7 times and
`](/backend/runtime-endpoints)` 10 times elsewhere in the content tree. The site
soft-404s on unknown paths, so a link cannot be verified by status code.

Defects 5 and 9 remain open and are not addressed here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 13:16:39 -05:00
Ben Taylor 15ee7c6e5f docs(langgraph): fix 8 verified defects in the LangGraph onboarding docs (refs OSS-857) (#6566)
Fixes 8 of the 12 defects in OSS-857 (the OSS-856 phase 1 validation
run). Defects **1, 2, 5 and 9** are owned by a parallel session working
in `backend/runtime-endpoints.mdx`,
`integrations/langgraph/inspector.mdx` and the root `quickstart.mdx` —
**do not close OSS-857 on this PR.**

Every claim below was re-derived from installed package source or a live
run. Nothing here is recalled.

## Scope correction worth flagging first

The task's file table mapped
`/langgraph-python/generative-ui/a2ui/fixed-schema` to
`integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx`. That is
not the file the URL serves. `langgraph-python` is `docs_mode:
generated`, so `page.tsx` tries `loadDoc(slugPath)` first and the
**root** `generative-ui/a2ui/fixed-schema.mdx` wins. Defects 10, 11 and
12 all live in the root file, which is shared by 21 frameworks — a much
larger blast radius than the table implied. Confirmed by rendering, not
by reading:

```
$ curl -sL localhost:3013/langgraph-python/generative-ui/a2ui/fixed-schema | grep -c "Load the schema JSON at startup"
2                      # root file's schema-loading branch
$ ... | grep -c "Action handler details"
0                      # the langgraph-scoped file's heading — never served
```

**The langgraph-scoped
`integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx` is dead
content at every URL.** Same for the sibling `index.mdx` and
`dynamic-schema.mdx`. Only `advanced.mdx` and `styling.mdx` survive,
because they have no root counterpart — and even those are unreachable
from the sidebar. Worth its own ticket; not touched here.

## What changed, defect by defect

### 3 — Route shape (partial, as scoped) ✅

Added a caution at the route step. Deliberately did **not** rewrite the
route.

The precise mechanism, which matters for how the caution is worded:
`copilotRuntimeNextJSAppRouterEndpoint` calls
`createCopilotEndpointSingleRoute`
(`packages/runtime/src/lib/integrations/nextjs/app-router.ts:39`). So
the quickstart's POST-only route is **single-route mode** and chat
genuinely works. It is not a broken route — it is the wrong mode for
Threads. The caution says exactly that, names the `[[...slug]]`
catch-all with `GET`/`POST`/`PATCH`/`DELETE`, ties it to the Inspector's
"Finish setting up Rich Threads" state, and links to
`/backend/runtime-endpoints#enable-rich-threads-routes` (anchor verified
present).

I did not assert that you can just add verbs to this handler — that
would be wrong, and it is entangled with defect 5, which the other
session owns.

### 4 — Port mismatch ✅

**Verified the default rather than trusting the ticket.** Both CLIs
default to **2024**:

```
$ npx @langchain/langgraph-cli@latest dev --help
  -p, --port <number>   port to run the server on (default: "2024")

$ grep -n -A3 '"--port"' langgraph_cli/cli.py
670:    default=2024,
```

The page was already internally consistent on 8123 — the trap is that
nothing said the bare command differs, and 8123 is the convention across
every sibling page (`deep-agents.mdx`, `deepagents/quickstart.mdx`, the
showcase integration). So I took the second option in the brief: keep
`--port 8123` and name the default. Added a callout at the start
command, a per-tab note on which port each path serves, and a
troubleshooting line.

Also fixed a **factually wrong comment** in
`showcase/integrations/langgraph-python/.env.example`, which claimed
"langgraph dev runs on port 8123 by default". That is the same
mis-belief, committed in the repo. One comment line, no behavior change;
called out here because it is outside the two files named in the brief.

### 6 — `@copilotkit/react-ui` installed and never used ✅

Checked the exports; **the install line was wrong**, not the import.

- `CopilotSidebar` is at
`packages/react-core/src/v2/components/chat/CopilotSidebar.tsx`,
exported via `@copilotkit/react-core/v2`.
- `@copilotkit/react-ui`'s `exports` map has no `./v2` JS entry at all —
only `./v2/styles.css`. Its root export does carry a v1
`CopilotSidebar`, which would be the wrong component under a v2
provider.
- `examples/v2/react/demo` does not depend on `@copilotkit/react-ui`.

Dropped it from the install line and said where the components come
from. No unused import added.

### 7 — Checkpointer guidance ✅

Added the reason to each tab; kept the code difference, which is
correct.

Both directions verified:

**LangSmith tab (bare compile).** `langgraph dev` sets
`LANGSMITH_LANGGRAPH_API_VARIANT="local_dev"`
(`langgraph_api/cli.py:271`), and under that variant `graph.py:821`
raises on a compiled-in checkpointer. Reproduced with a real boot:

```
error  Graph 'sample_agent' failed to load: ValueError: Heads up! Your graph 'graph'
from './main.py' includes a custom checkpointer (type <class
'langgraph.checkpoint.memory.InMemorySaver'>). With LangGraph API, persistence is
handled automatically by the platform, so providing a custom checkpointer ... isn't
necessary and will be ignored when deployed.
```

The server does not start. So a reader who "helpfully" adds
`MemorySaver()` here breaks their deployment — exactly the failure the
ticket predicted.

**FastAPI tab (`MemorySaver()` required).** `ag_ui_langgraph/agent.py`
calls `graph.aget_state(config)` (lines 236, 474), and
`Pregel.get_state`/`aget_state` raise `ValueError("No checkpointer
set")` when none is configured (`langgraph/pregel/main.py:1402`). The
checkpointer is not optional on that path.

### 8 — "Existing agent" install line ✅

Narrowed to `uv add langgraph langchain-openai langchain-core
python-dotenv`.

One correction to the ticket's framing: the over-add is **one** package,
not two. The line is shared by both tabs, and only `copilotkit` is
unused by the LangSmith path — the FastAPI tab already re-adds it in its
own step alongside `ag-ui-langgraph`. And `python-dotenv` stays: the
code in **both** tabs does `from dotenv import load_dotenv`, so removing
it because `langgraph.json` declares `"env"` would break the shown
snippet. Removing an import's package is not a docs fix.

Added the pinned-dependency warning.

`doctest.json` **needs no change**: its dep list backs the
`doctest="server"` snippet (the FastAPI `main.py`), which still imports
all eight. Checked rather than assumed.

### 10 — Three identical conditional branches ✅ (root cause was code,
not prose)

The HTML page was already correct — only the `schema-loading` branch
renders for langgraph-python. The defect is entirely in the **`.md` view
the validation run read**: `renderPageToLlmText` applied
`filterFrontendScopedBlocks` and `filterAngularBackendScopedBlocks` but
never `filterFrameworkScopedBlocks`, so raw Markdown emitted all three
branches *with the literal JSX tags*, and every `<Snippet>` inside them
resolved against the one requested framework.

Before:

```
286:<WhenFrameworkHas flag="a2ui_pattern" equals="schema-loading">
402:<WhenFrameworkHas flag="a2ui_pattern" equals="schema-inline">
519:<WhenFrameworkHas flag="a2ui_pattern" equals="llm-driven">
```

…with byte-identical Python under each. That is what put "the host
language doesn't ship a `load_schema` JSON loader" directly above a
snippet calling `a2ui.load_schema` — the prose was never wrong for its
own framework, it was just being shown to the wrong one.

Fixed by gating on the same framework the snippets resolve to (routed
through `pickFramework`, so prose and code agree even on unscoped
`/<slug>.md`). This also repairs the same class of bug for the other
five gated flags across every framework's `.md`. The filter is flat-only
by design, so the new block is a sibling, not nested.

Regression test added and **mutation-checked** — disabling the filter
fails it:

```
× raw Markdown keeps only the active framework's <WhenFrameworkHas> branch
```

### 11 — `StateGraph` example + missing install ✅

**Install half:** the `definitions-types`, `catalog-creation` and
`renderers-tsx` snippets all import `@copilotkit/a2ui-renderer`, and no
page installed it. Added a step for it plus `zod` (both are explicit
deps of the langgraph-python cell). `@copilotkit/a2ui-renderer` is a
real published package at 1.68.1, not private.

**`StateGraph` half:** added, with **verified** code — not a guess.

A re-verification pass sharpened this defect. `create_agent` appears on
that page **only as an import** — both snippet regions
(`backend-schema-json-load`, `backend-render-operations`) stop inside
the tool body, so the agent construction is never shown at all:

```
$ grep -n "create_agent" <rendered .md>
315:from langchain.agents import create_agent      # import only
347:from langchain.agents import create_agent      # import only
```

So the page leaves `create_agent`, `CopilotKitMiddleware` and
`ChatOpenAI` as imports the reader cannot act on. My first draft wrongly
said "the snippet above is the reference cell's `create_agent` form";
that is corrected in the second commit, and the step now also carries
over the cell's system-prompt caveat (the prompt tells the model to call
`display_flight` once and stop, because the tool result *is* the card).

Two probes, offline:

1. `ChatOpenAI(model="gpt-4.1-mini").bind_tools([display_flight])`
constructs (no network).
2. A `StateGraph` + `ToolNode` + `tools_condition` graph, bare
`compile()`, driven by a fake chat model, puts the A2UI container in the
`ToolMessage`:

```
operation kinds: ['createSurface', 'updateComponents', 'updateDataModel']
PROBE2 OK (bare compile, ToolNode, tools_condition, bind_tools)
```

Placement needed care, because the root page is shared by 21 frameworks
and `WhenFrameworkHas` gates only on manifest flags — `a2ui_pattern:
schema-loading` covers 14 non-LangGraph integrations, so putting it
there leaked LangGraph code to LlamaIndex/ADK/Pydantic-AI **and Python
code to langgraph-typescript**. Confirmed by rendering before gating:

```
llamaindex             stategraph=1     # wrong
langgraph-typescript   stategraph=1     # wrong: Python on a TS framework
```

So I added a narrow docs flag, `a2ui_agent_form: langgraph-state-graph`,
via the extension path `when-framework-has.tsx` documents (manifest
schema → `Integration` → `SupportedFlag` → manifest). Set on
`langgraph-python` and `langgraph-fastapi` only. After gating:

```
langgraph-python       stategraph=1
langgraph-fastapi      stategraph=1
langgraph-typescript   stategraph=0
llamaindex / google-adk / pydantic-ai / mastra / ms-agent-dotnet   stategraph=0
```

**Known gap, stated plainly:** `langgraph-typescript` gets no
`StateGraph` form. I did not write one, because I have not verified a
TypeScript LangGraph + A2UI form and a plausible-but-unrun TS snippet is
worse than the gap. Adding it is a follow-up; the flag is the seam for
it.

**One caveat on this snippet:** every other code block on that page is
machine-extracted from a running showcase cell. This one is hand-written
and probe-verified. Backing it with a real cell (a `StateGraph` A2UI
backend + fixture) would be the durable fix and is worth a follow-up.

### 12 — Two unreconciled doc trees ✅

`/integrations/langgraph/generative-ui/a2ui/fixed-schema` was not merely
the wrong prefix — it **301s straight back to the page it sits on**:

```
$ curl -o /dev/null -w "%{http_code} %{redirect_url}" .../integrations/langgraph/generative-ui/a2ui/fixed-schema
301 http://localhost:3013/langgraph-python/generative-ui/a2ui/fixed-schema
```

So the sentence promising "the full pattern" linked to itself, and for a
langgraph-typescript reader it also silently switched framework.
Repointed at the reference it actually promises, relative so it resolves
in the reader's own namespace — matching the `./dynamic-schema`
convention already on this page.

**Body-verified, not status-verified** (the site soft-404s with HTTP
200):

```
langgraph-python       bytes=353527  id="action-handlers"=1  onAction=9  soft404=0
langgraph-typescript   bytes=354215  id="action-handlers"=1  onAction=9  soft404=0
```

Non-LangGraph frameworks get the graceful "topic specific to other
integrations" page listing where it exists — not a dead end.

## Found while double-checking — reported, not changed

Both are on the page I own, both are real, and I left both alone
deliberately.

**The LangSmith tab runs a Python agent with the JavaScript CLI.** The
start command is `npx @langchain/langgraph-cli dev`, but the agent is
`main.py` and `langgraph.json` declares `"python_version": "3.12"`. I
expected this to fail. It does not — the JS CLI detects the Python
config and delegates, but prints:

```
warn: Launching Python server from @langchain/langgraph-cli is experimental.
      Please use the `langgraph-cli` package from PyPi instead.
info: Downloading uv 0.9.11 for darwin...
Installed 76 packages in 53ms
```

It then boots normally and honours `--port`. So this is not a copy-paste
failure — it is an experimental path that LangChain itself advises
against, plus a surprise toolchain download. I did **not** change the
command: it works, the recommended alternative would change the
dependency set (defect 8's territory), and the identical command appears
on three other pages (`integrations/langgraph/deep-agents.mdx`,
`integrations/deepagents/quickstart.mdx`, `deepagents/index.mdx`), so
changing one page in isolation would just create a new inconsistency.
Worth its own ticket across all four.

**The quickstart's runtime helper is deprecated.**
`copilotRuntimeNextJSAppRouterEndpoint` →
`createCopilotEndpointSingleRoute`, which carries `@deprecated Use
createCopilotHonoHandler with mode: "single-route" instead`
(`packages/runtime/src/v2/runtime/endpoints/hono-single.ts:24`). That is
defect 5's territory — the parallel session owns the handler-name
mapping — so per the brief I renamed nothing.

The upside of tracing it: it let me word the defect-3 caution precisely.
`createCopilotEndpointSingleRoute` calls `createCopilotRuntimeHandler({
mode: "single-route" })`, i.e. literally the same mode the
runtime-endpoints page documents, so the caution can say "runs the
runtime in single-route mode" as a fact rather than an inference.

## Not resolved / left for others

- **Defects 1, 2, 5, 9** — parallel session's files. Untouched,
including cross-references. In particular I renamed **no** providers or
handlers.
- **`langgraph-typescript` has no `StateGraph` form** — see defect 11
above.
- **The langgraph-scoped A2UI tree is dead content.**
`integrations/langgraph/generative-ui/a2ui/{index,fixed-schema,dynamic-schema}.mdx`
are shadowed at every URL; `advanced.mdx` and `styling.mdx` are
reachable but absent from the sidebar (`buildFrameworkOverridesNav`
surfaces top-level overrides like `subgraphs` and `configurable`, but
not these nested ones). Needs its own ticket.
- **The bring-your-own path on the shared quickstart is Python-only**
(`uv init`, `uv add`, `main.py`) for all three LangGraph frameworks,
including `langgraph-typescript`. Pre-existing; not widened by this PR,
but it is a real defect on a shared page.
- **`showcase/integrations/langgraph-fastapi`'s a2ui cell has a source
comment** pointing at
`docs/integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx` — i.e.
the shadowed file. Cosmetic, and inside a cell, so left alone.
- **`generative-ui/a2ui/index.mdx` links `./fixed-schema-streaming`**,
which does not exist at root. Noticed while verifying; out of scope.

## Testing

All from `showcase/shell-docs`.

```
$ npx tsc --noEmit
(clean)

$ npm run lint
0 errors  (pre-existing warnings only, none in touched files)

$ npx vitest run
Test Files  1 failed | 58 passed (59)
     Tests  1 failed | 417 passed (418)
```

The single failure is `channels-docs.test.ts > publishes the Channels
overview only through provider navigation`, about channels architecture
images. **Proven pre-existing** — `git stash -u` on this branch and
rerun gives the identical `1 failed | 29 passed`.

Manifest schema change validated:

```
$ cd showcase/scripts && npx vitest run __tests__/generate-registry-pattern.test.ts __tests__/create-integration.test.ts
Test Files  2 passed (2)      Tests  39 passed (39)

$ npm run pretypecheck   # regenerates registry.json from the manifests
langgraph-python  -> langgraph-state-graph
langgraph-fastapi -> langgraph-state-graph
```

Formatted with `oxfmt` (no changes needed). No changeset added.

### Render checks

Dev server on **3013**, not 3003 — 3003 was already held by another
worktree's docs server (`CopilotKit-oss844`), and reusing it would have
verified the wrong tree.

`quickstart` — identical across all three LangGraph frameworks, `.md`
and HTML:

| check | py | ts | fastapi |
|---|---|---|---|
| `npm install @copilotkit/react-core @copilotkit/runtime` | 1 | 1 | 1 |
| `uv add langgraph langchain-openai langchain-core python-dotenv` | 1 |
1 | 1 |
| route caution + `[[...slug]]` | 1 | 1 | 1 |
| "Port 8123 is not the default" / "serves on **2024**" | 1 | 1 | 1 |
| both checkpointer callouts | 1 | 1 | 1 |
| pinned-dependency warning | 1 | 1 | 1 |
| stale "Install LangGraph and AG-UI" heading | 0 | 0 | 0 |

Callouts confirmed rendering as components, not literal text (checked
the emitted React payload). Caught and fixed one real rendering bug
while doing this: Callout `title` is a plain string, so a backticked
title rendered its backticks literally.

Also re-checked the two directional cross-references, since those are
easy to get backwards: the "route below" note sits at line 289 and the
route step at 334 (below ✓), and the "route above" note at 487 (above
✓).

Cross-page link body-verified for all three LangGraph frameworks — the
`.md` view rewrites it into the reader's own namespace
(`/langgraph-python/backend/runtime-endpoints#enable-rich-threads-routes`),
and the target carries the anchor with no soft-404:

```
langgraph-python       bytes=374111  id="enable-rich-threads-routes"=1  soft404=0
langgraph-typescript   bytes=374871  id="enable-rich-threads-routes"=1  soft404=0
langgraph-fastapi      bytes=374301  id="enable-rich-threads-routes"=1  soft404=0
```

The `#registering-the-runtime` anchor referenced from the new A2UI step
was likewise confirmed present on that page.

`generative-ui/a2ui/fixed-schema` — `.md` across eight frameworks:

| framework | install step | StateGraph | old cross-tree link | new link
| raw JSX tags |
|---|---|---|---|---|---|
| langgraph-python | 1 | 1 | 0 | 1 | 0 |
| langgraph-fastapi | 1 | 1 | 0 | 1 | 0 |
| langgraph-typescript | 1 | 0 | 0 | 1 | 0 |
| llamaindex | 1 | 0 | 0 | 1 | 0 |
| google-adk | 1 | 0 | 0 | 1 | 0 |
| pydantic-ai | 1 | 0 | 0 | 1 | 0 |
| mastra | 1 | 0 | 0 | 1 | 0 |
| ms-agent-dotnet | 1 | 0 | 0 | 1 | 0 |

Branch selection now matches HTML per framework (`schema-loading` for
langgraph, `llm-driven` for mastra, `schema-inline` for ms-agent-dotnet)
with zero `WhenFrameworkHas` tags leaking into Markdown.

`doctest.json` was **not** treated as a gate — there is no runner for it
in the repo, and its dep set is unchanged anyway.
2026-08-19 12:58:12 -05:00
Benjamin Taylor f24c4e2f22 docs(langgraph): correct the A2UI StateGraph framing after re-verification (refs OSS-857)
Three fixes found on a second pass over the docs changes:

- The new StateGraph step claimed "the snippet above is the reference
  cell's `create_agent` form". It is not: `create_agent` appears on that
  page only as an *import* — both snippet regions stop inside the tool
  body, so the agent construction is never shown at all. Reworded to say
  that, which is the sharper version of defect 11: the page never shows
  how the tool attaches to any agent, leaving `create_agent`,
  `CopilotKitMiddleware` and `ChatOpenAI` as imports the reader cannot act
  on.
- Carry over the system-prompt caveat. The reference cell steers the model
  to call `display_flight` once and stop because the tool result *is* the
  card; a StateGraph reader who drops that gets repeat tool calls.
- The install note named only two of the four packages the FastAPI tab
  adds on top of the shared line. List all four.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 12:39:11 -05:00
Benjamin Taylor 3ec309b724 docs(langgraph): fix 8 verified defects in the LangGraph onboarding docs (refs OSS-857)
Fixes defects 3, 4, 6, 7, 8, 10, 11 and 12 from the OSS-856 phase 1
validation run. Every claim below was re-verified against installed
package source or a live run, not recalled.

LangGraph quickstart (`integrations/langgraph/quickstart.mdx`):

- Route shape: a caution at the route step. The POST-only route runs the
  runtime in single-route mode, which is all chat needs; Threads and the
  Inspector need the multi-route catch-all with GET/POST/PATCH/DELETE.
  Links to the canonical runtime-endpoints section.
- Port: bare `langgraph dev` serves 2024, not 8123. Verified against both
  CLIs (`@langchain/langgraph-cli` help output, and `default=2024` in
  `langgraph_cli/cli.py`). The guide keeps `--port 8123` to stay
  consistent with every sibling page, and now says so.
- Drop `@copilotkit/react-ui` from the install list. `CopilotSidebar`
  lives in `@copilotkit/react-core/v2`; react-ui exports no `./v2` JS
  entry point and the v2 react example does not depend on it.
- Checkpointer: state the reason each tab differs. `langgraph dev` fails
  to load a graph compiled with a custom checkpointer (reproduced), while
  the FastAPI tab needs one because `ag-ui-langgraph` calls
  `graph.aget_state(...)`, which raises `ValueError: No checkpointer set`.
- Narrow the shared `uv add` line to what both tabs import, and warn that
  a project with exact pins should add them by hand.

A2UI fixed schema (`generative-ui/a2ui/fixed-schema.mdx`):

- Add the missing install step for `@copilotkit/a2ui-renderer` + `zod`,
  which the catalog/definitions/renderer snippets all import.
- Add a `StateGraph` + `ToolNode` form for developers who already have a
  hand-built graph, gated to the Python LangGraph slugs by a new
  `a2ui_agent_form` docs flag so the shared page does not show Python to
  langgraph-typescript or LangGraph code to LlamaIndex/ADK/Mastra.
- Repoint the cross-tree `/integrations/langgraph/...` link, which 301'd
  back to this same page, at the action-handler reference it promises.

Raw Markdown pipeline (`src/lib/llm-text.ts`):

- `renderPageToLlmText` never applied `filterFrameworkScopedBlocks`, so
  `/<framework>/<page>.md` emitted every `<WhenFrameworkHas>` branch with
  raw JSX tags, each carrying the one selected framework's snippet. On the
  A2UI page that produced three mutually-exclusive "how the schema is
  delivered" sections whose prose contradicted the identical code under
  each. Gate on the same framework the snippets resolve to, with a
  regression test.

Also corrects a factually wrong comment in the langgraph-python showcase
`.env.example` that claimed 8123 was the `langgraph dev` default — the
same mis-belief this ticket found in the docs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 12:19:52 -05:00
Benjamin Taylor 5c0150392f ci: stop Playwright browser installs shelling out to apt
Every Playwright install in CI passed `--with-deps`, which runs `apt-get
update` before downloading the browser. apt on the runners cannot always
reach azure.archive.ubuntu.com; when it can't it retries for many minutes,
which is long enough to burn a job's whole `timeout-minutes` budget before
a single test runs. GitHub renders that kill as "The operation was
canceled", so it reads as a test failure rather than an infrastructure hang.

Chromium's system libraries are already present on the Ubuntu runner
images, and every one of these steps installs chromium only, so the browser
download is all they need. Six jobs lose their apt dependency:
test_unit, test_e2e-legacy-v1, test_e2e-showcase-on-demand,
test_showcase-frontend-matrix, showcase_eval and showcase_capture-previews.

Ports CopilotKit/website#529 to this repo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 12:06:44 -05:00
copilotkit-qa-bot[bot] c81c6e2535 fix: harden Strands TypeScript request boundaries 2026-08-19 08:45:15 -07:00
copilotkit-qa-bot[bot] 1d32e8bd31 Merge main into codex/fac-126-strands-ts-starter 2026-08-19 08:18:38 -07:00
github-actions[bot] f2ce7fa52d style: auto-fix formatting 2026-08-19 15:06:19 +00:00
Benjamin Taylor d37fe9cbd2 test(sdk-python): revalidate the poetry lock and cover the partialjson parse path
Widening the partialjson constraint in #6123 invalidated poetry.lock's
content-hash, so a bare `poetry install` in sdk-python fails with
"pyproject.toml changed significantly since poetry.lock was last generated".
CI never saw it because test_unit-python-sdk.yml runs `poetry lock` first, and
publishing is unaffected because `poetry build` ignores the lock — but local
dev is blocked until someone relocks. Refreshed with Poetry 2.1.3 (the lock's
own generator) so the diff stays limited to the hash, and moved partialjson to
1.1.0 so CI exercises the version a fresh install now resolves. ag-ui-langgraph
is deliberately left at 0.0.42: a from-scratch resolve pulls 0.0.43, which
fails four intercepted-tool-call tests on a missing `emit_raw_events`.

The parse path had no coverage at all — disabling JSONParser.parse outright
left all 225 tests passing, because every partialjson failure mode degrades to
"no predicted state was emitted" behind the bare `except` in predict_state().
These tests pin the guarantees the `>=0.0.8,<2.0.0` range must keep, and are
version-agnostic about intermediate frames, which legitimately differ (1.1.0
preserves trailing whitespace mid-string where 0.0.8 dropped it).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 10:04:11 -05:00
Tyler Slaton f8b5de55ab feat(runtime): report managed Channel drops and recoveries as telemetry (refs OSS-825) (#6465)
## Why

A managed Channel that loses its gateway link is invisible outside the
host process. The only trace is the injected `log` seam, wired to
`logger.warn` — which for a self-hosted or Railway-hosted runtime
reaches nobody who can act on it.

## What

- `oss.runtime.channel_session_dropped` — carries the cause already
computed for the log line (`reason`, and the transport `code` when the
transport named one).
- `oss.runtime.channel_session_recovered` — carries `downForMs`, so
outage duration is measurable rather than inferred from log timestamps.
- The drop cause is now replayed on every "still down" reminder. In prod
those lines read `still down after 233134s; Phoenix is retrying` with
**no cause at all**, so an operator had to scroll back to the first line
— 15 minutes earlier, or hours, given the exponential backoff — to learn
it was an HTTP 502.

## Deliberate choices

- **No Channel name in the events.** It is a customer-chosen identifier
that can carry business meaning, so it stays out of anonymous OSS
telemetry. No message content or credentials either. Per-channel
aggregate counts still work without it.
- **An `online` transition with no preceding drop emits nothing** — a
session can report online without having dropped, and that is not a
recovery.
- **Capture is fire-and-forget with failures swallowed**, the same
contract `fireInstanceCreatedTelemetry` uses. The `try` also covers a
`capture` that throws synchronously. Telemetry must never break a live
session.
- The `gave_up` line's OSS-670 wording is untouched — it deliberately
says retries continue, and that is now accurate.

## Testing

Three tests added to `channel-manager-reconnect.test.ts`, each watched
fail first: the dropped event with its cause, the recovered event with a
positive duration, and the no-bogus-recovery guard. A fourth pins the
cause on the repeat log line.

```
✓ src/v2/runtime/core/__tests__/channel-manager-reconnect.test.ts (11 tests)
Tests  11 passed (11)
```

Wider run: 106 tests pass across `core/__tests__` and `telemetry`. Two
notes, both verified pre-existing by stashing this branch's changes and
re-running:

- `channel-manager-recovery.test.ts` fails to *load* in my worktree
(`Cannot find package '@copilotkit/channels-slack/render'`) — a
subpath-export resolution artifact of a worktree with symlinked
`node_modules`, identical with these changes stashed.
- `tsc --noEmit` reports 11 errors, the same 11 before and after this
change, none in the files touched here.

`oxfmt` and `oxlint` clean on all three files. Lefthook was bypassed on
the commit because of the same worktree `node_modules` symlinking; I ran
both tools manually over exactly the staged files instead.

Refs OSS-825.
2026-08-18 17:49:55 -07:00
copilotkit-qa-bot[bot] 20e481b749 fix: make Strands TypeScript starter smokeable 2026-08-18 16:01:36 -07:00
copilotkit-qa-bot[bot] bd91313517 feat: add AWS Strands TypeScript starter 2026-08-18 15:51:47 -07:00
Martha Kelly Schumann 63392db20d docs(deepagents): make state rendering example executable (#6554)
## Summary

- replace the disconnected Deep Agents state emitters with complete
Python and TypeScript agent construction
- stream partial `searches` tool arguments and persist the completed
state with `Command` and `ToolMessage`
- add a rendered-document regression for both language paths

## Root cause

The guide rendered `agent.state.searches`, but its backend snippets
never connected their state-producing functions to a Deep Agent. The
frontend therefore had no executable path that could produce the
documented state.

## Validation

- focused rendered-doc test: red before the change, green after it
- Python smoke against `copilotkit==0.1.95` and `deepagents==0.7.7`
- TypeScript typecheck and command smoke against
`@copilotkit/sdk-js@1.68.1` and `deepagents@1.12.4`
- rendered-doc suite: 34/34
- shell-docs typecheck, lint, and production build

The full shell-docs suite has one unrelated failure already present on
`main`: the Channels overview repeats its light image where its existing
test expects the dark image.

Linear:
[FAC-50](https://linear.app/copilotkit/issue/FAC-50/showcase-docs-deep-agents-python-state-rendering-example-misses)
2026-08-18 15:34:51 -07:00
copilotkit-qa-bot[bot] 3b396fa9a7 Merge remote-tracking branch 'origin/main' into codex/fac-50-deepagents-state-rendering 2026-08-18 15:25:46 -07:00
Mark 8d32e2eaa3 fix(showcase): drop inline langgraph-ts heap cap that forced OOM restarts (#6552)
## Problem

PR #6505 added an inline `NODE_OPTIONS="--max-old-space-size=1536"` to
the `langgraph-typescript` agent launch in
`showcase/integrations/langgraph-typescript/entrypoint.sh`, intending to
bound V8 old-space on the many-core Railway host.

In staging this cap is forcing crash-restarts, not delivering savings.
Staging `showcase-langgraph-typescript` hit a V8 heap-OOM `exit 134` at
`2026-08-18T09:52:31Z` (RSS dropped `2.289 GB -> 0.902 GB` on the
crash-reset).

The cap is also structurally un-overridable. It's appended as
`${NODE_OPTIONS:+$NODE_OPTIONS }--max-old-space-size=1536`, so it is
always the *last* `--max-old-space-size` flag on the command line — and
V8 takes the last flag when the same one repeats. An operator-supplied
`NODE_OPTIONS` override therefore always loses to the inline `1536`, so
a Railway env var can't raise the ceiling for this process; only another
code change can.

## Change

Removes only the inline `--max-old-space-size=1536` addition (and its
now-stale explanatory comment) from `entrypoint.sh`, restoring the exact
pre-#6505 launch line:

```
cd /app/src/agent && PORT=8123 HOST=0.0.0.0 npm start &> >(awk '{print "[agent] " $0; fflush()}') &
```

`NODE_OPTIONS` now passes through untouched — an operator override wins
again, and with no `NODE_OPTIONS` set V8 falls back to its own default
sizing (pre-#6505 behavior).

Untouched, by design:
- Worker-recycle logic in the same entrypoint
- `langgraph-python` / `langgraph-fastapi` entrypoints and their
`MALLOC_ARENA_MAX` / `MALLOC_TRIM_THRESHOLD_` allocator tuning (also
from #6505)

`git diff --stat` confirms the diff is scoped to exactly one file:
```
showcase/integrations/langgraph-typescript/entrypoint.sh | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
```

## Local red-green proof

Reconstructed the NODE_OPTIONS composition with plain `node` (v25.8.0 —
absolute MiB numbers will vary by machine/Node version, but the
*ordering*, which is the defect, will not):

**RED — current (pre-fix) launch, operator override lost:**
```
NODE_OPTIONS="--max-old-space-size=3072 --max-old-space-size=1536" \
  node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
=> 1728
```
The operator asked for a 3072 MiB ceiling and got capped to 1728 — well
below what was requested, and the source of the crash-restart loop.

**GREEN 1/2 — fix applied, operator override now wins:**
```
NODE_OPTIONS="--max-old-space-size=3072" \
  node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
=> 3264
```

**GREEN 2/2 — fix applied, no NODE_OPTIONS set, V8 default restored
(pre-#6505 behavior):**
```
node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
=> 4288
```

## Post-merge validation gate

This PR does not attempt to prove the fix in production. Before this is
considered validated, it needs a **24h+ re-soak on a pinned image
digest** of the `showcase-langgraph-typescript` service to confirm the
OOM/exit-134 crash-restart loop is gone under real traffic.

Ref: #6505
2026-08-18 15:13:09 -07:00
copilotkit-qa-bot[bot] 4879b941ab docs(deepagents): make state rendering example executable 2026-08-18 14:40:02 -07:00
Martha Kelly Schumann 6ff9ff949a docs: initialize shared-state rendering example (#6553)
## Summary

- initialize the shared rendering example after `useAgent` reports that
the real agent is ready
- seed only missing title and item fields while preserving existing and
unrelated agent state
- cover the LangGraph Python, Strands Python, Strands TypeScript, and
Google ADK rendered routes
- remove a duplicated sentence from the shared-state callout

## Root cause

The shared page rendered `state.title` and `state.items`, but it never
supplied meaningful initial values. A fresh example therefore showed an
`Untitled` heading and an empty list. The initializer must also survive
the provisional-to-real agent swap and must not replace state owned by
the backend or the user.

## Validation

- `npx vitest run src/lib/__tests__/llm-text.test.ts` (33 passed)
- `npm run typecheck`
- `npm run lint` (passes with existing repository warnings)
- `npm run build` (223 pages generated)
- `oxfmt --check` on both changed files
- `git diff --check`

Linear: FAC-105
2026-08-18 14:28:33 -07:00
copilotkit-qa-bot[bot] ed5d370936 docs: initialize shared-state rendering example 2026-08-18 14:08:48 -07:00
Martha Kelly Schumann b80ae41768 docs: show Claude tool-rendering backend wiring (#6551)
## Summary

- add package-owned tool-rendering setup for Claude Agent SDK Python and
TypeScript
- expose the existing adapter, MCP server, allowlist, and executable
handler path from canonical source
- insert the setup once in the shared tool-rendering guide
- cover generated setup, visual MDX rendering, both LLM-text routes, and
an unaffected framework

## Why

The public Claude tool-rendering pages stopped after the backend schema
and pure handler. They did not show how the schema becomes an executable
SDK tool or reaches `ClaudeAgentAdapter` through an MCP server.

This fixes [FAC-132](https://linear.app/copilotkit/issue/FAC-132) and
[FAC-136](https://linear.app/copilotkit/issue/FAC-136).

## Validation

- focused shell-docs matrix: 44 tests passed
- shell-docs typecheck passed
- shell-docs production build passed
- D6 `claude-sdk-python:tool-rendering`: green
- D6 `claude-sdk-typescript:tool-rendering`: green
- unaffected LangGraph controls were blocked by local Docker `ENOSPC`
and a stale agent backend; the focused route-isolation test passed
2026-08-18 13:59:26 -07:00
Jordan Ritter f536d009c6 fix(showcase): drop inline langgraph-ts heap cap that forced OOM restarts
PR #6505 added an inline NODE_OPTIONS="--max-old-space-size=1536" to the
langgraph-typescript agent launch to bound V8 old-space on the many-core
Railway host. In production the cap is forcing crash-restarts rather than
saving memory: staging showcase-langgraph-typescript hit a V8 heap-OOM
exit 134 at 2026-08-18T09:52:31Z (RSS dropped 2.289 GB -> 0.902 GB on the
crash-reset).

The cap is also structurally broken for override: because it's appended
after ${NODE_OPTIONS:+$NODE_OPTIONS }, an operator-supplied
--max-old-space-size loses to the inline 1536 (V8 takes the last flag of
a duplicate, but the inline one is always last). A Railway env var can
raise the ceiling for the frontend process but not for the agent process
this line targets, so there's no way to dial the cap up without another
code change.

This removes only the inline --max-old-space-size=1536 addition (and its
now-stale explanatory comment) from entrypoint.sh, restoring the exact
pre-#6505 launch line so NODE_OPTIONS passes through untouched — an
operator override wins again, and with no NODE_OPTIONS set V8 falls back
to its own default sizing. Worker-recycle and the langgraph-python/
langgraph-fastapi allocator tuning (MALLOC_ARENA_MAX, MALLOC_TRIM_THRESHOLD_)
added in the same PR are untouched.

Local red-green proof (node v25.8.0, numbers will vary by machine/node
version but the ordering is the defect):

RED - current launch's NODE_OPTIONS composition, operator override lost:
  NODE_OPTIONS="--max-old-space-size=3072 --max-old-space-size=1536" \
    node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
  => 1728 (capped well below the requested 3072)

GREEN 1/2 - fix applied, operator override now wins:
  NODE_OPTIONS="--max-old-space-size=3072" \
    node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
  => 3264

GREEN 2/2 - fix applied, no NODE_OPTIONS set, V8 default restored (pre-#6505):
  node -e 'console.log(require("v8").getHeapStatistics().heap_size_limit/1048576)'
  => 4288

Post-merge validation gate: this needs a 24h+ re-soak on a pinned image
digest before it's considered proven in production; this PR does not
attempt that.
2026-08-18 13:58:14 -07:00
copilotkit-qa-bot[bot] c45a50fa71 docs: scope tool setup copy to Claude 2026-08-18 13:45:59 -07:00
copilotkit-qa-bot[bot] 30a8c36bc0 docs: clarify Claude tool-rendering fallback 2026-08-18 13:12:44 -07:00