mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
v1.68.2
14961 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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 |
||
|
|
b0233c4eb0 | chore: release monorepo v1.68.2 | ||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
f8160e09b9 | fix(react-core): gate suggestion submission on readiness + production-shaped SSE regression test | ||
|
|
9087121bd5 | fix(web-inspector): preserve state across pop-out | ||
|
|
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. |
||
|
|
463f589b4c | feat(react-core): add local message inspector links (#6575) | ||
|
|
9b0e3dc88a | fix(react-core): gate CopilotChat submission on runtime readiness (empty assistant response) | ||
|
|
f1b26e4aa8 | fix(react-core): hide local inspector action in production | ||
|
|
367e7bda15 | feat(react-core): add local message inspector links | ||
|
|
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.
|
||
|
|
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>
|
||
|
|
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)
|
||
|
|
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. |
||
|
|
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. |
||
|
|
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> |
||
|
|
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) |
||
|
|
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>
|
||
|
|
90d36a62c7 | Merge main into codex/fac-126-strands-ts-starter | ||
|
|
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. |
||
|
|
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> |
||
|
|
573a614112 | Merge main into codex/fac-126-strands-ts-starter | ||
|
|
b9d41c0e3a | Merge main into codex/fac-126-strands-ts-starter | ||
|
|
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)
|
||
|
|
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>
|
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
c81c6e2535 | fix: harden Strands TypeScript request boundaries | ||
|
|
1d32e8bd31 | Merge main into codex/fac-126-strands-ts-starter | ||
|
|
f2ce7fa52d | style: auto-fix formatting | ||
|
|
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> |
||
|
|
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. |
||
|
|
20e481b749 | fix: make Strands TypeScript starter smokeable | ||
|
|
bd91313517 | feat: add AWS Strands TypeScript starter | ||
|
|
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) |
||
|
|
3b396fa9a7 | Merge remote-tracking branch 'origin/main' into codex/fac-50-deepagents-state-rendering | ||
|
|
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 |
||
|
|
4879b941ab | docs(deepagents): make state rendering example executable | ||
|
|
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 |
||
|
|
ed5d370936 | docs: initialize shared-state rendering example | ||
|
|
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 |
||
|
|
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. |
||
|
|
c45a50fa71 | docs: scope tool setup copy to Claude | ||
|
|
30a8c36bc0 | docs: clarify Claude tool-rendering fallback |