Commit Graph

110 Commits

Author SHA1 Message Date
Jordan Ritter 510bb88553 fix(showcase): use each integration's own name in demo page titles
14 integrations' `src/app/demos/layout.tsx` hardcoded "LangChain - Python"
in `generateMetadata` — a copy-paste leftover from langgraph-python, which
the file was cloned from. Every `/demos/*` page in mastra, strands, ag2,
agno and 10 others rendered `<title>LangChain - Python</title>`.

Each now uses the display name from its own `manifest.yaml` `name:` field,
matching the convention the already-correct integrations use
(langgraph-typescript -> "LangGraph (TypeScript)", strands-typescript ->
"AWS Strands (TypeScript)").

langgraph-python itself is included: its manifest name and root layout both
say "LangGraph (Python)", so "LangChain - Python" (the legacy Notion
partner-column label) was stale there too.
2026-07-24 16:19:17 -07:00
Tyler Slaton 0f5a916075 fix(docs): clean Claude generative UI snippets 2026-07-08 20:38:13 -07:00
Jordan Ritter 9cbebe3d36 fix(showcase): gate per-request proxy logging behind SHOWCASE_ROUTE_DEBUG
Gates per-request POST + 2xx Response-status + GET health-probe logs behind SHOWCASE_ROUTE_DEBUG across 19 integrations to stay under Railway's 500-logs/sec cap, while logging non-2xx responses unconditionally so production errors stay visible.
2026-07-06 12:15:05 -07:00
Ran Shem Tov b985449e50 feat(showcase): add A2UI Error Recovery demo for langgraph + strands
Port the google-adk a2ui-recovery demo to langgraph (python, fastapi,
typescript) and aws-strands (python, typescript). Each ships a dedicated
recovery agent, route, demo page/chat/suggestions, manifest entry, aimock
d6 fixtures, e2e spec, and QA doc.

Backend-owned recovery on langgraph via get_a2ui_tools / getA2UITools
(injectA2UITool=false); auto-inject recovery on the strands adapter path.
Heal stages an invalid-then-valid render via aimock sequenceIndex (the
toolkit validate->retry loop rejects the whole surface, so a single-pass
parse_and_fix heal is ADK-specific and does not apply here). Recovery
prompts are unique per framework and the fixtures carry no context match
field, so they fire for real browser (dojo) traffic, not just the harness.

Also harden the strands declarative-gen-ui composition guide to name the
exact catalog component (Metric, not MetricTile) and update the
generate-catalog + aimock-fixtures test expectations.
2026-06-26 16:17:58 +02:00
Jordan Ritter 5057efce1a fix(showcase): render post-sign-out auth rejection across showcase integrations
The auth demo capped at D4 across integrations because the post-sign-out
rejection banner never rendered. The post-sign-out `agent_run_failed` is
delivered only on the agent-scoped `<CopilotChat onError>` channel — never the
provider-level `<CopilotKit onError>` the demos listened on — so the D5/D6 auth
probe's rejection-surface assertion failed and the cell was capped at D4.

Fix (applied to all 19 integrations whose auth demo reproduced the bug): wire a
stable `handleAuthError` onto the agent-scoped `<CopilotChat onError>` (keeping
the provider handler), key the error surface off auth-error STATE alone with a
clear-on-auth effect (removing the `&& !isAuthenticated` cross-slice race), and
harden the rejection-banner message fallback against nullish error events.

Scope: 19 of 20 integrations. built-in-agent already passes (renders via its
ChatErrorBoundary); claude-sdk-python adapted to its legacy/error-boundary shape.
2026-06-25 20:34:01 -07:00
Ran Shem Tov 24a93672f1 feat(showcase): bump CopilotKit 1.61.1 -> 1.61.2 and adopt A2UI catalog auto-inject (#5611)
Bump the canonical CopilotKit pin across all showcase integrations + shell
to 1.61.2 (canonical-pins.json, every package.json + package-lock.json),
which carries CopilotKit#5611: passing a catalog to the provider
(`<CopilotKit a2ui={{ catalog }}>`) now auto-enables A2UI and defaults tool
injection on, so the runtime no longer needs an explicit `a2ui` config.

Demonstrate the feature on the A2UI dynamic (declarative-gen-ui) demos by
removing the now-redundant runtime `a2ui` block (`injectA2UITool: true` +
`defaultCatalogId`) from:
  - langgraph-python, langgraph-fastapi, langgraph-typescript
  - strands, strands-typescript
  - google-adk

The forwarded catalog supplies its own catalogId (sdk-js A2UI middleware
auto-derives `defaultCatalogId` from it), so the previous "Catalog not found"
fallback no longer applies.

Verified: validate-pins drift ratchet unchanged (38 / same hash);
langgraph-python D6 `gen-ui-declarative` green end-to-end (no Catalog-not-found).
2026-06-25 14:03:36 +02:00
Jordan Ritter 6fbd66fa83 fix(showcase): mirror useInterrupt RESUME-PATH contract in 13 demo-local hooks
Each integration's interrupt-headless demo defines a local useHeadlessInterrupt
hook around the framework useInterrupt. Slot-2 originally identified 8
quarantined integrations (claude-sdk-typescript, langgraph-{fastapi,python,
typescript}, langroid, pydantic-ai, spring-ai, strands); review-round
follow-ups extended the sweep to llamaindex, mastra, ag2, agno, and
crewai-crews (5 more integrations sharing the same byte-identical hook).

The demo-local resolve() previously fire-and-forgot copilotkit.runAgent(...)
via `void runAgent(...).catch(() => {})`. Mirroring the framework fix:

- Make resolve async, return await copilotkit.runAgent(...).
- Use a pendingRef so resolve has stable identity (drop pending from
  useMemo deps).
- Type signature: resolve: (response: unknown) => Promise<unknown>.
- Wrap in try/catch + setPending(null) + console.error + rethrow,
  symmetric with the framework hook.
- onRunFailed also setPending(null).

13 integrations patched byte-identically.
2026-06-15 17:11:40 -07:00
Jordan Ritter 0f58f04e50 fix(showcase/renderers): stable row keys + per-card id + no-silent-zero charts
- DataTable rowKey uses first-column value + index instead of bare index,
  with JSON.stringify(row) fallback (stops re-mount on dynamic A2UI re-emits)
- Card emits data-card-id={props.title} so multi-card pills no longer
  collide on a single declarative-card testid
- PieChart/BarChart value coercion replaced 'Number(x) || 0' with
  finite-number check + console.warn on drift (no longer masks legitimate 0)
2026-06-15 09:35:45 -07:00
Jordan Ritter 8711326b5f fix(showcase/a2ui): tighten Zod schemas
- PrimaryButton.action: z.any() -> z.unknown() (forces caller narrowing)
- Row.justify/align + Column.align: z.string() -> z.enum() matching the
  renderer's CSS map
- DataTable rows accept numeric cells (z.union([string, number]))
- DataTable column-key refine documented in description (host
  CatalogComponentDefinition requires ZodObject, blocks .refine)
2026-06-15 09:35:45 -07:00
Jordan Ritter 0964823f3c fix(showcase/sales-context): honest duplication notice + extract TODO
Replace the misleading 'single source of truth' claim with an explicit
DUPLICATION NOTICE describing the per-integration parity convention and
a TODO(OSS-136) for the future shared-module extraction. Both copies
remain byte-identical.
2026-06-15 09:35:44 -07:00
Maxim 954e3b613d feat(showcase): align card internals and add severity icons to StatusBadge
Override the basic catalog's Text (its built-in 8px margin misaligned
card rows), keep badges content-sized instead of stretched by flex
parents, and prefix each badge with a hardcoded lucide icon per variant
(error/warning/success/info). Renderer-only — payloads and fixtures are
unaffected.
2026-06-13 00:16:54 +02:00
Maxim 1e0d200f53 feat(showcase): dashboard-grade surfaces on every declarative-gen-ui pill
Hero loses its surrounding card (bare KPI strip over the chart cards,
pinned to all six months); team performance pairs the rep table with a
quota-attainment bar chart; top account pairs the fact card with a
product-line pie (new dataset entry); at-risk becomes a risk panel — KPI
strip (ARR at risk / accounts / biggest exposure) over three side-by-side
severity cards with reason + next action. Fixtures re-captured from live
responses; D5 probe drops declarative-card from the hero set; e2e asserts
the accompanying charts and the risk panel; QA docs updated.
2026-06-13 00:16:53 +02:00
Maxim 06c819d0fb feat(showcase): match declarative-gen-ui renderers to beautiful-chat's sales dashboard
Ports beautiful-chat's exact visual language into the catalog renderers:
DashboardCard chrome (12px radius, 20px padding, soft shadow) for Card and
chart wrappers, its Metric typography with colored trend deltas, a recharts
donut (innerRadius 40, paddingAngle 2, tooltip, no legend) replacing the
custom SVG donut, and uniform blue bars on a dashed grid. E2E pie
fingerprints move from circle/legend assertions to recharts sectors; the
hero surface-count guard allows the two ResponsiveContainers (pie + bar)
one composed dashboard now produces.
2026-06-13 00:16:53 +02:00
Maxim 4de75ff900 feat(showcase): rework declarative-gen-ui demo into a sales-analyst dashboard (OSS-136)
The demo now plays an embedded sales analyst for a fictional company:
suggestion pills are natural business questions (chart-type steering moved
from user prompts into the system prompt), the hero pill composes a full
dashboard (KPI metrics + pie + bar in one surface) modelled on
beautiful-chat's sales dashboard, and the catalog gains DataTable,
gap-aware Row/Column, Metric trendValue, and the beautiful-chat palette.
Dataset + composition rules ship as frontend agent context
(sales-context.ts) so they reach both the primary agent and the secondary
A2UI planner in LGP and ADK alike. E2E specs and QA docs updated to the
new pill set.
2026-06-13 00:14:47 +02:00
Mark Fogle fb3d64ef83 fix(showcase): pin page-registered A2UI catalog as defaultCatalogId fleet-wide
The injected render_a2ui tool guide instructs models to omit catalogId
("the catalog id is set by the host"), and backend-owned generate_a2ui
tools see real models omit or late-stream it. Without defaultCatalogId
the a2ui middleware falls back to the spec basic catalog, which no
showcase page registers — surfaces fail with "Catalog not found:
https://a2ui.org/specification/v0_9/basic_catalog.json" (reported on
beautiful-chat / langgraph-python).

Pin each route to the catalog its page registers: beautiful-chat ->
copilotkit://app-dashboard-catalog, declarative-gen-ui ->
declarative-gen-ui-catalog. Routes with no a2ui block never attach the
middleware and are left untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 18:32:14 +00:00
Ran Shem Tov efd35f0f8d chore: align all a2ui instances with the latest implementations 2026-06-05 17:54:16 +02:00
Ran Shem Tov 20aa327a8c fix(showcase): enable injectA2UITool for langgraph-python declarative-gen-ui
It was left at false while fastapi/typescript are true. Under the opt-in
A2UI model false means no tool is injected, so the python demo rendered
no surfaces (and the docs code-tab showed no injectA2UITool). Set true to
match the other langgraph integrations.
2026-06-05 11:25:23 +02:00
Ran Shem Tov 02b11c985d feat(showcase): drive dynamic A2UI via CopilotKitMiddleware (langgraph)
The declarative-gen-ui demo across the three langgraph integrations now
relies on the middleware to inject and execute generate_a2ui — the agents
collapse to create_agent + CopilotKitMiddleware with no hand-rolled tool.
Adds render_a2ui fixtures for the new tool path and pins the integrations
to the A2UI alpha SDKs (copilotkit 0.1.94a1, @copilotkit/sdk-js 1.59.3-alpha.1).
2026-06-04 18:36:12 +02:00
Martha Schumann daff12758a fix(showcase): use uuid explicit thread demo id 2026-05-27 12:53:06 -07:00
Martha Schumann a879b8a062 test(react-core): tighten thread roundtrip coverage 2026-05-27 10:49:20 -07:00
Martha Schumann 24d93b52ad fix(react-core): preserve generated thread tool followups 2026-05-27 10:27:29 -07:00
Sam Julien 4680eb9c16 fix(showcase/headless-complete): tag page-send-message region
The programmatic-control docs page renders a yellow "Missing snippet"
box on the langgraph-python and google-adk variants because their
headless-complete cells were never tagged with the page-send-message
region the MDX requests. Add matching @region / @endregion markers
around the useAgent / useCopilotKit / send / reset block in
chat/chat.tsx so the Snippet component resolves on both integrations.
2026-05-22 15:32:04 -07:00
Tyler Slaton 64ffd19d8c fix(showcase): CR Round 2 cleanup — ADK reasoning graph name + dead CSS + comment + log tag
CR Round 2 confirmation surfaced one bucket (a) finding plus three
bucket (b) trivials worth rolling in together.

(a) `google-adk/src/app/demos/reasoning-{default,custom}/page.tsx`
    comments said "Both demos share the same backend (`reasoning_agent`
    graph)". That graph name is the langgraph-python convention —
    `reasoning_agent.py` in LGP — but the ADK demo doesn't have a
    graph by that name. `src/agents/registry.py:144-145` maps both
    `reasoning-custom` and `reasoning-default` to
    `AgentSpec(_thinking_chat)`, where `_thinking_chat` is built via
    `build_thinking_chat_agent`. Round 1 fixed the same class of bug
    in langgraph-typescript (which uses `agentic-chat-reasoning`) but
    missed ADK; this is the matching fix.

(b1) `.../headless-simple/chat.tsx` (3 files) emitted
    `console.error("[headless-simple] ...", err)` with no
    integration-slug prefix. A user testing demos across frameworks
    in the same browser session couldn't tell which integration's
    runAgent failed. Tag with the framework slug:
    `[google-adk:headless-simple]`, `[langgraph-python:headless-simple]`,
    `[langgraph-typescript:headless-simple]`.

(b2) `globals.css` lines 133-137 — the `.shell-docs-sidebar
    p[class*="sidebar-item-offset"] svg` rule (4×4 icons in accent
    purple) was dead in fumadocs v16. The v16 sidebar emits separator
    `<p>` elements with `inline-flex items-center gap-2` instead of
    the v15 `sidebar-item-offset` class fragment; the live rule on
    `p.inline-flex.gap-2 svg` (added earlier in this PR) already
    handles the same styling at the correct 16×16 size. Drop the
    dead rule.

(b3) `page-actions.tsx` — the regression-fix commit
    (`0186ae9f2`) wedged `getClientBaseUrl()` between the cache-
    describing block comment and the actual `cache = new Map(...)`
    declaration. The comment now sits above its own subject again;
    `getClientBaseUrl()` keeps its own JSDoc above its definition.

Call-site enumeration:
- ADK `_thinking_chat` reference — verified in
  `showcase/integrations/google-adk/src/agents/registry.py` (line
  144-145 + `build_thinking_chat_agent` import on line 23 + builder
  invocation on line 108). Comment-only change; no symbol signatures
  touched.
- Headless log tags — only the literal log string changes; no other
  call site reads it.
- `globals.css` dead rule — verified no other selector in the file
  depends on the removed lines (the section-header SVG color is set
  by the surviving `p.inline-flex.gap-2 svg` rule).
- `page-actions.tsx` comment move — no functional change.
2026-05-20 20:20:12 -07:00
Tyler Slaton 086e68c88b fix(showcase): log runAgent errors in headless-simple; correct LGT reasoning graph name
The Headless Simple demo's `chat.tsx` swallowed every `runAgent`
rejection with an empty arrow catch:

    void copilotkit.runAgent({ agent }).catch(() => {});

This is the canonical "two hooks, your design system" example users
copy-paste as a starting point — silent swallow modeled broken practice
to every CopilotKit user, and the @region[use-agent-simple] block we
inline into `/<framework>/headless` docs surfaces the anti-pattern as
the recommended snippet. Replace the empty catch with a
`console.error("[headless-simple] runAgent failed", err)` so network
failures, transport disconnects, and runtime errors surface in the
developer's console. Applied across google-adk, langgraph-python, and
langgraph-typescript variants.

`langgraph-typescript/src/app/demos/reasoning-default/page.tsx` had a
comment claiming the demo backed onto the `reasoning_agent` graph, but
the LGT route map in `src/app/api/copilotkit/route.ts` actually points
both `reasoning-default` and `reasoning-custom` at the
`agentic-chat-reasoning` graph (the companion `reasoning-custom/page.tsx`
comment already gets this right). The `reasoning_agent` label is the
Python / ADK convention. Update the comment to match the TS route map.

Call-site enumeration:
- `copilotkit.runAgent` (in headless-simple/chat.tsx, 3 files) — the
  return value is `Promise<void>`; existing callers don't await it, so
  swapping the catch is non-breaking. The previous `void` operator
  already discarded the promise value, so the runtime behavior of the
  surrounding `send()` is unchanged.
- LGT `reasoning-default` page.tsx — comment-only change, no symbol
  signatures touched.
2026-05-20 19:59:23 -07:00
Tyler Slaton 5728611dfd feat(shell-docs): upgrade to fumadocs 16 / next 16, polish layout, add llms.txt + page actions
Stack upgrade
- fumadocs-core/ui 15.8.5 → 16.8.12, next 15 → 16 (Turbopack), react 19 → 19.2
- Swap "next lint" → "oxlint ." to match the rest of the repo
- New deps for the page-actions component: @radix-ui/react-popover,
  class-variance-authority, clsx, tailwind-merge

Layout & brand polish
- Sidebar floats as a rounded-2xl card with column-aligned padding;
  framework picker pill, accent-purple section icons (16px), accent
  active state, and a single divider line at the footer
- New custom <ThemeSwitch> — single 50×28 neutral switch replaces the
  fumadocs sun/moon split (drops the vertical divider and purple tint)
- Sidebar folder collapse state persists across navigations via
  SidebarFolderStatePreserver
- BrandNav: wider top bar, lowercase "Talk to an engineer", BookIcon
  for Docs, GitHub/Discord icons rendered inline in our footer row
- Mobile: nav clipping + content padding fixes, content grid-span-full
- TOC-less pages: lift article max-width so content stretches into the
  empty TOC column on wide viewports

New routes
- /llms.txt — page index per fumadocs LLMs integration
- /llms-full.txt — concatenated full text of every docs page
- /<path>.md and /<path>.mdx — per-page raw markdown with <Snippet>
  regions inlined as fenced code blocks (resolver in lib/llm-text.ts
  reuses the same demo-content.json the <Snippet> runtime reads)
- Page-actions bar: Copy Markdown + Open in Claude / Claude Code /
  Windsurf / Codex (Codex links to https://chatgpt.com/codex for
  universal coverage)

Content fixes
- Reasoning page (generative-ui/reasoning.mdx): rewrite to point at
  the real reasoning-default / reasoning-custom cells instead of the
  stale agentic-chat-reasoning / reasoning-default-render names
- Strip <FeatureIntegrations /> chip list ("SUPPORTED BY ...") from
  16 docs MDX files (component definition kept in mdx-registry)
- Drop hideTOC: true from 11 pages so they pick up the lifted-cap rule
- Default home (/) to the built-in-agent authored sidebar; fix active
  state matching on the home url
- Restore default fumadocs Callout (drop the bespoke docs-callout)
- OpsPlatformCTA redesign — light bordered card with accent stripe
- FrameworkOverview redesign — drop atmospheric chrome, smaller hero
- Homepage / docs-landing redesign

Integrations (LGP / LGT / ADK)
- Tag @region[default-reasoning-zero-config] in reasoning-default and
  @region[reasoning-block-render] in reasoning-custom for all three
  frameworks so the docs <Snippet> calls resolve
- Tag @region[use-agent-simple] + @region[message-list-simple] in
  headless-simple and @region[use-rendered-messages-hook] +
  @region[manual-tool-call-rendering] +
  @region[manual-activity-message-rendering] + @region[custom-bubbles]
  across headless-complete

Other
- docs/components/layout/mobile-sidebar.tsx: lowercase "engineer" to
  match shell-docs
- .claude/launch.json + .claude/preview/ — dev launch configs for the
  worktree so /preview brings up shell-docs on :3003
2026-05-20 19:32:18 -07:00
Tyler Slaton 1a534ba9dd Merge remote-tracking branch 'origin/main' into tyler/laughing-burnell-67b26b
# Conflicts:
#	showcase/integrations/strands/package-lock.json
2026-05-20 12:55:00 -07:00
Jordan Ritter 662f757cd6 fix(showcase): un-skip gen-ui-interrupt tests — fix provisional agent race + resolve timing
Wait for CopilotKit runtime POST to complete before interacting so
messages aren't silently dropped by the provisional agent stub.
Defer resolve() via setTimeout so React commits the picked/cancelled
badge before useInterrupt unmounts the card. Add candidateSlots() to
the TS interrupt-agent to match the Python agent. Parse JSON-stringified
interrupt values in interrupt-headless. Default playwright configs to
local aimock.
2026-05-20 09:31:09 -07:00
Jordan Ritter 3889d934e8 fix(showcase/langgraph-python): fix selector mismatches in e2e tests
tool-rendering-default-catchall: page.tsx had inline 3-pill config but
suggestions.ts exists with 4 pills (including "Chain tools"). Switched
page.tsx to import useSuggestions() from ./suggestions so all 4 pills
render, matching the test expectations.

frontend-tools: test used stale selectors ("background-container",
"var(--copilot-kit-background-color)", "Change background" pill) that
didn't match the actual demo code. Updated test to use the real
data-testid ("frontend-tools-background"), real default ("#4f46e5"),
and real pill names ("Sunset/Forest/Cosmic theme").
2026-05-17 09:58:23 -07:00
Sam Julien 34b641874d fix(showcase): unified hoist across all integrations and sibling snippet files
Run the unified hoist codemod over showcase/integrations/* and adjacent
source roots (src/lib, src/agent, src/mastra, src/main/java for Spring AI,
agent/ for ms-agent-dotnet). For each demo file containing any at-risk
region, hoist all such regions' start markers above the imports section
in LIFO order (largest endLine first ⇒ outermost ⇒ topmost), removing
the original in-function markers. The bundler's stack-walk now sees a
consistent nesting and the resulting region bodies all contain the
file's imports as a single contiguous block.

Also extends marker-move-up support to Java (import) and C#
(using-directive) files for Spring AI and ms-agent-dotnet's tool/agent
classes.

Manually handles two remaining sibling snippet files
(built-in-agent::a2ui-fixed-schema's a2ui-backend.snippet.ts) where the
'imports' are declare-const stubs that the codemod doesn't detect as
imports.

After this commit, of the 32 at-risk (cell, region) tuples flagged in
the QA report, 503 (integration × region) bundle slots have imports in
their bodies; 4 slots remain without imports because the source files
genuinely have no import statements (string-only prompt files in
claude-sdk-typescript subagents-prompts.ts).

Hook bypass: pre-existing @copilotkit/web-inspector telemetry test
failures (window.localStorage + jsdom) are unrelated to this commit.
2026-05-14 15:07:04 -07:00
Sam Julien e7cb02bfdd fix(showcase): include imports in demo region snippets across integrations
Apply marker-move-up across 260 demo files in 17 integrations. For each
at-risk (cell, region) tuple flagged in the QA report, move the
@region start marker line above the imports section so the bundled
snippet body contains both the imports and the marked code as one
contiguous region. End markers stay where they are.

Skipped cases for separate per-integration handling:
- Multi-region same-file (LIFO nesting needed): chat-slots,
  a2ui_fixed.py, tool-rendering/page.tsx, hitl-in-chat/page.tsx,
  subagents.py, voice route.ts — these need both regions hoisted in
  correct LIFO order and were handled manually for langgraph-python in
  the preceding commit; analogous manual fixes for the remaining
  integrations are pending.
- Files where the target region is already wrapped by an outer region
  (e.g. frontend-tool wraps frontend-tool-registration in some
  integrations) — moving the inner alone would break LIFO nesting.

Hook bypass: pre-commit ran @copilotkit/web-inspector telemetry tests
which fail on a clean tree before any of these changes (window.localStorage
not initialised under jsdom in some test cases). Pre-existing failure
unrelated to this commit.
2026-05-14 14:59:08 -07:00
Sam Julien 240d881de8 fix(showcase/langgraph-python): include imports in demo region snippets
Move @region start markers above each demo file's imports so the bundled
region body contains both the imports and the marked code as one
contiguous block. Without this, snippets rendered in shell-docs were
missing the imports they depended on (z, useState, tool, etc.), forcing
readers to guess where each symbol came from.

Where two regions share the same file and were sequential (not nested)
in the original source, both start markers now sit at the top in proper
LIFO nesting order, and the original in-function start markers are
removed to avoid duplicate region slices being concatenated by the
bundler.

Affected regions in langgraph-python:
- frontend-tool-registration (frontend-tools/page.tsx)
- definitions-zod, create-catalog, provider-a2ui-prop (declarative-gen-ui)
- definitions-types, catalog-creation, backend-schema-json-load,
  backend-render-operations (a2ui-fixed-schema + a2ui_fixed.py)
- sandbox-function-registration (open-gen-ui-advanced)
- bar-chart-renderer (gen-ui-tool-based)
- render-weather-tool, render-flight-tool, weather-tool-backend
  (tool-rendering + tool_rendering_agent.py)
- headless-useinterrupt-primitives (interrupt-headless)
- hitl-hook, time-slots (hitl-in-chat)
- backend-interrupt-tool, frontend-useinterrupt-render (gen-ui-interrupt +
  interrupt_agent.py)
- subagent-setup, supervisor-delegation-tools (subagents.py)
- context-provider-sketch (readonly-state-agent-context)
- state-streaming-middleware (shared_state_streaming.py)
- transcription-service-guard, voice-runtime (voice route.ts)

Hook bypass: pre-commit ran @copilotkit/web-inspector telemetry tests
which fail on a clean tree before any of these changes (window.localStorage
not initialised under jsdom in some test cases). Pre-existing failure
unrelated to this commit.
2026-05-14 14:54:42 -07:00
Jordan Ritter fcc2cef9b2 fix(showcase): simplify health endpoints to local-only (no agent proxy)
All 18 integration health endpoints previously proxied to the backend
agent /health with a 3s timeout, causing false reds when agents were
slow but functional. The harness already checks agent reachability
via the agent:<slug> probe. Health endpoints now return a simple 200
confirming the Next.js process is alive.
2026-05-13 23:45:26 -07:00
Tyler Slaton c41c2dec71 fix(showcase/beautiful-chat): pin canvas to "beautiful-chat" agent id so shared state renders
`<CopilotKit agent="beautiful-chat">` routes the chat to agent id
"beautiful-chat", but ExampleCanvas called `useAgent()` with no args and
fell back to DEFAULT_AGENT_ID ("default"). The frontend's agent registry
tracks state per id, so `manage_todos` state-deltas from the chat run
landed on "beautiful-chat" and never reached the canvas's "default"
subscription — the Task Manager pill auto-flipped the panel to App mode
but the To Do column stayed empty. Drop the unused "default" alias from
the runtime route and pin the canvas to `useAgent({ agentId:
"beautiful-chat" })` so both halves share one ProxiedCopilotRuntimeAgent
instance. Adds a Playwright regression test asserting the 3 verbatim
todo titles render after the pill click, plus 3 aimock fixtures for the
multi-turn flow (enableAppMode -> manage_todos -> confirmation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:04:50 -07:00
Alem Tuzlak bb6554c433 fix(showcase/langgraph-python): chain reasoning-chain demo pills end-to-end
The tool-rendering-reasoning-chain demo previously promised chained tool
calls in its pill titles but the agent and fixtures only delivered single
tools — clicking "Weather + flights to Tokyo" produced just a WeatherCard,
"Compare two stocks" only fetched AAPL, "Find flights from SFO to JFK"
showed flights but no destination weather. Three changes close the gap.

Agent: replace the soft "call 2+ tools when relevant" system prompt with
concrete per-pill chain examples mirroring the pattern already used by the
langgraph-typescript `tool-rendering` agent (weather→flights, ticker→peer,
roll→contrast die, flights→destination weather).

Pills: drop the redundant Tokyo pill (it was the SFO/JFK chain in reverse)
and reword each remaining pill message to PRE-DISCLOSE the chain so the
model commits to the follow-up call:
  - "Compare AAPL and MSFT stocks for me."
  - "Roll a 20-sided die for me and compare it to a smaller one."
  - "Find flights from SFO to JFK and show me the weather there."

Fixtures: 9 fixtures (3 per pill: final-content → second-leg → first-leg,
ordered by toolCallId specificity for first-match-wins). Each fixture is
scoped by a langgraph-python-UNIQUE userMessage tail ("Compare AAPL and
MSFT stocks", "compare it to a smaller one", "show me the weather there").
Those substrings appear nowhere else across the 14+ integrations sharing
showcase-aimock on Railway, so the new fixtures cannot cross-contaminate
the other reasoning-chain demos that still ship the older prompt set.
A toolName-based gate was considered and rejected because most fleet
agents register `roll_dice` and aimock's `toolName` matcher is a tool-LIST
gate, not a tool-CALL gate — it would NOT have isolated this demo.

Probe: collapse the two-turn flow (Tokyo + SFO/JFK) into one chained turn
(SFO→JFK + JFK weather) that asserts BOTH per-tool renderers
(FlightListCard + WeatherCard) mount in a single response. Same coverage
at half the wall-clock and exercises the actual chained-tool path.
2026-05-12 17:21:23 +02:00
Tyler Slaton 04d8008ea7 fix(showcase/langgraph-python): unbreak shared-state pills, auth sign-out, gen-ui-agent progression, multimodal D5
Four independent showcase production bugs Alem reported, plus the
D5 multimodal harness regression they unblocked.

Shared-state-read-write: "Greet me" ("Say hi and introduce yourself.")
and "Plan a weekend" ("Suggest a weekend plan based on my interests.")
were matching the bare `hi` and `plan` catch-alls in feature-parity.json
and returning the generic showcase-assistant blurb / 5-step content plan
instead of shared-state-aware responses. Added pill-specific fixtures in
shared-state.json (mirrored into d5-all.json) so the longer userMessage
substrings win first-match-wins ahead of feature-parity.

Auth sign-out: signing out unmounted CopilotKit entirely and bounced
the user back to the SignInCard, so the demo never showcased the
runtime returning 401 — its whole point. The QA contract in
qa/auth.md spelled out the intended UX. Restored it: CopilotKit stays
mounted after the first sign-in, the AuthBanner flips to an amber
"Signed out — the agent will reject your messages" state with a
re-Sign-in button, and CopilotKit's `onError` callback drives a
`data-testid="auth-demo-error"` surface that displays the runtime's
401 the moment the user sends an unauthenticated message. Updated the
e2e spec to match (the old "SignInCard re-mounts after sign-out" test
pinned the regression).

Gen-ui-agent: the aimock fixture short-circuited the 7-step
progression spelled out in `gen_ui_agent.py`'s SYSTEM_PROMPT to a
single set_steps call with all three steps already `completed`, so
the InlineAgentStateCard rendered the final 3/3 state instantly with
no sequential pending → in_progress → completed animation.
Regenerated as a 7-leg toolCallId chain per pill (8 fixtures × 3
pills): seed leg keyed on userMessage with NO `hasToolResult` gate
(matching PR #4770's pattern — `hasToolResult: false` would block the
seed from firing on the second pill in a multi-pill session), then
six toolCallId-keyed transitions, then a final narration. Fixture
order: toolCallId legs FIRST so the most specific match wins.

Multimodal D5: the sample-attachment buttons auto-send via
`agent.addMessage + copilotkit.runAgent` (restored in PR #4761), but
the D5 harness still typed `input` + pressed Enter via the runner
after `preFill`, sending a second user message that competed with the
in-flight image upload — the v1 LangGraph runtime SSE stream got
tangled (browser DevTools showed `statusCode: pending` indefinitely)
and the assistant message never rendered. Added `skipSend?: boolean`
to ConversationTurn (distinct from `skipFill`, which still presses
Enter once the textarea has content) and switched d5-multimodal.ts to
`skipSend: true` with `responseTimeoutMs: 60_000` so the runner waits
on the assistant response without poking the chat further. Bumped the
PDF auto-prompt fixture in feature-parity.json to include the word
"document" so the existing `buildModalityAssertion("document")` check
still lands.

D5 result: 37 → 39 of 40 features passing. Only
`tool-rendering-reasoning-chain` remains and is a separate
agent/runtime bug (Tokyo Responses-API `reasoning` message survives
into the next turn's conversation history, runtime returns
`RUN_ERROR: "message role is not supported"`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:16:22 -07:00
Alem Tuzlak 792ae78799 fix(showcase/langgraph-python): remove dead "Show reasoning" pill from chat-slots
The chat-slots cell is wired to the neutral sample_agent graph (plain
ChatOpenAI, no Responses API, no reasoning config), so it never emits
AG-UI REASONING_MESSAGE_* events. The pill could never light up the
wrapped messageView.reasoningMessage slot, and its prompt didn't match
any fixture in showcase/aimock/d5-all.json — aimock-backed runs hit
"No fixture matched". Drop the pill (the QA doc and the e2e spec
already only expect "Write a sonnet" and "Tell me a joke") and leave a
note pointing reasoning demos at /demos/reasoning-default and
/demos/reasoning-custom where the dedicated reasoning_agent graph lives.
2026-05-11 17:15:24 +02:00
Alem Tuzlak 9bbcf876d8 fix(showcase/langgraph-python): drop nested-flex-gap arbitrary variant
The `[&_div[style*='flex-direction:_row']]:gap-4` arbitrary variant
(quotes inside doubly-nested brackets) is the most exotic Tailwind
syntax in this PR and lines up exactly with when the Vercel
form-filling deploy started failing. Tailwind v4's content scanner is
likely choking on the apostrophes in the nested attribute selector.

The Metric `flex-1 min-w-[120px]` and the chart `flex-1 min-w-0`
already give us even distribution inside the basic catalog's gap-less
Row; the auto-injected nested gap was nice-to-have, not load-bearing.
2026-05-11 16:25:17 +02:00
Alem Tuzlak cc6dd5c4a9 Merge branch 'main' into fix/showcase-declarative-gen-ui-card-width 2026-05-11 16:03:32 +02:00
Alem Tuzlak ba5369c930 refactor(showcase/langgraph-python): make A2UI renderers fill their slot instead of widening the chat
Drop the inline <style> override that widened the chat's `cpk:max-w-3xl`
column and the outer max-w-6xl bump. The chat keeps its normal width;
the real bug was that the basic catalog's Row/Column primitives are
bare `display: flex` divs with no gap and no min-width control on
children, so when the agent dropped multiple Metrics or charts into a
Row they collapsed to content width and looked glued together.

Four targeted fixes inside our renderers:

- Metric gains `flex-1 min-w-[120px]` so a row of KPI tiles distributes
  the available width evenly inside the gap-less basic Row, instead of
  shrinking to content.
- PieChart and BarChart switch from a hardcoded max-w to `flex-1
  min-w-0` so two charts side-by-side each take half the card column
  with Recharts' ResponsiveContainer doing the rest, instead of one
  chart insisting on 640px and overflowing.
- Card's CardContent picks up a Tailwind arbitrary variant
  `[&_div[style*='flex-direction:_row']]:gap-4` (plus the column
  equivalent) that injects a gap into any nested basic Row/Column the
  agent drops in. Underscores in the arbitrary value compile to literal
  spaces, matching React's serialized inline `flex-direction: row`.
- Card itself drops the old `min-w-[260px]` floor in favour of
  `min-w-0` so it cooperates if the agent ever stacks Cards horizontally
  inside a Row.
2026-05-11 16:01:11 +02:00
Alem Tuzlak 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.
2026-05-11 15:42:06 +02:00
Alem Tuzlak 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.
2026-05-11 15:19:34 +02:00
Alem Tuzlak 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).
2026-05-11 14:54:38 +02:00
Alem Tuzlak 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.
2026-05-11 14:45:10 +02:00
Alem Tuzlak 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
2026-05-11 13:26:19 +02:00
github-actions[bot] e831c72a8f style: auto-fix formatting 2026-05-10 22:19:25 +00:00
Tyler Slaton 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>
2026-05-10 15:16:02 -07:00
Tyler Slaton 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>
2026-05-10 15:15:27 -07:00
Tyler Slaton 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>
2026-05-10 15:14:43 -07:00
Tyler Slaton 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.
2026-05-08 22:26:14 -07:00
Sam Julien 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.
2026-05-08 13:03:50 -07:00