mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
v1.68.3
14980 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
34b10737b0 |
chore: release monorepo v1.68.3 (#6601)
## Release monorepo v1.68.3 **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.3` 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.3` - Creates git tag `monorepo/v1.68.3` - 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.3 |
||
|
|
aa3fb29dce | chore: release monorepo v1.68.3 | ||
|
|
7efa3b64f0 | fix(runtime): send global telemetry properties on the field the sink reads (#6603) | ||
|
|
16e2c3a69a |
fix(runtime): send global telemetry properties on the field the sink reads
Folded into `properties`, they arrived in the per-event slot. That works and it is the wrong place: the sink treats `global_properties` as the pass-through bag for `oss.runtime.*` and spreads it into the analytics event, and v1's client sends package name and version there for the same reason. Sending them as their own field keeps a process-level fact separable from an event's own properties the whole way to the warehouse. It also moves conflict resolution. Two fields cannot collide in the SDK, so a shared key survives on both and the sink decides, spreading the global bag last and therefore letting the global win. That is the opposite of what most readers expect from the word global, so the field docs now say not to reuse a key an event already sets, and a test pins the behaviour rather than leaving it to be discovered. |
||
|
|
dcaface1ed |
feat(runtime): let a caller name itself on the telemetry it already sends (#6599)
## The problem
The v2 telemetry client sends exactly the properties each call site
passes. There is no way for a product built on this runtime to be told
apart in the events that already go.
That leaves one option open to such a product: send its own events.
Which means a second pipeline describing the same runs, a second
namespace at the ingest gate, and two sources of truth for "how much
traffic came through us".
## What this adds
`telemetryProperties` on the runtime, merged into every event the client
sends.
```ts
new CopilotRuntime({
agents,
telemetryProperties: { accessibility_title: "OpenBot" },
});
```
Set beside the license token, in the shared base, for the same reason
that is: it describes the caller rather than the call, so every event
carries it whichever handler fired, `instance_created`,
`copilot_request_created` or any of the `agent_execution_stream_*`.
## Two decisions worth naming
**Per-event properties win on conflict.** A call site describing one
event knows more than a value set once at construction, so the general
must not overwrite the specific. Tested.
**No egress on its own.** Unset, nothing changes. Telemetry off, nothing
is sent, so nothing carries this. It adds a field to existing events
rather than adding events.
## Why
OpenBot needs to be separable from other runtime traffic in the existing
OSS analytics, and the ask there was explicitly *one field, no new
events, no new pipeline, no new namespace*. Without a seam here, the
only way to answer "which requests came through OpenBot" is to build the
thing nobody wanted.
The client is a private module singleton and the package `exports` map
does not expose it, which is correct, so a consumer cannot reach it to
set this itself. Verified by probing the deep import from a consuming
package: blocked.
## Tests
Six new, at the send boundary rather than on the instance, because a
field held correctly and dropped on the way out is the failure that
matters:
- carried on an event that sets none of its own
- carried alongside an event's own properties
- successive calls merge rather than replace
- an event's own property wins on conflict
- nothing sent at all when telemetry is disabled
- nothing added when none are set
`packages/runtime`: 11 telemetry tests pass, 1270 v2 tests pass, 0
failures. Build clean, `telemetryProperties` present in the emitted
`.d.mts`. Pre-commit gate green (lint 0 warnings, monorepo tests,
commitlint).
|
||
|
|
86a9f9b016 |
feat(runtime): let a caller name itself on the telemetry it already sends
The v2 telemetry client sends exactly the properties each call site passes, so there is no way for a product built on this runtime to be told apart in the events that already go. The only route open to one was to send its own events, which is a second pipeline describing the same runs. `telemetryProperties` on the runtime is merged into every event. Set beside the license token and for the same reason: it describes the caller rather than the call, so every event should carry it whichever handler fired. Per-event properties win on conflict. A call site describing one event knows more than a value set once at construction, and letting the general overwrite the specific would be the wrong way round. No behaviour change when unset, and nothing is sent when telemetry is off, so this adds no egress on its own. |
||
|
|
9df63beeef |
fix(runtime): name useSingleEndpoint when a single-route envelope hits a multi-route runtime (#6579)
Closes [OSS-882](https://linear.app/copilotkit/issue/OSS-882/add-to-existing-journeys-reach-for-the-v1-compat-copilotkit-wrapper). ## The failure The v1-compatible `<CopilotKit>` provider pins `useSingleEndpoint` to `true` ([`copilotkit.tsx:108`](https://github.com/CopilotKit/CopilotKit/blob/main/packages/react-core/src/components/copilot-provider/copilotkit.tsx#L108)), so its startup handshake POSTs `{ method: "info" }` at the base path. A multi-route runtime — the default — matches no route for that path and answered a bare `{"error":"Not found"}`, indistinguishable from a wrong `basePath` or an unmounted handler. Two independent onboarding validation runs hit this on their first browser attempt and each had to guess the cause. Both were *add-to-existing-app* journeys; the greenfield one reached for `CopilotKitProvider` and never saw it. ## What changed **The runtime says what happened.** `detectSingleRouteEnvelope` recognises a POST whose JSON body carries a `method` the single-route endpoint accepts, and the multi-route handler uses it at the one point routing gives up. The 404 now carries a `code` and a message naming the prop, plus a `logger.warn` so it lands in the dev-server terminal too. Deliberately conservative — wrong verb, non-JSON, unknown method, or a JSON POST that isn't an envelope all stay ordinary 404s, unchanged in status and shape. **The client stops discarding it.** All four `/info` callers (two in `agent-registry.ts`, two in `agent.ts`) threw away the response body and reported only the status, so a server-side diagnosis reached nobody. They now go through `runtimeInfoError`, which folds a string `message` from the body into the thrown error. Any future server-side diagnosis reaches the developer for free. **Docs.** Five pages paired a v2 multi-route handler with `<CopilotKit>` and never mentioned the prop. Rather than a warning under a snippet that is still wrong to copy, the snippets themselves now pass `useSingleEndpoint={false}`, with a short callout linking to the provider/handler mapping. Two pages were deliberately left alone: `backend/runtime-endpoints.mdx` already documents the pairing in full, and `cookbook/arcade.mdx` uses `mode: "single-route"` on purpose and already explains it. `backend/copilot-runtime.mdx` keeps its snippet as-is — it pairs with the v1 endpoint, where the default is correct — and gains the caveat only on its "switch to v2 handlers" note. Option 3 in the issue (reconsidering the compat default) is **not** in this PR. ## Testing ### Both halves connect, end to end Real `createCopilotRuntimeHandler` + real `CopilotKitCore` configured the way the v1 wrapper configures it — no mocks on either side: ``` code : runtime_info_fetch_failed message: Runtime info request failed with status 404: Received a single-route request envelope ({ method: "..." }) but this runtime is mounted in multi-route mode, so the request matched no route. If the frontend uses <CopilotKit> from @copilotkit/react-core/v2, pass useSingleEndpoint={false} — that provider defaults it to true. Otherwise mount the runtime with mode: "single-route" to serve this envelope. PASS — the diagnostic reached the client ``` The server-side `logger.warn` fired in the same run, carrying `{ url, path, method: 'info' }`. ### Unit tests `packages/runtime` — `single-route-envelope-diagnostic.test.ts` (2 positive, 5 control): ``` ✓ src/v2/runtime/__tests__/single-route-envelope-diagnostic.test.ts (7 tests) 26ms Tests 7 passed (7) ``` `packages/core` — `runtime-info-error-detail.test.ts` (2 positive, 5 control): ``` ✓ src/__tests__/runtime-info-error-detail.test.ts (7 tests) 267ms Tests 7 passed (7) ``` ### Mutation checks Every new test was verified to fail when its mechanism is broken, in both directions. Detector forced to `return null` — the two positives die, the four controls hold: ``` × names useSingleEndpoint when the envelope is an info call × diagnoses every method the single-route envelope accepts ✓ leaves an ordinary unmatched route as a plain 404 ✓ leaves a JSON POST that is not an envelope as a plain 404 ✓ leaves an unrecognized method name as a plain 404 ✓ does not diagnose a non-JSON POST ``` Detector forced to `return "info"` — the controls die instead, proving they are not vacuous: ``` ✓ names useSingleEndpoint when the envelope is an info call ✓ diagnoses every method the single-route envelope accepts × leaves an ordinary unmatched route as a plain 404 × leaves a JSON POST that is not an envelope as a plain 404 × leaves an unrecognized method name as a plain 404 × does not diagnose a non-JSON POST ``` `runtimeInfoError` with the detail dropped, then with the `typeof message === "string"` guard removed — each kills a different pair: ``` mutation: detail dropped → 2 failed | 5 passed mutation: accept any message field → 2 failed | 5 passed restored → 7 passed ``` ### Full suites, builds, docs | Check | Result | |---|---| | `packages/core` full suite | `Test Files 60 passed (60)` / `Tests 662 passed (662)` | | `packages/runtime` full suite | `Test Files 142 passed (142)` / `Tests 2067 passed (2067)` | | `packages/core` `tsc --noEmit` | clean | | `packages/runtime` `tsdown` | `416 files` — build complete | | MDX compile, 5 edited pages | all `OK` | | pre-commit `nx run-many -t test,publint,attw` | passed across affected projects | | CI on `f94d1ab0` | 72 pass, 3 skipping, 0 fail | Both suites are fully green. An earlier revision of this description reported 6 runtime failures as pre-existing on `main`; they were not. They were artifacts of a worktree whose `node_modules` had been assembled by hand, and a proper `pnpm install` cleared all of them along with the inspector-metadata failures from a stale `@copilotkit/shared` dist. `main` is clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
f36deaaa61 |
fix(docs): keep the useSingleEndpoint guidance mode-aware on multi-mode pages
Two pages document both transport modes and carry a single "point your
frontend at it" snippet serving every front door on the page. Baking
`useSingleEndpoint={false}` into those snippets traded one silent mismatch for
its mirror image: correct for the multi-route majority, wrong for anyone who
followed the `mode: "single-route"` example.
Both now state the rule conditionally next to the snippet instead of asserting
one side of it. Pages with a single handler mode (auth, custom-agent) are
unambiguous and keep the prop inline.
Also pins the one path where the diagnostic could have cost more than it gives:
`clone()` throws once a before-request middleware has drained the body, so the
detector must return null and let the plain 404 stand rather than surfacing a
500. The guard existed; nothing held it in place.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
76892a03b9 |
chore(deps): update depot/setup-action digest to 91bc849 (#6593)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [depot/setup-action](https://redirect.github.com/depot/setup-action) ([changelog](https://redirect.github.com/depot/setup-action/compare/15c09a5f77a0840ad4bce955686522a257853461..91bc8495a33ebfc504ffc89e5674379ccf23c29c)) | action | digest | `15c09a5` → `91bc849` | --- ### Configuration 📅 **Schedule**: (in timezone America/Los_Angeles) - Branch creation - "before 9am every weekday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/CopilotKit/CopilotKit). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zNS40IiwidXBkYXRlZEluVmVyIjoiNDQuMzUuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==--> |
||
|
|
d4f147aee8 | chore(deps): update depot/setup-action digest to 91bc849 | ||
|
|
6a36bfda7d |
feat: implement interrupt handling in AgentStore and add injectInterr… (#6538)
## Summary Closes #6509. Expose an interrupt controller directly on Angular’s `AgentStore`: ```ts const store = injectAgentStore("ticketing"); store().interruptController.hasInterrupt(); store().interruptController.resolve({ approved: true }); ``` This keeps messages, state, run status, and pending interrupts on the same conversation-scoped object. Consumers no longer need to separately inject a controller and repeat the agent ID for the common case. ## What changed - Added an eager, readonly `AgentStore.interruptController`. - Bound the controller to the store’s agent and thread. - Destroy the controller when its store is replaced or destroyed. - Made store teardown idempotent and unregister its `DestroyRef` callback. - Prevent stale interrupts from resuming after the agent changes threads. - Kept `injectInterrupt` for typed, filtered, and preprocessed interrupt handling. - Added a convenient agent-selection API matching `injectCapabilities`: ```ts injectInterrupt(); injectInterrupt("ticketing"); injectInterrupt(agentIdSignal); injectInterrupt("ticketing", { enabled, handler }); ``` - Preserved the original options-only form: ```ts injectInterrupt({ agentId: "ticketing", enabled, handler }); ``` - Moved `injectInterrupt` into its own module to avoid an `agent`/`interrupt` circular dependency. - Documented the coexistence limitation between store and specialized controllers. ## Design The store controller is created eagerly with the store. This avoids global coordination, lazy getters, and shared controller registries. Each store owns two local agent observers: 1. Store projection for messages, state, and run status. 2. Interrupt lifecycle observation. These are in-memory observers on the same agent, not additional network or SSE connections. Both are released during teardown. ## Specialized controllers `injectInterrupt` remains the advanced API for: - Typed interrupt payloads. - `enabled` filters. - Asynchronous or synchronous `handler` preprocessing. - Components following an ambient or explicitly selected agent. Controllers do not claim interrupts from each other. If a store controller and specialized controller observe the same agent, both can expose the same decision. Applications should render only one controller for a given decision. ## Testing - Three focused `AgentStore` integration tests. - Two `injectInterrupt` convenience and lifecycle tests. - Stale-thread behavior added to the existing controller lifecycle test. |
||
|
|
bf18677145 | preserve interrupted run IDs when resuming Angular agents | ||
|
|
736742f6f9 | test(angular): document unobservable thread changes | ||
|
|
ba41a31d7c | feat: implement interrupt handling in AgentStore and add injectInterrupt function | ||
|
|
85af4bedfb |
fix(showcase): gen-ui-tool-based uses shared pie-chart contract for all slugs (#6587)
## The bug (shared-probe-rule violation)
`showcase/harness/src/probes/scripts/d5-gen-ui-custom.ts` branched on
`integrationSlug` via a stale `CHART_INTEGRATIONS` allowlist: only ~5
slugs (langgraph-python, ms-agent-python, spring-ai, google-adk, mastra)
got the pie-chart prompt + assertions. Every other `gen-ui-tool-based`
slug got an **obsolete** `generate_haiku` prompt + `HaikuCard`
assertion.
This violates Showcase **iron rule 1** (one shared probe, no per-slug
`if slug === …` branch in the test) and no longer matches the product:
- All **21** `gen-ui-tool-based` pages register `render_bar_chart` +
`render_pie_chart` via `useComponent`.
- Every committed D6 `render-a2ui.json` fixture already carries the
chart exchange.
- On staging the non-allowlisted cells failed: the assistant container
renders but the `HaikuCard` assertion reports "rendered but has no text
content". Routing the cell through the pie-chart path greens it (SVG
renders, pie validated, narration appears).
## The change (probe only)
- Every `gen-ui-tool-based` integration now sends
`PIE_CHART_USER_MESSAGE` ("Show me a pie chart of revenue by category").
- The pie-chart SVG shape assertions + second-leg narration token check
run for **every** slug.
- Removed the slug-dependent `CHART_INTEGRATIONS` set /
`isChartIntegration` branch.
- Removed the obsolete haiku prompt + `HaikuCard` fallback (verified no
other usage anywhere in `showcase/harness/src`).
No allowlist was substituted with a larger allowlist. **No** fixture
re-record, backend, frontend, npm, or aimock change. Net `-248` lines
across the probe + its unit test.
## Red → Green (local proof)
The unit test was updated **before** the implementation so a
formerly-non-allowlisted slug (`ms-agent-dotnet`) fails pre-fix.
**RED (test updated, old implementation):** 6 failed / 2 passed
```
× buildTurns sends the pie chart message for a formerly-non-allowlisted slug (ms-agent-dotnet)
→ expected 'Write me a haiku about nature' to be 'Show me a pie chart of revenue by category'
× NO slug selects a different probe contract — every gen-ui-tool-based slug sends the pie chart message
→ slug ms-agent-dotnet must send the shared pie chart message: expected 'Write me a haiku about nature' to be 'Show me a pie chart of revenue by category'
× pie chart: assertion FAILS when the rendered component has no <svg> (ms-agent-dotnet)
→ got 'gen-ui-custom: matched cascade selector … but no haiku card or rendered component found in DOM'
× pie chart: assertion FAILS when SVG has too few drawing children (pydantic-ai)
× pie chart: assertion FAILS when assistant follow-up is missing expected tokens (ms-agent-dotnet)
× pie chart: assertion PASSES on a healthy donut render with full narration (ms-agent-dotnet)
```
**GREEN (after implementation):** 8 passed / 8
```
✓ src/probes/scripts/d5-gen-ui-custom.test.ts (8 tests) 23ms
Test Files 1 passed (1)
Tests 8 passed (8)
```
**Mutation-verified:** setting `PIE_CHART_USER_MESSAGE = "MUTANT"` fails
the two contract tests; disabling the narration token check (`if
(false)`) fails the missing-tokens test. Clean restore confirmed by
diff.
## Command results (from a fresh worktree off origin/main)
| Command | Result |
| --- | --- |
| `nx run @copilotkit/showcase-harness:test` (target file) | ✅ 8 passed
|
| `nx run @copilotkit/showcase-harness:test` (full) | ✅ 177 files / 3721
tests passed, 2 skipped, 0 failed |
| `nx run @copilotkit/showcase-harness:typecheck` | ✅ clean |
| `nx run @copilotkit/showcase-harness:build` | ✅ success |
| `showcase/bin/showcase fixtures validate` | ✅ exit 0, "All fixtures
valid" |
> Note: the full suite / typecheck initially reported failures in
`frontend-matrix.test.ts` and `d0-gone-predicate.test.ts`. These are
**pre-existing** and depend on gitignored generated artifacts
(`frontend-catalog.json`, `registry.json`) absent from a fresh worktree
— confirmed by reproducing them on pristine `origin/main` with my
changes stashed. After running the repo's `generate-registry` step they
pass. Neither file references gen-ui-custom.
## Value tests — HANDED OFF (control-plane unreachable here)
The production-shaped control-plane value tests must run **without**
`--direct`. Docker is not reachable in my environment (`docker info` /
`docker ps` exit 1; `--isolate` fails at `docker compose … ps`), so I
did **not** run them and did **not** substitute `--direct`. Please run
live:
```
showcase/bin/showcase test ms-agent-dotnet:gen-ui-tool-based --d5 --isolate --verbose
showcase/bin/showcase test pydantic-ai:gen-ui-tool-based --d5 --isolate --verbose
showcase/bin/showcase test langgraph-typescript:gen-ui-tool-based --d5 --isolate --verbose
showcase/bin/showcase test langgraph-python:gen-ui-tool-based --d5 --isolate --verbose # control
```
Expect: RED on the formerly-haiku cells (ms-agent-dotnet, pydantic-ai,
langgraph-typescript) before this change, GREEN after; langgraph-python
stays GREEN.
## Rollout
Needs a harness / control-plane deploy + a D5 sweep rerun to flip the
affected `gen-ui-tool-based` cells. **No** npm publish, backend, aimock,
or fixture re-record required.
Refs the `gen-ui-tool-based` shared-probe contract. Separate/unrelated:
LlamaIndex `done-signal-missing` (not touched here).
|
||
|
|
8f4adc9d1a |
fix(showcase): gen-ui-tool-based uses shared pie-chart contract for all slugs
The D5 gen-ui-custom probe branched on integrationSlug via a stale CHART_INTEGRATIONS allowlist: ~5 slugs got the pie-chart prompt + assertions, everyone else got an obsolete generate_haiku prompt + HaikuCard assertion. That violates Showcase iron rule 1 (one shared probe, no per-slug branching in the test) and no longer matches the product — all 21 gen-ui-tool-based pages register render_bar_chart + render_pie_chart, and every committed D6 render-a2ui fixture carries the chart exchange. Collapse to the single shared contract: every integration sends "Show me a pie chart of revenue by category" and runs the SVG/pie-chart shape + second-leg narration assertions. Remove the CHART_INTEGRATIONS allowlist / isChartIntegration branch and the now-unused haiku prompt + HaikuCard fallback (verified no other usage). No fixture, backend, frontend, npm, or aimock changes. |
||
|
|
60e8877e05 |
chore(showcase): upgrade CopilotKit to 1.68.2 (lands #6576 readiness fix) (#6585)
## Summary
Mechanical dependency-pin bump advancing the canonical Showcase
CopilotKit pin from `1.68.1` → `1.68.2`. This picks up the merged
**#6576** CopilotChat readiness fix onto staging. No source-logic
changes — pins + regenerated lockfiles only. This is the same pattern as
**#6510**.
## What changed
- `showcase/scripts/showcase-canonical-pins.json`:
`canonicalCopilotKitVersion` → `1.68.2` (overrides remain `{}`).
- Propagated the `@copilotkit/*` exact pins (`1.68.1` → `1.68.2`) across
all 22 showcase integrations + the Showcase shell (dependencies,
`overrides`, and `pnpm.overrides`).
- Regenerated every affected `package-lock.json` (`npm install
--package-lock-only`; integrations with `--legacy-peer-deps` per the
existing cmdk/react peer setup, shell strict — matching #6510).
**47 files changed:** 23 `package.json` + 23 `package-lock.json` + 1
canonical-pins JSON.
## Verification
- All `@copilotkit/*` siblings confirmed published on npm at `1.68.2`
(react-core, runtime, shared, core, react-ui, voice, a2ui-renderer,
sdk-js, web-inspector).
- Pin ratchet: `validate-pins.ts` → `FAIL=26`, hash unchanged
(`04b3415f…`) — matches the existing baseline exactly, so **no
re-baseline needed** (the bump neither added nor healed any FAIL).
- Shell `npm ci --ignore-scripts` succeeds and resolves
`@copilotkit/*@1.68.2` from the registry (matches the
`showcase_validate` workflow gate).
- Integration `npm ci` spot-check (built-in-agent) succeeds, installs
`@copilotkit/react-core@1.68.2`.
- Lockfile diffs are pin-only for integrations (0 structural churn); the
shell shows only npm's harmless `dev`↔`devOptional` reclassification
(same direction as #6510).
Refs #6576.
|
||
|
|
069501d6dc | chore(showcase): upgrade CopilotKit to 1.68.2 (lands #6576 readiness fix) | ||
|
|
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. |
||
|
|
f94d1ab0fb |
fix(runtime): name useSingleEndpoint when a single-route envelope hits a multi-route runtime
The v1-compatible `<CopilotKit>` provider pins `useSingleEndpoint` to `true`,
so it POSTs `{ method: "info" }` at the base path. A multi-route runtime — the
default — matches no route for that path and answered a bare `{"error":"Not
found"}`, which is indistinguishable from a wrong `basePath` or an unmounted
handler. Two independent onboarding validation runs hit this on their first
attempt and had to guess the cause.
The runtime now recognises the envelope at the one point multi-route routing
gives up, and answers the 404 with a message naming the prop, plus a
`logger.warn` so it also lands in the dev server terminal. Status and shape are
unchanged for every other miss.
That message was reaching nobody: all four `/info` callers threw away the
response body and reported only the status. They now route through
`runtimeInfoError`, which folds a string `message` from the body into the
error — so any future server-side diagnosis reaches the developer too.
Docs: five pages paired a v2 multi-route handler with `<CopilotKit>` without
mentioning the prop. Their snippets now pass `useSingleEndpoint={false}` and
link to the provider/handler mapping. `backend/runtime-endpoints.mdx` already
documents the pairing and is untouched; `cookbook/arcade.mdx` deliberately uses
single-route mode and already explains it.
Closes OSS-882
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
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> |