mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
codex/cloudplot-showcase-migration
15424 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ba41a31d7c | feat: implement interrupt handling in AgentStore and add injectInterrupt function | ||
|
|
61ac927bae | Merge branch 'main' into fix/state-manager-run-id | ||
|
|
0163beab8e |
feat(reskinnable-demo): stream the harness into a CLI console via AG-UI subagents
Makes the offsite-expenses beat legible while it runs, and gives it its own
model, by taking the AG-UI subagent surface from the canary line.
## The expense analyst is now a real subagent
banking gpt-5.4, temp 0
│ banking's prompt; browser frontend tools; Intelligence memory tools
└─ expense-analyst gpt-5.6-sol, reasoning_effort=high
│ sandboxed shell, submit_expense_report
└─ merchant-researcher gpt-5.4, one per merchant, Tavily
Previously the beat was a section of banking's prompt, which left nowhere to put
per-beat configuration: model, effort and recursion limit are all agent-level and
there was one agent. It also meant banking's ~21,000-character rulebook rode
every one of the ~20 model calls the run makes, re-sending rules about markdown
tables while the agent read a CSV.
Reached as a `CompiledSubAgent` because a raw `SubAgent` spec has no `subagents`
field and this one needs its own — the per-merchant fan-out is a headline of the
beat, and a flat subagent could only research serially. Verified nesting
survives: a probe showed the analyst's `task` dispatches, the researchers'
`search_merchant` calls and the final report tool all reaching `astream_events`.
`gpt-5.6-sol` additionally needs `use_responses_api=True`: with function tools
and `reasoning_effort` it 400s on /v1/chat/completions. The first probe missed
that by asking the model a question with NO tools bound — a model probe for an
agent has to bind one.
## The console: one CLI window, streaming
`shell/subagents/subagent-activity.tsx` subscribes to the agent's event stream
and folds it into console lines. Reading `agent.messages` (the previous design)
was wrong twice over: messages materialise at the `MESSAGES_SNAPSHOT`, two per
run, so the pane sat still for minutes and then filled at once; and persisted
messages carry no `subagentRunId`, so the harness's narration could not be told
from banking's own reply.
The fold is pure and idempotent — every line keyed by the id of the thing that
produced it — so the same code serves the live subscription and a replay of the
thread's stored events when a conversation is reopened.
Three heuristics are deleted, each replaced by identity the protocol already
carried:
- the console's "first tool call" anchor -> the run's first `task` call, from
MESSAGE order (durable; the
event-derived version rendered
one console per delegation on a
restored thread — six, measured)
- `CONSOLE_TOOL_NAMES` suppression list -> `subagentRunId` presence
- `disable_streaming` on the researchers -> the canary's per-lane state
`shell/subagents/subagent-message-filter.tsx` keeps subagent narration out of the
conversation. It suppresses the PROSE and keeps the TOOL CALLS: an agent
routinely narrates and calls a tool in one message, and returning null for the
whole message hid the REPORT CARD — the run looked perfect and ended with nothing
to show. Shell-level and inert for a skin whose agent has no subagents.
## Canary stack, contained to this app
The subagent surface only exists on the canary line, and a released
`@ag-ui/client` <= 0.0.57 rejects `SUBAGENT_*` events in the HTTP transport
before any middleware runs, killing the stream. So the demo leaves the root pnpm
workspace and ships its own lockfile, pinning `@copilotkit/* 1.68.3-canary` and
`@ag-ui/* 0.0.59-canary` locally instead of imposing an unreleased protocol on
every package in the monorepo.
A 1.62.2-based canary was tried first and could not compile the app: it silently
rewound the CopilotKit API five minors under a demo written against 1.67.1, and
`OpenGenerativeUIActivityRenderer` (a public `/v2` export since ~1.63) was the
first thing to break. `workspace:*` is not a version, so the app had no recorded
lower bound on the API it needs.
KNOWN GAP, deliberately not fixed here: Nx discovers projects THROUGH the pnpm
workspace (there is no `workspaceLayout` in `nx.json`), so leaving it also
removes the demo from the repo-wide `nx run-many -t build` and `-t check-types`
sweeps. Verified — `nx show project deep-agents` and the other standalone
showcases return "Could not find project". No workflow names this demo, so it is
currently unbuilt and untype-checked in CI and needs its own job. Run the four
gates locally until that lands. Documented in `pnpm-workspace.yaml`.
## Fixes
- The run clock is keyed per run and read through an injected `ToolRuntime`
instead of taking the oldest open stamp across the process. Model calls AFTER
the report re-stamped the clock and that leftover became the next run's start:
a two-minute run reported 333s. Now 86s reported against 98s wall clock — the
gap is thread-naming and delegation, before the analyst's first model call,
which is what the tile claims to measure.
- `merchantKind` non-answers are rejected on the leading token, on hedging
language, and over 40 characters. With no search tool the model wrote a bare
"unclear"; with Tavily live it hedges in prose ("unknown (likely
bookbindery/bookshop retail, but not established for this exact merchant)"),
which an exact-match filter passed into a 60-character label glued to the
merchant name.
- `vitest` no longer externalises `@copilotkit/*`. Installing them from npm moved
`src/app/layout.tsx`'s stylesheet import under `node_modules/.pnpm/`, where
Node's ESM loader threw `Unknown file extension ".css"` and took out 16 suites
while naming a stylesheet nobody had touched.
- `agent/main.py` reads the demo's `.env` as well as its own, so `TAVILY_API_KEY`
works wherever an operator puts it. Two env files to keep in sync is a trap
whose failure mode is "the agent ignores a key that is plainly sitting in .env".
## Upstream finding (reported separately, not fixed here)
`@copilotkit/runtime` drops `subagentRunId` when persisting messages: 2888 of
3026 stream events carry it, 0 of 53 persisted messages do. Reproduced with
Intelligence removed entirely, so it is the runtime's message shape rather than
the platform store — and `@copilotkit/runtime`'s dist contains no occurrence of
the field at all, while `@ag-ui/core`, `ag-ui-protocol` and `@copilotkit/core`
all model it. One field threaded through would let the console rebuild from
message history and delete the event-replay seeding added here.
`CLAUDE.md`'s appended block is generated by `next dev`
(`next/dist/server/lib/generate-agent-files.js`) and committed per its own
instruction to keep the tree clean.
Gates: lint 0, typecheck 0, test:unit 2460 passed across 216 files, build 0.
Measured end to end in Intelligence mode: 14 rows, 9 merchants researched, 6
charges filed with ids read out of real 201 bodies, totals reconciling against
their own rows, 3220 events with 6 SUBAGENT_STARTED/FINISHED pairs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JRubZT6AS6LCGkcE2KzcfA
|
||
|
|
8114ddd623 | style: auto-fix formatting | ||
|
|
a9714d1c02 |
docs: call Inspector out in quickstarts and feature pages
After the first chat, web quickstarts now tell the reader to open Inspector and confirm Agents, AG-UI Events, and Threads. Feature pages that map to a shipped pane get a short Callout. Angular links the Inspector install page first. Vue sets show-dev-console=auto so the overlay appears on localhost. The inspector-docs skill keeps pane-to-docs pointers in sync when Inspector panes change. |
||
|
|
f421ae6180 |
fix(showcase): serve the CrewAI Flows plain-assistant cells with a Flow, not a crew
The `crewai-crews` column is presented as "CrewAI Flows", but eleven of its demos were served by `add_crewai_crew_fastapi_endpoint` through a root catch-all: agentic-chat, gen-ui-tool-based, both prebuilt-chrome cells, chat-slots, chat-customization-css, headless-simple, readonly-state-agent-context, agent-config, auth and voice. That helper wraps the crew in `ChatWithCrewFlow`, whose system message comes from CrewAI's `build_system_message`. Its boilerplate is unconditional: it tells the model to introduce itself and to steer every answer back to the crew's purpose, illustrated with a research-report example. Since the catch-all served the scaffold research crew, those cells answered the user and then offered to research the latest AI developments. Measured on real OpenAI, turn two of a plain arithmetic question came back as "12 x 12 = 144." followed by "I'm here to help with researching the latest AI developments and producing actionable reports." Pre-seeding a hand-written crew description (the existing `preseed_system_prompt`) only retargets that tail; the boilerplate around it stays. Verified against the pre-seeded `/mcp-apps` crew, which still introduces itself and offers a diagram. Changes: - Add `chat_flow.PromptedChatFlow`, a neutral one-turn Flow that owns its prompt and forwards frontend tools, and serve it at `/chat` via `add_crewai_flow_fastapi_endpoint`. The conversational column already had this class inline; it now imports the same module so both columns share one prompt. - Point the runtime's default agent target plus the agent-config, auth and voice routes at `/chat`, and drop the root catch-all registration. An unrouted agent name now fails loudly instead of landing on someone else's backend. - Give gen-ui-tool-based its own `gen_ui_tool_based` Flow, mirroring langgraph-python's dedicated graph: the cell must force a `render_*` chart call on the user's turn, which a neutral assistant does not do. Wired into the conversational registry too. - Leave the remaining crew endpoints (`/mcp-apps`, `/byoc-hashbrown`, `/byoc-json-render`) alone; each already overrides the composed system message. - Refresh the comments that described the removed catch-all. Coverage: new `test_chat_flow.py` pins the prompt contract, the absence of crew-chat boilerplate and frontend-tool forwarding; a routing contract test asserts no cell can reach a crew endpoint by fall-through. |
||
|
|
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 |
||
|
|
a29bf0720a |
feat(reskinnable-demo): add the offsite-expenses pill and harden the report fields
THE PILL. The offsite-expenses beat had no entry point in the UI. The agent was
wired, the service was up, all four gates were green, and every verification I
ran POSTed directly at the runtime — so the beat was fully working and completely
unreachable for anyone opening the app. It is the ninth and last pill, after the
AWS charge, because it is the only one that does not answer in seconds.
`suggestions.test.ts` now pins it. That guard is not decoration: this pill has no
type referencing it, no matcher and no route, so nothing else in the tree
notices if it is dropped or retitled. It checks REACHABILITY, which is the
property nothing else was holding.
MERCHANT KIND HARDENING. `merchantKind` is a KIND ("hotel", "pharmacy") that the
report card prints inline beside the merchant name, where it has room for about
two words. The previous filter rejected exact matches of "unclear"/"unknown",
which was enough when there was no search tool and the model wrote a bare
"unclear". With Tavily live it hedges in prose instead — measured:
"unknown (likely wellness-related business)" and "unknown (likely
bookbindery/bookshop retail, but not established for this exact merchant)". Both
sailed through and would have rendered as a 60-character label glued to the
merchant name.
Now rejects on the leading token, on hedging language anywhere, and on anything
over 40 characters. The length cap is the backstop: it encodes the actual
constraint rather than a list of phrasings already observed, so it catches the
next wording nobody predicted. A measured run after the change leaked none, with
a longest surviving kind of 23 chars.
ONE ENV FILE. `agent/main.py` now loads the demo's `.env` in addition to its own,
with `agent/.env` winning on conflict. The app and this service need the same
keys, and asking an operator to keep two files in sync is a trap whose failure
mode is "the agent ignores a key that is plainly sitting in .env" — which is
exactly what happened when TAVILY_API_KEY was added to the demo's `.env` and the
service, reading only its own, never saw it.
`.env.example` documents TAVILY_API_KEY and BANKING_AGENT_URL, including what a
keyless run actually looks like: the research subagents are told plainly that no
search happened and instructed to report "could not establish" rather than
guess, so the run completes with several rows marked `unclear` and a "merchants
researched" tile reading 0. Nothing errors, which is why it needs writing down.
Measured with Tavily live: 14 rows, 10 merchants researched, 10 parallel
subagents, 31s, totals reconciling against their own rows, 7 charges filed with
ids read out of real 201 bodies, zero non-answer kinds. Research also CHANGES a
decision rather than only labelling one — The Copper Room resolved to
`restaurant_lounge` and moved from `unclear` to `expensable`.
Gates: lint 0, typecheck 0, test:unit 2460 passed across 216 files, build 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JRubZT6AS6LCGkcE2KzcfA
|
||
|
|
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. |
||
|
|
e4eb96f8d7 |
feat(reskinnable-demo): make banking's agent the Python deep agent
Banking's `agent.ts` stops returning a `BuiltInAgent` and returns an `HttpAgent` pointed at the Python deep agent instead. Six skins still run in-process; banking is the one that does not. WHY THE WHOLE AGENT, not just the offsite-expenses beat. Threads are scoped per agent — `listThreads` takes `agentId` as a REQUIRED parameter, and measured against the running app the two lists are disjoint (banking 46 threads, banking-expenses 10). The v2 runtime has no handoff mechanism, and `defineTool`'s `execute` takes `(args)` with no emitter, so a tool cannot stream a multi-minute run. Under a second agent id a presenter could start the analysis, switch threads, and have nothing to come back to. One conversation list means one agent. The expense task spec is appended to banking's own prompt as a CONDITIONAL job rather than a second identity — it opens by saying it applies only when the user hands over a statement, and to ignore it otherwise. Ported to Python: - `agent/prompt.py` — banking's system prompt, extracted from the TS template literal programmatically and asserted equal, not paraphrased. 21,208 chars carrying 56 distinct rules; a dropped rule silently breaks a beat that still looks like it works. - `agent/report.py` — `render_report` and the a2ui operations builder. Component order, ids and the `columns` arithmetic match the TS builder; the unique surface suffix uses uuid rather than a timestamp so two reports in the same millisecond cannot collide. Carried over from the TS `BuiltInAgent` because each had a reason written beside it: the non-mini model (the teach-and-recall arc routes unreliably on mini) and `temperature: 0` (tool routing must be deterministic). Also sets `emit_raw_events = False`. It defaults to True, which piggybacks LangChain's internal events onto the AG-UI stream: a measured run streamed 27,950,261 bytes, and the same run with it off streamed 374,086 — a 75x reduction with an identical report. This matters more than it looks because the thread PERSISTS those events for replay, and leaving a running thread and coming back to it is the point of this beat. Nothing downstream reads RAW. Verified against the running app, not reasoned about: - `/info` reports banking as HttpAgent and the other six as BuiltInAgent. - Canvas beat: `render_report` -> TOOL_CALL_RESULT -> the a2ui middleware emits `activityType: a2ui-surface` with createSurface + updateComponents. - Frontend-tool beat: given showTransactions + showPendingApprovals the agent picks showTransactions, emits no result (the client executes it) and emits no prose — the prompt's "the rendered list is the single source of truth" rule surviving the port. - Intelligence mode: the run is handed the browser's tool AND recall_memory / save_memory / forget_memory / copilotkit_knowledge_base_shell. - Durability: a run whose client disconnected at 8s finished unattended and left a replayable thread. Removes `expenses-agent.ts` and the non-skin `banking-expenses` registry key; banking's own id now serves both. `AgentRegistration.createAgent`'s comment is rewritten — it described a second remote key that no longer exists — and now gives a grep to derive the BuiltInAgent/HttpAgent split rather than asserting it. Gates: lint 0, typecheck 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JRubZT6AS6LCGkcE2KzcfA |
||
|
|
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. |
||
|
|
a6418bcc09 |
feat(reskinnable-demo): run the offsite-expenses beat on a LangChain deep agent
Replaces the Codex CLI subprocess with a Python LangChain deep agent
(`examples/showcases/reskinnable-demo/agent/`) reached over AG-UI: sandboxed
shell execution via deepagents' `LocalShellBackend`, parallel per-merchant
research subagents, no external harness binary, and our own API key.
Registered as `banking-expenses` in the server agent registry. That required
widening `AgentRegistration.createAgent` from `() => BuiltInAgent` to
`() => AbstractAgent` — the runtime's own `agents` option is
`Record<string, AbstractAgent>` and the v2 tree contains no
`instanceof BuiltInAgent` branch, so the demo's type was stricter than the
runtime it described.
Measured end to end against the real runtime: 58 `execute` calls, 7 concurrent
`task` subagents (peak concurrency 4/4 on a dedicated probe), RUN_FINISHED,
eight charges filed with ids read out of real 201 bodies, and 8221 replayable
AG-UI events persisted on the thread after the client disconnected 8s in.
Correctness fixes found by running it rather than reading it:
- `submit_expense_report` DERIVES the totals from the verdicts instead of
accepting them as arguments. A measured run had every per-row amount matching
the CSV while the headline totals came back $1.00 and $0.20 high — the model
authored them. The report card prints the total directly above the rows it is
the sum of, so tiles and rows must not be able to disagree.
- `amount` is coerced at the tool boundary; it arrived as a string on all 14
rows, which silently defeats the widget's currency formatting.
- `merchantKind` values that are non-answers ("unclear") are dropped rather than
rendered beside the merchant name as if they were findings.
- The recursion limit is set on the AGENT, not via `graph.with_config(...)`,
which the AG-UI adapter drops — the run completed the whole analysis and then
died at LangGraph's default of 25 supersteps.
- A `clone()` override works around `copilotkit` 0.1.95 being incompatible with
`ag-ui-langgraph` >= 0.0.42, whose base `clone()` (called per request) passes
kwargs the SDK subclass does not accept. Every request 500s without it.
Deletes the superseded Node-side harness scaffolding: `prompt.ts` (the task
specification now lives in the Python agent's system prompt), `workspace.ts`
(the sandbox owns the workspace) and their tests. `types.ts` stays — it is the
shared vocabulary the report card and the tool renderer both import.
Also drops the three unused `@tanstack/*` dependencies.
Reskin-skill impact: checked. `.claude/skills/reskin/` documents the `Skin`
contract, and no field of it changed — `banking-expenses` is NOT a skin and must
never look like one. It is absent from `registry.ts`, `skinIds`,
`skinIdentities` and `LINTED_SKIN_IDS`, and has no route, theme or identity. The
one documented thing that did change is `AgentRegistration.createAgent`'s type,
which SKILL.md describes in its registration section; that is updated in the
follow-up commit that makes banking itself a deep agent.
Gates: lint 0, typecheck 0, test:unit 2458 passed across 217 files, build 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JRubZT6AS6LCGkcE2KzcfA
|
||
|
|
6f58b2c6a4 |
fix(runtime): unify the Intelligence key name and publish the wiring (refs OSS-881)
Three names for one value were live in CopilotKit's own documentation, and following the wrong one with a CLI-provisioned project yields an undefined key: - `INTELLIGENCE_API_KEY` — what `copilotkit project select` writes, used by all 34 integration examples and the docs site. - `COPILOTKIT_INTELLIGENCE_API_KEY` — the seven Channels package READMEs and the packaged skills. Nothing ever read it. - `COPILOTKIT_API_KEY` — the Slack and Teams examples, and the TSDoc on `CopilotKitIntelligence` itself, which is what an IDE shows on hover. `INTELLIGENCE_API_KEY` wins, because it is the name the CLI provisions and changing it would break every scaffolded project in the wild. `COPILOTKIT_INTELLIGENCE_API_KEY` is retired outright — no code read it. `COPILOTKIT_API_KEY` stays readable as a deprecated alias in the two examples that consume it, so an existing `.env` keeps working, and is documented as deprecated everywhere it appears. The skills reference also documented `organizationId`, sourced from a fourth and fifth env name, as a `CopilotKitIntelligence` option. It is not one: `CopilotKitIntelligenceConfig` has no such field, so the copy-pasteable sample it appeared in would not compile. Removed from the samples, and the prose that told readers to fetch a value for it corrected. The Intelligence wiring itself was published only inside `node_modules/@copilotkit/runtime/skills/`, and the only docs pages showing `CopilotKitIntelligence` were the two Channels frontends — so a developer on the plain web path had no page to reach it from. Adds `/premium/connect-your-runtime`, which covers the wiring, how to confirm the credential is actually consumed, and the self-hosted two-URL rule. `scripts/validate-intelligence-env-names.ts` keeps this from drifting back. It runs unfiltered in CI on purpose: the two workflows that would otherwise cover it filter paths, and static/quality ignores `examples/**` — exactly where the deprecated alias lives. |
||
|
|
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>
|
||
|
|
4b2586bd90 | fix(web-inspector): load saved threads in active chats | ||
|
|
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) | ||
|
|
3fc33398af | Merge branch 'main' into codex/ent-1157-shared-clerk-session | ||
|
|
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.
|
||
|
|
af6c7ad5e0 | Merge branch 'main' into codex/ent-1157-shared-clerk-session | ||
|
|
4df1e3dccd |
docs(a2ui): require a literal-or-binding union for bound props (refs OSS-857)
Three findings from a LangGraph TypeScript onboarding run, plus the
supporting re-export.
The A2UI binder decides whether to resolve a `{ path }` binding by
inspecting the prop's Zod type: `scrapeSchemaBehavior` classifies a
`ZodUnion` containing an object with a `path` key as DYNAMIC and
everything else as STATIC, and STATIC returns the value untouched. A
bound prop declared as a plain `z.string()` therefore reaches the
renderer as the raw `{ path: "/origin" }` object, and the first thing
that renders it as text throws React error #31. The fixed-schema page
said the opposite — that renderer props are "plain z.string(), not a
path-or-literal union" — so the obvious declaration produced an opaque
crash. The reference cell already declares the union and carries a
comment explaining why, but that comment sits outside the
`definitions-types` region marker and so never reaches the page.
`DynamicStringSchema` is real; it lives in `@a2ui/web_core`, which is a
transitive dependency of `@copilotkit/a2ui-renderer` and so not
reliably importable from application code. Re-exported here with its
numeric/boolean/list siblings and their types.
The LangGraph quickstart's troubleshooting advice told everyone with a
connection problem to swap `localhost` for `0.0.0.0` or `127.0.0.1`.
That is backwards for the Node runtime: `langgraphjs dev` defaults to
`--host localhost`, which Node resolves to IPv6 and binds `::1` only,
so `127.0.0.1` is refused by the same running server. The Python CLI
defaults to `--host 127.0.0.1` and behaves the other way, so the advice
is now split across the page's existing Python/TypeScript language tabs
instead of stated once in shared prose.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
68d6c5c62d |
docs(inspector): document mounting the Inspector in Angular (refs OSS-857) (#6572)
## What this fixes
The Inspector is `cpk-web-inspector`, a framework-agnostic web component
from
`@copilotkit/web-inspector`. `@copilotkit/angular` does not reference
that package
and does not mount the element, so an Angular application has to create
it
itself. Nothing in the docs said so.
It was worse than a missing paragraph. `ANGULAR_DOC_REDIRECTS` mapped
the
`inspector` slug onto `guides/troubleshooting`, so
`/angular/*/inspector`
**redirected away from the Inspector**, and the Angular sidebar's
"Observe & Operate" section contained a single entry — the VS Code
extension:
```
== Observe & Operate
- VS Code Extension [vs-code-extension]
```
## What I documented
New Angular-owned page, `frontends/angular/inspector.mdx`, sourced from
`examples/integrations/adk-angular/src/app/web-inspector.ts`:
- the Inspector is a web component and `@copilotkit/angular` does not
mount it
- the mount component: `afterNextRender`, reuse-or-create, append to
`document.body`
- `inspector.core = copilotKit.core` plus `auto-attach-core="false"`,
and why —
given no core the element hunts for development globals such as
`window.__COPILOTKIT_CORE__`, so turning the search off is what
guarantees it
observes the app's core and never a different one
- anchoring the launcher bottom-left, clear of a chat panel's close
button
- keeping it out of production builds via `@defer (when isDev)` +
`isDevMode()`
- server rendering (`afterNextRender` + the deferred import vs.
`customElements`)
- cleanup through `DestroyRef.onDestroy`
Plus: the redirect is gone so the page is reachable, and
`frontends/angular/guides/troubleshooting.mdx` links to it.
**React's Inspector content is untouched** — not edited, not moved, not
gated.
### House style
Checked against the eleven existing Angular-owned pages rather than
written to
taste, which changed four things from my first draft:
- **`## Next steps` with a bare link list.** Every Angular guide closes
that way;
I had `## Related` with a prose gloss per link.
- **No `<video>`.** No Angular-owned page embeds media, and none uses
`<Callout>`
or `<Steps>` either — that surface is prose, tables, and fences. I had
carried
the Inspector video over from the shared snippet.
- **Imperative task headings**, matching "Send the current session" /
"Validate every runtime request" in `auth.mdx`: "Mount the element",
"Supply the application's core", "Position the launcher". I had
"Mount it yourself" and "Hand it the application's core".
- **Declarative sentences, no rhetorical fragments.** "The mount is
yours, so the
exclusion is yours as well." and a bare "`DestroyRef.onDestroy` does."
are not
this surface's register; both are now plain statements of mechanism.
Frontmatter (`title`/`description`/`icon`/`doc_type: how-to`), h2-only
structure, ~80-column wrapping, and the `{runtimeUrl}` placeholder
convention all
follow the siblings. `<AngularSnippet region=…>` does **not** apply —
that
component pulls code extracted from the Angular Showcase at build time,
and this
mount component is not in the Showcase. Nav needs no `meta.json` entry
either:
`frontends/meta.json` carries only a title, and the Angular sidebar is
derived in
`getAngularDocsNavTree`. Verified the entry renders anyway.
### Two deviations from the brief, both deliberate
**1. Structural gating instead of `<FrontendOnly frontend="angular">` in
the
shared snippet.** The brief described
`snippets/shared/premium/inspector.mdx` as
the real Inspector content with the per-framework pages as shims onto
it. On
current `main` that is only half true: `docs/inspector.mdx` is now a
131-line
standalone page that does **not** render `<Inspector />`, and it is what
the
Angular root and every `docs_mode: generated` framework resolve to. I
built the
`FrontendOnly` version first and it forced the Angular guide to be
duplicated
into two files that had already diverged. An Angular-owned page instead
matches
how all eleven existing Angular guides work, keeps one source of truth,
and
gates by resolution rather than by branch.
The repo's own test agrees on the direction —
`angular-docs-content.test.ts`
lists `<FrontendOnly` in `REACT_ONLY_CONTENT`, i.e. it treats the tag as
something that should not reach the Angular surface.
That test also gave me a real mutation check for free. My first attempt
leaked
React's `<CopilotKit … enableInspector={false}>` into 19 Angular pages,
and the
suite caught every one:
```
× keeps the complete Angular surface free of another frontend's code
+ "inspector: <CopilotKit
+ publicLicenseKey={process.env.NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY}
+ enableInspector={false}
+ >",
× keeps every Angular and backend combination frontend-native
expected [ …(18) ] to deeply equal []
```
**2. I document the CSS override for positioning, not
`setAttribute("anchor", …)`.**
The scaffold sets that attribute, but `cpk-web-inspector` never reads
it. Runtime
proof against the built `dist`:
```
observedAttributes: ["auto-attach-core"]
static properties keys: ["core","autoAttachCore","_capabilitiesVersion"]
'anchor' observed? -> false
```
There is no `getAttribute("anchor")` anywhere in the package, and
`defaultAnchor`
(the prop React's `CopilotKitInspector` accepts) is not consumed either.
What
actually moves the panel is the CSS in the scaffold's own `styles.css` —
as its
comment already says: "CSS in styles.css enforces this too." So the docs
describe
the mechanism that works. **The scaffold has one dead line** its owner
may want
to drop; I did not touch it (see below).
## The adk-angular dependency is discharged
`examples/integrations/adk-angular` is planned for removal, and its
`web-inspector.ts` comment was the only written record of this pattern.
That
pattern is now documented. **Whoever removes that scaffold no longer
needs to
preserve it.** I only read the scaffold — no file under
`examples/integrations/adk-angular` is modified by this PR.
## The VS Code extension claim: both halves reproduced
The report said Angular users are pointed at a VS Code extension
instead, that
its `cpk-debug-events` endpoint is documented at the wrong path, and
that it
produced no events for a real run. I verified each independently rather
than
acting on the report.
**Pointed at the extension — confirmed.** See the one-entry sidebar
above.
**Wrong path — confirmed, and fixed.** The router suffix-matches
`cpk-debug-events`, but a runtime mounted with a `basePath` rejects
anything
outside it. Against a real runtime on `basePath: "/api/copilotkit"`:
```
runtime mounted at basePath=/api/copilotkit, NODE_ENV=development
/cpk-debug-events -> 404 application/json {"error":"Not found"}
/api/copilotkit/cpk-debug-events -> 200 text/event-stream ": connected\n\n"
/api/copilotkit/info -> 200 application/json {"version":"1.64.1",…}
```
The docs said "available at `GET /cpk-debug-events` on your CopilotKit
runtime"
and gave the panel default as the bare origin `http://localhost:4000`,
so a
reader supplying their server's origin gets a 404. Now documented as
`GET {runtimeUrl}/cpk-debug-events`, base-path-relative, with the worked
`localhost:8200` example and a `curl` check, in both
`troubleshooting/event-inspector.mdx` and `vs-code-extension.mdx`.
**No events for a real run — confirmed, cause is runtime mode.** The
debug bus is
fed from exactly one place, `handlers/shared/sse-response.ts`, reached
only by
`handlers/sse/run.ts` and `handlers/sse/connect.ts`. An
Intelligence-configured
runtime dispatches to `handlers/intelligence/run.ts` and
`handlers/intelligence/connect.ts`, which return `Response.json` and
hand the
browser a realtime connection — no AG-UI event ever passes through the
runtime's
SSE layer. Neither file mentions `debugEventBus`. So on an
Intelligence-backed
runtime the endpoint connects, emits `: connected`, and then stays
silent
forever. That is now a callout on the event-inspector page pointing
readers at
the in-app Inspector, which reads the events client-side.
I did not change runtime code for this — it is a docs-accuracy gap, and
whether
the Intelligence path *should* feed the bus is a product decision, not
mine to
make here.
## Testing
From `showcase/shell-docs`:
**`npm run test`** — 403 passed, 1 failed, and that failure is
pre-existing on
`origin/main`. Verified in a pristine `origin/main` worktree with no
changes:
```
❯ src/lib/__tests__/channels-docs.test.ts (30 tests | 1 failed)
× publishes the Channels overview only through provider navigation
```
It asserts `channels-architecture-dark.png` in the Channels overview
source and
is unrelated to anything here. The seven `angular-docs-content.test.ts`
tests —
the ones that police frontend separation — all pass.
**`npm run typecheck`** — identical output on my branch and on a
pristine
`origin/main` worktree (5 pre-existing `@testing-library/react`
resolution
errors from my symlinked `node_modules`, all in test files I did not
touch). No
new errors.
**`npm run lint`** — exit 0, no warnings in any file I changed.
**`npx oxfmt --check`** on the one `.ts` file — "All matched files use
the
correct format."
### Render check, both namespaces
`next dev`, following redirects, checking bodies rather than status
codes since
this site soft-404s:
| URL | http | Angular mount content | React `enableInspector` |
| --- | --- | --- | --- |
| `/angular/langgraph-typescript/inspector` | 200 | yes
(`afterNextRender`, `auto-attach-core`, `cpk-web-inspector`) | **no** |
| `/langgraph-python/inspector` | 200 | **no** | yes |
Each namespace shows only its own instructions. The only `tsx` string on
the
Angular page is Next.js dev chunk filenames, not content.
Before this change `/angular/langgraph-typescript/inspector` answered
`307 -> /angular/langgraph-typescript/guides/troubleshooting`.
Also confirmed 200-with-content, no redirect, and the mount instructions
present
on `/angular/inspector`, `/angular/google-adk/inspector`, and
`/angular/mastra/inspector`; the sidebar now carries
`href="/angular/langgraph-typescript/inspector"` under "Observe &
Operate"; the
Angular troubleshooting page links to it; and the new event-inspector
callouts
render in both the React and Angular namespaces with `/inspector`
correctly
rewritten to `/angular/<backend>/inspector`.
## Notes for reviewers
- **OSS-857 stays open** — other defects on it are unresolved.
- No changeset, per this repo's release process.
- Follow-up for the adk-angular owner, not done here:
`setAttribute("anchor", "bottom-left")` in `web-inspector.ts` is a no-op
and
can be deleted; the `styles.css` rule below it is what positions the
panel.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
d77cd3815d |
test(sdk-python): revalidate the poetry lock and cover the partialjson parse path (#6547)
## What does this PR do? Follow-up to #6123, which relaxed `partialjson` to `>=0.0.8,<2.0.0` (issue #4131). Two loose ends from reviewing that change: 1. **`sdk-python/poetry.lock` was left invalid.** Any edit to the dependency table invalidates the lock's content-hash, so on current `main` a bare `poetry install` in `sdk-python` fails with `pyproject.toml changed significantly since poetry.lock was last generated`. Refreshed here. 2. **The parse path had zero test coverage.** `partialjson` has exactly one consumer — `JSONParser().parse(...)` at `copilotkit/runloop.py:306` — sitting inside a bare `except` that returns `None`. Every failure mode therefore degrades to "no predicted state was emitted", which nothing asserted. A widened range with no tripwire under it means a future release inside `<2.0.0` could regress streaming predicted state silently. ## Choices worth flagging - **Refreshed the lock with Poetry 2.1.3**, the generator the lock itself names. Poetry 2.4.x rewrites the header and adds unrelated entries (~120 lines of churn); 2.1.3 keeps the diff to the hash. - **Moved `partialjson` to 1.1.0 in the lock** (`poetry update partialjson`, 7 insertions) so CI exercises the version a fresh install now resolves, rather than the floor of the range. - **Left `ag-ui-langgraph` at 0.0.42 on purpose.** A from-scratch resolve (deleting the lock rather than refreshing it) pulls 0.0.43, which fails four `test_intercepted_tool_call_events` tests on `AttributeError: 'LangGraphAGUIAgent' object has no attribute 'emit_raw_events'`. That latent break is worth its own issue; it is not addressed here. - **Tests are version-agnostic about intermediate frames.** Values mid-stream legitimately differ across the allowed range — 1.1.0 preserves trailing whitespace inside a partially streamed string where 0.0.8 dropped it — so the assertions pin what the range must keep: a completed payload parses exactly, and a prefix yields a prefix. - Not touched here: `examples/integrations/langgraph-{fastapi,python}/Dockerfile:50` still hardcode `"partialjson>=0.0.8,<0.0.9"`, a hand-copy of the old pin that keeps those two images on 0.0.8. ## Testing **Lock validity — the actual bug, before and after** Pristine `main` before #6123 was consistent; #6123's one-line edit is what broke it. Verified in a clean worktree: ``` # main + only the constraint edit $ poetry check --lock Error: pyproject.toml changed significantly since poetry.lock was last generated. $ poetry install --with dev Installing dependencies from lock file pyproject.toml changed significantly since poetry.lock was last generated. Run `poetry lock` to fix the lock file. # with this PR's lock $ poetry check --lock (no error) ``` **CI simulated exactly** (`poetry lock && poetry install --with dev`, as in `test_unit-python-sdk.yml:54`): ``` resolved partialjson in venv: 1.1.0 locked ag-ui-langgraph: version = "0.0.42" 230 passed, 11 skipped, 18 warnings in 0.75s ``` 225 were passing before; the 5 new tests are the difference. **New tests pass on every version the range admits** ``` partialjson 0.0.8 -> 5 passed partialjson 0.0.9 -> 5 passed partialjson 0.1.0 -> 5 passed partialjson 1.0.0 -> 5 passed partialjson 1.1.0 -> 5 passed ``` **Mutation-checked, three ways** — the tests were confirmed to fail when the mechanism is broken, not merely to pass: | Mutation to `JSONParser.parse` | Result | | --- | --- | | baseline (unmodified) | 5 passed | | `raise RuntimeError` | 4 failed, 1 passed | | return values with strings reversed | 3 failed, 2 passed | | always return `{}` (the realistic silent regression) | 3 failed, 2 passed | For contrast, the same "disable `parse` entirely" mutation against the pre-existing suite left **all 225 tests passing** — which is what motivated this file. The one test that survives every mutation is `test_unterminated_escape_does_not_escape_predict_state`, by design: it asserts that a prefix older versions reject stays contained by the bare `except`, so a raising parser is the case it exists to tolerate. **Behavioural evidence that 1.1.0 is safe in the lock** (from reviewing #6123): a differential fuzz over every prefix of 9 realistic streamed tool-call payloads, 1232 cases per version across 0.0.8 / 0.0.9 / 0.1.0 / 1.0.0 / 1.1.0 — zero parse-to-raise regressions on any version, 75 cases improve from raise to parse, all 9 complete payloads parse identically. Driving the real `predict_state()` at chunk sizes 1/3/7/20 gives a byte-identical final `predicted_state` on all five versions. |
||
|
|
3801de3708 |
docs(runtime): map the provider/handler pairs and guard BuiltInAgent (refs OSS-857) (#6569)
Follow-up to #6566. Fixes **defects 5 and 9** of OSS-857, plus the half of **defect 6** that lives on the Built-in Agent quickstart. Defects **1 and 2** are deliberately left — they land with the non-interactive `project list`/`select` work, since the real fix is tooling that provisions and names the key, not prose. **Do not close OSS-857 on this PR** — 1 and 2 remain. ## The finding that reframes defect 5 The three names are **not interchangeable**. They pair up, and nobody had written the pairing down. Traced through source, not inferred: | Provider | `useSingleEndpoint` | Transport | Needs handler | | --- | --- | --- | --- | | `<CopilotKit>` (v1 wrapper) | omitted → `true` | `single` | single-route | | `<CopilotKit>` | `{false}` | `rest` | multi-route | | `<CopilotKitProvider>` (v2) | omitted | `auto`, detected from `/info` | either | | `<CopilotKitProvider>` | `{true}` | `single` | single-route | `copilotkit.tsx:108` is the whole story: `useSingleEndpoint={props.useSingleEndpoint ?? true}`. The v1 wrapper renders `<CopilotKitProvider>` internally and **pins single-route transport unless you pass the prop.** So the LangGraph quickstart is internally coherent — v1 provider asks for single, `copilotRuntimeNextJSAppRouterEndpoint` serves single — which is exactly why chat works there and Threads cannot. ### The constraint nobody had documented I swept every v1-era wrapper: - `copilotRuntimeNextJSAppRouterEndpoint` → `createCopilotEndpointSingleRoute` - `copilotRuntimeNodeHttpEndpoint` → `createCopilotEndpointSingleRoute` - `copilotRuntimeNextJSPagesRouterEndpoint`, `copilotRuntimeNodeExpressEndpoint`, `copilotRuntimeNestEndpoint` → all delegate to `copilotRuntimeNodeHttpEndpoint` **Every one builds its handler with `mode: "single-route"` and exposes no option to change it.** There is no v1-shaped multi-route handler anywhere in the package. The consequence is sharper than defect 5 as filed: **Rich Threads and the Inspector are unreachable from the wiring both quickstarts teach, at any provider setting.** Setting `useSingleEndpoint={false}` cannot fix it — it just points the browser at routes the wrapper will not serve. You need a v2 `CopilotRuntime` from `@copilotkit/runtime/v2` plus `createCopilotRuntimeHandler`. That is a server-side change, not a provider prop, and it is the structural reason defect 3's trap exists. Worth its own ticket. ## Why I did not converge the quickstarts on v2 That was the original plan for this PR and I abandoned it after checking the backend half. The split matters: - **Frontend would have been free.** Both quickstarts already import from `@copilotkit/react-core/v2`, where `CopilotKit` is labelled in source as a *"V1 backward-compat re-export"*. `CopilotKitProvider` ships from that same entry, and `CopilotSidebar` already depends on `useLicenseContext` from it. Swapping is an import change. - **Backend would not.** The multi-route handler takes a v2 `CopilotRuntimeLike`; the quickstart's v1 `CopilotRuntime` only reaches it via an internal `.instance` getter that lazily news up a `CopilotRuntimeVNext`. Converging means teaching v2 runtime construction and dropping `ExperimentalEmptyAdapter` mid-quickstart — a real v1→v2 migration for every reader of the two highest-traffic pages. v1 is supported, so the default path stays put. The mapping documents all pairs instead, and the Threads upgrade stays a labelled, complete recipe on the page the quickstarts already link to. ## What changed **`backend/runtime-endpoints.mdx`** — new "Provider and handler pairs" section: the provider table, the handlers-by-mode table, the deprecated-alias mapping (`createCopilotEndpoint`, `createCopilotEndpointSingleRoute`, and the Express pair), the wrapper constraint above, and a "read the symptom" callout (a mismatch fails at discovery — `GET {basePath}/info` 404s, or the Runtime rejects the envelope — never in your application code). **Both quickstarts** — a short callout naming the pair the page uses and linking the mapping. **Defect 9, `integrations/built-in-agent/quickstart.mdx`** — this is what `/quickstart` actually serves (verified: both URLs return the identical 8175-byte body; the root `quickstart.mdx` is a 17-line routing shim that 308-redirects to `/`). `BuiltInAgent` extends `AbstractAgent` and calls the model directly via `streamText`, so registering it as `default` replaces the developer's agent rather than connecting to it. Added a caution: readers with an existing agent take the frontend steps here and the runtime wiring from their framework's quickstart. **Defect 6, second half** — same page installed `@copilotkit/react-ui` and never used it, importing `CopilotKit`/`CopilotSidebar` from `@copilotkit/react-core/v2`. Dropped, matching #6566. ## Testing ``` $ npx vitest run Test Files 1 failed | 58 passed (59) Tests 1 failed | 417 passed (418) ``` The one failure is `channels-docs.test.ts > publishes the Channels overview only through provider navigation` — pre-existing, and proven so in #6566 by stashing on a clean tree. **I broke two tests and fixed them, which is worth recording** because it caught a real defect in my first draft. `angular-docs-content.test.ts` flagged: ``` built-in-agent/backend/runtime-endpoints: @copilotkit/react langgraph-python/backend/runtime-endpoints: @copilotkit/react ... 10 surfaces total ``` `backend/runtime-endpoints.mdx` also serves the **Angular** surface, and my provider prose named React packages there. Correct fix, not a suppression: the provider axis is React-only — Angular's `provideCopilotKit` has no `useSingleEndpoint` — so the provider table is now `<FrontendOnly frontend="react">` with an Angular branch saying only the handler half applies. Both Angular tests pass. ### Render checks Per surface, `.md` and HTML: | surface | provider table | Angular note | `@copilotkit/react` | wrapper callout | |---|---|---|---|---| | langgraph-python | ✅ | — | 3 | ✅ | | langgraph-typescript | ✅ | — | 3 | ✅ | | angular | — | ✅ | **0** | ✅ | The wrapper-constraint callout correctly stays on all three: it is a server-side fact that applies to Angular too. Defect 9 / 6b on `/quickstart` and `/built-in-agent/quickstart` — both 8175 bytes, caution present, `react-ui` gone from the install line, pair pointer present. Every link I added was **body-verified, never by status code** (this site soft-404s with HTTP 200): ``` /langgraph-python/quickstart bytes=428497 soft404=0 h1=Quickstart / bytes=248255 soft404=0 h1=CopilotKit /backend/runtime-endpoints bytes=375782 soft404=0 h1=Runtime HTTP endpoints /langgraph-python/backend/runtime-endpoints bytes=395130 soft404=0 h1=Runtime HTTP endpoints ``` New anchors confirmed present (`id="provider-and-handler-pairs"`, `id="which-handlers-serve-which-mode"`), and the pointer rewrites into the reader's namespace correctly — `/langgraph-python/backend/...` from the LangGraph page, `/backend/...` from the root surface. ## Voice pass A third commit runs a tone/voice check over everything added for OSS-857, measured against the corpus instead of guessed. It also corrects the wording that already landed in #6566, so the whole ticket reads in one voice. **Second person stays.** It is emphatically the house voice: 22 of 29 top-level and backend pages use `you`/`your`, and the three pages involved used it **17, 23 and 64 times** before any of these edits. Stripping it would make the new prose stand out, not blend in. Mid-sentence `**bold**` also stays — the corpus does that 17 times. What genuinely drifted, and is now fixed: | Issue | Was | Now | |---|---|---| | British spelling | `honours` | `serves` | | Third person on a second-person page | `A developer adding A2UI to an agent they already wrote…` | `If you added A2UI to an agent you already wrote…` | | Essay register | `That default is the one thing to remember:` | plain statement of the fact | | Meta phrasing | `so this is the mapping` | `so this table is the mapping` | | Conversational | `no provider pairing to get wrong` | `to configure` | | Conversational | `` `uvicorn` is told to listen on `8123` `` | `` `main.py` sets uvicorn's port to `8123` `` | | Literary | `you may also meet these deprecated aliases` | `Older code may use these deprecated aliases` | | Coinage | `agent construct` | `how the agent itself is built` | | Coinage | `without that steer` | `Without it, the model tends to…` | | Aphoristic Callout title | `Mismatched pair? Read the symptom, not the code` | `A mismatched pair fails at discovery` | | Epigram | `It replaces your agent; it does not connect to one.` | `It replaces your agent rather than connecting to it.` | | Redundancy | `nothing supplies persistence for you` | `nothing supplies persistence` | Two of these were objective, not stylistic: the corpus is American English (`behavior` 66:6, `customize` 77:4, `serialize` 18:1, `organize` 15:0) and its only `honour` was mine; and it contains exactly two instances of `a developer`, one of which was mine on a page that addresses the reader directly throughout. Callout titles were checked against the house set — declarative or plain question (`v1 behaves differently`, `Three routes are not user-scoped`, `Using a custom backend?`) — which is why the aphorism was the one outlier. Re-verified after the rewording: tests back to the single pre-existing failure, every reworded string renders on the right surface, Angular still shows **zero** React package mentions, and the `StateGraph` step is still gated to langgraph-python + langgraph-fastapi only. ## Coordination Draft PR #6112 (onsclom) also touches `integrations/built-in-agent/quickstart.mdx`, but only two prose lines — the signup sentence and the "Already have an app?" callout. My hunks are the install line and the runtime step, so they should merge cleanly. Flagging rather than assuming. ## Follow-ups this surfaced - **Threads needs a v2 server migration** from either quickstart's starting point. No v1-shaped multi-route handler exists. Own ticket. - **Defects 1 and 2** ride the non-interactive project-selection work. |
||
|
|
9ffe2546ce |
docs(inspector): document mounting the Inspector in Angular
The Inspector is the framework-agnostic `cpk-web-inspector` web component. `@copilotkit/angular` does not reference or mount it, so an Angular app has to create the element itself — and nothing said so. Worse, the Angular docs mapped the `inspector` slug onto `guides/troubleshooting`, so `/angular/*/inspector` redirected away from the Inspector entirely and the only thing left under "Observe & Operate" was the VS Code extension. Add an Angular-owned Inspector page covering the mount component, the `core` handoff with `auto-attach-core="false"`, positioning, production exclusion, server rendering, and cleanup on destroy. Drop the redirect so the page is reachable, and point at it from the Angular troubleshooting guide. React's Inspector content is untouched and unmoved. Also correct the `/cpk-debug-events` path: it is relative to the runtime's mounted `basePath`, not the server origin, and it only carries events for a self-hosted SSE runtime — an Intelligence-backed runtime answers runs over the platform's realtime connection, so the stream connects and stays empty. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
7cb5205437 |
feat: add AWS Strands TypeScript starter (#6555)
## Summary - add a standalone AWS Strands TypeScript starter with shared state, tools, A2UI, Channels, and Docker support - register the starter in parity, migration, docs, and PR smoke coverage - publish the canonical `aws-strands-ts` command in the shared AWS Strands documentation - keep the starter out of the live Railway fleet map until a service is provisioned ## Why FAC-126 reports that `copilotkit create` offers AWS Strands only in Python. The maintained TypeScript integration already exists in the showcase, but there was no standalone starter for the CLI to download. This is part 1 of 2. [CopilotKit/Intelligence#878](https://github.com/CopilotKit/Intelligence/pull/878) adds the CLI catalog entry and aliases. Merge this PR first, then merge #878. The CLI PR is pinned to reachable commit `20e481b749141db40fb3126ed39d73e74e8b197c`. ## Validation - `npm run typecheck` in the starter agent - `npx tsc --noEmit` in the starter root - `npm run build` in the starter root - `pnpm parity:verify --target=strands-typescript` - focused shell-docs tests and typecheck - slug-map and starter-mapping drift tests - repository config allowlist check - agent module startup and strict CSV load - GitHub starter Docker image build - `git diff --check` The local Docker smoke attempt could not extract the Playwright image because the machine ran out of disk. GitHub CI runs the same Compose smoke stack. Linear: [FAC-126](https://linear.app/copilotkit/issue/FAC-126/aws-strands-typescript-starter-missing-from-copilotkit-create) |
||
|
|
6c1a9eb4b4 |
docs: match the house voice in the OSS-857 prose (refs OSS-857)
A voice pass over everything added for OSS-857, measured against the
corpus rather than guessed.
Second person stays: it is emphatically the house voice — 22 of 29
top-level and backend pages use you/your, and the three pages involved
used it 17, 23 and 64 times before any of these edits. Mid-sentence
`**bold**` for emphasis also stays; the corpus does that 17 times.
What actually drifted:
- `honours` → `serves`. The corpus is American English (behavior 66:6,
customize 77:4, serialize 18:1, organize 15:0) and the single
`honour` in it was mine.
- `A developer adding A2UI to an agent they already wrote…` → second
person. The corpus contains exactly two `a developer`, and one was
mine; the page around it addresses the reader directly throughout.
- Essay register: "That default is the one thing to remember:" → a plain
statement of the fact. "so this is the mapping" → "so this table is
the mapping".
- Conversational: "no provider pairing to get wrong" → "to configure";
"`uvicorn` is told to listen on 8123" → "`main.py` sets uvicorn's port
to 8123"; "you may also meet these deprecated aliases" → "older code
may use these deprecated aliases".
- Coinages: "agent construct" → "how the agent itself is built"; "that
steer" → "Without it, the model tends to…".
- Aphoristic Callout title "Mismatched pair? Read the symptom, not the
code" → "A mismatched pair fails at discovery". House titles are
declarative or plain questions ("v1 behaves differently", "Three
routes are not user-scoped", "Using a custom backend?").
- Epigram: "It replaces your agent; it does not connect to one." → "It
replaces your agent rather than connecting to it."
- Redundancy: "nothing supplies persistence for you" → "nothing
supplies persistence".
The a2ui and LangGraph quickstart wording landed in #6566; those files
are corrected here so the whole ticket reads in one voice.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
90d36a62c7 | Merge main into codex/fac-126-strands-ts-starter | ||
|
|
1cafb58b4a |
ci: stop Playwright browser installs shelling out to apt (#6567)
Ports [CopilotKit/website#529](https://github.com/CopilotKit/website/pull/529) to this repo. CI workflow config only — six files under `.github/workflows/`, no package or source code touched. ## The problem Every Playwright browser install in this repo passes `--with-deps`, which runs `apt-get update` before downloading the browser. apt on the runners cannot always reach `azure.archive.ubuntu.com`; when it can't, it retries for many minutes before falling back to `archive.ubuntu.com`. In the website repo that burned ~14 of a job's 15 minute `timeout-minutes` budget and the job was killed before it ran a single test — and GitHub renders a `timeout-minutes` kill as "The operation was canceled", so it shows up in the checks list looking like a test failure rather than an infrastructure hang. One thing is worse here than in website. Website only took the apt branch on PRs that touched `pnpm-lock.yaml` (a cache-key interaction). **This repo has no Playwright browser cache at all** — `grep -rn ms-playwright .github/` returns nothing — so all six of these jobs shell out to apt unconditionally, on every run. ## The change ```diff - run: pnpm exec playwright install --with-deps chromium + run: pnpm exec playwright install chromium ``` Chromium's system libraries are already present on the Ubuntu runner images, and **every one of these six steps installs chromium only**, so the browser download is all any of them needs. A comment records the reasoning in-file at each site so the next person doesn't helpfully restore `--with-deps`. | Workflow | Step | Job timeout | |---|---|---| | `test_unit.yml` | Install Chromium for packed Angular browser smoke | 25m | | `test_e2e-legacy-v1.yml` | Install Playwright browsers | 20m | | `test_e2e-showcase-on-demand.yml` | Install Playwright | 15m | | `test_showcase-frontend-matrix.yml` | Install Chromium | 45m / 15m | | `showcase_eval.yml` | Install Playwright chromium | 45m | | `showcase_capture-previews.yml` | Install Playwright | 30m | ## Verification The substantive claim — "Chromium launches without `install-deps` on the runner images" — is about the runner image and cannot be checked locally. **This PR's own CI run is the verification, and it holds:** 23 checks pass, 2 skipped, 0 failures. Two jobs here actually launch a browser: - **`test / e2e / legacy-v1`** — success. All five example legs (`chat-with-your-data`, `form-filling`, `research-canvas`, `state-machine`, `travel`) ran their Playwright suites to completion on `depot-ubuntu-24.04-4`. - **`test / unit`** — success. The packed Angular browser smoke launched Chromium on both Node 22.x legs. Confirmed independently in ag-ui-protocol/ag-ui#2468, where all 24 `dojo / *` legs ran their Playwright suites green on `depot-ubuntu-24.04` after the same change. Between the two PRs that is 31 browser-launching jobs on Depot images with no `install-deps` anywhere. ### Measured effect Same step, same workflow, `main` vs this branch: | | `Install Chromium for packed Angular browser smoke` | |---|---| | `main` — run [32271967199](https://github.com/CopilotKit/CopilotKit/actions/runs/32271967199) | **86s**, **104s** | | this PR — run [32281720527](https://github.com/CopilotKit/CopilotKit/actions/runs/32281720527) | **7s**, **8s** | apt was ~92% of that step even on a run where it *wasn't* hanging. The failure mode this PR removes is the tail, not the mean. Static checks: ``` $ python3 -c "yaml.safe_load each touched workflow" ok .github/workflows/test_unit.yml ok .github/workflows/showcase_capture-previews.yml ok .github/workflows/showcase_eval.yml ok .github/workflows/test_e2e-showcase-on-demand.yml ok .github/workflows/test_e2e-legacy-v1.yml ok .github/workflows/test_showcase-frontend-matrix.yml ``` `actionlint` on the six touched files, `origin/main` vs this branch (line:col stripped so comment insertions don't shift the comparison): ``` $ diff before.txt after.txt before=27 after=27 IDENTICAL — no new actionlint findings ``` The 27 findings are pre-existing on `main` — `depot-ubuntu-*` runner labels actionlint doesn't know, and shellcheck `SC2086`/`SC2129` info in unrelated steps. Current timings, for what the change is worth: on run [32271967199](https://github.com/CopilotKit/CopilotKit/actions/runs/32271967199) the `Install Chromium` step took **86s and 104s** across the two Node 22.x matrix legs. So apt is reachable from our runners *today* — this is preventive, plus ~1–1.5 min per job, not a fix for something currently red. ## Risk ~~Guido proved the no-`install-deps` claim on GitHub's `ubuntu-latest`. Three of these jobs run on `depot-ubuntu-24.04-*`, and Depot mirroring GitHub's image is the one thing this PR's CI needs to confirm.~~ **Resolved** — see Verification above; Chromium launches on the Depot images. The residual risk is coverage, not the claim. Four of the six workflows are `workflow_dispatch`/`issue_comment`-gated and so do not run on this PR: `test_e2e-showcase-on-demand`, `test_showcase-frontend-matrix`, `showcase_eval`, `showcase_capture-previews`. Their edit is textually identical to the two that *were* exercised and all six installed chromium only, so this is one shared claim rather than four independent ones — but say the word and I'll dispatch any of them against the branch before merge. If a library does turn out to be missing, the fallback is `timeout 300 pnpm exec playwright install-deps chromium` — bounding the hang instead of removing it — rather than restoring the unbounded `--with-deps`. ## Notes for review - **A companion change is needed in ag-ui.** `apps/dojo/e2e/package.json` there has `"postinstall": "playwright install --with-deps"`, and our `test_e2e-dojo.yml` installs that package with `pnpm install` (scripts enabled), so our dojo job has been pulling all three browser engines through apt while `playwright.config.ts` declares a chromium project only. ag-ui's own workflow dodges it with `--ignore-scripts`. Fixed in [ag-ui-protocol/ag-ui#2468](https://github.com/ag-ui-protocol/ag-ui/pull/2468); since e2e-dojo pulls ag-ui at floating `main`, it reaches this repo's CI as soon as that lands. - `showcase_capture-previews.yml` still does `sudo apt-get update && apt-get install -y ffmpeg` one step earlier, so that job keeps an apt call with the same hang exposure. Left alone — separate concern, happy to bound it in a follow-up. - Dockerfiles under `showcase/` keep `--with-deps` deliberately: those build on Debian/Alpine images that genuinely lack the libraries. Local-dev docs (`examples/e2e/AGENTS.md`) are unchanged for the same reason. - No changeset: CI config only, nothing published. |
||
|
|
4078a11f36 |
docs(runtime): map the provider/handler pairs and guard BuiltInAgent (refs OSS-857)
Fixes defects 5 and 9 from the OSS-856 phase 1 validation run, plus the half of defect 6 that lives on the Built-in Agent quickstart. Every claim was traced through package source. Defect 5 — three provider/handler names presented as interchangeable. They are not interchangeable; they pair up, and the pairing is what was undocumented. Added a "Provider and handler pairs" section to `backend/runtime-endpoints.mdx`: - The v1 `<CopilotKit>` wrapper renders `<CopilotKitProvider>` internally and pins `useSingleEndpoint` to `true` unless the prop is passed (`copilotkit.tsx:108`), so it asks for single-route transport even against a multi-route Runtime. `<CopilotKitProvider>` with the prop omitted resolves to `auto` and detects from `/info`. - A table of which handlers serve which mode, and the deprecated aliases (`createCopilotEndpoint`, `createCopilotEndpointSingleRoute`, and the Express pair) mapped to their replacements. - The constraint nobody had written down: every `copilotRuntime*Endpoint` wrapper builds its handler with `mode: "single-route"` and exposes no option to change it. Next.js App Router and node-http call the single-route helper directly; pages-router, node-express and nest all delegate to node-http. So Rich Threads is unreachable from the wiring the quickstarts teach at ANY provider setting — it needs a v2 `CopilotRuntime` plus a multi-route handler. That is the structural reason behind defect 3. - Provider half is scoped to `<FrontendOnly frontend="react">` with an Angular branch, because this page also serves the Angular surface and `provideCopilotKit` has no `useSingleEndpoint`. Both quickstarts gain a short callout naming the pair they use and linking the mapping. Defect 9 — the Built-in Agent quickstart (what `/quickstart` actually serves) instantiates `new BuiltInAgent(...)` as the `default` agent with nothing warning a reader who already has one. `BuiltInAgent` extends `AbstractAgent` and calls the model directly via `streamText`, so registering it replaces the developer's agent rather than connecting to it — the `user_code_preservation` violation the ticket describes. Added a caution telling readers with an existing agent to take the frontend steps here and the runtime wiring from their framework's quickstart. Defect 6, second half — the same page installed `@copilotkit/react-ui` and never used it, importing `CopilotKit` and `CopilotSidebar` from `@copilotkit/react-core/v2`. Dropped it, matching the LangGraph fix in #6566. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
573a614112 | Merge main into codex/fac-126-strands-ts-starter | ||
|
|
b9d41c0e3a | Merge main into codex/fac-126-strands-ts-starter | ||
|
|
f40e532822 |
docs(backend): construct the Intelligence client and name its key (refs OSS-857) (#6568)
Fixes OSS-857 defects 1 and 2, which turn out to be one root cause.
## The problem
`backend/runtime-endpoints.mdx` shows this:
```ts
const runtime = new CopilotRuntime({
agents,
intelligence,
identifyUser: async (request) => { /* ... */ },
});
```
`intelligence` is a bare identifier. No import, no shape, no env source,
and no
page on the web path constructs it — so the example is not copyable.
That is also why `INTELLIGENCE_API_KEY` appeared to have no consumer,
which the
ticket called its "defect that matters most". `copilotkit project
select` writes
that key into `.env`, and `apiKey` on the Intelligence client is what
reads it.
Because no web page ever built the client, the variable looked orphaned.
## The fix
The construction was already documented correctly — but only on the
Channels
pages (`frontends/slack.mdx:120`, `frontends/teams.mdx`). This adds a
step to
the web path using that same pattern rather than inventing a second
vocabulary
for it:
```ts
import { CopilotKitIntelligence } from "@copilotkit/runtime/v2";
const intelligence = new CopilotKitIntelligence({
apiKey: process.env.INTELLIGENCE_API_KEY!,
});
```
It also documents the paired-override rule for `apiUrl` / `wsUrl`,
because the
API and realtime planes are separate hosts and setting one alone logs a
warning.
## The Inspector page was not wrong
`NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY` is the correct variable for the
Inspector.
The defect is that a reader whose `.env` holds `INTELLIGENCE_API_KEY`
cannot tell
whether the two are the same credential. So
`snippets/shared/premium/inspector.mdx`
now disambiguates them — publishable browser key versus server-side
project key,
with a pointer to what consumes the latter — rather than substituting
one for the
other.
## Verified against source, not inferred
- `CopilotKitIntelligence` is publicly exported from
`@copilotkit/runtime/v2`
(`intelligence-platform` → `v2/runtime/index.ts` → `v2/index.ts`)
- `apiKey` is the only required field of `CopilotKitIntelligenceConfig`
- `apiUrl` and `wsUrl` default to the managed platform, and
`warnOnPartialHostOverride` logs a warning when one is set without the
other
## What I could not verify
The site build and its vitest suite did not run: this was authored in a
fresh
worktree with no installed toolchain, and `oxlint` covers JS/TS rather
than MDX,
so it would not have exercised these edits anyway. CI is the first real
gate.
Checked instead:
- `<Step>`, `<FrontendOnly>` and code-fence balance in both files
- both new links against existing usage in the content tree —
`](/inspector)`
appears 7 times and `](/backend/runtime-endpoints)` 10 times. The site
soft-404s on unknown paths, so a link cannot be verified by status code.
## Scope
Defects 3, 4, 6, 7, 8, 10, 11 and 12 landed in #6566. Defects 5 and 9
are being
handled separately and are untouched here.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
99d3f99f4c |
docs(backend): construct the Intelligence client and name its key (refs OSS-857)
Fixes OSS-857 defects 1 and 2, which are one root cause. No page on the web
path ever constructs `CopilotKitIntelligence`, so `intelligence` reads as an
undefined identifier in the `new CopilotRuntime({ agents, intelligence,
identifyUser })` example, and `INTELLIGENCE_API_KEY` reads as a credential
with no consumer. `apiKey` IS that consumer.
The construction was already documented correctly, but only on the Channels
pages (frontends/slack.mdx, frontends/teams.mdx). This lifts the same pattern
onto the web path rather than inventing a second vocabulary for it.
Verified against packages/runtime source rather than inferred:
- `CopilotKitIntelligence` is exported publicly from `@copilotkit/runtime/v2`
via intelligence-platform -> v2/runtime/index.ts -> v2/index.ts
- `apiKey` is the only required field of `CopilotKitIntelligenceConfig`
- `apiUrl` and `wsUrl` default to the managed platform, and
`warnOnPartialHostOverride` logs a warning when one is set without the other,
which is why the docs now say to override both together
The Inspector page was NOT wrong to show `NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY` --
that is the correct variable for that purpose. The defect is that a reader whose
.env holds `INTELLIGENCE_API_KEY` cannot tell whether the two are the same
credential. So that page disambiguates rather than substitutes: publishable
browser key versus server-side project key, with a pointer to what consumes the
latter.
Not verified: the site build and its vitest suite. A fresh worktree has no
installed toolchain (oxlint is absent), and oxlint covers JS/TS rather than MDX,
so it would not have exercised these edits. What was checked instead: <Step>,
<FrontendOnly> and code-fence balance in both files, and both new links against
existing usage -- `](/inspector)` appears 7 times and
`](/backend/runtime-endpoints)` 10 times elsewhere in the content tree. The site
soft-404s on unknown paths, so a link cannot be verified by status code.
Defects 5 and 9 remain open and are not addressed here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
15ee7c6e5f |
docs(langgraph): fix 8 verified defects in the LangGraph onboarding docs (refs OSS-857) (#6566)
Fixes 8 of the 12 defects in OSS-857 (the OSS-856 phase 1 validation run). Defects **1, 2, 5 and 9** are owned by a parallel session working in `backend/runtime-endpoints.mdx`, `integrations/langgraph/inspector.mdx` and the root `quickstart.mdx` — **do not close OSS-857 on this PR.** Every claim below was re-derived from installed package source or a live run. Nothing here is recalled. ## Scope correction worth flagging first The task's file table mapped `/langgraph-python/generative-ui/a2ui/fixed-schema` to `integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx`. That is not the file the URL serves. `langgraph-python` is `docs_mode: generated`, so `page.tsx` tries `loadDoc(slugPath)` first and the **root** `generative-ui/a2ui/fixed-schema.mdx` wins. Defects 10, 11 and 12 all live in the root file, which is shared by 21 frameworks — a much larger blast radius than the table implied. Confirmed by rendering, not by reading: ``` $ curl -sL localhost:3013/langgraph-python/generative-ui/a2ui/fixed-schema | grep -c "Load the schema JSON at startup" 2 # root file's schema-loading branch $ ... | grep -c "Action handler details" 0 # the langgraph-scoped file's heading — never served ``` **The langgraph-scoped `integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx` is dead content at every URL.** Same for the sibling `index.mdx` and `dynamic-schema.mdx`. Only `advanced.mdx` and `styling.mdx` survive, because they have no root counterpart — and even those are unreachable from the sidebar. Worth its own ticket; not touched here. ## What changed, defect by defect ### 3 — Route shape (partial, as scoped) ✅ Added a caution at the route step. Deliberately did **not** rewrite the route. The precise mechanism, which matters for how the caution is worded: `copilotRuntimeNextJSAppRouterEndpoint` calls `createCopilotEndpointSingleRoute` (`packages/runtime/src/lib/integrations/nextjs/app-router.ts:39`). So the quickstart's POST-only route is **single-route mode** and chat genuinely works. It is not a broken route — it is the wrong mode for Threads. The caution says exactly that, names the `[[...slug]]` catch-all with `GET`/`POST`/`PATCH`/`DELETE`, ties it to the Inspector's "Finish setting up Rich Threads" state, and links to `/backend/runtime-endpoints#enable-rich-threads-routes` (anchor verified present). I did not assert that you can just add verbs to this handler — that would be wrong, and it is entangled with defect 5, which the other session owns. ### 4 — Port mismatch ✅ **Verified the default rather than trusting the ticket.** Both CLIs default to **2024**: ``` $ npx @langchain/langgraph-cli@latest dev --help -p, --port <number> port to run the server on (default: "2024") $ grep -n -A3 '"--port"' langgraph_cli/cli.py 670: default=2024, ``` The page was already internally consistent on 8123 — the trap is that nothing said the bare command differs, and 8123 is the convention across every sibling page (`deep-agents.mdx`, `deepagents/quickstart.mdx`, the showcase integration). So I took the second option in the brief: keep `--port 8123` and name the default. Added a callout at the start command, a per-tab note on which port each path serves, and a troubleshooting line. Also fixed a **factually wrong comment** in `showcase/integrations/langgraph-python/.env.example`, which claimed "langgraph dev runs on port 8123 by default". That is the same mis-belief, committed in the repo. One comment line, no behavior change; called out here because it is outside the two files named in the brief. ### 6 — `@copilotkit/react-ui` installed and never used ✅ Checked the exports; **the install line was wrong**, not the import. - `CopilotSidebar` is at `packages/react-core/src/v2/components/chat/CopilotSidebar.tsx`, exported via `@copilotkit/react-core/v2`. - `@copilotkit/react-ui`'s `exports` map has no `./v2` JS entry at all — only `./v2/styles.css`. Its root export does carry a v1 `CopilotSidebar`, which would be the wrong component under a v2 provider. - `examples/v2/react/demo` does not depend on `@copilotkit/react-ui`. Dropped it from the install line and said where the components come from. No unused import added. ### 7 — Checkpointer guidance ✅ Added the reason to each tab; kept the code difference, which is correct. Both directions verified: **LangSmith tab (bare compile).** `langgraph dev` sets `LANGSMITH_LANGGRAPH_API_VARIANT="local_dev"` (`langgraph_api/cli.py:271`), and under that variant `graph.py:821` raises on a compiled-in checkpointer. Reproduced with a real boot: ``` error Graph 'sample_agent' failed to load: ValueError: Heads up! Your graph 'graph' from './main.py' includes a custom checkpointer (type <class 'langgraph.checkpoint.memory.InMemorySaver'>). With LangGraph API, persistence is handled automatically by the platform, so providing a custom checkpointer ... isn't necessary and will be ignored when deployed. ``` The server does not start. So a reader who "helpfully" adds `MemorySaver()` here breaks their deployment — exactly the failure the ticket predicted. **FastAPI tab (`MemorySaver()` required).** `ag_ui_langgraph/agent.py` calls `graph.aget_state(config)` (lines 236, 474), and `Pregel.get_state`/`aget_state` raise `ValueError("No checkpointer set")` when none is configured (`langgraph/pregel/main.py:1402`). The checkpointer is not optional on that path. ### 8 — "Existing agent" install line ✅ Narrowed to `uv add langgraph langchain-openai langchain-core python-dotenv`. One correction to the ticket's framing: the over-add is **one** package, not two. The line is shared by both tabs, and only `copilotkit` is unused by the LangSmith path — the FastAPI tab already re-adds it in its own step alongside `ag-ui-langgraph`. And `python-dotenv` stays: the code in **both** tabs does `from dotenv import load_dotenv`, so removing it because `langgraph.json` declares `"env"` would break the shown snippet. Removing an import's package is not a docs fix. Added the pinned-dependency warning. `doctest.json` **needs no change**: its dep list backs the `doctest="server"` snippet (the FastAPI `main.py`), which still imports all eight. Checked rather than assumed. ### 10 — Three identical conditional branches ✅ (root cause was code, not prose) The HTML page was already correct — only the `schema-loading` branch renders for langgraph-python. The defect is entirely in the **`.md` view the validation run read**: `renderPageToLlmText` applied `filterFrontendScopedBlocks` and `filterAngularBackendScopedBlocks` but never `filterFrameworkScopedBlocks`, so raw Markdown emitted all three branches *with the literal JSX tags*, and every `<Snippet>` inside them resolved against the one requested framework. Before: ``` 286:<WhenFrameworkHas flag="a2ui_pattern" equals="schema-loading"> 402:<WhenFrameworkHas flag="a2ui_pattern" equals="schema-inline"> 519:<WhenFrameworkHas flag="a2ui_pattern" equals="llm-driven"> ``` …with byte-identical Python under each. That is what put "the host language doesn't ship a `load_schema` JSON loader" directly above a snippet calling `a2ui.load_schema` — the prose was never wrong for its own framework, it was just being shown to the wrong one. Fixed by gating on the same framework the snippets resolve to (routed through `pickFramework`, so prose and code agree even on unscoped `/<slug>.md`). This also repairs the same class of bug for the other five gated flags across every framework's `.md`. The filter is flat-only by design, so the new block is a sibling, not nested. Regression test added and **mutation-checked** — disabling the filter fails it: ``` × raw Markdown keeps only the active framework's <WhenFrameworkHas> branch ``` ### 11 — `StateGraph` example + missing install ✅ **Install half:** the `definitions-types`, `catalog-creation` and `renderers-tsx` snippets all import `@copilotkit/a2ui-renderer`, and no page installed it. Added a step for it plus `zod` (both are explicit deps of the langgraph-python cell). `@copilotkit/a2ui-renderer` is a real published package at 1.68.1, not private. **`StateGraph` half:** added, with **verified** code — not a guess. A re-verification pass sharpened this defect. `create_agent` appears on that page **only as an import** — both snippet regions (`backend-schema-json-load`, `backend-render-operations`) stop inside the tool body, so the agent construction is never shown at all: ``` $ grep -n "create_agent" <rendered .md> 315:from langchain.agents import create_agent # import only 347:from langchain.agents import create_agent # import only ``` So the page leaves `create_agent`, `CopilotKitMiddleware` and `ChatOpenAI` as imports the reader cannot act on. My first draft wrongly said "the snippet above is the reference cell's `create_agent` form"; that is corrected in the second commit, and the step now also carries over the cell's system-prompt caveat (the prompt tells the model to call `display_flight` once and stop, because the tool result *is* the card). Two probes, offline: 1. `ChatOpenAI(model="gpt-4.1-mini").bind_tools([display_flight])` constructs (no network). 2. A `StateGraph` + `ToolNode` + `tools_condition` graph, bare `compile()`, driven by a fake chat model, puts the A2UI container in the `ToolMessage`: ``` operation kinds: ['createSurface', 'updateComponents', 'updateDataModel'] PROBE2 OK (bare compile, ToolNode, tools_condition, bind_tools) ``` Placement needed care, because the root page is shared by 21 frameworks and `WhenFrameworkHas` gates only on manifest flags — `a2ui_pattern: schema-loading` covers 14 non-LangGraph integrations, so putting it there leaked LangGraph code to LlamaIndex/ADK/Pydantic-AI **and Python code to langgraph-typescript**. Confirmed by rendering before gating: ``` llamaindex stategraph=1 # wrong langgraph-typescript stategraph=1 # wrong: Python on a TS framework ``` So I added a narrow docs flag, `a2ui_agent_form: langgraph-state-graph`, via the extension path `when-framework-has.tsx` documents (manifest schema → `Integration` → `SupportedFlag` → manifest). Set on `langgraph-python` and `langgraph-fastapi` only. After gating: ``` langgraph-python stategraph=1 langgraph-fastapi stategraph=1 langgraph-typescript stategraph=0 llamaindex / google-adk / pydantic-ai / mastra / ms-agent-dotnet stategraph=0 ``` **Known gap, stated plainly:** `langgraph-typescript` gets no `StateGraph` form. I did not write one, because I have not verified a TypeScript LangGraph + A2UI form and a plausible-but-unrun TS snippet is worse than the gap. Adding it is a follow-up; the flag is the seam for it. **One caveat on this snippet:** every other code block on that page is machine-extracted from a running showcase cell. This one is hand-written and probe-verified. Backing it with a real cell (a `StateGraph` A2UI backend + fixture) would be the durable fix and is worth a follow-up. ### 12 — Two unreconciled doc trees ✅ `/integrations/langgraph/generative-ui/a2ui/fixed-schema` was not merely the wrong prefix — it **301s straight back to the page it sits on**: ``` $ curl -o /dev/null -w "%{http_code} %{redirect_url}" .../integrations/langgraph/generative-ui/a2ui/fixed-schema 301 http://localhost:3013/langgraph-python/generative-ui/a2ui/fixed-schema ``` So the sentence promising "the full pattern" linked to itself, and for a langgraph-typescript reader it also silently switched framework. Repointed at the reference it actually promises, relative so it resolves in the reader's own namespace — matching the `./dynamic-schema` convention already on this page. **Body-verified, not status-verified** (the site soft-404s with HTTP 200): ``` langgraph-python bytes=353527 id="action-handlers"=1 onAction=9 soft404=0 langgraph-typescript bytes=354215 id="action-handlers"=1 onAction=9 soft404=0 ``` Non-LangGraph frameworks get the graceful "topic specific to other integrations" page listing where it exists — not a dead end. ## Found while double-checking — reported, not changed Both are on the page I own, both are real, and I left both alone deliberately. **The LangSmith tab runs a Python agent with the JavaScript CLI.** The start command is `npx @langchain/langgraph-cli dev`, but the agent is `main.py` and `langgraph.json` declares `"python_version": "3.12"`. I expected this to fail. It does not — the JS CLI detects the Python config and delegates, but prints: ``` warn: Launching Python server from @langchain/langgraph-cli is experimental. Please use the `langgraph-cli` package from PyPi instead. info: Downloading uv 0.9.11 for darwin... Installed 76 packages in 53ms ``` It then boots normally and honours `--port`. So this is not a copy-paste failure — it is an experimental path that LangChain itself advises against, plus a surprise toolchain download. I did **not** change the command: it works, the recommended alternative would change the dependency set (defect 8's territory), and the identical command appears on three other pages (`integrations/langgraph/deep-agents.mdx`, `integrations/deepagents/quickstart.mdx`, `deepagents/index.mdx`), so changing one page in isolation would just create a new inconsistency. Worth its own ticket across all four. **The quickstart's runtime helper is deprecated.** `copilotRuntimeNextJSAppRouterEndpoint` → `createCopilotEndpointSingleRoute`, which carries `@deprecated Use createCopilotHonoHandler with mode: "single-route" instead` (`packages/runtime/src/v2/runtime/endpoints/hono-single.ts:24`). That is defect 5's territory — the parallel session owns the handler-name mapping — so per the brief I renamed nothing. The upside of tracing it: it let me word the defect-3 caution precisely. `createCopilotEndpointSingleRoute` calls `createCopilotRuntimeHandler({ mode: "single-route" })`, i.e. literally the same mode the runtime-endpoints page documents, so the caution can say "runs the runtime in single-route mode" as a fact rather than an inference. ## Not resolved / left for others - **Defects 1, 2, 5, 9** — parallel session's files. Untouched, including cross-references. In particular I renamed **no** providers or handlers. - **`langgraph-typescript` has no `StateGraph` form** — see defect 11 above. - **The langgraph-scoped A2UI tree is dead content.** `integrations/langgraph/generative-ui/a2ui/{index,fixed-schema,dynamic-schema}.mdx` are shadowed at every URL; `advanced.mdx` and `styling.mdx` are reachable but absent from the sidebar (`buildFrameworkOverridesNav` surfaces top-level overrides like `subgraphs` and `configurable`, but not these nested ones). Needs its own ticket. - **The bring-your-own path on the shared quickstart is Python-only** (`uv init`, `uv add`, `main.py`) for all three LangGraph frameworks, including `langgraph-typescript`. Pre-existing; not widened by this PR, but it is a real defect on a shared page. - **`showcase/integrations/langgraph-fastapi`'s a2ui cell has a source comment** pointing at `docs/integrations/langgraph/generative-ui/a2ui/fixed-schema.mdx` — i.e. the shadowed file. Cosmetic, and inside a cell, so left alone. - **`generative-ui/a2ui/index.mdx` links `./fixed-schema-streaming`**, which does not exist at root. Noticed while verifying; out of scope. ## Testing All from `showcase/shell-docs`. ``` $ npx tsc --noEmit (clean) $ npm run lint 0 errors (pre-existing warnings only, none in touched files) $ npx vitest run Test Files 1 failed | 58 passed (59) Tests 1 failed | 417 passed (418) ``` The single failure is `channels-docs.test.ts > publishes the Channels overview only through provider navigation`, about channels architecture images. **Proven pre-existing** — `git stash -u` on this branch and rerun gives the identical `1 failed | 29 passed`. Manifest schema change validated: ``` $ cd showcase/scripts && npx vitest run __tests__/generate-registry-pattern.test.ts __tests__/create-integration.test.ts Test Files 2 passed (2) Tests 39 passed (39) $ npm run pretypecheck # regenerates registry.json from the manifests langgraph-python -> langgraph-state-graph langgraph-fastapi -> langgraph-state-graph ``` Formatted with `oxfmt` (no changes needed). No changeset added. ### Render checks Dev server on **3013**, not 3003 — 3003 was already held by another worktree's docs server (`CopilotKit-oss844`), and reusing it would have verified the wrong tree. `quickstart` — identical across all three LangGraph frameworks, `.md` and HTML: | check | py | ts | fastapi | |---|---|---|---| | `npm install @copilotkit/react-core @copilotkit/runtime` | 1 | 1 | 1 | | `uv add langgraph langchain-openai langchain-core python-dotenv` | 1 | 1 | 1 | | route caution + `[[...slug]]` | 1 | 1 | 1 | | "Port 8123 is not the default" / "serves on **2024**" | 1 | 1 | 1 | | both checkpointer callouts | 1 | 1 | 1 | | pinned-dependency warning | 1 | 1 | 1 | | stale "Install LangGraph and AG-UI" heading | 0 | 0 | 0 | Callouts confirmed rendering as components, not literal text (checked the emitted React payload). Caught and fixed one real rendering bug while doing this: Callout `title` is a plain string, so a backticked title rendered its backticks literally. Also re-checked the two directional cross-references, since those are easy to get backwards: the "route below" note sits at line 289 and the route step at 334 (below ✓), and the "route above" note at 487 (above ✓). Cross-page link body-verified for all three LangGraph frameworks — the `.md` view rewrites it into the reader's own namespace (`/langgraph-python/backend/runtime-endpoints#enable-rich-threads-routes`), and the target carries the anchor with no soft-404: ``` langgraph-python bytes=374111 id="enable-rich-threads-routes"=1 soft404=0 langgraph-typescript bytes=374871 id="enable-rich-threads-routes"=1 soft404=0 langgraph-fastapi bytes=374301 id="enable-rich-threads-routes"=1 soft404=0 ``` The `#registering-the-runtime` anchor referenced from the new A2UI step was likewise confirmed present on that page. `generative-ui/a2ui/fixed-schema` — `.md` across eight frameworks: | framework | install step | StateGraph | old cross-tree link | new link | raw JSX tags | |---|---|---|---|---|---| | langgraph-python | 1 | 1 | 0 | 1 | 0 | | langgraph-fastapi | 1 | 1 | 0 | 1 | 0 | | langgraph-typescript | 1 | 0 | 0 | 1 | 0 | | llamaindex | 1 | 0 | 0 | 1 | 0 | | google-adk | 1 | 0 | 0 | 1 | 0 | | pydantic-ai | 1 | 0 | 0 | 1 | 0 | | mastra | 1 | 0 | 0 | 1 | 0 | | ms-agent-dotnet | 1 | 0 | 0 | 1 | 0 | Branch selection now matches HTML per framework (`schema-loading` for langgraph, `llm-driven` for mastra, `schema-inline` for ms-agent-dotnet) with zero `WhenFrameworkHas` tags leaking into Markdown. `doctest.json` was **not** treated as a gate — there is no runner for it in the repo, and its dep set is unchanged anyway. |
||
|
|
f24c4e2f22 |
docs(langgraph): correct the A2UI StateGraph framing after re-verification (refs OSS-857)
Three fixes found on a second pass over the docs changes: - The new StateGraph step claimed "the snippet above is the reference cell's `create_agent` form". It is not: `create_agent` appears on that page only as an *import* — both snippet regions stop inside the tool body, so the agent construction is never shown at all. Reworded to say that, which is the sharper version of defect 11: the page never shows how the tool attaches to any agent, leaving `create_agent`, `CopilotKitMiddleware` and `ChatOpenAI` as imports the reader cannot act on. - Carry over the system-prompt caveat. The reference cell steers the model to call `display_flight` once and stop because the tool result *is* the card; a StateGraph reader who drops that gets repeat tool calls. - The install note named only two of the four packages the FastAPI tab adds on top of the shared line. List all four. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
3ec309b724 |
docs(langgraph): fix 8 verified defects in the LangGraph onboarding docs (refs OSS-857)
Fixes defects 3, 4, 6, 7, 8, 10, 11 and 12 from the OSS-856 phase 1 validation run. Every claim below was re-verified against installed package source or a live run, not recalled. LangGraph quickstart (`integrations/langgraph/quickstart.mdx`): - Route shape: a caution at the route step. The POST-only route runs the runtime in single-route mode, which is all chat needs; Threads and the Inspector need the multi-route catch-all with GET/POST/PATCH/DELETE. Links to the canonical runtime-endpoints section. - Port: bare `langgraph dev` serves 2024, not 8123. Verified against both CLIs (`@langchain/langgraph-cli` help output, and `default=2024` in `langgraph_cli/cli.py`). The guide keeps `--port 8123` to stay consistent with every sibling page, and now says so. - Drop `@copilotkit/react-ui` from the install list. `CopilotSidebar` lives in `@copilotkit/react-core/v2`; react-ui exports no `./v2` JS entry point and the v2 react example does not depend on it. - Checkpointer: state the reason each tab differs. `langgraph dev` fails to load a graph compiled with a custom checkpointer (reproduced), while the FastAPI tab needs one because `ag-ui-langgraph` calls `graph.aget_state(...)`, which raises `ValueError: No checkpointer set`. - Narrow the shared `uv add` line to what both tabs import, and warn that a project with exact pins should add them by hand. A2UI fixed schema (`generative-ui/a2ui/fixed-schema.mdx`): - Add the missing install step for `@copilotkit/a2ui-renderer` + `zod`, which the catalog/definitions/renderer snippets all import. - Add a `StateGraph` + `ToolNode` form for developers who already have a hand-built graph, gated to the Python LangGraph slugs by a new `a2ui_agent_form` docs flag so the shared page does not show Python to langgraph-typescript or LangGraph code to LlamaIndex/ADK/Mastra. - Repoint the cross-tree `/integrations/langgraph/...` link, which 301'd back to this same page, at the action-handler reference it promises. Raw Markdown pipeline (`src/lib/llm-text.ts`): - `renderPageToLlmText` never applied `filterFrameworkScopedBlocks`, so `/<framework>/<page>.md` emitted every `<WhenFrameworkHas>` branch with raw JSX tags, each carrying the one selected framework's snippet. On the A2UI page that produced three mutually-exclusive "how the schema is delivered" sections whose prose contradicted the identical code under each. Gate on the same framework the snippets resolve to, with a regression test. Also corrects a factually wrong comment in the langgraph-python showcase `.env.example` that claimed 8123 was the `langgraph dev` default — the same mis-belief this ticket found in the docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |