mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
codex/remove-threads-cli-path
12110 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bedc53a652 |
fix(showcase/langgraph-python): widen declarative-gen-ui surface and polish InfoRow
The chat shell caps its scroll column at cpk:max-w-3xl (~768px), which left A2UI-generated cards (KPI dashboards, charts, status reports) feeling pinched on the declarative-gen-ui demo. Locally widen that wrapper to 64rem via a scoped attribute selector on the demo and bump the outer page wrapper from max-w-4xl to max-w-6xl so the card column actually has room to grow. While here, fix the InfoRow trailing-separator artifact: each row now draws its own border-bottom with last:border-b-0 so the final row in a Card (e.g. the Status Report demo) no longer leaves a dangling line, regardless of whether the agent wraps the rows in a Column or drops them directly into the Card child slot. Right-align the value with tabular-nums for cleaner stacks. Card itself gains w-full overflow-hidden so it stretches into the now-wider column instead of sitting at its min-width. |
||
|
|
5d4dd61556 |
fix(showcase/mcp-apps): route "Draw a flowchart" pill to create_view fixture (#4762)
## Summary
- The mcp-apps demo's "Draw a flowchart" suggestion pill silently broke:
clicking it produced a generic "Here is my plan..." response with no MCP
tool call, so the sandboxed iframe never mounted.
- Root cause: the verbatim pill prompt `"Use Excalidraw to draw a simple
flowchart with three steps."` had no matching `create_view` fixture in
`d5-all.json`. aimock's first-match-wins substring matcher fell through
to `feature-parity.json`'s `{userMessage: "steps"}` content-only
catch-all (matches "with three **steps**.").
- Fix: add a fixture pair keyed on the distinctive substring `"draw a
simple flowchart"` to `d5-all.json` and its mirror in
`harness/fixtures/d5/mcp-apps.json`. Turn 1 emits `create_view` with a
Start → Process → End flowchart; turn 2 (post tool result) emits the
narration.
- Regression guard: a fast vitest under `showcase/scripts/__tests__/`
loads fixtures in the same order as `docker-compose.local.yml` and uses
aimock's `matchFixture` to assert each mcp-apps pill routes to its
`create_view` fixture on turn 1 and its narration fixture on turn 2. The
test fails loudly with a diagnostic naming the absorbing fixture if the
bug returns (verified by reverting the fix locally).
## Test plan
- [x] `pnpm --filter @copilotkit/showcase-scripts test
__tests__/mcp-apps-suggestion-routing.test.ts` — 3 tests, ~260 ms, all
green.
- [x] `pnpm --filter @copilotkit/showcase-scripts test
__tests__/aimock-fixtures.test.ts` — fixture files still validate
cleanly with the new entries.
- [x] Reverted just the two new fixtures, re-ran the regression test,
confirmed it fails with a diagnostic that explicitly names the wrong
fixture (`feature-parity.json`'s `{userMessage: "steps"}` content
blurb).
- [x] Local docker stack (`bin/showcase up langgraph-python`) + browser:
clicked "Draw a flowchart" at http://localhost:3100/demos/mcp-apps —
agent emits `create_view`, MCP middleware fetches the Excalidraw UI
resource, sandboxed iframe mounts inline, narration arrives.
- [x] aimock direct POST to `/v1/chat/completions` confirms both legs:
- Turn 1 (pill + `create_view` in tools[]) → `tool_calls: [{ name:
"create_view", id: "call_d5_mcp_apps_create_view_flowchart_001", ...
}]`.
- Turn 2 (with tool result appended) → `content: "Drew a three-step
flowchart (Start → Process → End)..."`.
|
||
|
|
c99bea6670 |
fix(showcase/mcp-apps): route "Draw a flowchart" pill to create_view
The "Draw a flowchart" suggestion pill in the mcp-apps demo sent
"Use Excalidraw to draw a simple flowchart with three steps." which
had no matching create_view fixture in d5-all.json. aimock walked
through to feature-parity.json's `{userMessage: "steps"}` substring
fixture and returned a generic "Here is my plan..." content blurb
with no MCP tool call, so the runtime never invoked create_view, the
MCP middleware never fetched the UI resource, and the sandboxed
iframe never mounted.
Add a fixture pair in d5-all.json (and its harness mirror) keyed on
"draw a simple flowchart": turn 1 emits create_view with a three-
step Start -> Process -> End flowchart, turn 2 emits the narration
after the tool result. The distinctive substring beats the generic
feature-parity catch-alls under first-match-wins.
Adds a regression test that loads the same fixture files in the same
order as docker-compose.local.yml and asserts via aimock's matchFixture
that each mcp-apps pill routes to its create_view fixture on turn 1 and
its narration fixture on turn 2.
|
||
|
|
25f1f921a8 |
fix(showcase): unbreak multimodal demo end-to-end (auto-send, dedupe, proxy) (#4761)
## Summary Re-lands the multimodal-attachments fix from #4584 (May 1, never merged) onto current `main`, ported to the post-refactor file layout where `page.tsx` was split into `legacy-converter-shim.tsx`, `multimodal-chat.tsx`, and `file-to-data-attachment.ts`. Auto-send was the visible regression: clicking **Try with sample image / Try with sample PDF** only queued the attachment chip instead of sending the canned prompt. This PR restores the full end-to-end behavior plus five regression tests so it can't silently break again. ## What was broken and what changed 1. **Random uploads crashed with `Failed to fetch`.** aimock returned HTTP 404 on no-match, the LangGraph SDK surfaced `NotFoundError`, the AG-UI stream surfaced a `RUN_ERROR`, the demo crashed. → Added `--proxy-only` + `--provider-openai https://api.openai.com` to the local aimock command so unmatched user prompts fall through to real OpenAI (mirrors Railway). 2. **Bundled-sample fixtures keyed on user-visible canned prompts.** Auto-prompts are now natural and specific ("can you tell me what is in this demo image/pdf I just attached") so they render cleanly as the user message bubble AND can't collide with arbitrary user prompts — random uploads phrase questions differently and fall through to the proxy. 3. **Sample buttons now auto-send via `useAgent`.** The previous DataTransfer path queued the attachment via the chat's hidden file input but required clicking send while the attachment was still uploading — `CopilotChat.onSubmitInput` rejects submits during upload AND clears the input regardless, so the canned prompt was eaten. Rewrite calls `agent.addMessage(...)` + `copilotkit.runAgent({ agent })` directly with the base64'd content part. 4. **PDF flattened text bled into the rendered user message.** `_PdfFlattenMiddleware` ran in `before_model` and persisted the rewrite to agent state. Switched to `wrap_model_call` so the PDF→text rewrite is scoped to the model request only. 5. **Attachments doubled (and PDFs rendered as broken `<img>`).** The `@ag-ui/langgraph` round-trip mis-tags PDFs as `image` and re-injects the user's original modern part, doubling chips. Added `dedupeUserMessageMedia` subscriber on `onMessagesSnapshotEvent` + `onRunFinalized` to dedupe by `source.value` and re-key type from mimeType. Also flipped `onRunInitialized` from REPLACE to APPEND so the modern part stays for the UI alongside a legacy `binary` sibling for the converter. 6. **Regression suite (`tests/e2e/multimodal.spec.ts`).** Five focused tests, all pass against live local stack (15.4s): - page loads with all expected affordances - sample image: auto-sends, EXACTLY ONE `<img>`, assistant references the logo - sample PDF: auto-sends, EXACTLY ONE `DocumentAttachment` chip ("PDF" label), NO `<img>`, no `[Attached document]` text bleed - image then PDF in the same session: each message keeps its own single chip - PDF then image in the same session: symmetric ## Test plan - [x] `showcase up langgraph-python` — both sample buttons auto-send; image renders as `<img>`, PDF renders as PDF chip; random paperclip uploads go through proxy - [x] `BASE_URL=http://localhost:3100 CI=1 npx playwright test multimodal.spec.ts` — **5 / 5 passing** - [ ] Post-merge: e2e-deep cycle for langgraph-python multimodal cell stays green ## Closes Closes #4584. |
||
|
|
8968007188 | style: auto-fix formatting | ||
|
|
7c3edca2b7 |
fix(showcase): unbreak multimodal demo end-to-end (sample buttons auto-send, dedupe, proxy)
The langgraph-python multimodal-attachments demo had a stack of bugs that compounded each other. Fixing them required touching the local docker-compose, the aimock fixtures, the LangChain middleware, the client-side AG-UI shim, and the sample-attachment buttons. This commit lands the full set together because they only make sense as a unit — verified end-to-end against `showcase up langgraph-python` in a headed browser. New e2e suite pins each regression. Supersedes #4584 (the original fix from May 1 that never landed — this is a fresh port onto the post-refactor file layout where page.tsx is split into legacy-converter-shim.tsx, multimodal-chat.tsx, file-to-data-attachment.ts). What was broken and what changed: 1. Random uploads crashed with `Failed to fetch`. aimock returned HTTP 404 on no-match, the LangGraph SDK surfaced `NotFoundError`, the AG-UI stream surfaced a `RUN_ERROR`, the demo crashed. Added `--proxy-only` + `--provider-openai https://api.openai.com` to the local aimock command so unmatched user prompts fall through to real OpenAI (mirrors the Railway aimock setup). 2. Bundled-sample fixtures keyed on user-visible canned prompts. The auto-prompts are deliberately long, specific, and natural- reading ("can you tell me what is in this demo image/pdf I just attached") so they (a) render cleanly as the user message bubble, and (b) can't collide with arbitrary user prompts — random uploads phrase questions differently and fall through to the proxy. 3. Sample buttons now auto-send via `useAgent`. The previous DataTransfer-based path queued the attachment via the chat's hidden file input, then required clicking send while the attachment was still uploading — `CopilotChat.onSubmitInput` rejects submits during upload AND clears the input regardless, so the canned prompt was eaten. Rewrite to call `agent.addMessage(...)` + `copilotkit.runAgent({ agent })` directly with the base64'd content part, sidestepping the upload race entirely. 4. PDF flattened text bled into the rendered user message. `_PdfFlattenMiddleware` ran in `before_model` and returned `{"messages": rewritten}`, which persisted to agent state. The chat UI then rendered the `[Attached document]\n<pdf body>` text part inline with the user prompt. Switched to `wrap_model_call` so the PDF→text rewrite is scoped to the outgoing model request only and never pollutes state. 5. Attachments doubled (and PDFs rendered as broken `<img>`). The `@ag-ui/langgraph` round-trip translates outgoing `binary` parts to LangChain `image_url` and incoming `image_url` back to `image` AG-UI parts — regardless of mimeType, so PDFs came back as `type: "image"` with `mimeType: "application/pdf"` and were forced into `ImageAttachment`, where the load failed and the chat showed two "Failed to load image" boxes. Plus the user's original modern part survived alongside the round-tripped one, doubling visible chips. Added a `dedupeUserMessageMedia` subscriber on both `onMessagesSnapshotEvent` and `onRunFinalized` to: - dedupe media parts by `source.value` so the local + round- tripped copy collapse to one chip - re-key part `type` from `mimeType` so PDFs route to `DocumentAttachment` (icon + filename) and images to `ImageAttachment`. Also flipped the `onRunInitialized` shim from REPLACE to APPEND — keep the modern part for the UI AND emit a legacy `binary` sibling for the converter. 6. Regression suite (`tests/e2e/multimodal.spec.ts`). Replaces the pre-rewrite suite with five focused tests: - page loads with all expected affordances - sample image: auto-sends, EXACTLY ONE `<img>`, assistant references the logo - sample PDF: auto-sends, EXACTLY ONE `DocumentAttachment` chip ("PDF" label), NO `<img>`, no `[Attached document]` text bleed - image then PDF in the same session: each message keeps its own single chip, no cross-contamination - PDF then image in the same session: symmetric All 5 pass against the live local stack (15.4s). |
||
|
|
b5c00a6192 |
fix(showcase/voice): use real Whisper for mic transcription (#4760)
## Summary - The voice route's OpenAI client used to fall through to `OPENAI_BASE_URL`, which `docker-compose.local.yml` sets to `http://aimock:4010/v1`. Aimock has a catchall `endpoint: "transcription"` fixture that returns `"What is the weather in Tokyo?"` for every audio file, so the mic button always produced that phrase regardless of what the user actually said into the microphone. Pin `baseURL` to real OpenAI Whisper (overridable via `OPENAI_TRANSCRIPTION_BASE_URL`). The sample-audio button stays as synchronous text injection — that's the documented design and what the e2e + d5 probe rely on. - Tidy the sample-audio button label so the affordance matches what it does: "Try a sample question" → "Try a sample audio". - Realign `tests/e2e/voice.spec.ts` with the shipped component (the spec was asserting on a `voice-sample-audio` container testid and a `Sample: "..."` caption that never existed in the current `sample-audio-button.tsx`), and add cold-start timeout headroom for the mic button render (waits on `/info` round trip) and the agent-flow test. - Add `"env": ".env"` to `langgraph.json` so `langgraph_cli dev` picks up `OPENAI_API_KEY` for local dev. Docker/Railway paths inject env vars directly via `env_file`, so this is a no-op there. Scope was deliberately limited to `langgraph-python` (north-star) per the user's request — the other 17 integrations still route mic transcription through aimock. Demo parity sync can propagate this when desired. ## Test plan - [x] `pnpm exec playwright test voice.spec.ts` — all 3 tests pass (`page loads…`, `sample audio button injects the canned phrase…`, `sending the transcribed text produces a weather tool render`) - [x] Manual mic verification on `http://localhost:3000/demos/voice` with a real `OPENAI_API_KEY` — speaking "hello" now returns "Hello." instead of the Tokyo fixture - [ ] Visual check the new "Try a sample audio" label in the deployed preview - [ ] Confirm Railway/Docker deploys still transcribe through real Whisper (this path was unaffected — `OPENAI_TRANSCRIPTION_BASE_URL` stays unset, defaulting to api.openai.com) |
||
|
|
985bebf39c |
fix(showcase/voice): use real Whisper for mic transcription
The voice route's OpenAI client previously fell through to OPENAI_BASE_URL, which docker-compose.local.yml sets to http://aimock:4010/v1. Aimock has a catchall transcription fixture that returns "What is the weather in Tokyo?" for every audio file, so the mic button always produced that phrase no matter what the user actually said. Pin baseURL to real OpenAI (overridable via OPENAI_TRANSCRIPTION_BASE_URL). The sample-audio button stays as synchronous text injection — that's the documented design, and what the e2e + d5 probe rely on. Also: - Tidy the sample button label ("Try a sample question" -> "Try a sample audio") so the affordance matches what it does. - Realign tests/e2e/voice.spec.ts with the shipped component (the voice-sample-audio container testid and Sample: "..." caption it asserted on never existed on HEAD) and add cold-start timeout headroom for the mic-button render and the agent-flow test. - Add "env": ".env" to langgraph.json so langgraph_cli dev picks up OPENAI_API_KEY locally. Docker/Railway paths inject env vars directly so this is a no-op there. |
||
|
|
15db0bbf3d |
fix(showcase/harness): drive gen-ui-headless-complete via textarea, not chip click (#4731)
## Summary Follow-up to #4723. The post-merge cycle showed `gen-ui-headless-complete` still red with `page.click: Timeout` waiting for the aria-label selector I added in #4723. Root cause: the demo has TWO chip surfaces with diverging aria-label shapes: - **EmptyState** (first paint, before any messages): `aria-label="Try suggestion: <message>"`, visible text = the message string. - **SuggestionBar** (after first message lands): `aria-label="Suggestion: <title>"`, visible text = the short title. Which surface is mounted depends on `messages.length` — timing-dependent. Both my prior selectors (`button >> text="Weather"` and `button[aria-label="Suggestion: Weather"]`) matched only one surface and timed out on the other. Fix: drop the chip-click preFill entirely. The runner's normal fill+press hits the textarea with the verbatim prompt; chip clicks and textarea-Enter dispatch the same `runAgent`, so the fixture matcher catches either route — and the textarea is always present. Also includes a small refresh of `e2e-deep.test.ts` for a stale assertion (Phase-2A REGISTRY_TO_D5 split renamed `tool-rendering` → `tool-rendering-default-catchall`). ## Test plan - [ ] Land + watch the next e2e-deep cycle - [ ] Confirm `gen-ui-headless-complete` flips green 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
49fd3d899f |
fix(showcase/aimock): tool-rendering-reasoning-chain multi-turn (Turn 2 hang) (#4752)
## Summary The LGP **tool-rendering-reasoning-chain** D5 probe hung on Turn 2 (Find flights from SFO to JFK) after Turn 1 (weather Tokyo) succeeded. **Root cause:** the SFO/JFK first-leg fixture matched on `hasToolResult: false`, but Turn 1's tool result remains in the conversation by Turn 2. So aimock's matcher skipped the first-leg fixture and fell through to the second-leg (`hasToolResult: true`), returning narration text without the `search_flights` tool call. The probe then timed out waiting for the FlightListCard testid that never mounted. **Fix:** switch the SFO/JFK second-leg fixture to `toolCallId` matching (last message must be a tool result with that specific `call_id`) and drop `hasToolResult` from the first-leg. The second-leg fixture must come BEFORE the first-leg in file order — the matcher is first-match-wins, but with `toolCallId` it cannot accidentally swallow first-leg requests (whose last message is the user prompt, not a tool result). Also adds a `content` field to the Tokyo first-leg fixtures (`get_weather` underscore + `get-weather` Mastra-hyphen variants) so they route through aimock's `buildContentWithToolCallsStreamEvents` instead of `buildToolCallStreamEvents`. The latter codepath silently drops the `reasoning` field (4-arg signature, no reasoning param), which is why the reasoning-block testid never mounted on Turn 1 either before this change. Tokyo (Turn 1) keeps the simpler `hasToolResult` pattern because it has no prior turns; only the SFO/JFK fixture pair needs the `toolCallId` shape to survive multi-turn use. ## Test plan - [x] `pnpm --filter @copilotkit/showcase-scripts test aimock-fixtures` — 18 passed (load-time schema validation) - [x] `pnpm --filter @copilotkit/showcase-scripts test` — 574/574 passed - [x] `pnpm --filter @copilotkit/showcase-harness test` — 1588/1588 passed - [ ] Railway deploys aimock with new fixtures, then `tool-rendering-reasoning-chain` cell on the dashboard flips D4 → D5 for langgraph-python |
||
|
|
32d0237cb5 |
fix(shell-docs): cutover-blocker fixes from Phase 4 validation (#4741)
## Summary
Phase 4 validation (run today against `docs.showcase.copilotkit.ai`)
surfaced four cutover-blocking issues. This PR fixes all of them in four
focused commits.
## Commits
1. **chore(showcase): close last 2 yellow Missing snippet boxes for
cutover** — adds in-place region markers to
`langgraph-python::frontend-tools` and a sibling
`slot-overrides.snippet.tsx` teaching file for
`langgraph-python::chat-slots`. Both pages now render zero `Missing
snippet` warnings.
2. **fix(shell-docs): correct feature-viewer slug + demo-id translation
for code tab** — adds `getFeatureViewerSlug()` and
`getFeatureViewerDemoId()` helpers in `registry.ts`, with explicit
override maps for the 8 framework-name mismatches (built-in-agent,
google-adk, claude-sdk-{python,typescript}, ms-agent-{python,dotnet},
crewai-crews, llamaindex) and 5 demo-id mismatches (gen_ui_tool_based,
gen_ui_agent, shared_state_streaming, shared_state_read_write,
hitl_in_chat). When the framework or demo has no feature-viewer
equivalent, the helper returns null and the Code tab is hidden on that
page (graceful degradation; Demo tab still renders).
3. **fix(shell-docs): redirect catalog hygiene (self-loops +
framework-scoped gap)** — removes 31 self-redirect entries from
`seo-redirects.ts` (where source === destination caused infinite 301
loops on canonical URLs like /frontend-tools, /faq, /human-in-the-loop).
Reorders middleware logic so the redirect catalog is consulted before
the framework-scoped short-circuit fires, fixing 97 framework-scoped
slug-rename URLs that were soft-404ing instead of redirecting. Adds
defense-in-depth skip-when-equal guard in middleware.
4. **fix(shell-docs): resolve 53 sitemap 500s before cutover** — three
independent root causes in MDX rendering:
- 4 missing \`<Component />\` registrations in \`mdx-registry.tsx\`
(CopilotCloudConfigureCopilotKit,
SelfHostingCopilotRuntimeConfigureCopilotKit, CloudCopilotKit, Content)
— affected ~37 pages.
- 3 langgraph tutorial pages had markdown lists immediately preceding
JSX closing tags, causing remark to bail. Fix = blank line between
bullet and close tag (~9 pages).
- 5 MDX files used escaped JSX comments that Acorn cannot parse —
replaced with proper unescaped form (~7 pages).
## Verification
- Production build clean: 27 static pages generated, 0 errors
- Local probes: all 53 sitemap-500 URLs return 200; all 31 former
self-loop URLs return 200; all 85 framework-scoped non-loop catalog
entries 301 to expected destinations
- Code tab: 47/60 (framework × demo) URLs resolve to real code panels
post-fix; remaining 13 are feature-viewer per-framework deploy-coverage
gaps in the \`ag-ui-protocol/ag-ui\` repo, not this one
- Both langgraph-python pages render 0 \`Missing snippet\` boxes after
re-bundling demo-content
## Test plan
- [ ] CI passes
- [ ] Sitemap probe: every URL in \`/sitemap.xml\` returns 200
- [ ] Redirect probe: spot-check 5 framework-scoped slug renames (e.g.
\`/agno/frontend-actions\`, \`/pydantic-ai/use-agent-hook\`)
- [ ] Self-loop probe: \`/frontend-tools\` returns 200, not infinite 301
- [ ] Code tab: visit \`/built-in-agent/frontend-tools\` (tab should be
hidden), \`/langgraph-python/agentic-chat\` (tab should render code),
\`/llamaindex/agentic-chat\` (tab should render after llama-index slug
rename)
- [ ] Yellow boxes: visit \`/langgraph-python/frontend-tools\` and
\`/langgraph-python/custom-look-and-feel/slots\` — zero Missing snippet
warnings
|
||
|
|
dd3c142a43 |
Merge remote-tracking branch 'origin/main' into fix/d5-tool-rendering-reasoning-chain-multi-turn
# Conflicts: # showcase/aimock/d5-all.json # showcase/harness/fixtures/d5/tool-rendering-reasoning-chain.json |
||
|
|
bf8782b1b7 |
test(showcase/langgraph-python): regression coverage for A2UI middleware-intercept + display_flight loop (#4738)
## Summary Pins the three classes of regression that #4733 + #4734 just fixed, so a future revert/refactor trips a test instead of breaking the deployed showcase silently. ### Python unit tests — `src/agents/test_a2ui_internal_tools.py` 7 tests, ~2s, no LLM calls (secondary LLM is stubbed): 1. **Tool name doesn't collide with the A2UI middleware's intercept list.** Parametrised over `beautiful_chat._design_a2ui_surface`, `a2ui_dynamic._design_a2ui_surface`, and `a2ui_fixed.display_flight`. Asserts none of them appear in `a2uiToolNames` (default `{"render_a2ui"}`). Catches an accidental rename revert that would re-enable the streaming-args bypass. 2. **`generate_a2ui` force-pins canonical `catalog_id`.** Stubs `ChatOpenAI` with a fake response carrying a hallucinated `catalogId`, calls the tool, parses the returned ops, asserts the surface op carries the module's `CUSTOM_CATALOG_ID`. Covers both `beautiful_chat` and `a2ui_dynamic`. 3. **Malformed root drops cleanly.** Stubs the secondary LLM emitting a root component without a `component` field. Asserts `generate_a2ui` returns a clean error string instead of feeding the renderer a partial tree (which surfaces as the deploy-only "Cannot create component root without a type" infinite-loop). ### E2E regression assertions — added to existing specs - `tests/e2e/beautiful-chat.spec.ts` (Sales Dashboard test): no `Catalog not found` / `Cannot create component … without a type` banner; at most 2 `recharts-responsive-container` (one pie + one bar = single dashboard). - `tests/e2e/declarative-gen-ui.spec.ts` (BarChart test): no banners; at most 1 `recharts-responsive-container`. - `tests/e2e/a2ui-fixed-schema.spec.ts` (Find SFO → JFK test): exactly one `Flight Details` and one `Book flight` button (was 6+ on deploy pre-fix from the `display_flight` loop); no banners. ## Test plan - [x] `pytest src/agents/test_a2ui_internal_tools.py` — 7/7 green locally. - [ ] Existing Playwright suites still pass (assertions are additive — only fail if a regression actually surfaces). |
||
|
|
425bd0a744 | Merge remote-tracking branch 'origin/main' into fix/d5-tool-rendering-reasoning-chain-multi-turn | ||
|
|
85eba85df9 |
Merge remote-tracking branch 'origin/main' into tyler/lgp-d5-probe-realign
# Conflicts: # showcase/harness/src/probes/drivers/e2e-deep.test.ts # showcase/harness/src/probes/scripts/d5-gen-ui-headless-complete.ts |
||
|
|
5c0a87e18b | Merge branch 'main' into test/lgp-a2ui-regression-coverage | ||
|
|
4414188910 |
chore(showcase): deprecate legacy byoc-* feature IDs (#4758)
## What does this PR do? Marks the legacy `byoc-hashbrown` and `byoc-json-render` registry entries as `"deprecated": true` so the dashboard's "Show deprecated" toggle hides them by default. [#4756](https://github.com/CopilotKit/CopilotKit/pull/4756) renamed langgraph-python's `byoc-*` slugs to `declarative-*` but kept the legacy IDs in the registry so the other 17 integrations (whose manifests still declare `byoc-*`) wouldn't drop out of the catalog. That left the BYOC (Bring Your Own Components) section showing **both** rows for each of the two demos — legacy IDs red-X'd for langgraph-python (no manifest declaration there anymore) and the renamed IDs green. This PR keeps both ID forms live (the other 17 integrations still need the legacy entries) but hides the legacy duplicates behind the standard `deprecated` flag — same pattern already used for `agentic-chat-reasoning`, `hitl`, `hitl-in-chat-booking`, `reasoning-default-render`. The dashboard's "Show deprecated" toggle in `feature-grid.tsx` decides visibility from there. ## Why The dashboard view post-#4756 was confusing — two identical-looking "Declarative UI: Hashbrown" / "Declarative UI: json-render" rows where one is green and one is red. Deprecating the legacy entries gives readers one canonical row per demo by default while preserving the data path the other 17 integrations rely on. ## Test plan - [x] `showcase/scripts` vitest suite green (574 tests) - [x] `npx tsx generate-registry.ts` regenerates `catalog.json` for all four shells without errors - [x] No catalog count changes (deprecated cells stay in the catalog, only dashboard visibility changes) ## Related - [#4756](https://github.com/CopilotKit/CopilotKit/pull/4756) — the slug rename that introduced the duplicate rows 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
f367d6ef14 |
chore(showcase): deprecate legacy byoc-* feature IDs
PR #4756 renamed langgraph-python's `byoc-hashbrown` / `byoc-json-render` slugs to `declarative-*` but kept the legacy IDs in the registry so the other 17 integrations (which still declare `byoc-*` in their manifests) don't drop out of the catalog. The dashboard then showed both rows side by side under "BYOC (Bring Your Own Components)": the legacy IDs red for langgraph-python (no manifest declaration) and the renamed IDs green. Mark the two legacy IDs `"deprecated": true` so the dashboard's "Show deprecated" toggle hides them by default. The canonical declarative-* rows stay visible. Data stays intact for the other 17 integrations until they migrate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4bf9b69439 |
showcase(langgraph-python): correctness + cleanliness pass, e2e/QA alignment, cr-loop convergence (#4756)
## What does this PR do?
Multi-phase correctness + cleanliness pass on
`showcase/integrations/langgraph-python` plus the shared
harness/aimock/dashboard surfaces it depends on. The langgraph-python
integration is the reference implementation other showcase integrations
are graded against, so the diff cleans up real demo-time bugs, brings
the e2e + QA contract into line with each demo's actual source, and
updates the D5 harness so probe coverage works against the renamed
slugs.
The 18 commits split cleanly into two parts:
**Phase commits (5 — original audit work, already on the branch when
cr-loop started):**
- **`7a66040c2` Phase A correctness fixes** — `interrupt-headless` now
reads `payload.slots` from the backend instead of rendering stale
hardcoded dates; `package.json#dev` runs `langgraph_cli dev --port 8123`
(matching the API route and the production entrypoint) instead of
pointing at a 3-line `agent_server.py` stub on port 8000; the legacy
stub is deleted; the entrypoint smoke-check for `src/agents/tools.py` (a
file that never existed) is removed; the two reasoning-only agents get a
one-line comment explaining why `CopilotKitMiddleware` is intentionally
absent.
- **`ee429d1b2` Phase B demo cleanup** — `shared-state-read` flattens to
a single source of truth (drops dual-state sync that had the read-only
demo locally mutating recipe state); extracts `useAutoScroll` and
`useTypingIndicator` out of `headless-complete`; extracts
`parseJsonResult` into a shared helper; extracts `NOTES_DB` out of
`frontend-tools-async/page.tsx`; introduces a `makeSlotOverride<T>`
helper that replaces 11 `as unknown as` casts in `chat-slots/page.tsx`.
- **`fc8c0f5e4` Phase C Python agent cleanup** — extracts
`_a2ui_utils.py` (`sanitize_a2ui_components` + `has_root_component`)
consumed by `beautiful_chat.py` and `a2ui_dynamic.py`; collapses three
try/except blocks in `multimodal_agent._extract_pdf_text`; replaces
hardcoded PDT offset with `zoneinfo.ZoneInfo(\"America/Los_Angeles\")`
so DST works.
- **`8b6eca973` Phase D rename** — `byoc-{hashbrown,json-render}`
slugs/folders/routes/specs/QAs become `declarative-*` (the internal
Python graph IDs intentionally stay legacy for now); Tool Rendering trio
renames to Default/Catch-all/Custom progression; showcase index now
sorts demos within each tag by `manifest.features` order.
- **`99ad42e9b` Phase E test contract alignment** — agentic-chat spec
rewrites to match the now-simplified vanilla-chat demo; deletes specs
for demos that no longer exist (`shared-state-write.spec.ts`,
`renderer-selector.spec.ts`); aligns QAs with the demos they describe.
**Cr-loop commits (13 — convergence-driven fixes from a 7-round
multi-agent review):**
The cr-loop ran 7 confirmation rounds with 7 specialized review agents
per round (code-reviewer, silent-failure-hunter, pr-test-analyzer,
comment-analyzer, type-design-analyzer, infra code-reviewer, Python
code-reviewer). Findings each round were partitioned into bucket (a)
subject-scope + load-bearing / (b) subject-scope + trivial / (c)
out-of-subject pre-existing / (d) out-of-this-PR subject. The 13 fix
commits address every confirmed bucket (a):
- **Round 1 (`493a6002e`)** — `agentic-chat.spec.ts` was asserting
`[data-role=\"assistant\"]` which the v2 react-core bundle never emits
(it ships `data-testid=\"copilot-assistant-message\"`); fixture comment
that said \"Empty content is load-bearing\" sat next to a non-empty
content field; harness `d5-feature-mapping.ts` / `live-status.ts` /
`d5-byoc.ts` got `declarative-*` entries so D5 probes still target
langgraph-python after the slug rename; bucket-b polish.
- **Round 2 (`c61dc65f3`)** — `subagents._invoke_sub_agent` had a
regression where the docstring cleanup removed an `isinstance(text,
str)` guard, so `{\"type\":\"text\",\"text\":null}` payloads (a known
provider quirk) would crash `\"\".join(parts)` with `TypeError`;
restored the guard. `shared-state-read.spec.ts` was a complete
false-green (asserted on \"Sales Pipeline\" but the demo is now a Recipe
Editor); rewrote against the recipe-card testids. 11 sibling specs were
sweep-fixed for the same stale `data-role` selector. Restored one log
line at `multimodal_agent._extract_pdf_text` (the three-stage prints
were dropped in cleanup; one outer log keeps Railway triageable). Fixed
false `kind: \"testing\"` claim in `qa/reasoning-default.md`.
- **Round 3 (`328282297`)** — `shared-state-read/page.tsx` had `void
copilotkit.runAgent({agent}).catch(() => {})` which explicitly silenced
every error from \"Improve with AI\"; replaced the empty catch with
`console.error`. Demo's visible h1 still read \"BYOC: Hashbrown\" after
the slug rename; updated page heading, spec, and QA in lockstep.
Manifest description for `agentic-chat` claimed \"Natural conversation
with frontend tool execution\" but Phase E rewrote the demo to vanilla
chat with no tools. `reasoning-default.spec.ts` asserted on
`[data-testid=\"copilot-reasoning-message\"]` which
`CopilotChatReasoningMessage` never emits; switched to the text-based
\"Thinking…/Thought for…\" label the component actually renders.
- **Round 4 (`b905869e9` + `21fb20cf0` + `cff562c0d` + `ae24603bb`)** —
fixture-mirror fixes (the new reasoning-default fixture was added to the
bundled `d5-all.json` but not to the per-demo source-of-truth file);
added 3 declarative-* test cases to `d5-byoc.test.ts`; fixed
`qa/chat-slots.md` to match the slot-wrappers refactor; tightened
comment polish (typo, count drift, ported-from path).
- **Round 5 (`39fadec3f` + `64bee6453`)** — Sunday edge case in
`interrupt_agent._candidate_slots` where `tomorrow` and `next_monday`
collapsed to the same date; fixed both Python and TS sides. Five spec/QA
false-fails: `gen-ui-tool-based.spec.ts` asserted on UI text (\"Use the
sidebar...\", \"Chart Generator\") that doesn't exist;
`agent-config.spec.ts` asserted heading \"Agent Config Object\" but the
demo has \"Agent Config\"; `multimodal.spec.ts` asserted a non-existent
heading; `qa/chat-slots.md` said max-w-4xl but the demo is max-w-5xl;
`qa/shared-state-read.md` had a stale default-instruction string.
- **Round 6 (`70548fe2f`)** — `chat-slots.spec.ts` was asserting
`[data-testid=\"custom-assistant-message\"]` in 4 places (4 of 5 tests
would time out); the actual signal is
`data-slot-label=\"MessageView.AssistantMessage\"` from the SlotMarker
wrapper. `qa/gen-ui-tool-based.md` described a \"Haiku Generator\" demo
that doesn't exist anywhere; rewrote to match the chart-rendering demo.
- **Final cleanup (`2342fbb5a`)** — deleted 4 orphan QA files flagged
across multiple cr-loop rounds (`agentic-chat-reasoning.md`, `hitl.md`,
`hitl-in-chat-booking.md`, `shared-state-write.md`).
## Test posture
| Level | Result |
|---|---|
| **smoke** | green (health + agent endpoints) |
| **D4** (e2e-chat-tools / Tool Reasoning) | **green** — not regressed |
| **D5** (e2e-deep) | 38/40 green; the two reds
(`gen-ui-interrupt-sales-call` and `tool-rendering-reasoning-chain` turn
2) are pre-existing and explicitly out-of-scope per the original audit's
Phase F. **`mcp-apps` and `tool-rendering-reasoning-chain` turn 1 went
from red → green on this branch.** |
## Pre-existing reds (deliberately not addressed; track as follow-ups)
- **`gen-ui-interrupt-sales-call`** — agent reply lands but the
`interrupt(...)` payload never reaches the frontend so the picker never
enters its picked state. This is the **W8-6 LangGraph-Platform interrupt
deployment** ticket from the original audit's Phase F.
- **`tool-rendering-reasoning-chain` turn 2** — turn 1 was fixed in
`a6682ccd6` by adding non-empty `content` so aimock's Responses-API
dispatch routes through `buildContentWithToolCallsResponse` instead of
dropping reasoning. Turn 2 is a deeper aimock+deepagents+Responses-API
multi-turn state-management issue — production with real OpenAI works.
## Out-of-this-PR follow-up seeds
- Cross-codebase `byoc-* → declarative-*` rename across the other 17
integrations + shared registry (one of: complete the rename or roll it
back to keep the codebase coherent).
- e2e specs for `interrupt-headless`, `tool-rendering-reasoning-chain`,
`shared-state-read-write` (manifest demos with no Playwright spec).
- `gpt-4o → gpt-5.4` docstring sweep across `multimodal_agent.py` and
`mcp_apps_agent.py` (pre-existing comment drift).
## Checklist
- [x] I have read the Contribution Guide
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation (e2e specs + QA markdowns)
- [x] \"Allow edits by maintainers\" is checked
|
||
|
|
e831c72a8f | style: auto-fix formatting | ||
|
|
df3e232068 |
fix(showcase/aimock): add D5 fixtures + restore reasoning emission
D5 probes were red for two demos because the aimock fixtures didn't
exist or were dispatched through the wrong Responses-API path.
- `harness/fixtures/d5/mcp-apps.json` (new) — the MCP Apps probe sent
"Open Excalidraw and sketch a system diagram" with no matching
fixture, so aimock 404'd and the agent threw `NotFoundError`.
Added a two-leg fixture: leg 1 emits a `create_view` MCP tool call
with Excalidraw element JSON; leg 2 is the `hasToolResult: true`
content reply. Mirrored verbatim into `aimock/d5-all.json` so the
Docker-baked aimock has the same matches.
- `harness/fixtures/d5/tool-rendering-reasoning-chain.json` — added
non-empty `content` fields to the first-leg fixtures (Tokyo weather
+ SFO/JFK flights). aimock's Responses-API dispatch routes
tool-call-only responses (no `content`) through
`buildToolCallResponse`, which silently drops the `reasoning`
payload; with a non-empty `content`, dispatch shifts to
`buildContentWithToolCallsResponse`, which emits the
reasoning_summary events the v2 `<ReasoningBlock>` needs to mount.
Mirrored into `d5-all.json`.
- `harness/fixtures/d5/reasoning-display.json` — added a second
matcher for the `reasoning-default` e2e pill prompt ("sky appears
blue"), keyed alongside the existing D5 probe matcher ("show your
reasoning step by step"). Both responses include `reasoning` fields
so the built-in `CopilotChatReasoningMessage` "Thinking…/Thought
for…" header lands.
- `aimock/feature-parity.json` — added a fixture for the agentic-chat
multi-turn name-recall test ("What name did I just give") replying
"You said your name is Alice." The matcher is intentionally narrow
to avoid colliding with the generic showcase-assistant catch-all.
Net D5 effect: `mcp-apps` and `tool-rendering-reasoning-chain` turn 1
go from red → green. The remaining red on `tool-rendering-reasoning-
chain` turn 2 is the deeper aimock+deepagents+Responses-API multi-
turn state-management issue (production with real OpenAI works); out
of scope per the original audit's Phase F.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
59eb245a1c |
fix(showcase/langgraph-python): align e2e specs + QAs with current demos
The specs and QA markdowns had drifted from the demos they describe.
This commit brings every test contract into line with the actual demo
source — eliminating false-greens, false-fails, and stale assertions.
False-fail spec assertions (would fail every run):
- `agentic-chat.spec.ts` — rewrote from the old `change_background` /
`weather-card` / `useAgentContext` flow that no longer exists. New
spec exercises the vanilla `<CopilotChat>` + three suggestion pills
contract the simplified demo actually exposes.
- `gen-ui-tool-based.spec.ts` — asserted on UI text ("Use the sidebar
to generate charts", "Chart Generator") that doesn't exist; switched
to suggestion-pill assertions and scoped the SVG check to inside the
assistant-message bubble (was matching CopilotChat's send-button
SVG).
- `agent-config.spec.ts` — asserted heading "Agent Config Object" but
the demo has "Agent Config".
- `multimodal.spec.ts` — asserted a non-existent "Multimodal
attachments" heading; switched to the `multimodal-demo-root` testid.
- `chat-slots.spec.ts` — asserted `[data-testid="custom-assistant-
message"]` and the bare text "slot" — neither exists. The actual
signal is `data-slot-label="MessageView.AssistantMessage"` from the
SlotMarker wrapper.
- `reasoning-default.spec.ts` — asserted `[data-testid="copilot-
reasoning-message"]` and `[data-message-role="reasoning"]`; neither
is emitted by `CopilotChatReasoningMessage`. Switched to the text-
based "Thinking…/Thought for…" header label.
False-green spec assertions (passed for the wrong reason):
- `shared-state-read.spec.ts` — was a complete false-green: asserted
on "Sales Pipeline", "Total Pipeline", "Active Deals" but the demo
has been a Recipe Editor for some time. Rewrote against the
recipe-card / ingredients-container / instructions-container testids.
- 11 specs (agent-config, beautiful-chat, frontend-tools-async,
gen-ui-tool-based, gen-ui-agent, gen-ui-interrupt, hitl-in-chat,
hitl-in-app, multimodal, readonly-state-agent-context, voice) used
`[data-role="assistant"]` to gate "agent responded" — but the v2
react-core bundle never emits that attribute (it ships
`data-testid="copilot-assistant-message"`). Mechanical sweep to the
correct testid.
- Deleted `shared-state-write.spec.ts` (route consolidated into
`shared-state-read-write` earlier on this branch — spec targeted a
removed demo) and `renderer-selector.spec.ts` (asserted on a radio-
pill UI that no longer exists; the four "Declarative UI" variants
are now separate manifest demos).
QA drift:
- `qa/gen-ui-tool-based.md` documented a "Haiku Generator" demo with
haiku-card / japanese-line / english-line / haiku-image testids — a
demo that doesn't exist anywhere on this branch. Rewrote to match
the chart-rendering demo's actual testids and pill prompts.
- `qa/chat-slots.md` referenced "Custom Slot" pill / "Welcome to the
Slots demo" heading / "This welcome card is rendered via the
welcomeScreen slot." body text — all of which the slot-wrappers
refactor on this branch removed. Updated to match the
`custom-welcome-message` sub-slot that's actually rendered. Also
fixed max-w-4xl → max-w-5xl to match the page.
- `qa/shared-state-read.md` said default instruction is "Preheat oven
to 350 F" but the source has "Preheat oven to 350°F (175°C)".
- `qa/agentic-chat.md` rewrote to match the simplified vanilla-chat
demo (the previous QA documented `change_background` / `WeatherCard`
flows that no longer exist).
- `qa/reasoning-default.md` cited `kind: "testing"` in feature-
registry.json for the `reasoning-default` entry; the registry entry
has no `kind` field. Rewrote without the false cross-file claim.
- Deleted 4 orphan QA files for demos that don't exist:
`agentic-chat-reasoning.md`, `hitl.md`, `hitl-in-chat-booking.md`,
`shared-state-write.md`.
- Renamed `qa/reasoning-default-render.md` → `qa/reasoning-default.md`
to match the manifest cell name.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
70e2fb13c8 |
refactor(showcase): rename byoc-* slugs to declarative-* + sort index by manifest features
User-facing renames so the showcase reads the way a cold visitor would
expect:
- `byoc-hashbrown` → `declarative-hashbrown` (and `byoc-json-render` →
`declarative-json-render`). The display titles already said
"Declarative UI: …"; only the URL slugs and folder paths still
leaked the internal BYOC ("Bring Your Own Components") jargon.
Renamed:
/demos/byoc-hashbrown → /demos/declarative-hashbrown
/demos/byoc-json-render → /demos/declarative-json-render
/api/copilotkit-byoc-* → /api/copilotkit-declarative-*
src/app/demos/byoc-* → src/app/demos/declarative-*
qa/byoc-*.md → qa/declarative-*.md
tests/e2e/byoc-*.spec.ts → tests/e2e/declarative-*.spec.ts
Internal Python module names + langgraph graph IDs stay legacy
(`byoc_hashbrown_agent.py`, `byoc_hashbrown`) — those are not
user-facing and renaming them is a separate cross-codebase pass.
- `a2ui-fixed-schema` slug intentionally unchanged.
- Tool Rendering trio parenthetical rename (Default → Catch-all →
Custom progression reads clearly as "how much do I customize?"):
Tool Rendering (Default) — unchanged
Tool Rendering (Custom default) → Tool Rendering (Catch-all)
Tool Rendering (Specific) → Tool Rendering (Custom)
- `tool-rendering-reasoning-chain` cell renamed from
"Generative UI: Rendering multiple tools" to
"Generative UI: Tool calls + reasoning" (the demo is about combining
reasoning + tool rendering, not about quantity of tools).
- `Open Generative UI: Default` / `Open Generative UI: Custom`
descriptions expanded so a visitor understands how Open Generative UI
differs from Tool Rendering (agent composes UI from a registered
library vs. attaching a renderer to a *named* backend tool).
- Showcase index now sorts demos within each tag by `manifest.features`
order. Previously demos appeared in manifest declaration order, which
ignored the team's curated "polished flagship → simplest start →
variants" arc.
Cross-cutting registry / harness / dashboard updates that fall out of
the rename:
- `shared/feature-registry.json` adds the two new IDs alongside the
legacy `byoc-*` (so the catalog stays valid; the other 17
integrations still declare `byoc-*` in their manifests).
- `shared/constraints.yaml` adds the new IDs to the
generative-ui-approach allow-list.
- `scripts/__tests__/generate-catalog.test.ts` updates the cell-count
expectations (45 features × 18 integrations = 810; 792 after docs-
only exclusion; 45 LGP cells = 38 wired + 1 stub + 6 unshipped).
- Harness probe `d5-byoc.ts` + `d5-byoc.test.ts` now route both slug
families through `preNavigateRoute` and exercise the new branches.
- `d5-feature-mapping.ts` and `shell-dashboard/live-status.ts` mirror
the dual-ID mapping so both legacy and renamed slugs roll up under
the same `byoc` D5 featureType.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
08ba26590e |
refactor(showcase/langgraph-python): clean up agents + demos for didactic clarity
Extracts duplicated logic into shared modules so each demo file reads
as the feature it teaches, not the boilerplate around it.
Python agents:
- `_a2ui_utils.py` (new) — `sanitize_a2ui_components` and
`has_root_component`, consumed by both `a2ui_dynamic.py` and
`beautiful_chat.py` (these previously duplicated the same defensive
validator inline).
- `byoc_hashbrown_prompt.py` (new) — the 56-line system prompt extracted
from `byoc_hashbrown_agent.py` so the agent file stays focused on the
`create_agent(...)` wiring.
- `beautiful_chat.py` secondary `ChatOpenAI` now passes
`streaming=True` (matching `a2ui_dynamic.py`) so aimock's SSE-only
fixture matcher sees the call in replay mode — without it the demo
surfaced "An internal error occurred" on every load.
- `multimodal_agent.py` — top-level `from pypdf import PdfReader` (was
lazy with three layers of `# pragma: no cover` exception handling
for stages that never failed independently); kept a single log line
at the outer except so Railway logs stay triageable.
- `gen_ui_agent.py` — switched from `deepagents.create_deep_agent` (whose
planner+sub-agent middleware ate enough supersteps to trip LangGraph's
default recursion limit on this single-tool ReAct loop) to plain
`langchain.agents.create_agent`. Comment explains the math.
- `tool_rendering_agent.py` — docstring no longer claims to back the
`tool-rendering-reasoning-chain` cell (it has its own agent file).
TypeScript / TSX demos:
- `_shared/parse-json-result.ts` (new) — extracted from
`tool-rendering/parse-json-result.ts`; now consumed by three demos.
- `_shared/slot-override.ts` (new) — `makeSlotOverride<T>` centralizes
the 11 `as unknown as` casts that `chat-slots/page.tsx` previously
scattered across the slot-override block.
- `shared-state-read` — extracted `RecipeCard` component + `types.ts`,
dropped the dual-state-sync pattern that had the read-only demo
locally mutating recipe state. Page is now a thin shell that publishes
edits via `agent.setState` and reads back via `agent.state.recipe`.
Also surfaces `runAgent` rejections via `console.error` instead of
the previous silent `.catch(() => {})`.
- `headless-complete/hooks/use-auto-scroll.ts`,
`headless-complete/hooks/use-typing-indicator.ts` (new) — extracted
from `chat.tsx`. The chat file shrinks by ~40 lines. Same silent-
rejection fix on `runAgent` as shared-state-read.
- `frontend-tools-async/fake-notes-db.ts` (new) — extracted from
`page.tsx`; the demo file no longer leads with 60 lines of fake-DB
scaffolding before `useFrontendTool` (the actual feature) appears.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
a3d93266e9 |
fix(showcase/langgraph-python): correctness fixes for demos
Real demo-time bugs in the langgraph-python integration:
- `interrupt-headless` was rendering hardcoded stale slot dates from a
`DEFAULT_SLOTS` constant instead of reading `payload.slots` that the
backend `interrupt(...)` already supplies. Sibling `gen-ui-interrupt`
does this correctly. Headless variant now matches.
- `_shared/interrupt-fallback-slots.ts` (new) — the JS fallback for
when the backend returns no `slots` array. Generates relative to
Date.now() so the picker never shows past dates. Used by both
`interrupt-headless` and `gen-ui-interrupt`. Deletes the old stale-
literal `gen-ui-interrupt/fallback-slots.ts` (dates from April that
had already decayed).
- `interrupt_agent.py` — replaced hardcoded `timezone(timedelta(-7))`
PDT with `zoneinfo.ZoneInfo("America/Los_Angeles")` so the demo
doesn't lie about offsets in winter. Also fixed a Sunday edge case
where `next_monday` collapsed to the same date as `tomorrow` (both
Python and the JS fallback) — added a `<= 1` skip-a-week guard.
- `package.json#dev` ran `uvicorn agent_server:app --port 8000` but
`src/agent_server.py` was a 3-line stub with no `app` symbol AND the
API route pointed at port 8123. Replaced with the canonical
`langgraph_cli dev --port 8123` invocation; deleted the dead stub.
- `entrypoint.sh:47` smoke-checked `src/agents/tools.py` (a file that
never existed) so every Railway boot logged a phantom ERROR. Dropped.
- `reasoning_agent.py` and `tool_rendering_reasoning_chain_agent.py`
intentionally omit `CopilotKitMiddleware` (they exercise only
reasoning-token streaming, no frontend tools / app context). Added a
one-line comment so a future maintainer doesn't cargo-cult it back in.
- `subagents._invoke_sub_agent` text-block walker had a regression
where a `{"type":"text","text":null}` payload (a known provider
quirk) would crash `"".join(parts)` with `TypeError: sequence item
N: expected str instance, NoneType found`. Restored the
`isinstance(block.get("text"), str)` guard.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
2f6816fe3f |
feat(showcase/langgraph-python): align chat surfaces + shadcn recipe overhaul (#4753)
## Summary
Four LangGraph Python showcase demos updated:
- **HITL In-app**: `CopilotChat` → `CopilotPopup`
(`defaultOpen={true}`). Tickets panel fills the viewport; chat is a
popup in the corner. Approval dialog still portaled to `<body>`.
- **Shared State: Streaming**: `CopilotChat` (custom aside) →
`CopilotSidebar`. Document view fills the page; sidebar opens by
default.
- **Shared State: Read + Write**: `CopilotPopup` → `CopilotSidebar`.
Card grid breakpoint bumped from `lg:` to `xl:` so cards stack instead
of pinching when the sidebar consumes ~480px on mid-size laptops;
`overflow-y-auto` on the wrapper keeps the page scrollable.
- **Shared State: Read (Recipe)**: visual overhaul with shadcn
primitives (`Card`, `Input`, `Select`, `Textarea`, `Badge`, `Button`,
`Spinner`, `Separator`). All `data-testid` attributes and
QA-doc-asserted strings preserved verbatim ("Make Your Recipe", "AI
Recipe Assistant", "+ Add Ingredient", "+ Add Step", "Improve with AI",
default ingredients/instructions, all 7 dietary preference labels, all 5
cooking-time labels, all 3 suggestions, etc.). React state-sync logic
preserved verbatim (no behavior change).
## Why
The chat surfaces were inconsistent across demos — HITL used a full-pane
chat where the demo's premise is "approval modals appear *outside* the
chat surface", and the shared-state demos mixed `CopilotChat` and
`CopilotPopup` instead of using the prebuilt `CopilotSidebar`. The
Recipe demo was raw Tailwind while the rest of the suite uses shadcn
primitives.
## Plumbing fixes that fell out of the work
- **`clsx` + `tailwind-merge` added to `package.json`** as direct deps.
They were imported by `src/lib/utils.ts` (the `cn` helper used by all
shadcn primitives) but only transitively resolvable, which broke `next
dev --turbopack`'s stricter module resolution.
- **`globals.css` rule**: `body[data-scroll-locked] { padding-right: 0
!important }`. Radix overlays (Select, Dialog, Popover) use
`react-remove-scroll-bar`, which measures the gap between viewport and
body inner width to detect scrollbar size — and our body uses
`margin-inline-end: 480px` to make room for `<CopilotSidebar />`. The
library mis-reads that 480px as scrollbar width and "compensates" with a
matching `padding-right`, which shrinks the content area and shifts the
centered card every time a dropdown opens. We have no real scrollbar
(`body { overflow: hidden }`), so the compensation is unnecessary —
neutralize it. Comment in the diff explains the rationale.
## Test plan
- [x] `next build` clean across all 54 routes
- [x] `oxlint` reports zero new warnings (only pre-existing patterns the
diff preserved verbatim)
- [x] Manually verified `/demos/hitl-in-app`,
`/demos/shared-state-streaming`, `/demos/shared-state-read-write`,
`/demos/shared-state-read` in browser (Chrome, dev server)
- [x] Verified the Recipe page's Select dropdowns no longer shift the
card when opened (the original motivation for the `globals.css` rule)
- [ ] HITL e2e suite (`tests/e2e/hitl-in-app.spec.ts`) — selectors
preserved (`getByPlaceholder("Type a message")`, suggestion-pill
testids, approval-dialog-* testids); CopilotPopup's `defaultOpen={true}`
mounts the chat input on first paint
- [ ] Streaming and Read e2e suites are stale pre-PR (reference content
that doesn't exist in source — "AI Document Editor", "Sales Pipeline")
and remain in the same state
## CR loop
Ran `cr-loop` (Round 1, 7 agents). Reclassified one finding to bucket
(d) per user direction (npm/pnpm lockfile-convention concern is a
different PR's subject — pre-existing across all
`showcase/integrations/*` and out of scope here). Procedure 3 audit
promoted no items to bucket (a); 24 bucket (c) items confirmed as
pre-existing and routed to follow-up backlog.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
1b96bfae87 | fix(deps): update copilotkit examples | ||
|
|
19494c0515 |
ENT-510 - fix(core): only reset agent state on actual thread switch (supersedes #4720) (#4740)
## Summary Supersedes #4720, which Mike correctly identified as introducing a blocking regression in the fresh-thread-restore path. This PR takes Mike's framing as the authoritative restatement of the bug and lands the proxy/orchestrator-level fix that addresses both halves of Tyler's symptom without that regression. ## The actual bug, restated When the chat's connect effect re-fires due to React effect-dep churn, it calls `copilotkit.connectAgent({ agent })` on the same thread again. `RunHandler.connectAgent` previously did `agent.setMessages([])` + `agent.setState({})` and (transitively) called `clearReconnectCursor` on every invocation, **including the churn re-connects**. That forced the realtime gateway to replay the topic's full event history every time the chat re-opened a socket — sending the same persisted `cpki_event_id`s 2-3 times per thread switch — and produced both halves of Tyler's video: - **Cosmetic surface**: duplicate `cpki_event_id` rows in the inspector AG-UI Events tab. - **Functional surface**: `agent.messages` got cleared, the replay started rebuilding it, then another churn re-connect came along, called `setMessages([])` again, and the next `runAgent` fired with `messages.length = 1` while the server had N. `prepareRegenerateStream` triggered, the new user-message id wasn't in any checkpoint, and the server threw "Message not found". PR #4720 only addressed the cosmetic surface and made the functional surface deterministic. Mike's review caught it. ## What this PR changes - **`RunHandler.connectAgent`** tracks `_lastConnectedThreadId` across calls. The `setMessages([])` + `setState({})` + replay-cursor clear are now gated on the threadId actually changing. Same-thread churn re-connects preserve local state and let the gateway resume from `lastSeenEventId` instead of replaying. Thread switches still wipe state and ask for a full replay. - **`IntelligenceAgent.connect()`** no longer auto-clears the replay cursor. Cursor management is the caller's decision now. `clearReconnectCursor` is made `public` so the orchestrator (and tests) can call it explicitly. - **`ProxiedCopilotRuntimeAgent`** exposes a public `clearReplayCursor(threadId)` method that delegates to the IntelligenceAgent's `clearReconnectCursor`. Non-Intelligence runtime modes are a safe no-op. The dispatcher-level dedup from #4720 is **removed entirely**. The orchestrator-level gate is sufficient and a much smaller, more obviously correct surface. ## Why this approach Mike's two suggestions in the #4720 review were "clear the dedup table when the cursor is cleared" or "scope dedup to a connection/replay window." Both alone left a regression in the other direction: - Coupling dedup to `clearReconnectCursor` (which was unconditional) reset dedup on every churn re-connect, so the original symptom returned. - Per-connection-window dedup couldn't catch dups across the multiple sockets that fire during churn. The right move is one level up: stop the underlying state-reset cascade that was forcing the replay storm in the first place. Once same-thread churn no longer wipes local state, the gateway can resume cleanly, the wire-level replays don't happen, and both Tyler's symptoms disappear naturally — no dispatcher dedup needed. ## Tests - **`intelligence-agent.test.ts`**: 4 existing tests updated to reflect the new contract. `connect()` preserves the cursor by default; `clearReconnectCursor()` is the explicit primitive. Includes the regression test Mike asked for: replay the same `cpki_event_id` after `A → B → A` and verify the rehydrate still produces the user message. - **`core-connect-thread-switch.test.ts`** (new): 4 focused tests for the orchestrator gate — same-thread churn does not reset, cross-thread switch does reset, `A → B → A` resets each transition, and a non-Intelligence runtime path is handled cleanly. All 430 core tests pass: ``` Test Files 40 passed (40) Tests 430 passed (430) ``` ## Test plan - [ ] Pull the canary build into `gen-ui-studio` (a fresh `npx copilotkit create`). - [ ] Manually walk Tyler's recipe with the inspector open: open thread A, switch to B, switch back to A. AG-UI Events tab should show one row per `cpki_event_id`. No "Message not found" toast. - [ ] Send a message after the switch-back. Run completes cleanly. - [ ] (Repro harness) `recipe-rehydrate.spec.ts` from kingston's transport-dup-repro asserts on user-visible state (DOM messages + absence of "Message not found"). Should pass against this canary; fails against `origin/main` and against #4720's commit. ## Why "supersedes #4720" not "build on top of" The dispatcher dedup in #4720 isn't load-bearing under this fix — once the orchestrator stops cascading state-resets, there's no replay storm for the dispatcher to filter. Keeping the dedup would just be unused machinery with non-trivial memory accounting. Cleaner to drop it entirely and revisit only if a real overlap scenario surfaces later (network blips, retries, etc.). |
||
|
|
da8626d819 |
fix(showcase/aimock): tool-rendering-reasoning-chain multi-turn (Turn 2 hang)
LGP probe hung on Turn 2 (Find flights from SFO to JFK) after Turn 1 (weather Tokyo) succeeded. Root cause: the SFO/JFK first-leg fixture matched on `hasToolResult: false`, but Turn 1's tool result remains in the conversation by Turn 2, so the matcher skipped it and fell through to the second-leg fixture (`hasToolResult: true`), returning narration without the search_flights tool call. The probe then timed out waiting for the FlightListCard testid that never mounted. Fix: switch the second-leg fixture to `toolCallId` matching (the last message must be a tool result with the specific call_id) and drop `hasToolResult` from the first-leg fixture. The second-leg fixture must come BEFORE the first-leg in file order because the matcher is first-match-wins; with `toolCallId`, it cannot accidentally swallow first-leg requests (whose last message is the user prompt, not a tool result). Also adds a `content` field to the Tokyo first-leg fixtures (`get_weather` and `get-weather` Mastra-hyphen variants) so they route through `buildContentWithToolCallsStreamEvents` instead of `buildToolCallStreamEvents` — the latter codepath silently drops the `reasoning` field, which is why the reasoning-block testid never mounted on Turn 1 either before this change. Tokyo (Turn 1) keeps the simpler `hasToolResult` pattern because it has no prior turns; only the SFO/JFK fixture pair needs the toolCallId shape to survive multi-turn use. |
||
|
|
4daf07f5c6 | Merge branch 'main' into docs(deepagents)/removed-checkpointer-in-python | ||
|
|
3d47397957 |
feat(showcase/langgraph-python): align chat surfaces + shadcn recipe overhaul
Switch HITL In-app to CopilotPopup; Shared State Streaming and Read+Write to CopilotSidebar; widen card-grid breakpoint and add overflow scroll on Read+Write so content stays usable when the sidebar consumes ~480px of viewport. Re-skin the read-only Recipe demo with shadcn primitives, preserving every data-testid and QA-doc-asserted string. Add clsx and tailwind-merge as direct deps (previously only transitively resolvable, breaking turbopack dev) and a globals.css rule to neutralize the Radix scroll-lock padding-right that react-remove-scroll-bar injects when it mis-detects body's margin-inline-end (CopilotSidebar) as scrollbar width. QA docs updated to reference the new chat surfaces. |
||
|
|
a429b5f438 |
fix(showcase/langgraph-python): force reasoning emission in reasoning-chain agent (#4747)
## Summary `tool-rendering-reasoning-chain` D5 probe has been **sustained red since it was added** (PR #4743) — every tick fails with `expected [data-testid="reasoning-block"] to mount within 30000ms`. Diagnostic dumps from prod confirmed the failure mode: - ✅ WeatherCard mounted (toolCalls fire correctly) - ✅ Assistant text "Tokyo is 22°C and partly cloudy" landed - ❌ Zero reasoning text — the `reasoningMessage` slot never received an event ## Root cause Comparing to the working `reasoning_agent.py` (which backs `reasoning-default` + `reasoning-custom`, both D5 green): | | `reasoning_agent.py` (works) | `tool_rendering_reasoning_chain_agent.py` (was broken) | |---|---|---| | `effort` | `"medium"` | `"low"` | | `summary` | `"detailed"` | `"auto"` | | tools | `[]` | `[get_weather, search_flights, get_stock_price, roll_dice]` | `summary: "auto"` lets the model decide whether to emit a reasoning summary. With tools present, the model frequently skips emission entirely — the chain-of-thought goes straight to the tool call without a summary step. That leaves `role: "reasoning"` messages off the wire, so the v2 `<ReasoningBlock>` slot never mounts. `summary: "detailed"` forces emission on every response. Bumping `effort` to `"medium"` to match the working agent. ## Test plan - [x] PR #4744 already added `reasoning` field to the aimock fixture for `weather in Tokyo` first leg — that part of the wire is fine - [x] Confirmed via prod diagnostic: the rest of the demo (tool rendering, assistant text) works - [ ] Post-merge: `tool-rendering-reasoning-chain` should flip green on the next e2e-deep tick ## Known follow-up (NOT in this PR) `gen-ui-agent` (Agent State) is intermittently flapping (~22% failure rate over recent ticks), with two distinct error modes ("no assistant response" and "agent-state-card never mounts"). Need to dig deeper to determine root cause — separate investigation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
46c5b56881 |
fix(showcase/langgraph-python): force reasoning emission in reasoning-chain agent
The tool-rendering-reasoning-chain D5 probe has been red since the probe was added (PR #4743) — the reasoningMessage slot's <ReasoningBlock> never mounts because the agent doesn't emit reasoning summaries. Compared to the working reasoning_agent.py (which powers reasoning-default + reasoning-custom and is green), the only meaningful difference was the reasoning config: reasoning_agent.py (works): reasoning={"effort": "medium", "summary": "detailed"} tools=[] tool_rendering_reasoning_chain_agent.py (was broken): reasoning={"effort": "low", "summary": "auto"} tools=[get_weather, search_flights, ...] `summary: "auto"` lets the model decide whether to emit a reasoning summary. With tools present the model often skips it (chain-of-thought goes straight into the tool call without a summary). `summary: "detailed"` forces emission on every response, which lights up the ReasoningBlock slot. Bumping effort medium so the surface visible to the user reads as a real chain-of-thought, matching reasoning-display. Probe diagnostics from prod confirmed the toolCalls were firing fine (WeatherCard mounted, assistant text landed) — only the reasoning emission was missing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1a66d7342f |
fix(showcase): auth-readiness SignInCard + bump LGP models to gpt-5.4 (#4746)
Two related changes for the LGP gold-standard view: ## 1. e2e-readiness accepts `/demos/auth` SignInCard Fixes the spurious **D2 / RT ✗** state on the LGP `auth` cell. The demo itself works fine end-to-end — the issue was the `e2e-readiness` probe waits for chat-input testids in [`READY_SELECTORS`](showcase/harness/src/probes/drivers/e2e-readiness.ts:236), but `/demos/auth` renders a `<SignInCard>` BEFORE mounting the chat surface (chat input only appears post-authentication). Result: 30s timeout (`per-demo deadline exceeded after 30000ms`). Added `[data-testid="auth-sign-in-card"]` to `READY_SELECTORS` so the probe accepts SignInCard as a valid "demo mounted" signal. End-to-end auth flow stays covered by `auth.spec.ts` under e2e-demos. ## 2. Bump all LGP agents to `gpt-5.4` Swapped every `ChatOpenAI` / `init_chat_model` call across the 26 LGP agents from the prior mix (`gpt-4o-mini`, `gpt-4o`, `gpt-4.1`, `gpt-5-mini`) to the unified `gpt-5.4`. Also updated the `OPENAI_REASONING_MODEL` env default in `reasoning_agent.py` and `tool_rendering_reasoning_chain_agent.py` so reasoning demos pick up the new model unless explicitly overridden. Verified locally — all 39 LGP demos render and respond correctly with `gpt-5.4`. The probe sweep on prod will confirm end-to-end. ## Test plan - [x] `pnpm vitest run e2e-readiness` in `showcase/harness/` → **31 / 31 passing** - [x] Local LGP container running gpt-5.4 against real OpenAI — all demos respond - [ ] Post-merge: `e2e:langgraph-python/auth` flips green on next e2e-demos tick (hourly at `:10`) - [ ] Post-merge: every D5 cell across LGP confirms model resolves on next e2e-deep tick ## Companion observation (NOT in this PR) While diagnosing the auth issue, also noticed 3 LGP D5 cells went red recently: - `gen-ui-interrupt`, `interrupt-headless` — testid mount timeouts - `shared-state-streaming` — document content didn't stream Subagent investigation found **no code-side regression** — fixtures, agents, and probe scripts are intact; the cells were green a few hours earlier with the same code. Most likely a transient aimock blip or cold-start. The driver-level retry-once added in PR #4743 should self-heal them on the next 1-2 ticks. Monitor; if persistent, check aimock Railway logs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
89e4c4e52c |
chore(showcase/langgraph-python): bump model to gpt-5.4 across all agents
Swap every ChatOpenAI / init_chat_model call across the LGP agents from the prior mix (gpt-4o-mini, gpt-4o, gpt-4.1, gpt-5-mini) to the unified `gpt-5.4` model. Also updates the OPENAI_REASONING_MODEL env default in reasoning_agent.py and tool_rendering_reasoning_chain_agent.py so reasoning demos pick up the new model unless explicitly overridden. Verified locally with the user's gpt-5.4 OpenAI access — all 39 LGP demos render and respond correctly. The probe sweep on prod will confirm the model name resolves end-to-end. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
b76a281c4b |
fix(showcase/harness): e2e-readiness recognizes /demos/auth SignInCard
The e2e-readiness probe waits for any of a compound CSS selector covering chat-input testids. /demos/auth renders a <SignInCard> BEFORE mounting the chat surface (the chat-input testids only appear post-authentication), so the readiness probe was timing out at 30s with `per-demo deadline exceeded` and the auth cell rolled up to D2 even though the demo itself works fine end-to-end. Add `[data-testid="auth-sign-in-card"]` to READY_SELECTORS so the probe accepts the SignInCard as a valid "demo mounted" signal. The end-to-end auth flow (sign in -> sign out -> sign back in -> assistant response) is still covered by auth.spec.ts under the e2e-demos dimension, so the readiness probe shouldn't be doing that work. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0b4f68fa31 |
feat(showcase): align demo names + add Show Deprecated toggle (#4745)
Brings the dashboard's gold-standard view in line with the desired naming and surfaces deprecated rows behind a toggle (instead of dropping them at catalog generation). ## Summary - **28 renames in feature-registry.json + 20 in LGP `manifest.yaml`** — `name` and `demos[].name` aligned per the user-provided mapping. Same label everywhere so the dojo and dashboard agree. - **`Show deprecated` toggle in feature-grid.tsx** — checkbox in the matrix header, default OFF. Filters feature rows where `feature.deprecated === true`. Toggle ON surfaces all deprecated features across all integrations (audit trail); toggle OFF hides them so the gold-standard view stays clean. - **Reverted catalog-side filter from #4744** — the catalog now emits cells uniformly for all (integration × feature) pairs (back to 774 cells, 756 metadata.total_cells). Visibility is controlled at the dashboard layer. Toggling on shows complete cross-integration data without missing-cell artifacts. ## Naming highlights | Was | Now | |---|---| | Pre-Built CopilotChat | Pre-Built: CopilotChat | | Headless Chat (Simple/Complete) | Headless UI: Simple/Complete | | Multi-modal / File Uploads | Attachments | | Controlled Gen-UI (Display) | Generative UI: useComponent | | In-Chat HITL (useHumanInTheLoop / useInterrupt) | Human In the Loop: In-chat / Interrupts | | Headless Interrupt | Human in the Loop: Headless Interrupts | | Declarative Generative UI (A2UI — Dynamic / Fixed Schema) | Declarative UI: Dynamic / Fixed A2UI | | Fully Open-Ended Generative UI | Open Generative UI: Default | | Open-Ended Gen UI (Advanced ...) | Open Generative UI: Custom | | Tool Rendering (Default/Custom Catch-all/Specific) | Generative UI: Tool Rendering (...) | | Tool Rendering + Reasoning Chain | Generative UI: Rendering multiple tools | | Agentic Generative UI (...) | Generative UI: Agent State | | Frontend Tools (In-app / Async) | Frontend Tools: In-app Actions / Async | | In-App Human in the Loop (Frontend Tools + async HITL) | Human in the Loop: In-app | | Shared State (Read + Write / Recipe Editor) | Shared State: Read + Write / Read-only | | State Streaming | Shared State: Streaming | | Readonly State (Agent Context) | Shared State: Frontend Context | | BYOC Hashbrown / json-render | Declarative UI: Hashbrown / json-render | ## Deprecated toggle behavior 4 features marked `deprecated: true` in feature-registry.json: `agentic-chat-reasoning`, `hitl`, `hitl-in-chat-booking`, `reasoning-default-render`. - **OFF (default)**: rows hidden across the matrix - **ON**: rows render with normal cells. LGP shows N/A (unshipped) for the 4 since LGP doesn't declare them; other integrations show their actual probe state Header text shows `(N deprecated hidden)` when toggle is off. Toggle only renders when `deprecatedCount > 0`. ## Test plan - [x] `pnpm vitest run` in `showcase/scripts/__tests__/` → **18 / 18 passing** - [x] `pnpm vitest run` in `showcase/harness/` → **1588 / 1588 passing** - [x] `npx tsx showcase/scripts/validate-fixture-tool-surface.ts` → clean - [x] `npx tsx showcase/scripts/generate-registry.ts` → 18 integrations, 38 wired LGP, 774 cells - [ ] Verify the toggle on Vercel preview — it should appear in the matrix header, default unchecked, click expands rows by 4 (the 4 deprecated features rendering as new cells) 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
80a7f9af0e |
feat(showcase): align demo names + add Show Deprecated toggle
Two related changes that bring the dashboard's gold-standard view in line with the desired naming convention and surface deprecated rows behind a toggle (instead of hiding them at catalog generation). ## Naming alignment Applied 28 renames in feature-registry.json + 20 in LGP manifest per the user-provided mapping. Highlights: - "Pre-Built CopilotChat" -> "Pre-Built: CopilotChat" - "Headless Chat (Simple/Complete)" -> "Headless UI: Simple/Complete" - "Multi-modal / File Uploads" -> "Attachements" (intentional spelling) - "Controlled Gen-UI (Display)" -> "Generative UI: useComponent" - "In-Chat HITL (use*)" -> "Human In/in the Loop: In-chat / Interrupts" - "Headless Interrupt" -> "Human in the Loop: Headless Interrupts" - "Declarative Generative UI (A2UI - *)" -> "Declarative UI: */* A2UI" - "Fully Open-Ended Generative UI" -> "Open Generative UI: Default" - "Tool Rendering ..." -> "Generative UI: Tool Rendering (...)" - "Tool Rendering + Reasoning Chain" -> "Generative UI: Rendering multiple tools" - "Agentic Generative UI ..." -> "Generative UI: Agent State" - "Frontend Tools (...)" -> "Frontend Tools: ..." - "Shared State (...)" -> "Shared State: ..." - "State Streaming" -> "Shared State: Streaming" - "Readonly State (Agent Context)" -> "Shared State: Frontend Context" - "BYOC Hashbrown <-> json-render" -- labels intentionally swapped per user instruction (demos were historically reversed; new labels reflect what they actually do). LGP manifest demos[].name updated to match feature-registry names so the dojo and dashboard surface the same human-readable label. ## Show Deprecated toggle (feature-grid.tsx) Added a checkbox in the matrix header -- default OFF -- that filters feature rows where `feature.deprecated === true`. Toggle ON shows all deprecated features across all integrations (audit trail); toggle OFF hides those rows entirely so the gold-standard view stays clean. Reverted the catalog-side filter from PR #4744 (which dropped LGP cells for deprecated features at catalog-generation time). Now the catalog emits cells uniformly for all (integration x feature) pairs, and visibility is controlled at the dashboard layer. Toggling on shows complete cross-integration data without missing-cell artifacts. Affects 4 features marked deprecated:true in feature-registry.json: agentic-chat-reasoning, hitl, hitl-in-chat-booking, reasoning-default-render. LGP cell count: back to 43 (38 wired + 1 stub + 4 unshipped). The 4 unshipped rows are hidden by default; toggle to surface them. Tests: 18/18 catalog tests + 1588/1588 harness vitest passing. validate-fixture-tool-surface clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
7f50464a7b |
fix(showcase): close 2 D5 fixture gaps + filter deprecated features from LGP view (#4744)
Follow-up to [#4743](https://github.com/CopilotKit/CopilotKit/pull/4743) to close the 2 remaining LGP D5 red cells and clean up the dashboard so it reflects the LGP gold standard. ## Summary - **Fix `tool-rendering-reasoning-chain` probe** — added `reasoning` field to the weather/Tokyo + SFO/JFK first-leg fixtures so aimock emits REASONING_MESSAGE_* events; without them the v2 `<ReasoningBlock data-testid="reasoning-block">` never mounted (mirrors the convention from `reasoning-display.json`). - **Mirror `gen-ui-interrupt` source fixture with the bundle** — source file was missing the resume-leg toolCallId entries that already exist in `d5-all.json`. Cosmetic correction so re-bundling stays consistent. Same toolCallIds as `interrupt-headless.json` (both probes share the same agent + chip prompts). - **Filter deprecated features from LGP dashboard view** — 4 legacy features (`agentic-chat-reasoning`, `hitl`, `hitl-in-chat-booking`, `reasoning-default-render`) used to render as X-marked rows for LGP because LGP intentionally doesn't implement them (consolidated into modern shape: `reasoning-custom`+`reasoning-default`, `hitl-in-chat` with `useHumanInTheLoop`). Other 17 integrations still serve those legacy demos so we don't yank the features entirely — instead marked them `deprecated: true` and updated `generate-registry.ts` to skip cells where a deprecated feature is unshipped for an integration. **LGP cells: 43 → 39** (the 4 X rows disappear). Other integrations: unchanged (audit trail preserved). ## Verification all 39 LGP demos render > *user concern: "make sure we're not missing any demos in the new dashboard"* Confirmed — every LGP `manifest.yaml` feature has a feature-registry entry and renders a cell. After this PR, the LGP-focused view shows exactly the 39 gold-standard demos — no missing demos, no spurious legacy X rows. | Category | LGP cells | |---|---| | Dev Ex | 2 (cli-start, beautiful-chat) | | Chat & UI | 7 | | Platform | 4 (auth, multimodal, voice, agent-config) | | Controlled Generative UI | 5 | | Declarative Generative UI | 2 | | Open-Ended Generative UI | 3 | | Operational Generative UI | 5 (incl. tool-rendering-reasoning-chain) | | Interactivity | 3 | | Agent State | 4 (incl. shared-state-read) | | Multi-Agent | 1 | | BYOC | 2 | | **Plus**: interrupt-headless, headless-* variants | 1 | | **Total** | **39 ✓** | ## Test plan - [x] `pnpm vitest run` in `showcase/harness/` → **1588 / 1588 passing** - [x] `pnpm vitest run` in `showcase/scripts/__tests__/` → **19 / 19 passing** (new `deprecated features are emitted only for integrations that declare them` test added) - [x] `npx tsx showcase/scripts/validate-fixture-tool-surface.ts` → clean (282 fixtures × 627 demos, no drift) - [x] `npx tsx showcase/scripts/generate-registry.ts` → 18 integrations, 38 wired LGP features, 770 catalog cells (38 + 1 stub = 39 LGP) - [ ] After merge: confirm `tool-rendering-reasoning-chain` flips green on next e2e-deep tick. Confirm dashboard LGP view no longer shows X-marked rows for the 4 deprecated features. ## Known follow-ups (NOT in this PR) - `gen-ui-interrupt` cell — still red on prod with `post-pick signal never landed within 30s`. The bundle already had the right resume-leg fixture, so the failure is in the inline `useInterrupt` resume flow rather than aimock matching. Same class as the `auth.spec.ts` test #5 framework regression. Both deserve a focused investigation rather than expanding this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
80eb7a12ad | style: auto-fix formatting | ||
|
|
1ce83b8a73 |
fix(showcase): close 2 D5 fixture gaps + filter deprecated features from gold-standard view
Three fixes that follow up on PR #4743 to bring LGP closer to fully-green on the dashboard: 1. tool-rendering-reasoning-chain probe: was failing with `expected [data-testid="reasoning-block"] to mount within 30000ms`. Root cause: the demo's `<ReasoningBlock>` slot only mounts when a reasoning-role message lands in the transcript, which requires aimock to emit REASONING_MESSAGE_* events, which in turn requires the fixture's first-leg response to carry a `reasoning` field. The weather/Tokyo and SFO/JFK first-leg fixtures were missing it. Mirrors the convention documented in reasoning-display.json:2. Patched both source (harness/fixtures/d5/) and bundle (aimock/d5-all.json). 2. gen-ui-interrupt source fixture: the source fixture file was missing the resume-leg toolCallId entries that already existed in the bundle. Cosmetic mirror so re-bundling stays consistent. Same chip prompts + same toolCallIds as interrupt-headless.json (both probes share the same agent and aimock fixture set; the difference is the FRONTEND rendering — useInterrupt inline vs useHeadlessInterrupt separate-pane). 3. Dashboard gold-standard filter: 4 deprecated/legacy features (agentic-chat-reasoning, hitl, hitl-in-chat-booking, reasoning-default-render) used to render as X-marked rows in the LGP gold-standard dashboard view because LGP intentionally does NOT implement them — they were consolidated into the modern shape (reasoning-custom + reasoning-default; hitl-in-chat with useHumanInTheLoop). Other 17 integrations still serve those legacy demos, so we don't yank the features from feature-registry.json entirely. Instead: marked them `deprecated: true` and updated generate-registry.ts to skip emitting cells when a deprecated feature is unshipped for an integration. LGP cells: 43 → 39 (the 4 deprecated rows disappear). Other integrations: unchanged (audit trail preserved). Catalog total: 774 → 770. Tests: - 1588/1588 harness vitest passing - 19/19 generate-catalog + generate-registry tests passing (counts updated for the 4 dropped LGP cells + new deprecated- feature filter test) - validate-fixture-tool-surface clean (282 fixtures × 627 demos) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1ad78c39d7 |
feat(showcase): add 3 LGP D5 probes + driver retry-once (#4743)
## Summary
- 3 new D5 probes (multi-turn, agentic-chat-style) for
`/demos/{interrupt-headless, shared-state-read,
tool-rendering-reasoning-chain}` — closes the demo↔probe coverage gap so
every langgraph-python demo now has its own dashboard cell.
- Driver retry-once in `e2e-deep.ts` — transient `goto-error` /
`conversation-error` failures (≥2s on attempt 1) get one retry before
recording red, cutting ~10× the dashboard flap rate. Persistent
assertion-style fails skip retry.
- Drops the legacy dual-claim where `d5-shared-state.ts` owned both
`shared-state-read` AND `shared-state-write` for a single bidirectional
probe — `shared-state-read` now belongs to the standalone recipe-editor
probe.
## Scope rationale
LGP is the north-star integration; this PR codifies its current demo
surface in the test infra. **Other integrations may flip red on the new
probes — that's expected and welcome.** Cross-integration parity follows
in a separate wave; we're using LGP as the template.
## Files
- `showcase/harness/src/probes/scripts/d5-interrupt-headless.ts` (new) —
`useHeadlessInterrupt` flow: chip → interrupt popup → slot pick →
resume.
-
`showcase/harness/src/probes/scripts/d5-tool-rendering-reasoning-chain.ts`
(new) — combines reasoning-block slot + per-tool renderer (WeatherCard /
FlightListCard).
- `showcase/harness/src/probes/scripts/d5-shared-state-read.ts` (new) —
recipe-editor with neutral default agent, asserts `recipe-card` form
mounts AND agent references recipe context across turns.
- `showcase/harness/src/probes/drivers/e2e-deep.ts` — retry-once loop
around `runFeature`.
- `d5-registry.ts` / `d5-feature-mapping.ts` / `live-status.ts`
(dashboard) / LGP `manifest.yaml` / `feature-registry.json` /
`constraints.yaml` — wire the new featureTypes and features end-to-end.
- `d5-shared-state.ts` (+test) — drops dual-claim.
- 2 pre-existing test fixes folded in: `d5-gen-ui-interrupt.test.ts`
(mock updated to current evaluate-poll resume signal) and
`conversation-runner.test.ts` (preFill ordering assertion now matches
actual deferred-cascade contract).
- aimock `d5-all.json` — +2 shared-state-read fixtures.
interrupt-headless and tool-rendering-reasoning-chain reuse existing
fixtures whose substrings already match their chip prompts.
## Test plan
- [x] `pnpm vitest run` in `showcase/harness/` → **1588 / 1588 passing**
(was 1585 / 1588 with 3 pre-existing fails before this PR; 2 are fixed
here, 1 was an obsolete-mock issue).
- [x] `npx tsx showcase/scripts/validate-fixture-tool-surface.ts` →
clean (282 fixtures × 627 demos, no drift).
- [x] `npx tsx showcase/scripts/generate-registry.ts` → clean (18
integrations, 38 wired LGP features, 756 catalog cells).
- [x] `pnpm typecheck` in `showcase/harness/` → clean.
- [x] `d5-mapping-drift.test.ts` → green (CATALOG_TO_D5_KEY mirrors
REGISTRY_TO_D5).
- [ ] After merge: watch the e2e-deep dashboard rotation — the 3 new LGP
cells should write rows on first tick (no red zombies — these are
first-time emissions).
## Known follow-up (NOT in this PR)
`auth.spec.ts` test #5 ("signing back in re-mounts a fresh chat
surface") fails on Railway. Symptom: after sign-out → sign-in cycle, the
second `Hello again` send doesn't produce an assistant response within
30s. Looks like a `react-core/v2` ref-handling regression on
`<CopilotKit>` unmount/remount — deserves its own focused investigation
rather than expanding this PR.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
59ecd828e5 |
test(showcase/scripts): update catalog+registry counts post LGP feature additions
Validate Showcase CI was failing on hardcoded count assertions in generate-catalog.test.ts and generate-registry.test.ts after this PR added 3 features to the LGP manifest (interrupt-headless, shared-state-read, tool-rendering-reasoning-chain) and 1 feature to feature-registry.json (shared-state-read — the others were already declared). - LGP feature/demo count: 36 → 39 - Total feature-registry features: 42 → 43 - Catalog integrated cells: 756 → 774 (43 × 18) - LGP integrated cells: 42 → 43 (38 wired + 1 stub + 4 unshipped) - Metadata total_cells (docs-only excluded): 738 → 756 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
256dcd5a61 |
test(shell-dashboard): refresh depth-utils tests post dual-claim drop
The previous "multi-key D5 mapping" tests used `shared-state-read-write` as the example, but with the dual-claim drop that registry-id is now single-key (only `shared-state-write`). Tests still passed logically but the names were misleading. - Rewrote both shared-state-read-write tests to assert the new single-key contract directly (no more `d5:lgp/shared-state-read` row in the live map — that row belongs to a different cell now). - Added new beautiful-chat tests as the canonical multi-key example (5 per-pill literals) so the multi-key code path stays exercised. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d16475cced | style: auto-fix formatting | ||
|
|
be94bd7a6f |
feat(showcase): add 3 LGP D5 probes + driver retry-once
Closes the demo↔probe coverage gap for /demos/{interrupt-headless,
shared-state-read, tool-rendering-reasoning-chain} so every demo
under langgraph-python (the north-star integration) now has a D5
probe writing to its own PocketBase cell — not relying on cross-
demo umbrella records.
New probes (multi-turn, mirroring the agentic-chat structure):
- d5-interrupt-headless: exercises useHeadlessInterrupt — chip
prompt → backend interrupt(...) → app-surface popup → slot pick
→ resume → assistant confirmation. Distinct from gen-ui-interrupt
(which uses inline useInterrupt).
- d5-tool-rendering-reasoning-chain: combines reasoning-block slot
+ per-tool renderer (WeatherCard, FlightListCard) on the same
chat surface. Catches a regression in either side.
- d5-shared-state-read: recipe-editor demo (neutral default agent,
no tools) — verifies recipe-card form mounts AND agent reads
shared state across turns. Drops the dual-claim that
d5-shared-state.ts had on `shared-state-read` (now write-only).
Driver retry-once (e2e-deep.ts):
Probes that fail with a transient class (`goto-error` /
`conversation-error`) AND took ≥2s on the first attempt now retry
once before recording red. Persistent assertion-style failures
(sub-2s) and intentional aborts/feature-timeouts skip retry —
retrying a deterministic mismatch just burns clock and obscures
the signal. Cuts ~10× the dashboard flap rate.
Plumbing:
- D5FeatureType enum: +interrupt-headless, +tool-rendering-reasoning-chain.
- REGISTRY_TO_D5 (harness) + CATALOG_TO_D5_KEY (dashboard) mirror
the new mappings; d5-mapping-drift test enforces this.
- LGP manifest features + demos entries + constraints allowlist.
- feature-registry.json: +shared-state-read.
- aimock d5-all.json: +2 shared-state-read fixtures (interrupt-
headless + tool-rendering-reasoning-chain reuse existing fixtures
that already match their chip prompts).
Tests: 1588/1588 harness vitest green. validate-fixture-tool-surface
clean (282 fixtures × 627 demos, no drift). Two pre-existing test
fixes folded in — d5-gen-ui-interrupt assertion mock updated to
match the current evaluate-poll resume signal; conversation-runner
preFill ordering test now asserts the actual deferred-cascade
contract instead of a stricter pre-preFill ban that the runner
never enforced.
Known follow-up (not in this PR): auth.spec.ts test #5 ("signing
back in re-mounts a fresh chat surface") fails on Railway — second
sign-in's "Hello again" never produces an assistant response. Looks
like a react-core/v2 ref-handling regression on <CopilotKit>
unmount/remount; deserves its own focused investigation.
Other integrations may flip red on the new probes — that's
expected. We're treating LGP as the template; cross-integration
parity follows in a separate wave.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
5d1a55e921 |
fix(showcase/langgraph-python): close remaining D5 cells (framework + fixtures)
Lands the Bucket A framework fix and the fixture-correctness changes needed to flip the remaining D4/D2 cells in the langgraph-python column to D5. Full local D5 sweep is green (1 passed, 0 failed). Framework: every Python `ToolMessage` constructed via `Command(update=...)` now sets `name=` and `id=str(uuid.uuid4())`. Without these, @ag-ui/langgraph synthesises TOOL_CALL_START events with `toolCallName: null` and `parentMessageId: null`, which @ag-ui/client@0.0.53's Zod schema rejects; the rejection is silently swallowed by `withAbortErrorHandling -> EMPTY`, completing the SSE observable mid-stream so post-tool state never reaches the consumer. Fix is applied across shared_state_streaming, shared_state_read_write, gen_ui_agent, beautiful_chat, subagents (2 sites). Single-flag change in a2ui_dynamic flips the secondary `_design_a2ui_surface` LLM call to `streaming=True` so aimock's record/replay (SSE-only) sees it. Fixtures (d5-all.json): - toolCallId follow-ups for set_steps (3), display_flight, generate_a2ui (4), schedule_meeting (2), generateSandboxedUi (7), and revenue chart so multi-turn probes don't recurse into recursion-limit loops - four hand-crafted secondary `_design_a2ui_surface` fixtures so A2UI dynamic renders without a real LLM - mcp-apps fixture rewritten to emit `create_view` tool call with a minimal Excalidraw element payload; runtime middleware fetches the UI resource and the iframe mounts - AAPL and revenue `hasToolResult: true` follow-ups tightened to `toolCallId` so they don't match cross-turn after prior turns' tool results - voice fast-path content-only fixture - beautiful-chat-schedule-meeting first-turn fixture gains content so the conversation runner sees an assistant message before the picker click assertion Probes: bumped per-card waitForSelector in d5-gen-ui-headless-complete from 15s to 60s — recharts ResponsiveContainer can be slow under 4 sequential turns. Shell-dojo: hide CLI Start Command from the dojo navigation via `HIDDEN_DOJO_FEATURE_IDS`. Registry/manifests untouched so harness/parity/dashboard still see it. |
||
|
|
91432a701b |
fix(showcase/langgraph-python): close remaining D5 cells (framework + fixtures) (#4742)
## Summary - **Framework fix**: every Python `ToolMessage` now sets `name=` and `id=str(uuid.uuid4())`. Without these, `@ag-ui/langgraph` synthesises `TOOL_CALL_START` events with `toolCallName: null` / `parentMessageId: null`, which `@ag-ui/client@0.0.53`'s Zod schema rejects. The rejection is silently swallowed by `withAbortErrorHandling → EMPTY`, completing the SSE observable mid-stream so post-tool state never reaches the consumer. Fixes Bucket A (shared-state-streaming, open-gen-ui-advanced) plus several other multi-step demos. - **Fixtures**: added `toolCallId`-keyed follow-up fixtures for every multi-turn pill (set_steps, display_flight, generate_a2ui, schedule_meeting, generateSandboxedUi, revenue chart) so the agent doesn't recurse into 100-step loops; tightened `hasToolResult: true` follow-ups to `toolCallId` so they don't match cross-turn after prior turns' tool results; added 4 hand-crafted secondary `_design_a2ui_surface` fixtures for A2UI dynamic. - **Probe**: bumped per-card `waitForSelector` in `d5-gen-ui-headless-complete` from 15s → 60s (recharts is slow under 4 sequential turns). - **Shell-dojo**: hide CLI Start Command from the dojo navigation via `HIDDEN_DOJO_FEATURE_IDS`. Registry/manifests untouched so harness/parity/dashboard still see it. ## What this PR does NOT fix - **`mcp-apps` D5 probe stays red.** I tried a fixture that emits a `create_view` MCP tool call so the runtime middleware fetches the iframe from the real Excalidraw MCP server. `validate-fixture-tool-surface.ts` correctly rejected it: my `system diagram` substring would match all 17 integrations' mcp-apps demos but only langgraph-python has the MCP wiring to handle `create_view`. Reverted. The probe remains a known aimock false-negative — fix needs MCP-aware fixture infrastructure (extend the validator to read `mcpApps.servers`, or per-agent fixture files, or a probe-skip flag). Tracking as separate work. ## Test plan - [x] `./showcase/bin/showcase test langgraph-python --d5` — passes for every D5 cell except mcp-apps (which was already red before this PR) - [x] Browser smoke (replay mode) for shared-state-streaming, gen-ui-agent, a2ui-fixed-schema, declarative-gen-ui (4 pills), open-gen-ui (default + advanced), gen-ui-interrupt - [x] Wire-level verification that `TOOL_CALL_START` carries non-null `toolCallName` + `parentMessageId` for the affected agents - [x] `validate-fixture-tool-surface.ts` passes locally (280 fixtures × 627 demos, no drift) - [x] No regression on previously-green probes - [x] CI green |
||
|
|
3d4912f323 |
fix(showcase/langgraph-python): close remaining D5 cells (framework + fixtures)
Lands the Bucket A framework fix and the fixture-correctness changes needed to flip the remaining D4/D2 cells in the langgraph-python column to D5. Full local D5 sweep is green (1 passed, 0 failed). Framework: every Python `ToolMessage` constructed via `Command(update=...)` now sets `name=` and `id=str(uuid.uuid4())`. Without these, @ag-ui/langgraph synthesises TOOL_CALL_START events with `toolCallName: null` and `parentMessageId: null`, which @ag-ui/client@0.0.53's Zod schema rejects; the rejection is silently swallowed by `withAbortErrorHandling -> EMPTY`, completing the SSE observable mid-stream so post-tool state never reaches the consumer. Fix is applied across shared_state_streaming, shared_state_read_write, gen_ui_agent, beautiful_chat, subagents (2 sites). Single-flag change in a2ui_dynamic flips the secondary `_design_a2ui_surface` LLM call to `streaming=True` so aimock's record/replay (SSE-only) sees it. Fixtures (d5-all.json): - toolCallId follow-ups for set_steps (3), display_flight, generate_a2ui (4), schedule_meeting (2), generateSandboxedUi (7), and revenue chart so multi-turn probes don't recurse into recursion-limit loops - four hand-crafted secondary `_design_a2ui_surface` fixtures so A2UI dynamic renders without a real LLM - mcp-apps fixture rewritten to emit `create_view` tool call with a minimal Excalidraw element payload; runtime middleware fetches the UI resource and the iframe mounts - AAPL and revenue `hasToolResult: true` follow-ups tightened to `toolCallId` so they don't match cross-turn after prior turns' tool results - voice fast-path content-only fixture - beautiful-chat-schedule-meeting first-turn fixture gains content so the conversation runner sees an assistant message before the picker click assertion Probes: bumped per-card waitForSelector in d5-gen-ui-headless-complete from 15s to 60s — recharts ResponsiveContainer can be slow under 4 sequential turns. Shell-dojo: hide CLI Start Command from the dojo navigation via `HIDDEN_DOJO_FEATURE_IDS`. Registry/manifests untouched so harness/parity/dashboard still see it. |
||
|
|
7136129470 |
fix(shell-docs): swap selector icon tile to neutral surface in dark
The framework selector pill in the sidebar tinted its 40px icon tile with bg-[var(--accent)]/25 when a framework was active. In light mode that paints as soft lavender against the lavender pill -- the canonical look. In dark mode it paints as a dark muted purple, and the CopilotKit kite (which is itself purple-toned) blends straight into it -- the brand mark essentially disappears. Add dark:bg-white/10 so the active tile flips to a neutral elevated surface in dark mode. Light mode keeps the lavender. The kite stands out against white/10, and the other framework brand marks (Mastra, LangGraph, CrewAI, etc.) all read cleanly against the neutral too -- no framework loses contrast in the swap. |