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 | |
|---|---|---|---|---|
|
|
26a6c07fdd |
style(shell-docs): align framework landing + not-available pages to canonical shell
The framework-scoped routes had two more places still rendering against the pre-wave3 shell that the root /docs page just got migrated off of: - FrameworkLandingPage (e.g. /mastra, /langgraph-python) used the old 240px sidebar with p-4 + bg-[var(--bg)] + browser-default scrollbar, plus a max-w-4xl content column with no centering. - NotAvailableForFrameworkPage (rendered when a slug exists for some frameworks but not the URL's) used the same old shell. Move both onto the SidebarNav + .docs-content-wrapper + max-w-[900px] mx-auto pattern docs-page-view uses, and update RenderNav to match the new section/page/group treatment from OverviewNavItem (15px banner sections at depth 0, 11px text-faint demoted labels at depth > 0, h-10 rounded-lg pill page links with dark-aware hover, border-l tree on nested groups). Picking a different framework now produces the same chrome as the root overview, instead of revealing the old shell. |
||
|
|
ee41d6061e | style: auto-fix formatting | ||
|
|
927cb56101 |
style(shell-docs): polish docs page chrome (header spacing, sidebar, root overview)
Tighten the gap between the page header and the body to canonical's mb-8 (was mb-14 with a responsive ladder that opened a half-inch hole at xl widths between the description paragraph and the first prose paragraph). Align the sidebar treatment to canonical: - Section header banner uses the same Plus Jakarta default-weight uppercase + tracking as canonical's separator, sized up to 15px so it sits above the link list as a clear divider rather than a tiny caption below it. - Section divider rule uses --border (white/10 in dark, #d9d9e0 in light) so the horizontal line survives the dark token set. - Active-link pill picks up dark-mode contrast: --bg-hover surface with a 1px white/10 ring instead of the near-flat --bg-surface that read as undifferentiated against the sidebar bg in dark. - Idle pages get a white/5 hover affordance in dark. - Nested section separators (depth > 0) demote to a quiet 11px uppercase label in --text-faint with no divider rule, so the Build Generative UI > Controlled / Declarative / Open-Ended subsection breaks read as inline labels inside their parent group instead of competing banner headers. Move the root /docs overview route onto the same SidebarNav + .docs-content-wrapper + max-w-[900px] mx-auto pattern docs-page-view uses, and rewrite OverviewNavItem so sections, pages, and groups paint with the same tokens as the per-doc routes -- previously the root was still rendering against the pre-wave3 shell with a 240px sidebar, p-4 padding, browser-default scrollbar, and an off-center max-w-4xl content column. Rename the "Give Your App Agent Powers" main-meta section to "Adding Agent Powers" per product copy. |
||
|
|
a3c777ae92 |
fix(shell-docs): TOC scrollspy activates last heading at scroll bottom
The TOC scrollspy used IntersectionObserver with a -20%/-70% root margin band, which never fires for the last heading once the user has scrolled it past that band. The active state stayed parked on whichever heading last entered the band even when the user had clearly arrived at the document end. Replace with a scroll listener on .docs-content-wrapper that walks the heading list, picks the last heading whose top has crossed the trigger line (~25% from the viewport top), and forces the final heading active when the scroll container is at scrollMax. Falls back to window scroll for routes that don't wrap content in .docs-content-wrapper. |
||
|
|
84fc2b2c27 |
feat(shell-docs): port canonical dark mode parity
Add a .dark token block to globals.css mirroring canonical
docs.copilotkit.ai for every var the wave3 chrome consumes (--bg,
--bg-surface, --bg-elevated, --bg-hover, --border, --border-dim,
--sidebar, --glass-background, --text*, --accent*, --violet*, --blue,
--scrollbar-color, --scrollbar-track). The navbar already shipped a
Toggle theme button + sun/moon SVGs + documentElement.classList
.toggle('dark') + localStorage.theme persistence; this commit makes
that toggle paint the rest of the page because all wave3 chrome
(sidebar, navbar, banner, callouts, tables, TOC, content wrapper)
consumes those vars.
Add @custom-variant dark (&:is(.dark *)) so dark: Tailwind utilities
react to the .dark class instead of prefers-color-scheme. Without
this, the navbar's class-driven swap pairs (slanted-end-border-dark
vs -light, theme-moon vs theme-sun, every dark: utility) are dead
when the theme toggle runs.
Add an inline beforeInteractive script in <head> that reads
localStorage.theme (falling back to prefers-color-scheme) and applies
the class before first paint, with suppressHydrationWarning on <html>
so Next.js doesn't revert the class to match the server output.
Apply scrollbar-width: thin and scrollbar-color to .docs-content-wrapper
and the sidebar's inner scroll container so the thumb tracks the
active theme instead of paying the bright browser default that pops
against dark surfaces.
Bump dark-mode contrast on the icon-button hover surface in the
navbar (GitHub, Discord, theme toggle) to a rounded black/5 in light
and white/10 in dark so the buttons read as interactive.
|
||
|
|
f2c5506d07 |
fix(shell-docs): portal search modal so fixed positioning escapes navbar
The search modal renders inside SearchTrigger, which lives in the navbar's right cluster. The cluster has backdrop-blur-lg, and backdrop-filter creates a containing block for fixed-position descendants. The modal's `fixed inset-0` overlay was therefore being clamped to the cluster's bounding rect (~505x70 at 1440x900) instead of the viewport, so the overlay+card rendered as a tiny clipped strip under the search button. Wrap SearchModalWrapper in createPortal mounted on document.body. The modal now resolves position: fixed against the viewport like a normal overlay. |
||
|
|
aa08743c7e |
fix(core): only reset agent state on actual thread switch (supersedes #4720)
When the chat's connect effect re-fires due to React effect-dep churn, it
calls copilotkit.connectAgent({ agent }) on the same thread again. The
RunHandler previously called agent.setMessages([]), agent.setState({}),
and (transitively) clearReconnectCursor on every such call. That forced
the realtime gateway to replay the topic's full event history on every
churn re-connect — sending the same persisted cpki_event_ids 2-3 times
per thread switch — and produced both halves of Tyler's bug: duplicate
rows in the inspector AG-UI Events tab plus "Message not found" toasts
when the next runAgent fired with an empty agent.messages.
This change makes the orchestrator detect actual thread switches:
- RunHandler tracks _lastConnectedThreadId across connectAgent calls.
On a fresh restore (different threadId from last call) it does the
reset and clears the replay cursor. On churn (same threadId) it
skips the reset entirely so local messages/state are preserved and
the gateway resumes from lastSeenEventId instead of replaying.
- IntelligenceAgent.connect() no longer auto-clears the cursor;
cursor management is the caller's decision now. clearReconnectCursor
is made public so RunHandler (and tests) can call it explicitly.
- ProxiedCopilotRuntimeAgent exposes a clearReplayCursor(threadId)
method that delegates to the IntelligenceAgent. Non-Intelligence
runtime modes are a safe no-op.
This supersedes #4720, which attempted to solve only the inspector
duplicate-row symptom by adding a dispatcher dedup. That approach
introduced a blocking regression in the A → B → A restore path: the
dedup persisted across thread switches and suppressed the gateway's
restore replay, leaving agent.messages at [] and triggering the very
"Message not found" toast we were trying to prevent. Mike's review
caught it. The dispatcher dedup is removed entirely; the
orchestrator-level gate is sufficient and a smaller surface change.
Tests:
- intelligence-agent.test.ts: updated 4 tests that codified the old
"always clear cursor" semantics. Added an explicit test that
clearReconnectCursor() empties the cursor for the next connect, and
Mike's regression — 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): four tests for the
RunHandler gate covering churn, single switch, A → B → A, and the
no-clearReplayCursor non-Intelligence path.
All 430 core tests pass.
|
||
|
|
8d360c0dc6 |
fix(shell-docs): resolve 53 sitemap 500s before cutover
The 53 hard-500 URLs in the public sitemap split into three independent
root causes, all surfaced in production-mode rendering only because the
underlying issues throw inside next-mdx-remote:
1. tutorials/ai-powered-textarea/step-2-setup-copilotkit and
tutorials/ai-todo-app/step-2-setup-copilotkit reference
<CopilotCloudConfigureCopilotKit>,
<SelfHostingCopilotRuntimeConfigureCopilotKit>, and
crewai-flows/quickstart references <CloudCopilotKit> — three
unsuffixed component names whose only registered counterparts in
docsComponents end in "Provider". MDX rendering throws "Expected
component X to be defined" and 500s. Adds the unsuffixed names as
aliases of the existing Provider stubs in mdx-registry.
deploy-agentcore (langgraph variants + aws-strands) uses
<Content framework="..." />, also unregistered. Adds Content as a
children-passthrough stub for the same reason.
2. Three langgraph tutorial pages (agent-native-app/step-6-shared-state,
ai-travel-app/step-3-setup-copilotkit,
ai-travel-app/step-4-integrate-the-agent) place a closing </Step>
tag immediately under a markdown bullet list with no blank line
separator. The remark parser treats the closing tag as a list-item
continuation, errors out with "Expected the closing tag </Step>",
and ships a 500. Adds the missing blank line before the close tag.
3. Five MDX files (llamaindex + adk shared-state/predictive-state-updates,
pydantic-ai shared-state/in-app-agent-write, plus crewai-flows and
pydantic-ai human-in-the-loop/index — last two not in the 53 but
share the bug) use {/\\* ... \\*/} where the asterisks are escaped.
Acorn cannot parse the resulting expression and the page 500s.
Replaces the escapes with proper {/* ... */} JSX comments.
Verified: a clean production build of shell-docs followed by
`npx next start` and a curl probe of all 53 URLs from
validation/test2_results.json returns 200 across the full set with
zero MDX or React errors in the server log.
|
||
|
|
39d1b91ac6 |
fix(shell-docs): redirect catalog hygiene (self-loops + framework-scoped gap)
Two issues found in Phase 4 validation against docs.showcase.copilotkit.ai. 1. 31 entries in seo-redirects.ts had source === destination, causing middleware to issue infinite 301 loops on canonical URLs like /frontend-tools, /faq, /human-in-the-loop. Remove the dead entries and add a defense-in-depth skip-when-equal guard in middleware so future drift cannot regress. 2. Framework-scoped paths (e.g. /agno/frontend-actions) bypassed the redirect catalog entirely because the pathIsFrameworkScoped short- circuit fired before any catalog lookup. Reorder middleware so the exact-match catalog is consulted first for every request, including framework-scoped paths. Wildcard scan still skips legacy patterns that would hijack canonical framework URLs, but allows same-framework wildcard rewrites (e.g. /agno/concepts/:path* -> /agno) to fire. 85 framework-scoped redirects across 18 registry slugs now resolve instead of soft-404ing. Verified by curl probes against localhost: all 85 framework-scoped catalog entries 301 to the expected destination, all 31 former self- loop URLs return 200, and canonical framework URLs (/agno, /langgraph- python/quickstart, etc.) still pass through unchanged. |
||
|
|
d7d7b27ff0 |
fix(shell-docs): correct feature-viewer slug + demo-id translation for code tab
The InlineDemo Code tab constructs a feature-viewer.copilotkit.ai URL from the integration's docs-folder name, but feature-viewer expects its own slug scheme. Six framework slugs 404'd outright (built-in-agent, google-adk, claude-sdk-python, claude-sdk-typescript, ms-agent-python, ms-agent-dotnet) and two more were named differently (crewai-crews needed crewai, llamaindex needed llama-index). Demo IDs also diverged (gen_ui_tool_based vs tool_based_generative_ui, hitl_in_chat vs human_in_the_loop, etc.) so even when the framework slug was right the Code panel rendered an empty 404 page. Add getFeatureViewerSlug() and getFeatureViewerDemoId() to registry.ts with explicit override maps. Both return null when the integration or demo has no feature-viewer counterpart. Update mdx-registry.tsx to use both and to suppress the Code tab (rendering the Demo iframe alone) whenever either helper returns null. Verified by probing feature-viewer.copilotkit.ai for each (framework x demo) combination using NEXT_HTTP_ERROR_FALLBACK soft-404 detection plus inspection of the rendered code panel; all post-fix URLs that the helpers emit resolve to real code panels for the six demos feature-viewer ships (agentic_chat, tool_based_generative_ui, agentic_generative_ui, predictive_state_updates, shared_state, human_in_the_loop). |
||
|
|
938b8d8dd3 |
chore(showcase): close last 2 yellow Missing snippet boxes for cutover
/langgraph-python/frontend-tools referenced regions frontend-tool-registration and frontend-tool-handler which were missing markers on the production demo. Added in-place @region markers on the existing useFrontendTool block in showcase/integrations/langgraph-python/src/app/demos/frontend-tools/page.tsx since the demo is a clean teaching example. /langgraph-python/custom-look-and-feel/slots referenced regions register-welcome-slot, register-assistant-message-slot, and register-disclaimer-slot. The chat-slots production demo registers ~12 slot overrides at once with `as unknown as typeof X` casts that obscure the per-pattern teaching shape, so added a sibling slot-overrides.snippet.tsx file (mirrors the llamaindex chat-slots sibling pattern) with the three minimal teaching regions. Verified by re-bundling demo-content.json, running shell-docs production build, and curling both pages on a local server: zero Missing snippet boxes, and the region code (change_background, CustomWelcomeScreen, CustomDisclaimer, CustomAssistantMessage) renders on the pages. |
||
|
|
a44d0be955 |
fix(shell-docs): align docs sidebar pill and content column with canonical
The active-link pill in the docs sidebar rendered flush against the scroll gutter because the inner scroll container had no right padding; canonical adds pr-1 on its scroll container so the pill stops 4px short of the scrollbar. Match that. The content column used px-8 py-6 xl:px-16 xl:py-12 with a non-centered max-w-[900px] cap, which pushed content 32px to the right of canonical at xl widths and left a wide gap between content and the right rail. Replace with canonical's exact pattern: px-4 py-6 md:px-6 md:pt-8 xl:px-8 xl:pt-14 outside, max-w-[900px] mx-auto inside, so the column centers between sidebar and TOC and the h1 lands at the same x as docs.copilotkit.ai at 1440. |
||
|
|
20185cf5c1 | style(shell-docs): port canonical right-rail TOC (fumadocs outline + masked sliding highlight) | ||
|
|
b2e419a83a | feat(shell-docs): port canonical dismissable top promo banner | ||
|
|
6de00bfae2 | style(shell-docs): port canonical two-piece navbar (slanted separator, glass panels, search trigger, per-link underline animation, brand assets) | ||
|
|
a00c4bf9b8 | fix(shell-docs): replicate canonical page layout architecture (fixed-height body, internal scroll on content wrapper, sidebar pinning, TOC inside wrapper, route shells) | ||
|
|
708e5aa5f1 | style(shell-docs): port canonical visual baseline (color tokens, typography, callouts, tables, code chrome, content wrapper styles) | ||
|
|
af9fbd59a9 |
fix(showcase/aimock): correct D5 fixture matching for agent-config + shared-state-streaming (#4737)
## Summary Two D5 fixture-correctness fixes for the langgraph-python column. Together they flip `agent-config` to D5 and unblock the recursion-loop failure mode for `shared-state-streaming` (the cell still has a separate framework-level state-binding regression that prevents it from rendering — tracked separately). - **agent-config**: drop the "introduce yourself per your config" baseline fixture. It substring-matched every prefixed probe prompt (`tone:professional`, `expertise:beginner`, `responseLength:concise`, …), forcing byte-identical responses across all six knob probes and masking the per-knob behavior the cell is meant to demonstrate. - **shared-state-streaming**: add toolCallId-keyed follow-up fixtures (poem / email / quantum) above each first-turn entry so aimock returns content-only after the tool result lands. Without these, the unchanged last user message kept re-matching the first-turn fixture, the agent re-fired `write_document`, and langgraph hit its 100-step recursion limit. Synced to `showcase/aimock/d5-all.json` so replay-mode picks up both fixes. ## Test plan - [x] Local replay: `agent-config` flips GREEN (each knob probe receives its dedicated fixture) - [x] Local replay: `shared-state-streaming` no longer hits `GraphRecursionError`; remaining failure is the framework state-binding bug (separate work) - [x] aimock fixture count went up by the expected amount on container restart (`Loaded N fixture(s)`) - [x] lefthook hooks pass (lint-fix, sync-lockfile, test-and-check-packages all clean) |
||
|
|
ca22e38e20 |
Merge remote-tracking branch 'origin/main' into alem/d5-fixture-fixes-bucket-a
# Conflicts: # showcase/aimock/d5-all.json |
||
|
|
3aa64b02f9 |
fix(showcase/harness): probe-side DOM-signal alignments — flips 5 more D4 cells to D5 (#4732)
## Summary Six probe-side fixes landing **5 additional D5 flips** on the langgraph-python column. None of the fixes touch demo or runtime code — just the harness-side selectors / signal predicates so each probe asserts on what the published langgraph-python image actually renders today. ## D5 impact Stacks on PR #4728 (merged). After this branch (live in PocketBase): | Cell | Before this PR | After | |---|---|---| | `tool-rendering-default-catchall` | red | **green** | | `beautiful-chat` | red | **green** | | `reasoning-default` | red | **green** (rolled with reasoning-custom on the same `d5:reasoning-display` row) | | `frontend-tools` | regressed in earlier replay sweep | **green** (toolCallId disambiguation in PR #4728) | **Net dashboard count: 11 → 5 D4 cells in the langgraph-python column** (including PR #4724 + #4728's flips). ## Per-probe changes - **`d5-tool-rendering-default-catchall`** — add a fallback that scans `[data-testid="copilot-assistant-message"]` bubbles for the literal tool name + a `done`/`running` status label, alongside the strict testid contract. Strict path (the `[data-testid="copilot-tool-render"]` wrapper added in commit `ba60df5d3`) re-engages once `@copilotkit/react-core` ships a release with it; until then the bubble-text scan is the only stable hook on 1.56.5. - **`d5-reasoning-display`** — published built-in `CopilotChatReasoningMessage` carries no testid. Accept the verbatim `Thought for` / `Thinking…` header text the slot emits, in addition to the four pre-existing testid selectors used by the `reasoning-custom` override. - **`d5-gen-ui-headless-complete`** — the `SuggestionBar` renders agent-generated chip phrasing alternately with the static `useConfigureSuggestions` titles. Switch from `aria-label="Suggestion: <Title>"` to a per-chip alias list (e.g. `["stock", "aapl"]`) that matches BOTH forms via case-insensitive CSS attribute substring (`button[aria-label*="..." i]`). - **`d5-gen-ui-interrupt`** — widen the post-pick assertion to accept any of (a) the `time-picker-picked` testid, (b) the visible `Booked` badge text, or (c) the agent's `scheduled` / `confirmed` resume continuation. The picked-state Card unmounts as soon as langgraph resumes after `resolve`, so a 5s testid wait races the unmount; the OR catches whichever signal lands first. - **`_beautiful-chat-shared` (toggle-theme)** — two-track signal: pass on EITHER the `html.dark` class flipping from its initial reading OR the visible `Theme toggled` assistant content rendering. The class-flip is the strongest signal but `useFrontendTool`'s dispatch occasionally drops the handler call without dropping the agent's follow-up content message; track (b) catches the "tool semantics reached the UI" state in the meantime. - **`_beautiful-chat-shared` (search-flights)** — swap the literal `United Airlines` wait for the short brand label `United`, which appears in BOTH the FlightCard a2ui surface (when it paints) and the assistant's `$349 / $289` narration. Price literals stay as the canonical 2-flight fingerprint. ## Conversation-runner adjustment Reverse the partial-fix from PR #4724: try chat-input cascade resolution AT BOOT first (and read baseline at boot too); only defer to post-`preFill` on auth-shape demos where the cascade fails. Without this, demos where `preFill` itself fires the message (chip clicks in headless-complete) had baseline read AFTER the assistant bubble already appeared and the settle waited indefinitely for further growth that never came. ## Remaining 5 D4 cells | Cell | Class | |---|---| | `agent-config` | Bucket A — runtime/streaming defect | | `shared-state-streaming` | Bucket A — same defect class | | `open-gen-ui-advanced` | Bucket A — same defect class | | `gen-ui-headless-complete` | First 3 of 4 chip turns now pass; 4th turn (`revenue` chart) still fails. Suggestion drift across 4 sequential turns means the 4th chip's aria-label sometimes drifts outside both alias forms. Worth narrowing once dev-debug-mode confirms what the 4th-turn chip rendered. | | `gen-ui-interrupt` | Post-pick signal still elusive — `Booked` badge / `scheduled` continuation are not landing in the rendered DOM after a slot click in the local environment. Further investigation needed via debug-mode trace. | Bucket A is deferred per prior discussion; the other two would benefit from `debug: true` on the runtime/provider to see exactly what events fire after the slot click / 4th chip click. ## Test plan - [x] Full d5 sweep against local replay confirms 5 → 5 red d5 keys (down from 8 pre-PR; -3 net flips on this branch alone) - [x] PocketBase reflects current state — 5 D4 cells visible on dashboard - [ ] CI's langgraph-python D5 cron passes the same 8 cells on a deploy of this branch - [ ] `dashboard.showcase.copilotkit.ai` shows 11 → 5 D4 transitions on the langgraph-python column once Railway picks this up |
||
|
|
ccc2eabfc2 |
test(showcase/langgraph-python): regression coverage for A2UI middleware-intercept + display_flight loop
Three classes of regression are now pinned: 1. Secondary-LLM tool name doesn't collide with the A2UI middleware's default intercept list (`render_a2ui`). New `src/agents/test_a2ui_internal_tools.py` parametrises over `beautiful_chat._design_a2ui_surface`, `a2ui_dynamic._design_a2ui_surface`, and `a2ui_fixed.display_flight` and asserts none match the middleware's `a2uiToolNames` default. Catches accidental rename reverts that would re-enable the bypass. 2. `generate_a2ui` force-pins the canonical `catalog_id` even when the secondary LLM hallucinates a wrong one. The new test stubs `ChatOpenAI` with a fake response carrying a bogus catalogId and asserts the surface op carries the module's `CUSTOM_CATALOG_ID`. 3. `generate_a2ui` short-circuits with a clean error string when the LLM emits a root component without a `component` field — never feeds the renderer the partial tree that surfaced as the "Cannot create component root without a type" infinite-loop. 7 unit tests, all green locally (`pytest src/agents/test_a2ui_internal_tools.py`). E2E tests on the same fixes now also assert: - No `A2UI render error: Catalog not found` banner on the page after Beautiful Chat → Sales Dashboard, Declarative Gen UI → BarChart, and A2UI Fixed Schema → Find SFO → JFK round-trips. - No `Cannot create component … without a type` banner on the same three pills. - Exactly ONE flight card on A2UI Fixed Schema (was 6+ on deploy pre-fix from the `display_flight` loop) — `Flight Details` count pinned to 1, `Book flight` count pinned to 1. - At most one ResponsiveContainer on the BarChart pill (loops would stack multiple). - At most two ResponsiveContainers on Beautiful Chat → Sales Dashboard (one pie + one bar = single dashboard render). |
||
|
|
22a8446586 |
fix(showcase/aimock): correct D5 fixture matching for agent-config + shared-state-streaming
agent-config: drop the "introduce yourself per your config" baseline — it substring-matched every prefixed probe prompt (tone:, expertise:, responseLength:), forcing byte-identical responses and masking the per-knob behavior the cell is meant to demonstrate. shared-state-streaming: add toolCallId-keyed follow-up fixtures (poem/email/quantum) above each first-turn entry so the matcher returns content-only after the tool result lands. Without these the unchanged last user message kept re-matching the first-turn fixture, the agent re-fired write_document, and langgraph hit its 100-step recursion limit. The frontend state-binding regression that prevents the streamed document from rendering is a separate framework-level issue. Synced to showcase/aimock/d5-all.json so replay-mode picks up both fixes. |
||
|
|
e1137bb2f7 | Merge branch 'main' into alem/fix-bucket-c-d5-probes-followup | ||
|
|
d1827973bd |
fix(showcase/langgraph-python): rename internal A2UI tool so middleware doesn't intercept (#4734)
## Summary Follow-up to #4733. The Sales Dashboard pill on Beautiful Chat and the KPI Dashboard pill on Declarative Gen UI were still failing on deploy with: - `A2UI render error: Catalog not found: declarative-gen-ui-catalog` (beautiful-chat) - `A2UI render error: Cannot create component root without a type` infinite loop (declarative-gen-ui) ### Root cause `@ag-ui/a2ui-middleware`'s default `a2uiToolNames = ["render_a2ui"]` makes the middleware **synthesise ACTIVITY_SNAPSHOT events from the streaming tool-call args of any matching call**, using the LLM's RAW `catalogId` + `components` before the Python tool body runs. Both `generate_a2ui` implementations bound a structured-output helper named `render_a2ui` to a secondary LLM — so the secondary LLM's hallucinated `catalogId` and malformed root components were getting emitted to the frontend through the bypass. The force-pin and defensive validation #4733 added were correct but ran on the tool-result; the middleware had already fired its synthetic events from the streaming args. ### Fix Rename the internal helper from `render_a2ui` to `_design_a2ui_surface` so it falls outside the middleware's intercept list. The outer `generate_a2ui`'s `a2ui.render(operations=...)` return is then the only path to the frontend, and the Python validation layer is authoritative again. Two files: `src/agents/beautiful_chat.py`, `src/agents/a2ui_dynamic.py`. No frontend / runtime / package changes. ## Test plan - [x] **Local — Beautiful Chat → Sales Dashboard pill**: renders dashboard surface (Total Revenue / New Customers / etc.) with no errors. Previously: `Catalog not found: declarative-gen-ui-catalog`. - [x] **Local — Beautiful Chat → Search Flights pill**: still renders FlightCards (regression check on the previous fix). - [ ] **Deploy — Beautiful Chat → Sales Dashboard pill**: confirm no `Catalog not found` error. - [ ] **Deploy — Declarative Gen UI → KPI Dashboard pill**: confirm no `Cannot create component root without a type` loop. |
||
|
|
c91a9c9aff |
fix(showcase/langgraph-python): A2UI fixed-schema loop + propagate rename to shared tools and aimock
Two follow-up fixes layered on the previous internal-tool rename: (1) `a2ui_fixed.py` — fixed-schema demo infinite loop on deploy. The `display_flight` tool returns the raw `a2ui.render(...)` JSON descriptor as its tool result. gpt-4o-mini reads that opaque blob, can't tell the flight was rendered, and re-calls `display_flight` indefinitely (visible on the deployed showcase as 6+ duplicate flight cards stacked under repeated assistant text). Local was just lucky. Hardened the docstring + system prompt to spell out: the JSON return value is the surface descriptor, the card is already rendered, do NOT call again, reply with one short confirmation and stop. (2) Rename `render_a2ui` → `_design_a2ui_surface` in shared and langgraph-python parity copies of `tools/generate_a2ui.py` (+ `tools/__init__.py` re-export `RENDER_A2UI_TOOL_SCHEMA` → `DESIGN_A2UI_SURFACE_TOOL_SCHEMA`), and in `showcase/shared/typescript/ tools/generate-a2ui.ts`. These shared helpers were the source-of-truth for the secondary-LLM tool name across integrations; renaming here keeps parity with the langgraph-python agents already renamed in `beautiful_chat.py` / `a2ui_dynamic.py`. Other framework integrations keep their own `render_a2ui` for now (separate parity sweep). (3) `showcase/aimock/feature-parity.json` — added a sibling fixture matching `toolName: "_design_a2ui_surface"` for the beautiful-chat Sales Dashboard pill so the langgraph-python e2e suite still hits a deterministic mock on Railway. The original `render_a2ui` fixture is kept above it so other integrations whose secondary LLM still requests `render_a2ui` continue to match. (4) Comment update in `beautiful-chat.spec.ts` to name the new internal tool. |
||
|
|
f8b2be774d |
chore: retarget "Talk to engineers" CTAs to /talk-to-an-engineer (#4735)
## Summary - Retargets the docs navbar and showcase shell-docs brand-nav "Talk to engineers" CTAs from `copilotkit.ai/contact-us` to `copilotkit.ai/talk-to-an-engineer`. - PostHog `talk_to_us_clicked` capture is unchanged — only the destination URL moves. ## Test plan - [ ] Click "Talk to engineers" in the docs navbar and confirm it lands on `/talk-to-an-engineer`. - [ ] Click "Talk to engineers" in the showcase shell-docs brand-nav and confirm the same destination. - [ ] Verify `talk_to_us_clicked` still fires in PostHog with `location: "docs_nav"`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
017e19455a |
chore: retarget "Talk to engineers" CTAs to /talk-to-an-engineer
Updates the docs navbar and showcase shell-docs brand-nav so the "Talk to engineers" CTA points at copilotkit.ai/talk-to-an-engineer instead of the deprecated /contact-us endpoint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5d3abc6680 |
fix(showcase/langgraph-python): rename internal A2UI tool so middleware doesn't intercept
The A2UI middleware (`@ag-ui/a2ui-middleware`) defaults `a2uiToolNames` to `["render_a2ui"]` and synthesises ACTIVITY_SNAPSHOT events from the streaming tool-call args of any matching call — using the LLM's RAW catalogId and components verbatim, before the Python tool body has a chance to validate or normalise. Both `beautiful_chat.py` and `a2ui_dynamic.py` use a `generate_a2ui` tool that internally invokes a secondary LLM bound to a structured-output `render_a2ui` helper. Because the helper's name matched the middleware's default intercept list, the secondary LLM's hallucinated catalogId (`declarative-gen-ui-catalog` leaking into the beautiful-chat dashboard) and malformed root components (no `component` field on KPI dashboard) were emitted to the frontend bypass, surfacing as: - "A2UI render error: Catalog not found: declarative-gen-ui-catalog" on the beautiful-chat Sales Dashboard pill - "A2UI render error: Cannot create component root without a type" infinite-loop on the declarative-gen-ui KPI Dashboard pill The earlier force-pin of `catalog_id` and the defensive component sweep in `generate_a2ui` were correct but ran too late — they execute on the tool-result, after the middleware has already fired surface events from the streaming args. Fix: rename the internal helper to `_design_a2ui_surface` (and update `tool_choice`, prompt header, and module docstring) so it falls outside the middleware's intercept list. The explicit `a2ui.render(...)` ops the outer `generate_a2ui` returns are then the only path to the frontend, and our Python validation layer is authoritative. Verified locally: Beautiful Chat → Sales Dashboard pill renders Total Revenue / New Customers / etc. with no errors. |
||
|
|
3b3908e353 |
fix(showcase/langgraph-python): restore A2UI rendering for beautiful-chat + declarative-gen-ui (#4733)
## Summary - Beautiful Chat **Search Flights** pill: restored `_build_flight_components` so the agent emits a flat literal-children FlightCard tree (the structural-children template form via `flight_schema.json` + `update_data_model` doesn't expand correctly through GenericBinder for our custom catalog — it was working until the recent flagship-cell pass swapped it back). FlightCards render again instead of falling through to the default tool card. - Beautiful Chat **Sales Dashboard** pill: hardened `generate_a2ui` so the secondary LLM gets explicit catalog-id + component-shape rules and the resulting `catalog_id` is force-pinned to the registered catalog. Kills the "Catalog not found: declarative-gen-ui-catalog" sibling-demo hallucination. - **Declarative Gen UI** (`a2ui_dynamic.py`): same `generate_a2ui` hardening, plus a defensive sweep that drops malformed components and bails clean when the LLM omits a typed root. Kills the "Cannot create component root without a type" infinite-loop renderer error reported on the KPI Dashboard pill. Two files touched (`src/agents/beautiful_chat.py`, `src/agents/a2ui_dynamic.py`); no frontend / runtime / package changes. Existing aimock fixtures in `feature-parity.json` already use the canonical catalogId and well-formed components, so e2e specs should pass without fixture changes. ## Test plan - [x] Verified locally: `langgraph_cli dev` + `next dev`, clicked **Search Flights** on `/demos/beautiful-chat` — Delta DL 405 ($329) and United UA 120 ($289) FlightCards rendered live with airline, route, times, status, Select. - [x] Verified locally: clicked **Show a KPI dashboard** on `/demos/declarative-gen-ui` — REVENUE / SIGNUPS / CHURN metric tree rendered cleanly, no "Cannot create component root without a type" error. - [ ] CI / `nx run @copilotkit/showcase-langgraph-python:e2e` (beautiful-chat spec already authored against the literal-children form). |
||
|
|
d1efb2bbc4 | style: auto-fix formatting | ||
|
|
462e200d45 |
fix(showcase/harness): assert on actual DOM signals, not unreleased testids
Six probe-side fixes landing five additional D5 flips on the
langgraph-python column. None of the fixes touch demo or runtime
code — just the harness-side selectors / signal predicates so each
probe matches what the published langgraph-python image actually
renders today.
Per-probe changes:
- d5-tool-rendering-default-catchall: add a fallback path that
scans copilot-assistant-message bubbles for the literal tool name
+ a 'done'/'running' status label, alongside the strict testid
contract added in unreleased commit
|
||
|
|
3ac103b3bf |
fix(showcase/langgraph-python): restore A2UI rendering for beautiful-chat + declarative-gen-ui
Three regressions, two files. Without these the Search Flights pill falls
through to the default tool card instead of rendering FlightCards, the
Sales Dashboard pill errors with "Catalog not found:
declarative-gen-ui-catalog", and the Declarative Gen UI cell loops on
"Cannot create component root without a type."
beautiful_chat.py — search_flights:
- Restore _build_flight_components and have search_flights emit the flat
literal-children component tree it produces, instead of the
flight_schema.json structural-children template (Row.children =
{ componentId, path: "/flights" }) plus update_data_model. The
GenericBinder doesn't reliably expand the structural form for our
custom FlightCard catalog — sibling demos avoid the form for the same
reason. The literal form has been the working shape since it was
introduced; the recent flagship-cell pass swapped it back to the
schema/data-model form and broke fixed-schema rendering.
- Make Flight TypedDict permissive (total=False) and drop the required
id / statusIcon fields. langchain rejected calls when the LLM (or
aimock fixture) omitted those, surfacing the validation string as the
tool result and never producing a surface.
beautiful_chat.py + a2ui_dynamic.py — generate_a2ui:
- Prepend a hard-requirements header to the secondary LLM's prompt
pinning the canonical catalogId and the component-shape contract
(every entry — including root — must carry both `id` AND `component`).
With injectA2UITool: false the runtime context alone leaves the LLM
enough room to hallucinate sibling-demo catalog IDs (e.g.
declarative-gen-ui-catalog leaking into the beautiful-chat dashboard)
and to omit `component` on the root entry (the source of the
"Cannot create component root without a type" infinite loop).
- Force catalog_id to the module-level CUSTOM_CATALOG_ID after the tool
call so any residual hallucination still routes to the registered
frontend catalog.
- Drop malformed component entries before constructing the operations
list, and bail with a clean error string if no valid root survives —
fail-soft instead of looping the renderer.
The renderer-side definitions.ts/renderers.tsx changes from the same
flagship pass are kept as-is; their Row/Column children union
(string-array OR { componentId, path }) is forward-compatible and
doesn't hurt the literal-children path.
|
||
|
|
4ce76d4576 |
fix(showcase/harness): drive gen-ui-headless-complete via textarea, not chip click
The demo has TWO chip surfaces with diverging aria-label shapes: EmptyState (first paint) emits aria-label='Try suggestion: <message>' with the visible text being the message string, while SuggestionBar (post-first-message) emits aria-label='Suggestion: <title>' with visible text being the short title. Which surface is mounted at any given turn depends on messages.length — timing-dependent. Both my prior selectors matched only one surface and timed out on the other. Drop the chip-click preFill entirely; let the runner's normal fillAndPress hit the textarea with the verbatim prompt. Chip clicks and textarea-Enter dispatch the same runAgent path, so the fixture matcher catches either route — and the textarea is always present. Also refresh e2e-deep.test.ts: a stale test assertion expected the old REGISTRY_TO_D5 mapping shape (tool-rendering-default-catchall → tool-rendering D5 type), but the Phase-2A split repointed it to its own D5 type of the same name. Update the expected skipped list and sideKeys to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4541d3a7dd | Merge branch 'main' into claude/publish-agentcore-runner-NarcF | ||
|
|
1d8d1b0783 |
fix(showcase/aimock): disambiguate frontend-tools fixtures with toolCallId follow-ups
In replay mode (no real OpenAI), the existing frontend-tools fixtures match by 'userMessage' substring only. Each pill (Sunset / Forest / Cosmic) had a single fixture that returned both content + a change_background toolCall. After the frontend tool ran, the agent's follow-up LLM call still has the same last user message — substring matches the same fixture again — agent re-fires change_background, loops to langgraph's recursion limit, probe's settle window never quiets, run reds out at the assistant-settle timeout. Add a toolCallId-keyed follow-up per pill that returns content-only, plus a static tool_call_id on the first-turn toolCall for the follow- up to pin to. The follow-up combines userMessage + toolCallId so it can't cross-match the next pill's first-turn request (which still has a tool result in history from the prior pill, but a different last user message). Probe result: d5:langgraph-python/frontend-tools flips green again in replay mode — was passing in PR #4724 only because the real-LLM run that PR was tested against happened to settle without re-firing. |
||
|
|
c2bc645228 |
fix(showcase/aimock): drop redundant recorded fixtures, let canonical d5-all.json take precedence
Investigation of the remaining bucket-C D4 cells uncovered that the 'recorded' fixtures shipped in PR #4725 are at best redundant with hand-curated canonical fixtures already in d5-all.json, and at worst override them with worse data — the recordings collapsed beautiful-chat's canonical $349/$289 search_flights payload to the LLM-of-the-day's $319/$289 (probe asserts $349 verbatim) and reasoning-custom's canonical fixture (which carries a 'reasoning' field) with a content-only recording (refused chain-of-thought disclosure). Net D5 effect of removing the recordings: - d5:langgraph-python/gen-ui-custom (catalog gen-ui-tool-based) → green (canonical d5-all.json #39/#40) - d5:langgraph-python/reasoning-display (catalog reasoning-custom) → green (canonical d5-all.json #91 with 'reasoning' field that cleanly satisfies the probe's reasoning-role testid contract) Both flips confirmed live against PocketBase via --d5 --live. The aimock record/replay infrastructure introduced alongside these fixtures (showcase/docker-compose.{record,replay}.yml, showcase/scripts/record-d5-fixtures.mjs) stays — it is reusable for future demos where canonical fixtures don't yet cover the prompts — just without the misleading initial recordings. Bucket-C cells that remain at D4 after this change require fixes outside the fixture/recording scope; see the PR description for per-cell findings (release-blocked package testids, frontend-tool dispatch defect, suggestion-bar misrender, resume-from-interrupt UI, built-in reasoning-message testid). |
||
|
|
88b61cb3e4 | style: auto-fix formatting | ||
|
|
f8c711d2bb |
feat(showcase): aimock record/replay infra for deterministic D5 fixtures
Adds a record/replay loop on top of the existing local Docker stack so each langgraph-python D5 demo can capture real-LLM responses once and replay them deterministically thereafter. One fewer source of D5 flake per demo: no more 'tests pass with real OpenAI / fail with aimock' because the prompts have no fixture coverage. What lands here: - showcase/docker-compose.record.yml — overlays aimock with --record + --provider-openai/anthropic and a writable mount for the recording dir. Drops the baseline d5-all.json/feature-parity.json/smoke.json loads so prompts that already match a stale fixture can still proxy through to the real provider. - showcase/docker-compose.replay.yml — same writable mount, no --record, no provider URLs; layers the per-demo fixtures alongside the baseline ones for normal probe runs. - showcase/scripts/record-d5-fixtures.mjs — orchestrator. For each demo (catalog feature ID), drops any prior consolidated <slug>.json, restarts aimock to clear in-memory recorded fixtures, snapshots recorded/, runs the d5 probe through pnpm exec tsx, then merges every per-call file written under recorded/ into a single showcase/aimock/d5-recorded/<slug>.json (one fixture per LLM turn, in chronological order). - showcase/aimock/d5-recorded/<slug>.json × 6 — initial recordings for the still-red bucket-C cells: beautiful-chat (8), gen-ui-interrupt (2), gen-ui-tool-based (1), headless-complete (1), reasoning-custom (1), tool-rendering-default-catchall (2). 15 fixtures total. - showcase/aimock/d5-recorded/.gitignore — keeps the per-call recorded/ scratch dir out of the tree (orchestrator deletes per-call files after consolidation, this just guards against re-runs). D5 impact: replaying the recordings flips d5:langgraph-python/gen-ui-custom (catalog gen-ui-tool-based) from red to green deterministically. The other five demos still fail their UI or assertion-side checks, but their LLM-side responses are now fixed, so the remaining work is probe/UI fixes against a stable baseline rather than flake hunting. Aimock recorder requires a one-line patch (turnIndex + hasToolResult on each recorded fixture's match) for multi-turn flows to record correctly. Upstream fix proposed for @copilotkit/aimock; until it ships, the orchestrator probes for the patch and aborts loudly with the missing-fields message rather than silently producing single-turn fixtures. See the script's header comment for the exact patch payload. |
||
|
|
920e0bcc01 |
fix(showcase/langgraph-python): flip auth, frontend-tools, voice from D4 to D5 (#4724)
## Summary Three independent D5 fixes for the langgraph-python column. Together these flip 3 cells from D4 → D5 in the showcase dashboard. Production also has these same D4 cells, so the harness/showcase changes here apply to prod as well once merged. - **auth** — conversation runner now defers chat-input resolution until after the first turn's `preFill` runs, so idiomatic auth demos that mount the chat tree only after a sign-in click work end-to-end. - **frontend-tools** — D5 assertion accepts any chromatic-family hex via RGB-channel-dominance, not just the fixture-pinned substrings. Real OpenAI returned valid forest greens (`#005f00`, `#4caf50`) that the fixed substring list couldn't enumerate. - **voice** — disabled `<cpk-web-inspector>` on the voice demo. The dev-only inspector auto-mounts on any localhost host (including local Docker at `localhost:3100`) and intercepts pointer events on the voice sample-audio button. Production isn't localhost, so prod was unaffected — that's why prod was D5 and local was D4. Each commit is scoped to one fix with regression tests where applicable. ## Verification Verified locally against a fresh `aimock` + `pocketbase` + `dashboard` + `langgraph-python` stack with real `OPENAI_API_KEY`: | Cell | Before | After | |---|---|---| | `d5:langgraph-python/auth` | red | green | | `d5:langgraph-python/frontend-tools` | red | green | | `d5:langgraph-python/voice` | red | green | Harness tests added: - `conversation-runner.test.ts` — pins the post-fix invariant: cascade probe throws while the chat input is unmounted, `preFill` makes it visible, runner then resolves and proceeds. Without the fix the runner would resolve up-front and time out. - `d5-frontend-tools.test.ts` — two new tests: accepts arbitrary green hex via channel-dominance (real-LLM nondeterminism guard), and still rejects sunset-hex emitted under the forest pill (regression guard so the fallback can't degrade into "any color passes"). All 42 tests in the affected files pass; format and oxlint both clean on touched files. ## Test plan - [ ] CI green on the `langgraph-python` D5 cron (auth, frontend-tools, voice) - [ ] Production `dashboard.showcase.copilotkit.ai` shows 3 D4 → D5 transitions on the langgraph-python column after deploy - [ ] No regression on the rest of the langgraph-python column |
||
|
|
247f061456 |
fix(showcase/langgraph-python): disable inspector on voice demo for D5 parity
The voice demo's <CopilotKit> didn't pass enableInspector, so
shouldShowDevConsole(undefined) defaulted to isLocalhost(), which
auto-mounts <cpk-web-inspector> on any local Docker host
(localhost:3100 in showcase compose). The inspector overlay
intercepts pointer events on top of the voice sample-audio button,
so dev/D5 probe runs can't click it through Playwright.
Production isn't localhost, so the inspector never mounts there —
voice is D5 in prod and D4 locally for this reason alone. Set
enableInspector={false} explicitly so the demo behaves the same in
both environments.
Probe result: d5:langgraph-python/voice flips green.
|
||
|
|
2e27b8c7c2 |
fix(showcase/harness): accept arbitrary green hex via channel-dominance fallback
PILL_GRADIENT_HINTS pinned the fixture/aimock output deterministically with a fixed substring list (color words + the exact hex codes from the fixtures). Real OpenAI emits any chromatic-family hex (e.g. forest as '#005f00 / #4caf50') that the fixed substring list can't enumerate, so the assertion failed for valid green output. Add a channel-dominance fallback: parse all 6-digit hex codes from the gradient and accept when at least one satisfies the per-pill RGB rule (g > r && g > b for forest, r > g && r > b for sunset, b > g or purple-channel for cosmic). MIN_DOMINANCE_DELTA + MIN_DOMINANT_VALUE prevent near-grey or near-black hexes from cross-matching. Word and fixture-hex match still runs first; channel-dominance is the fallback only. Probe result: d5:langgraph-python/frontend-tools flips green. |
||
|
|
8b095e1340 |
fix(showcase/harness): defer chat-input cascade until after preFill
Idiomatic auth demos (langgraph-python) render a SignInCard until the user clicks 'Sign in with demo token' — the chat textarea only mounts after that click, which preFill performs. The conversation runner was resolving the chat-input cascade up front, before any turn-level preFill ran, so the cascade timed out at 5s on SignInCard and turn 1 failed with 'chat input not found'. Move resolution and the initial assistant-message baseline into the per-turn loop, lazy on first turn. Subsequent turns reuse the cached selector. Probe result: d5:langgraph-python/auth flips green. |
||
|
|
f5987af1fd |
chore(showcase): snippet sweep pre-cutover (region markers + state-streaming unsupported flips) (#4717)
## Summary Closes the remaining yellow-box snippet gaps in shell-docs ahead of the Tue 5/12 cutover. Replaces 5 individual one-PR-per-framework attempts with a single consolidated PR. ## What's in here **Region marker additions** (5 commits, comment-only changes — zero runtime impact): - `claude-sdk-typescript` `gen-ui-interrupt::backend-tool-call` — sibling teaching file (no per-demo backend in claude-sdk-ts; mirrors claude-sdk-python's Strategy B SYSTEM_PROMPT shape) - `langroid` `gen-ui-interrupt::backend-tool-call` — in-place around the existing `ScheduleMeetingTool` `ToolMessage` subclass (preserves langroid's idiom — no forced LangGraph shape) - `pydantic-ai` `gen-ui-tool-based::bar-chart-renderer` — sibling teaching file (production demo is haiku-generator via `useFrontendTool`, not a `useComponent` bar-chart) - `spring-ai` `shared-state-streaming` (2 regions: `frontend-use-coagent-state` + `state-streaming-middleware`) — in-place; backend Java file already in `manifest.yaml` `highlight:` - `strands` `gen-ui-interrupt::backend-tool-call` — in-place around the canonical `@tool def schedule_meeting` All follow the [Mastra Round playbook](https://www.notion.so/34f3aa38185281c0b41dc6b6c63c89c6) for in-place vs sibling decisions. **Catalog flips** (2 commits, manifest-only): - 11 non-LangGraph frameworks: move `shared-state-streaming` from `features` to `not_supported_features` (ag2, agno, claude-sdk-{python,typescript}, crewai-crews, langroid, llamaindex, mastra, ms-agent-{dotnet,python}, pydantic-ai) - 6 more without working demos: built-in-agent, google-adk, strands, langgraph-typescript, langgraph-fastapi, spring-ai - Per team's call 2026-05-07: state-streaming only works on LangGraph variants currently. Anything without a working demo gets the blue `UnsupportedBox` instead of yellow `Missing snippet` warnings. Engineering can flip these back to `features` once impls land. Final catalog state for `shared-state-streaming`: 17 unsupported, 1 wired (`langgraph-python` — canonical reference). ## Why now This PR is cutover-blocking. Sam's bar for Tuesday: zero yellow boxes anywhere in shell-docs. The current state had 33+ yellow boxes from the post-2026-04-29 audit refresh; this PR drives that to zero (in conjunction with the previously-merged PDX-122 fix in #4685). ## Verification - `npx tsx showcase/scripts/bundle-demo-content.ts` — all newly-marked regions resolve in `demo-content.json` - `npx tsx showcase/scripts/generate-registry.ts` — catalog regenerates clean with the manifest changes - Generated `catalog.json` files are gitignored artifacts; not in this diff ## Test plan - [ ] Build shell-docs locally: `cd showcase/shell-docs && npm run build` clean - [ ] Visit a few `shared-state/streaming.mdx` pages on framework variants — should render the blue "Not supported on X" box for the 17 unsupported frameworks - [ ] Visit `langgraph-python/shared-state/streaming.mdx` — should still render the working snippets - [ ] Visit the 4 fixed B-cell pages (claude-sdk-typescript/langroid/strands `human-in-the-loop/useInterrupt.mdx`, pydantic-ai `generative-ui/tool-based.mdx`, spring-ai `shared-state/streaming.mdx`) — all snippets resolve, no yellow boxes |
||
|
|
afcc7e4880 |
feat(shell-docs): add sitemap, robots, and per-framework self-canonical metadata (#4703)
## Summary
Phase 3 of the docs.copilotkit.ai cutover. Surfaces a complete sitemap,
basic robots config, and per-framework self-canonical metadata so every
URL variant is indexed under its own canonical instead of collapsing
onto a single root.
- **sitemap.ts** — emits one entry per (root URL × framework variant)
pair plus reference, AG-UI, and per-framework override pages.
`lastModified` resolves from MDX frontmatter \`lastmod\` first, then
file mtime, then \`new Date()\`. Strips Next.js route-group \`(name)\`
segments and trailing \`/index\` so URLs match what the routers actually
serve. ~2,250 entries.
- **robots.ts** — allow all, disallow \`/api/\`, sitemap pointer at
\`\${NEXT_PUBLIC_BASE_URL}/sitemap.xml\`.
- **sitemap-helpers.ts** — shared MDX walking + base-URL resolution.
- **generateMetadata()** added to the four catch-all docs routes
(\`[[...slug]]\`, \`[framework]/[[...slug]]\`, \`reference/[...slug]\`,
\`ag-ui/[[...slug]]\`). Each sets \`alternates.canonical\` to the page's
own full URL — per-framework self-canonical, not root canonical. So
\`/langgraph-python/quickstart\` declares itself canonical,
\`/agno/quickstart\` declares itself canonical, and the bare
\`/quickstart\` declares itself canonical too.
- **.env.example** — documents \`NEXT_PUBLIC_BASE_URL\` and
\`NEXT_PUBLIC_SHELL_URL\`. Extended the existing comment in
\`next.config.ts\` with the new consumers.
## Test plan
- [x] \`npm run build\` from \`showcase/shell-docs/\` passes; route
table shows \`/sitemap.xml\` and \`/robots.txt\` as static.
- [x] \`curl http://localhost:3099/sitemap.xml\` returns valid XML;
2,254 \`<url>\` entries covering bare unscoped, framework-scoped,
reference, and AG-UI URLs; no \`(other)\` route-group leakage; no
trailing \`/index\` artifacts.
- [x] \`curl http://localhost:3099/robots.txt\` returns the expected
User-Agent / Allow / Disallow / Sitemap config.
- [x] \`/shared-state\` HTML contains \`<link rel="canonical"
href=".../shared-state">\`.
- [x] \`/langgraph-python/quickstart\` HTML contains \`<link
rel="canonical" href=".../langgraph-python/quickstart">\` (NOT pointing
at the bare \`/quickstart\`).
- [x] \`/agno/quickstart\` and \`/reference/components/CopilotChat\` and
\`/ag-ui/concepts/architecture\` all self-canonical.
|
||
|
|
a6a74c513d |
chore(reference): handle langgraph_agent → langgraph_agui_agent rename (#4701)
## Summary - Updates the V1 reference autogen entry in `scripts/docs/lib/files.ts` for the upstream rename of `sdk-python/copilotkit/langgraph_agent.py` to `langgraph_agui_agent.py`. The class also renamed from `LangGraphAgent` to `LangGraphAGUIAgent` (now subclasses the upstream `LangGraphAgent`). - Updates `sourcePath`, `destinationPath` (now `LangGraphAGUIAgent.mdx`), `title`, `description`, and `pythonSymbols` to match. - Regenerates `showcase/shell-docs/src/content/reference/sdk/python/LangGraphAGUIAgent.mdx`. The autogen run now reports 26/26 entries succeeding (was 25/26 — the previous entry failed silently via `Promise.allSettled` because the source file no longer existed). Stacked on top of #4693 (autogen-retarget). Once that lands this PR can be retargeted at `main`. ## Test plan - [x] `tsx scripts/docs/gen.ts` from repo root succeeds with `All reference docs processed (26/26 succeeded)`. - [x] `npm run build` in `showcase/shell-docs/` clean (Next build prerendered 27/27 routes). - [ ] Spot-check rendered `/reference/sdk/python/LangGraphAGUIAgent` on a dev server. Note: the new `LangGraphAGUIAgent` class in `sdk-python` does not yet carry a class-level docstring, so the generated MDX is currently frontmatter-only. Adding a docstring upstream will populate the page on the next pipeline run. |
||
|
|
d35e114e93 |
feat(reference): retarget V1 reference autogen pipeline to shell-docs (#4693)
## Summary
Two commits porting the V1 reference autogen pipeline so it writes into
shell-docs instead of the legacy upstream tree. Without this,
`/reference/v1/*` URLs (around 20k pageviews per quarter on
`docs.copilotkit.ai`) would 404 or 301 to a stub on shell-docs after the
cutover.
- `c30613c8d` Retarget the autogen pipeline. `scripts/docs/gen.ts` is
the entrypoint; `scripts/docs/lib/files.ts` carries the `REFERENCE_DOCS`
array with hardcoded `destinationPath` strings. Switched all
destinationPath strings from `docs/content/docs/reference/v1/...` to
`showcase/shell-docs/src/content/reference/v1/...`. Routing was verified
via `src/app/reference/[...slug]/page.tsx` (which reads from
`src/content/reference/`, not the legacy `content/docs/reference/`
tree). Anchored cwd to repo root in `gen.ts` to fix a latent
path-resolution bug that had broken the pipeline upstream too. Switched
the orchestration to `Promise.allSettled` so one source-rename rot
doesn't abort the rest.
- `55e72eeec` Lefthook auto-format pass.
## What this generates
25 of 26 V1 reference docs land in
`showcase/shell-docs/src/content/reference/v1/`:
- 20 under `reference/v1/{components,hooks,classes}` (TypeScript-source
autogen)
- 5 under `reference/v1/sdk/python/` (Python-source autogen)
The 26th entry (`sdk-python/copilotkit/langgraph_agent.py` to
`langgraph_agui_agent.py` rename) is tracked separately as a follow-up.
## Test plan
- [ ] `npm run build` from `showcase/shell-docs/` clean.
- [ ] Visit `/reference/v1/hooks/useCopilotAction`,
`/reference/v1/classes/CopilotRuntime`,
`/reference/v1/components/chat/CopilotChat`,
`/reference/v1/sdk/python/LangGraph` on the dev server. Confirm full
content renders.
- [ ] Re-run `tsx scripts/docs/gen.ts` on a clean checkout. Confirm
25/26 entries succeed; the LangGraph SDK Python entry fails gracefully
without aborting the rest.
## Timing note
Merging this pre-cutover means upstream's
`docs/content/docs/reference/v1/*` MDX files freeze at their current
state. If anyone re-runs autogen between now and 5/12 the regenerated
MDX goes to shell-docs only. V1 surface is stable so the practical risk
is small, but the safest move is to hold this PR until cutover day. Open
question for review.
|
||
|
|
e69cdd660d |
chore(README): Update video asset the the "What is CopilotKit" section (#4698)
Updated AG-UI Protocol link and asset URL in README. <!-- Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. **Please PLEASE reach out to us first before starting any significant work on new or existing features.** By the time you've gotten here, you're looking at creating a pull request so hopefully we're not too late. We love community contributions! That said, we want to make sure we're all on the same page before you start. Investing a lot of time and effort just to find out it doesn't align with the upstream project feels awful, and we don't want that to happen. It also helps to make sure the work you're planning isn't already in progress. As described in our contributing guide, please file an issue first: https://github.com/ag-ui-protocol/ag-ui/issues Or, reach out to us on Discord: https://discord.com/invite/6dffbvGU3D You can learn more about contributing to copilotkit here: https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md Happy contributing! --> ## What does this PR do? (Describe the changes introduced in this PR) ## Related PRs and Issues - (Direct link to related PR or issue, if relevant) ## Checklist - [ ] I have read the [Contribution Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md) - [ ] If the PR changes or adds functionality, I have updated the relevant documentation - [ ] "Allow edits by maintainers" is checked (lets us help iterate on your PR directly — faster turnaround for everyone) |
||
|
|
7155da28df |
fix(showcase): realign D5 probes/fixtures with idiomatic langgraph-python demos (#4723)
## Summary Five targeted fixes for the post-merge red rows on langgraph-python's D5 column, all driven from PB error-class diagnostics on the cycles after #4718 + #4722. Each is independently load-bearing. - **chat-css**: probe selector now matches v2's PREFIXED utility classes (`cpk:bg-muted`) instead of bare `bg-muted`. - **gen-ui-agent**: probe rewritten for the `last-write-wins` reducer model — drop the cross-pill baseline assumption, assert ≥ 2 visible rows + content fingerprint dedup. - **gen-ui-headless-complete**: chip click via stable `aria-label` attribute, not text-content chained selector. - **shared-state-streaming**: fixture argument key was `content`, but `write_document(document: str)` tool expects `document` — renamed in both per-feature fixture and `d5-all.json`. - **reasoning-display**: fixture now emits a `reasoning` field so aimock fires REASONING_MESSAGE_* events; probe's `[data-testid="reasoning-block"]` mounts only when a reasoning-role message lands. The remaining 6 reds (auth, frontend-tools, gen-ui-open*, agent-config, beautiful-chat-toggle-theme, beautiful-chat-search-flights, gen-ui-declarative, tool-rendering-{default,custom}-catchall, gen-ui-interrupt) need either runtime debugging or more investigation; they're tracked separately. ## Test plan - [ ] Land + watch the next e2e-deep cycle in PB - [ ] Confirm chat-css, gen-ui-agent, gen-ui-headless-complete, shared-state-streaming, reasoning-display all flip green - [ ] No regression on previously-green features 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
e60332bf02 |
fix(showcase): realign D5 probes/fixtures with idiomatic langgraph-python demos
After PR #4718 + the timeout bump in #4722 unblocked the abort-cascade, post-merge cycles surfaced the real per-probe failures that were previously hidden. Each fix here is targeted at one real failure mode identified from PB error class + message: * chat-css: HALCYON probe selector was `[class~="bg-muted"]`, but v2 emits PREFIXED utilities (`cpk:bg-muted`). Whole-token match on the prefixed name (`[class~="cpk:bg-muted"]`) fixes both the static USER_BUBBLE_INNER_SELECTOR and the page.evaluate selector — and is unambiguous against `cpk:bg-muted-foreground` on nested children. * gen-ui-agent: probe assumed `agent-step` DOM rows accumulated across pills (delta ≥ 2 vs. pre-pill baseline). The backend's `set_steps` reducer is `last-write-wins` (per `gen_ui_agent.py`), so each pill REPLACES `state.steps` and the DOM swaps. delta was always 0 after pill 1, even when the new steps rendered correctly. Drop the baseline-capture preFill, assert ≥ 2 visible rows + per-pill fingerprint dedup. Tests rewritten to match the swap model. * gen-ui-headless-complete: chip click used `button >> text="<title>"` (Playwright chained selector). The button has a stable `aria-label="Suggestion: ${title}"` attribute set inline; switch to `button[aria-label="Suggestion: ${title}"]` so we match the moment the DOM exists rather than waiting for inner text-node hydration. * shared-state-streaming: fixture sent `{"content": "..."}` but the langgraph-python `write_document(document: str)` tool expects `document`. Mismatch meant `state.document` never updated; probe saw no content delta. Rename the argument key to `document` in both the per-feature fixture and `d5-all.json` (the runtime fixture). The middleware's `tool_argument="document"` config requires this name. * reasoning-display: fixture only emitted `content` (text response). Probe asserted the v2 `<ReasoningBlock>` (rendered behind `[data-testid="reasoning-block"]`), which mounts only when a reasoning-role message lands in the transcript. Add a `reasoning` field so aimock emits REASONING_MESSAGE_* events. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
90dba50dee |
fix(showcase/harness): raise e2e-deep outer timeout 3min → 10min (#4722)
## Summary - PR #4718 took langgraph-python's D5 feature set to ~28; with FEATURE_CONCURRENCY=2 that's ~210s wall-clock, blowing the prior 3-min outer cap. - Post-merge run confirmed: 17 features flipped green, ~10 hit `errorClass: "abort"` (cascade where the global cap fires before the per-feature loop reaches them). - Bump outer cap to 10 min. Per-feature 5-min cap still bounds wedged features. Lighter integrations exit early so cycle wall-clock barely changes. ## Test plan - [ ] Land + watch the next e2e-deep cycle in PB - [ ] Verify the 10 abort-cascade features (auth, agent-config, voice, multimodal, gen-ui-open, gen-ui-open-advanced, beautiful-chat-pie-chart/bar-chart/search-flights/schedule-meeting) flip from `errorClass: "abort"` to either green or a real `errorClass` - [ ] Confirm other integrations' cycle wall-clock stays unchanged 🤖 Generated with [Claude Code](https://claude.com/claude-code) |