- Replace the silent empty `catch {}` with a proper error state:
clipboard write failures now set state to "error", surface a
"Copy blocked" label for 2s, and log the original error so devs
can debug (permissions, insecure context, etc.) instead of the
button failing invisibly.
- Collapse the two booleans into a single `CopyState` so idle/copied/
error styling and aria-label stay in sync.
- Guard `reg.code` as a string before rendering; malformed
`demo-content.json` (missing `code`, stale bundle) now produces a
visible WarningBox instead of crashing React on `undefined`.
- `resolveHljsLanguage` warns once per unknown language via a
module-scope Set, so authors learn the right names to use and stop
relying on hljs.highlightAuto guessing wrong.
- hljs try/catch now logs key/file/language + original error instead of
swallowing silently, so authors can spot bad snippets.
- When highlighting fails, drop the `hljs language-*` class so the
escaped plain-text fallback isn't styled as though it were highlighted.
- Defense-in-depth non-string hljs return guard.
- `regionFromFile` normalizes by stripping a single trailing newline
once, then splits — trailing-newline shape is consistent whether or
not `lines=` is supplied, so CopyButton text is predictable.
- Clamp `end` via `effectiveEnd = Math.min(end, allLines.length)` and
warn when an explicit range drifts past the file.
- Move the `WarningMessage` interface up next to the other type decls.
- Escape every interpolated value in convertMarkdownTableToHtml to
close an XSS vector: MDX table cells with HTML-significant characters
(e.g. <script>, &) previously landed raw in the generated markup.
- Scope readTitle and loadDoc title/description lookups to the
frontmatter block so a 'title:' / 'description:' that happens to
appear inside the MDX body (code samples, example config) can't
override the real frontmatter.
- Export a small escapeHtml helper for reuse within this module;
duplicated rather than imported from snippet.tsx to keep
docs-render server-only.
The img and video MDX shims spread props then overrode className to
undefined, silently dropping any className from authors' MDX. Remove the
bogus override so user-supplied className flows through.
Button had no type attribute, defaulting to type="submit" inside a
form (unintentional submits). Default to type="button", accept and
forward onClick/disabled/aria-label, and emit a dev-mode warning when
rendered without onClick so MDX authors learn their Button is
non-interactive.
IframeSwitcher had no sandbox attribute, letting user-controlled MDX embed
malicious-origin iframes with full browser capabilities. Mirror the
InlineDemo sandbox policy (scripts/same-origin/forms/popups) and add an
a11y title.
YouTubeVideo was missing both a title (screen readers announced only the
URL) and a sandbox policy. Add sandbox tuned for YouTube embeds
(scripts/same-origin/presentation/popups) and title fallback.
React 19 / Next 15 expects modern runtimes; ES2017 is stale. ES2022 gives
us top-level await, class fields, and error cause without needing additional
helpers. `next build` still passes.
- Add `engines.node >=18.18` to match Next.js 15 runtime requirements.
- Align `npm run start` with the dev port (3003) for local parity; the
Docker runner sets PORT=10000 via ENV and is unaffected.
- Drop unused dependencies that are not imported anywhere in shell-docs:
`react-markdown`, `react-syntax-highlighter`, `rehype-raw`, and
`@types/react-syntax-highlighter`. These are used in showcase/shell/
but not here; removing them keeps the dependency surface honest.
- Regenerate package-lock.json to match.
Add `.env*.local` and `*.log` entries so accidental secrets and debug
logs never land in the tree. Matches the pattern used by showcase/shell.
Leave the generated /src/data/*.json files tracked, as they are today.
- Re-declare COMMIT_SHA and BRANCH ARGs in the runner stage so ENV
interpolation resolves (ARGs do not cross stages in multi-stage builds).
- Declare NEXT_PUBLIC_BASE_URL as a build-time ARG/ENV so CI can pass it
via --build-arg for the production `next build` (next.config.ts requires it).
- Copy lockfile for shell-docs and switch to `npm ci` for reproducible installs.
scripts/ has no committed lockfile yet, so keep `npm install` there.
- Add .dockerignore so local .next/, node_modules/, .git, logs, and .env*
are not slurped into the build context.
- Invoke next via node_modules/.bin/next (both build and CMD) instead of
npx to avoid runtime network-fallback risk.
- Document the required build context at the top of the Dockerfile.
- Note the libc6-compat discussion: the slim base is Debian (glibc), so
no compat shim is required; note how to enable it if we ever move to
node:20-alpine.
The component's name, comments, and stated purpose are to highlight the
user's remembered framework pick on the docs root pivot. The code was
keying off 'framework' (strictly URL-derived), which is always null on
/docs/* where this component is actually mounted — the 'Your choice'
badge and accent ring NEVER rendered.
Now reads 'storedFramework' (the remembered advisory preference) and
compares it against the card's slug, which is what the rest of the file
already documents it doing.
Functional regressions in the docs router pivot:
1. The redirect effect was reading 'framework' (URL-derived) only. On
/docs/<feature> the URL prefix 'docs' is never in knownFrameworks, so
'framework' is always null and the effect never fired. The whole
'picked-once, sticks' feature was silently broken — users with a
stored preference were never redirected. Now prefers URL framework,
falling back to storedFramework, as a single 'target' signal.
2. The 'Loading <framework> view...' placeholder was unreachable for the
same reason. Now renders when 'target' is set.
3. The supported/unsupported filters disagreed on whether 'deployed'
applied. supported = withCell (ignored deployed); unsupported =
!withCell && deployed. Now both require deployed; undeployed
integrations are omitted entirely rather than surfacing dead links.
4. FrameworkGuardedContent previously returned null whenever 'framework'
was null, which on /docs/* is always. The MDX body was permanently
hidden. Now it hides only while a redirect is imminent (URL framework
set, or storedFramework set — both cases are about to navigate away);
users with no stored preference see the pivot alongside the MDX body.
- Move highlight.js @import ahead of @import "tailwindcss" so Tailwind
utility layers can still override specific hljs selectors when needed
rather than being silently shadowed in Tailwind v4's layer ordering.
- Scope the dark-dimmed theme via prefers-color-scheme so it only
paints when the user's system is in dark mode. shell-docs does not
yet ship a dark theme, but this makes syntax blocks correct the
moment it does.
- useFramework() now throws when called outside FrameworkProvider instead
of returning a silent no-op context. Silent fallback was masking wiring
bugs where components rendered outside the provider would report no
framework forever.
- readStoredFramework / writeStoredFramework now log once per session on
failure (guarded by module-scope flags) instead of swallowing errors
entirely. localStorage may still be unavailable (SSR, private mode),
but devs get a warning the first time.
- Dropped 'stored' from the URL-persist effect's deps. It was causing
redundant re-check cycles every time we called setStored from within.
The internal !== guard still short-circuits the no-op case.
- setStoredFramework now validates against knownFrameworks. Previously
any string could poison the stored preference (e.g. a route segment
like 'docs'); invalid slugs now warn and no-op.
`docs_pageview` was firing on every matched request — HEAD probes,
POSTs, and Next.js router prefetches all counted as pageviews, which
inflated counts and polluted funnels. Next.js App Router prefetches
links via low-priority fetches that still hit middleware, so they're
especially noisy on pages with long link lists.
We now bail out of tracking when:
- the method is not GET
- `next-router-prefetch: 1` is set (Next.js App Router)
- `purpose: prefetch` is set (generic prefetch hint)
The response is still served normally; only the PostHog capture is
skipped.
- Add aria-hidden=true so the SHA is not announced by screen readers.
- Shorten to the conventional 7-char git short-sha (was 9).
- Distinguish 'dev' (NEXT_PUBLIC_COMMIT_SHA undefined) from 'unknown'
(env present but empty string) so Docker ARG-scope bugs surface as
something other than a misleading 'dev' label in production.
Three smaller cleanups to the middleware:
1. Matcher regex: `(?!api|...)` matched `/apidocs` as well as `/api`,
dropping analytics for any docs path whose first segment starts with
'api'. The pattern now uses `api/` with a terminator, and also
excludes `robots.txt`, `sitemap.xml`, `manifest.webmanifest`, and
the `.well-known/` prefix, which some static-path tooling expects
to reach without middleware interception.
2. Capture errors are now logged via `console.warn` rather than
silently swallowed. PostHog 401/403/5xx, DNS failures, etc. were
invisible to operators.
3. The missing-`POSTHOG_PROJECT_KEY` warning now fires once at module
load rather than via a module-scoped mutable flag. Edge runtime
isolates are short-lived and per-request, so the in-memory
warn-once flag was unreliable. Module-load is the cleanest
available single-fire hook.
If a registry integration ever ships a slug matching a top-level route
segment (docs, ag-ui, reference, api, matrix, integrations), the
FrameworkProvider.urlFramework resolver would treat the route as a
framework scope and hijack navigation. Filter those slugs out in the
root layout and log a dev-only console.error so the collision is
visible to the maintainer.
The previous hard-coded distinct_id ("docs-pageview-tracker") collapsed
every visitor into a single synthetic PostHog person, which destroyed
unique-visitor analytics.
Each visitor now gets a stable UUID minted on first visit, persisted
in a first-party `ph_distinct_id` cookie (Lax, Secure, ~2 year TTL)
and read back on subsequent requests. This avoids IP+UA hashing and
the PII concerns that come with it.
Also wraps the PostHog capture POST in `event.waitUntil()` — the
middleware signature now takes `NextFetchEvent` — so the Edge runtime
keeps the request alive until the POST resolves. A bare fire-and-forget
fetch can be torn down as soon as `NextResponse.next()` returns,
dropping events.
- Extend .oxfmtrc.json ignore to cover shell-docs/src/content
(mirrors existing shell/src/content ignore, which was not updated
when shell-ops-v2 moved MDX content into the new shell-docs package)
- Format showcase/scripts/generate-registry.ts and probe-docs.ts
Matches shell/ and shell-dashboard/ which commit their npm lockfiles to
pin standalone (non-pnpm-workspace) install closures. Ensures reproducible
Docker builds in CI.
shell-docs renders pure MDX docs with iframed live demos (via <InlineDemo>
and <IframeSwitcher>) — it never instantiates the live copilot runtime
inline, so it doesn't need @copilotkitnext/react or its styles. Dropping
the import also removes the package from shell-docs's dep closure, keeping
the docs shell lean.
These files were added in #4085 but landed in showcase/shell/src/content/docs/
after the MDX-docs extraction had already moved the rest of content/docs into
shell-docs. Follow The Rule (MDX docs content belongs in shell-docs) and
relocate them so they render correctly on docs.showcase.copilotkit.ai.
MDX docs moved from shell to shell-docs, but several generated artifacts
are still consumed by both shells:
- registry.json: shell uses it (home grid, integrations, matrix,
middleware, layout); shell-docs uses it (docs renderer framework lookup)
- demo-content.json: shell uses it (integrations/[slug]/[demo]); shell-docs
uses it (<Snippet> in docs renderer)
- search-index.json: shell-docs consumes it for the docs search modal;
shell also keeps a copy so its header search still works — links 301
across to docs.showcase.copilotkit.ai.
Updated scripts:
- generate-registry.ts: dual-emits registry.json to both shells
(constraints.json stays shell-only — integration-explorer is shell)
- bundle-demo-content.ts: dual-emits demo-content.json
- generate-search-index.ts: scans from shell-docs/src/content (where MDX
now lives), writes to both shells' data dirs
- probe-docs.ts: scans shell-docs/src/content/docs (content source moved),
still writes docs-status.json under shell/ for the dashboard
- sync-docs-from-main.ts: target path updated to shell-docs/src/content
Tests in __tests__/ reference shell/src/data paths; dual-emit keeps
those stable so existing afterEach-restore hooks continue to work.
Shell no longer hosts MDX docs routes — they live on shell-docs
(docs.showcase.copilotkit.ai). Add permanent redirects from the legacy
shell paths so old URLs and SEO authority carry over to the new host.
Framework slugs are enumerated from registry.json at build time (not a
:slug* wildcard) so /integrations and /matrix — both still owned by
shell — are NOT caught by the redirect. Fixed routes (/docs, /ag-ui,
/reference) cover the three other docs catch-alls.
Extracts everything that exists to render MDX documentation (docs/[[...slug]],
[framework]/[[...slug]], ag-ui/[[...slug]], reference/[...slug]) out of shell
into the new shell-docs package that will serve docs.showcase.copilotkit.ai.
Moves (git mv preserves history):
- App routes: /docs, /[framework], /ag-ui, /reference
- Docs-only components: docs-page-view, docs-callout, docs-steps, docs-tabs,
mdx-components, framework-tabs, framework-selector, sidebar-*, snippet,
property-reference, router-pivot, stored-framework-highlight, react/*
- Docs-only libs: lib/docs-render, lib/mdx-registry
- All content: content/docs, content/ag-ui, content/reference, content/snippets
- .docs-sync-sha marker (follows the content)
Duplicates into shell-docs (both shells need them):
- brand-nav, search-modal, search-trigger, copy-button, framework-provider
- lib/registry.ts, data/registry.json, data/demo-content.json,
data/search-index.json
- app/layout.tsx + globals.css + public/{images,logos}
shell-docs gets its own minimal middleware (PostHog-only — no SEO redirect
table, docs host never served legacy URLs). shell keeps seo-redirects.ts
for the legacy-URL migration table; framework-scope protection in its
middleware is now effectively dead but harmless (next.config.ts redirects
fire before middleware ever sees /<framework>/ paths).
InlineDemo updated for cross-host context: 'Open full demo' link points
at the shell host (showcase.copilotkit.ai) since the integration profile
route only exists there.
- Renamed showcase/shell-internal/ → showcase/shell-dashboard/ (git mv for history).
- Updated package name to @copilotkit/showcase-shell-dashboard (+ lockfile).
- Updated external references: showcase/scripts/{probe-docs,generate-status}.ts comments and showcase/README.md.
- Added dispatch + filter + ALL_SERVICES entry for shell-dashboard in .github/workflows/showcase_deploy.yml.
- Provisioned Railway service showcase-shell-dashboard (id 4d5dfd74-be61-40b2-8564-b53b7dd4c15b):
- image source ghcr.io/copilotkit/showcase-shell-dashboard:latest
- env vars OPENAI_API_KEY, ANTHROPIC_API_KEY, PORT copied from showcase-shell
- custom domain dashboard.showcase.copilotkit.ai attached (CNAME → 6u9icvje.up.railway.app)
- image will be built and pushed via showcase_deploy.yml on merge
Production showcase-starter-langroid returns ``{"status":"degraded","agent":"down"}`` HTTP 503
at ``/api/health`` — the exact path the showcase-deploy workflow's ``ALL_SERVICES.health_path``
verify step asserts, so the next CI redeploy of this starter would fail verification.
Root cause: two compounding bugs in ``showcase/starters/langroid/entrypoint.sh``.
1. Process-substitution log prefixers suppressed stdout. Both backgrounded
services were wrapped with ``> >(sed 's/^/[agent] /') 2>&1 &`` /
``> >(sed 's/^/[nextjs] /') 2>&1 &``. In Railway's V2 runtime this shape
reliably produced ZERO ``[agent]``/``[nextjs]`` log lines (confirmed against
several weeks of Railway logs for this service) and correlated with
agent-unreachable 503s at ``/api/health``. The package entrypoint
(``showcase/packages/langroid/entrypoint.sh``) uses the plain-``&`` pattern
with no wrapper, stays green on the same Railway runtime, and shows full
uvicorn ``INFO:`` startup logs including ``127.0.0.1:... "GET /health
HTTP/1.1" 200 OK`` from Next.js's fetch. Match the working package pattern.
2. Cold-start race amplified by ``sleepApplication=true``. Railway sleeps
idle services. On wake, Next.js is ready in <1s but Python + langroid
imports take 10-20s. Without a readiness gate, Next.js answered the first
post-wake ``/api/health`` probe with ``agent:"down"`` before uvicorn had
bound port 8123. The deploy workflow's verify step then saw the 503 and
reported the deploy as unhealthy. Add a 30s readiness probe that curls
``http://127.0.0.1:8123/health`` in a loop before starting Next.js. The
IPv4 literal (``127.0.0.1`` not ``localhost``) is load-bearing — Node
22+'s fetch resolves ``localhost`` to IPv6 ``::1`` first, and uvicorn
binds IPv4 only; the readiness probe must not false-negative on resolver
semantics alone.
Also export ``PYTHONUNBUFFERED=1`` so Python import-time tracebacks (e.g.
langroid module-load failures) reach the container log immediately instead
of sitting in userspace buffers until process exit closes them off.
Verification:
- Built langroid starter image locally from this branch. ``/api/health``
returns 200 with ``{"status":"ok","agent":"ok"}``. Full uvicorn INFO
logs visible including ``127.0.0.1:xxxxx - "GET /health HTTP/1.1"
200 OK`` confirming Next.js -> agent path works.
- Readiness probe fires before Next.js launch: ``[entrypoint] Agent
/health ready after 3s``.
- New regression guards in ``starter-consistency.test.ts`` cover all four
invariants (no sed wrapping around uvicorn, no sed wrapping around next
start, ``PYTHONUNBUFFERED=1`` export, readiness probe on 127.0.0.1:8123
before ``next start``). Verified red→green (reverted entrypoint -> 4
fails; restored -> 4 pass). Full showcase/scripts suite: 1079/1079 pass.
Restores the API-surface change from the original QA PR #3866 (merged
via mirror #4040) that was inadvertently reverted in 804c5d0f. Keeps
Jordan's other fixes (imports, model, null guards, grammar) intact.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The auditableDemos filter (introduced for cli-start's informational
`command:` entry) was applied to the spec/qa SHOULD checks but not
the missing-demo-dir MUST check. Result: cli-start in langgraph-python's
manifest triggered a false missing-dir failure even though it has no
on-disk folder by design.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Post-merge CI caught two regressions:
1. shared-state-read-write demo directories were on disk but never
committed — 16 packages' manifests reference the demo but the
page.tsx scaffolds weren't tracked. This failed validate-parity,
bundle-demo-content tests, and drift-check transitively.
2. langgraph-python starter templates drifted after main added
docstring region markers to weather-tool-backend; regenerating
via `npx tsx generate-starters.ts` syncs the 17 starters.
Bundle (showcase/shell/src/data/demo-content.json) regenerated to
pick up the new demo content.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops the aspirational 185-line prompt (read_me preflight, multi-call
iteration, palette discipline, zone backgrounds, label/fixedPoint rules,
opening+mid+final cameraUpdates) in favor of a ~35-line shape that biases
the agent toward exactly one create_view call with 3-5 elements and a
single framing cameraUpdate. Downgrades gpt-4.1 → gpt-4o-mini since the
element schema is simple JSON and model latency dominates end-to-end time.
Measured end-to-end (agent/run SSE to RUN_FINISHED) on the showcase
runtime: 5-6s per prompt across two prompts × two runs, all producing a
single create_view call with 8 elements (clean 3-step flowchart;
client/server/db diagram). Previously 3-5 minutes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restructure the headless-interrupt cell so the app surface is empty by
default and the popup appears there (not inside the chat or as a global
modal) when the backend calls `interrupt()`. The user triggers the run
from a pre-built suggestion chip in the right-hand `CopilotChat`, which
mirrors the other in-app-action demos (hitl-in-app, gen-ui-interrupt).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Convert unselected/prebuilt-components.mdx single-file into a folder
matching the main /docs/prebuilt-components/ structure:
index.mdx, chat.mdx, sidebar.mdx, popup.mdx, meta.json
This way the nav builder creates a GROUP with CopilotChat /
CopilotSidebar / CopilotPopup children in the Built-in Agent sidebar
section, not just a single page link.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reimplements the approach from the now-closed PR #4093 (which I closed
after #4095 merged the agno 2.5.17 upgrade, on the belief that the SDK
bump had fixed the underlying SSE termination bug).
Follow-up evidence collected 2026-04-19 showed the SDK upgrade only
addressed the error path — production /api/smoke with real API keys
still hangs because the agno SDK does not reliably emit TEXT_MESSAGE_END
/ RUN_FINISHED on the success path. Documented in Notion page
3473aa381852815b9765fd28fa53275a, item #5.
Change: instead of `await res.text()` (which only resolves when the
server closes the stream), read res.body incrementally with
getReader() + TextDecoder. Short-circuit as soon as the buffer contains
`"type":"TEXT_MESSAGE_CONTENT"` with `"OK"` — the agent has produced
the expected output, so we cancel the reader and return a 200 success
envelope without awaiting a terminal event that may never arrive. If
the stream closes cleanly without confirmation, return a diagnostic
502 with stage="response_incomplete" so regressions surface clearly.
Keep the existing 45s AbortSignal timeout as a final safety net.
Response envelope shape is preserved for the smoke monitor parser.
This is a client-side mitigation, not a fix. The real fix belongs
upstream in the agno SDK's AG-UI interface. Keep this PR open until
upstream is addressed and verified in production with real keys.
Rewrites the mcp-apps agent system prompt from a minimal "call a tool and
populate the canvas" instruction into a detailed Excalidraw-aware
playbook. Adoptions:
- Workflow: instructs the agent to call `read_me` first (the Excalidraw
MCP server's own format reference) before `create_view`, and to use
`restoreCheckpoint` for follow-up edits.
- Layout principles: left-to-right vs. top-down vs. hub-and-spoke,
3-7 node target, consistent sizing (160x70 rectangles, 120x80
diamonds) and spacing (40-80px gutters, 60-120px viewport padding).
- Camera framing: opening `cameraUpdate` with a 4:3 size (400x300 →
1600x1200), optional mid-diagram pans, and a REQUIRED final
cameraUpdate that re-frames the whole diagram (otherwise the Excalidraw
animation camera ends zoomed on the last-drawn element).
- Labels: prefer `label: {text, fontSize}` on shapes/arrows (auto-centers,
auto-resizes) over bare `text:` fields (which Excalidraw silently
ignores on rectangles).
- Arrow bindings via `fixedPoint` edge anchors rather than hand-placed
coordinates; dashed stroke for async/optional paths; short label
annotations on decision transitions.
- Palette discipline: draws from the read_me palette (pastel fills +
primary strokes), caps at 3-4 background colors per diagram, assigns
them semantically (blue=frontend, green=success, yellow=decision,
red=error).
- Progressive emission order so the draw-on animation tells a story
(zone → shape → its label → its outgoing arrows → next shape), with
decorations last.
Also upgrades the model from gpt-4o-mini to gpt-4.1 because Excalidraw
element emission is structured/coordinate-heavy and a smarter model
produces visibly cleaner layouts (aligned nodes, edge-bound arrows,
labeled shapes) in practice.
Before: 3 colored boxes with no text (bare `text:` field silently
dropped), arrows ending on shape centers, no camera framing, no title.
After: 3 labeled boxes with consistent palette, edge-bound arrows with
transition labels, title text, cameraUpdate framing the diagram, and
the agent correctly consults `read_me` once per conversation for the
authoritative format reference.
Progressive streaming (Part 2 of the ask) was investigated and flagged
as shared-package-bound: `@ag-ui/mcp-apps-middleware` emits a single
`ACTIVITY_SNAPSHOT` only AFTER `RUN_FINISHED`, so there are no partial
tool-input events to consume in the cell. The Excalidraw MCP server does
animate elements in order once the full input arrives, which gives the
visual impression of progressive drawing without runtime changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the generic greeting-card / Pomodoro / revenue-chart suggestions
on the Fully Open-Ended Generative UI (minimal) cell with a set tuned for
intricate, educational visualisations: 3D airplane pitch/yaw/roll, a
feed-forward neural network's forward pass, quicksort, and a Fourier
series square-wave build-up.
Uses the provider's `openGenerativeUI.designSkill` prop (which injects
agent context for the built-in `generateSandboxedUi` tool) to swap in a
visualisation-tuned authoring prompt in place of the default shadcn
design language — covering SVG/canvas geometry, CSS keyframe motion,
mandatory labels + legends + callouts, a semantic palette (indigo /
emerald / amber / rose / slate), typography scale, and the self-running
constraint for the minimal cell. Agent system prompt updated in parallel
so the LLM knows the cell's focus and contract up-front.
Advanced variant untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-kickoff `agent.setMessages([])` call was racing with the
subsequent `addMessage` + `runAgent` pair, causing the second run
attempt to silently not dispatch (connection-refused on resume in some
timings). Drop the reset — rely on the fresh langgraph thread that each
`runAgent` implicitly produces, and on the existing `runId` marker to
gate ResultCard visibility so the stale result doesn't flash under the
button mid-run.
Validated: initial → modal → result → re-click → modal appears again,
all without a page refresh.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`create_deep_agent` does not accept `state_schema=` as a kwarg (confirmed
against the installed signature; state schema is only pluggable via
middleware). The minimal state-extending middleware is kept but renamed
to `_GenUiStateMiddleware` with a comment pinning its one purpose, and
`CopilotKitMiddleware` is added so this cell matches every other
langgraph-python cell.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MDX wraps inline text inside HTML elements in <p> tags. Using <p> as
the outer wrapper for each card's description causes <p><p>text</p></p>
which breaks hydration. Switch to <div> as the outer wrapper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The sandboxed iframe runs with `sandbox="allow-scripts"` only, so a
`<form>` with `<button type="submit">` had its submit blocked by the
browser BEFORE the onsubmit handler could call `e.preventDefault()` —
which meant `Websandbox.connection.remote.evaluateExpression(...)`
never fired. The agent also read `res.result` while the host handler
returns `{ ok, value }`.
Tightened the system prompt and per-suggestion prompts to explicitly
forbid `<form>` / `type="submit"` and to steer the LLM toward the
handler's exact return shape (`res.value` / `res.error`). Validated
end-to-end via Playwright: both `evaluateExpression` and `notifyHost`
now round-trip with visible results in the sandbox UI.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The PieChart + BarChart renderers were added in 8be81821e as part of the
brand-polish pass, but the a2ui_dynamic agent's system prompt was still
only mentioning dashboards/status/KPIs. Expand the prompt to enumerate
the registered catalog (Card, StatusBadge, Metric, InfoRow, PrimaryButton,
PieChart, BarChart) and name when each chart fits — so the LLM reliably
reaches for PieChart on part-of-whole breakdowns and BarChart on
cross-category comparisons.
Validated on port 4100 with Playwright: "Show a pie chart of sales by
region" renders a brand-coloured donut with legend + percentages, and
"Render a bar chart of quarterly revenue" renders a polished Recharts bar
chart with tooltip. No "Unknown component" errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reorders gen-ui-agent (Agentic Generative UI / In-Chat State Rendering)
to appear AFTER Reasoning (Default Render) in the Operational
Generative UI category, per user preference.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>