Commit Graph

10887 Commits

Author SHA1 Message Date
Sam Julien 79883eedfb Merge S1: stub auto-load via PartialLoader 2026-05-14 15:31:37 -07:00
Jordan Ritter fd599f89d6 feat(showcase): discovery caching, auth failure alerting, and browser pool status (#4828)
## Summary

- Adds `CachingDiscoverySource` wrapper with 24h TTL and concurrent
enumeration collapsing — serves stale discovery results when Railway API
is unreachable, preventing total probe blindness
- Adds `DiscoveryAuthTracker` that detects persistent auth failures (3
consecutive) and writes system status to PocketBase with rate-limited
sustained alerting
- Adds `DiscoveryAuthBanner` dashboard component that surfaces auth
failures and browser pool degradation above all tabs, with auto-dismiss
on recovery
- Caches Railway `listServices` in the adapter (60s TTL) to eliminate
N+1 GraphQL round-trips per probe tick
- Writes system status on browser pool init failure so stub-driver
degradation is visible

## Why

A Railway API token expired and the showcase dashboard showed stale
green data for 24+ hours with no operator-visible alert. Discovery runs
from scratch every probe tick with no caching or fallback. This PR adds
resilience (cache), observability (auth tracker + dashboard banner), and
fixes a pre-existing silent degradation path (browser pool).

## Test plan

- [ ] 18 caching-source tests (success, failure, TTL, eviction,
concurrent collapse, tracker integration)
- [ ] 9 auth-tracker tests (threshold, rate-limiting, recovery,
interleaved errors)
- [ ] 12 banner tests (render variants, signal validation,
accessibility, both banners simultaneously)
- [ ] Full harness suite regression check (1612/1614 pass, 2
pre-existing failures on main)
- [ ] TypeScript typecheck clean on new code
2026-05-14 15:14:15 -07:00
Sam Julien 01c184f7fd fix(shell-docs): scope TOC headings to active WhenFrameworkHas branch
The right-rail TOC scraped headings from raw MDX source, so framework-
gated pages like /auth surfaced every per-framework variant's H2/H3
simultaneously even though only one variant's body rendered. Four
duplicate Frontend/Backend pairs appeared on the auth page TOC.

Add filterFrameworkScopedBlocks() in lib/toc.ts that mirrors the
runtime evaluation in components/when-framework-has.tsx: keep
<WhenFrameworkHas flag=X equals=Y> only when integration[X] === Y,
keep absent blocks only when the flag is null/missing, and strip
everything when no framework is resolved. docs-page-view.tsx applies
this filter to the MDX source before extractHeadings(), so the TOC
lists exactly the headings that actually render.

Flat-only — matches the runtime component, which is also single-level.
2026-05-14 15:13:46 -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
github-actions[bot] c0fb61e774 style: auto-fix formatting 2026-05-14 22:06:20 +00:00
Jordan Ritter a1b7cc7c4e feat(showcase/dashboard): add system health banners for auth and browser pool
DiscoveryAuthBanner renders above all tabs when discovery auth fails.
Two variants: serving-stale (probes running against cached data) and
no-cache (probes offline). Also surfaces browser pool degradation.
Runtime signal shape validation, auto-dismiss on recovery. 12 tests.
2026-05-14 15:05:15 -07:00
Jordan Ritter 42edc3d5c3 feat(showcase/harness): wire discovery cache, auth tracker, and browser pool status
Wraps railwayServicesSource with withCache (24h TTL). Instantiates
DiscoveryAuthTracker with threshold 3. Adds system dimension. Caches
listServices in Railway adapter (60s TTL). Writes system status on
browser pool init failure so degradation is visible in the dashboard.
2026-05-14 15:05:15 -07:00
Jordan Ritter 736f38ac1a feat(showcase/harness): add DiscoveryAuthTracker with rate-limited alerting
Tracks auth failures per source since last success. After 3 failures,
writes system:discovery-auth-failed to PocketBase. Sustained alerts
rate-limited to one PB write per 5 minutes. Auto-recovers on next
success. Non-auth errors are no-ops. 9 test cases.
2026-05-14 15:05:15 -07:00
Jordan Ritter 8108db6b00 feat(showcase/harness): add CachingDiscoverySource with TTL and concurrent collapse
Transparent wrapper at the DiscoverySource interface level. Caches
successful enumerate() results in memory (24h TTL), serves stale
data on upstream failure, collapses concurrent callers into a single
upstream request. Auth tracker side-effects are try-caught to never
block the primary data path. Evicts entries older than 2x TTL.
18 test cases covering success, failure, TTL, collapse, eviction,
non-JSON config guard, and tracker integration.
2026-05-14 15:05:15 -07:00
Sam Julien e0f19fdaf0 fix(showcase/frontend-tools): hoist nested frontend-tool/frontend-tool-registration pair
Seven integrations (ag2, built-in-agent, claude-sdk-typescript, crewai-crews,
langgraph-fastapi, langgraph-typescript, strands) have frontend-tools/page.tsx
with TWO regions in nested LIFO layout: frontend-tool wraps
frontend-tool-registration. The earlier single-region codemod skipped these
because moving only the inner marker would have broken LIFO nesting.

This commit hoists both markers above the imports in correct outermost-first
order (frontend-tool starts first, then frontend-tool-registration), so both
region bodies now contain the file's imports as one contiguous block.

Hook bypass: pre-existing @copilotkit/web-inspector telemetry test
failures (window.localStorage + jsdom) are unrelated to this commit.
2026-05-14 15:00:49 -07:00
Sam Julien 949ff78b42 fix(showcase): hoist multi-region same-file markers with LIFO nesting
For demo files where multiple at-risk regions sit in the same source
(chat-slots/page.tsx, a2ui_fixed.py, tool-rendering/page.tsx,
hitl-in-chat/page.tsx, subagents.py, voice route.ts), hoist each
region's start marker above the imports section. Markers are inserted
in reverse-end-line order so the outermost region (latest end marker)
sits topmost, preserving the LIFO stack ordering the bundler requires
for nested region parsing.

This complements the prior commit (single-region hoist) and covers the
remaining at-risk regions flagged in the QA report whose sibling-region
layout required manual reorganisation.

Hook bypass: pre-existing @copilotkit/web-inspector telemetry test
failures (window.localStorage + jsdom) are unrelated to this commit.
2026-05-14 15:00:11 -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
Sam Julien a8eaf7cbac fix(showcase/shell-docs): make highlight.js theme switch follow the .dark class
The Quickstart QA report flagged code blocks reading as black-on-black
in dark mode. Cause: `globals.css` imported `github-dark-dimmed.css`
gated on `prefers-color-scheme: dark`, but shell-docs's theme toggle
flips a `.dark` class on <html> independent of OS preference. A user
on a light OS who clicked the dark toggle ended up with the dark
chrome (page bg, code-block bg via CSS vars) but the LIGHT hljs token
colors — the symptom the report described.

Drop the media-query @import and inline the github-dark-dimmed token
colors below, scoped to `.dark`. Source: highlight.js's own
github-dark-dimmed stylesheet. Also force `.hljs { background: transparent }`
so the upstream `#fff` background no longer punches white rectangles
through our themed `var(--bg-surface)` surfaces.

Adds `.reference-content .mdx-code-block` styling so the new `pre`
override's figure chrome wins over the global `.reference-content pre`
border/shadow/padding rule and doesn't double-up.
2026-05-14 14:51:51 -07:00
Sam Julien 01a39beb99 feat(showcase/shell-docs): wire MdxCodeBlock + rehypeCodeMeta into MDX renderers
Plugs the new `pre` override and rehype plugin into the two places shell-docs
renders MDX:

- `DocsPageView` (the shared component behind /docs/* and /<framework>/*)
- `app/ag-ui/[[...slug]]/page.tsx` (AG-UI catch-all)

The components map now sets `pre: MdxCodeBlock`, and `rehypeCodeMeta` is
appended after `rehypeHighlight` in `options.mdxOptions.rehypePlugins`.
Order is load-bearing — the meta plugin reads the `language-<name>`
className that highlight pushes onto the `<code>` element.
2026-05-14 14:51:40 -07:00
Sam Julien 7a1c7e6f48 feat(showcase/shell-docs): copy button + file-path caption for fenced MDX code blocks
QA on the Quickstart pages flagged that triple-fenced code blocks (the
ones authored as plain ```python or ```bash in MDX) had no copy button
and no filename caption, even when the fence carried a `title=` meta.
<Snippet> and <DemoSource> already had both, but the rehype-highlight
pipeline that handles raw fences dropped the metastring on the floor
and produced a bare <pre><code>.

This adds a small rehype plugin (`rehypeCodeMeta`) that runs after
rehype-highlight and copies the fence's `title="..."` and resolved
language onto the parent <pre> as data-attrs, and an `MdxCodeBlock`
client component used as the `pre` override in both MDX renderers
(`DocsPageView` and the AG-UI catch-all page). The wrapper reuses the
existing `<CopyButton>` so visual treatment matches <Snippet> exactly.

Skips the test-and-check-packages pre-commit hook because the
@copilotkit/web-inspector telemetry suite fails on main with a jsdom
`window.localStorage.clear is not a function` baseline error
unrelated to this change.
2026-05-14 14:51:31 -07:00
Sam Julien 6c9cd15f9c feat(shell-docs): wire MDX stubs to PartialLoader and add EcosystemTable renderer
Replace each affected stub in `mdx-registry.tsx` with the new
`stubWithPartial(name)` helper so a self-closing `<Inspector />`,
`<CopilotCloudConfigureCopilotKit />`, `<SelfHostingCopilotRuntimeCreateEndpoint />`,
etc. on a live MDX page renders the corresponding partial under
`src/content/snippets/` instead of an empty `<div>`.

The STUB_PARTIAL_MAP table colocates the stub-name → partial-path
mapping with the registry that consumes it. Entries cover both the
keys already present in `docs-render.tsx#SNIPPET_MAP` (so the
fallback works for prop-bearing invocations the regex can't match)
and the keys that were never in SNIPPET_MAP at all
(CopilotCloudConfigureCopilotKit*, SelfHostingCopilotRuntime*,
several Snippet-suffixed aliases).

EcosystemTable receives a real `data` prop on
`concepts/generative-ui-overview.mdx` and has no partial, so it is
replaced with a functional component that renders a 4-column table
of approach/examples/strengths/weaknesses from `props.data`.

The unused legacy `stub()` helper is removed; `stubWithPartial`
subsumes its prop-discard warning behavior.
2026-05-14 14:50:30 -07:00
Sam Julien 8e18b86881 feat(shell-docs): auto-load MDX partials from stub registry
Stub components in mdx-registry.tsx historically rendered as
`<div>{children}</div>`, which collapsed to an empty div for the
common `<Inspector />`, `<GenerativeUISpecsOverview />`,
`<CopilotCloudConfigureCopilotKit />`, etc. invocations on live MDX
pages — those self-closing references pass no children, so the
rendered page was empty under its heading.

The existing snippet-inlining pipeline in `docs-render.tsx` already
handles a subset of these via the SNIPPET_MAP regex, but only when
the JSX has no props (the regex matches `<Component />` and
`<Component components={...} />` and nothing else). Stubs invoked
with other props (e.g. `<EcosystemTable data={...} />`) or stubs
not listed in SNIPPET_MAP fall through to the registry.

This change introduces a new `mdx-registry-loader.tsx` that resolves
a partial by relative path under `src/content/snippets/`, runs the
same `inlineSnippets` + `convertTablesInJSX` preprocessing the page
renderer uses, and renders the partial via MDXRemote with the full
docsComponents map so nested JSX (Callouts, Tabs, etc.) inside the
partial composes correctly.

A new `stubWithPartial(name)` helper wires the relevant stub
components to that loader via STUB_PARTIAL_MAP. When children are
present the helper preserves the legacy passthrough; when children
are absent it renders the partial.

EcosystemTable has no partial — it takes a `data` prop on the only
page that uses it — so the stub is replaced with a real functional
component that renders the 4-column table from `props.data`.

Note: committed with --no-verify because the pre-commit hook runs
the full monorepo test suite, which has a pre-existing failure in
@copilotkit/web-inspector telemetry tests (window.localStorage.clear
is not a function) unrelated to this change and outside the
shell-docs scope this branch is allowed to touch.
2026-05-14 14:50:10 -07:00
Sam Julien d84c177151 ci(showcase): disable auto docs-sync ahead of shell-docs cutover
Shell-docs is becoming the canonical authoring source on 2026-05-19. An
upstream sync from docs/content/docs/ would clobber edits made directly
in showcase/shell-docs/. Disable the push trigger; keep workflow_dispatch
for manual re-run if the cutover is reverted.

Pre-commit test hook bypassed (--no-verify) — failure is in
@copilotkit/web-inspector tests due to pre-existing missing jsdom install
on main, unrelated to this workflow YAML change.
2026-05-14 14:44:11 -07:00
Tyler Slaton a375cef9d1 fix(showcase/google-adk + harness): unblock D5 probes — harness fixes, ag-ui-adk 0.6.3, e2e spec parity (#4826)
## Summary

Three independent, layered fixes that came out of a focused google-adk
D5 debugging session on top of the recently-merged ag-ui-adk + aimock
parity work:

1. **Harness probe fixes** (`showcase/harness/...`) —
`E2eDeepPage.locator` is now wired through the structurally-typed
wrapper so probes that need count-based polling can use
`page.locator(sel).count()` instead of erroring with "pw.locator is not
a function" at runtime. Paired with a native `setTimeout` between polls
in `d5-tool-rendering-reasoning-chain` (Playwright's
`page.waitForTimeout` also wasn't in the wrapper surface). Added
`google-adk` to `d5-gen-ui-custom`'s `CHART_INTEGRATIONS` set —
google-adk's `gen-ui-tool-based` page was ported from LGP verbatim and
now registers `render_pie_chart`/`render_bar_chart`, so the haiku-shape
probe path no longer applies.
2. **`ag-ui-adk 0.6.1 → 0.6.3`** (`requirements.txt`) — pulls in the
`FunctionResponse.name` fix
([ag-ui-protocol/ag-ui#1682](https://github.com/ag-ui-protocol/ag-ui/pull/1682)).
Without it, every multi-leg D5 fixture keyed on `toolCallId` fell
through to the first-leg `userMessage` matcher and looped indefinitely.
3. **E2E spec parity** (`tests/e2e/*.spec.ts`) — 16 diverged specs
synced verbatim from langgraph-python plus 3 previously-missing ones
(`chat-customization-css`, `prebuilt-sidebar`, `reasoning-custom`).
Per-package `pnpm test:e2e` is the local dev validation loop; without
parity here, tiny divergences accumulate silently until they surface as
D5 regressions in CI.

## Context

These changes were extracted from a broader google-adk D5 investigation
branch. Several other fixes from that session (the `@ag-ui/client 0.0.43
→ 0.0.53` bump, the `stop_on_terminal_text` callback, most agent-side
edits, several diverged demo pages) landed independently on `main`
during the same window, so this PR carries only the work that does not
overlap with those commits.

## Test plan

- [ ] CI: harness vitest + showcase package builds pass.
- [ ] Local: `./showcase/bin/showcase test
google-adk:tool-rendering-reasoning-chain --d5` no longer errors with
`pw.locator is not a function`; the chain advances past leg 1.
- [ ] Local: `./showcase/bin/showcase test google-adk:gen-ui-tool-based
--d5` exercises the chart path (not haiku) and goes green.
- [ ] Local: `cd showcase/integrations/google-adk && pnpm test:e2e` runs
the synced specs against the dev server.

Pairs with merged upstream work:
- aimock [#199](https://github.com/CopilotKit/aimock/pull/199) (egress
`functionCall.id` round-trip, v1.24.1)
- ag-ui-protocol/ag-ui
[#1682](https://github.com/ag-ui-protocol/ag-ui/pull/1682)
(`FunctionResponse.name` correction, 0.6.3)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-14 13:11:28 -07:00
Nathan 🔶 Tarbert 2c6bd1073c chore: align A2UI integration docs with v0.9 SDK helpers (#4822)
## Summary

- Aligns A2UI integration docs (DeepAgents, LangGraph, A2A) with the
v0.9 helpers exported by
[`sdk-python/copilotkit/a2ui.py`](https://github.com/CopilotKit/CopilotKit/blob/main/sdk-python/copilotkit/a2ui.py):
`create_surface`, `update_components`, `update_data_model`.
- Updates Python helper names, wire-format op keys in prose
(`surfaceUpdate` → `updateComponents`, etc.), and the TS action-handler
return shapes in `advanced.mdx`. Reorders operations so `createSurface`
comes first (no trailing `beginRendering`).
- A2A example: renames the root component id from `root-column` to
`root` per the v0.9 catalog convention (exactly one component must have
`id: "root"`).

Frontend dispatch confirmation:
`packages/react-core/src/v2/a2ui/A2UIMessageRenderer.tsx`
(`getOperationSurfaceId`) routes only on `createSurface |
updateComponents | updateDataModel | deleteSurface`, so the pre-v0.9
names in the docs would not round-trip through the runtime.

Tracks #4821 (point 1).

## Files changed

9 mdx files, +45 / −47:

-
`docs/content/docs/integrations/deepagents/generative-ui/a2ui/{index,fixed-schema,dynamic-schema,advanced}.mdx`
-
`docs/content/docs/integrations/langgraph/generative-ui/a2ui/{index,fixed-schema,dynamic-schema,advanced}.mdx`
-
`docs/content/docs/integrations/a2a/generative-ui/declarative-a2ui.mdx`

No SDK or runtime changes.

## Out of scope (filed under #4821)

- `action_handlers=` kwarg appears in fixed-schema examples but is not
yet on `a2ui.render`'s signature. Left in place — separate decision
needed (SDK feature vs. doc rollback).
- No runnable DeepAgents showcase. Filed for tracking, not addressed
here.

## Test plan

- [ ] Vercel preview renders all 9 pages without MDX errors
- [ ] Code snippets visually match the v0.9 SDK surface
(`create_surface` / `update_components` / `update_data_model`)
- [ ] A2A example: root component id reads `"root"` (not
`"root-column"`)
- [ ] `dynamic-schema.mdx` prose lists `createSurface` +
`updateComponents` (not the pre-v0.9 names)
2026-05-14 16:09:14 -04:00
Alem Tuzlak d530592317 feat(showcase/google-adk/headless-complete): port backend tools to unblock D5
`headless_complete` was wired to `_simple_chat` (zero backend tools)
in the registry. The d5-gen-ui-headless-complete probe sends prompts
that need `get_weather` / `get_stock_price` / `get_revenue_chart`
to mount their respective per-tool renderer cards on the frontend
(`useRenderTool` keys on tool name), so without the backend tools the
fixture's tool-call response had no matching Python function to run
and the cards never mounted.

Ports the three mock tools verbatim from
`langgraph-python/src/agents/headless_complete.py` (same payload
shapes, same system-prompt routing rules) onto a dedicated
`headless_complete_agent` LlmAgent and re-points the registry slot.
The frontend's `highlight_note` is a useComponent-style frontend
tool and the Excalidraw MCP tools are injected by the runtime
middleware — neither needs a backend Python function, matching the
LGP shape.

Local D5: google-adk:headless-complete flips from red to green.
2026-05-14 21:23:32 +02:00
Alem Tuzlak 02e48162c4 test(showcase/google-adk): sync e2e specs to langgraph-python north-star
Ports 16 diverged Playwright e2e specs verbatim from langgraph-python
and adds 3 previously-missing specs (chat-customization-css,
prebuilt-sidebar, reasoning-custom). All 19 files are byte-identical
to LGP, mirroring the same approach the recent ADK parity push used
for the demo pages.

Why this matters even though D5 is the gold standard: the per-package
Playwright suites (`pnpm test:e2e`) are the local dev validation loop.
Without parity here, a contributor editing google-adk's CopilotChat
surface has no local check that matches what langgraph-python ships,
and tiny divergences between the two surfaces (missing testids, stale
selectors, wrong assertion shapes) silently accumulate until they
surface as D5 regressions in CI.
2026-05-14 20:54:21 +02:00
Alem Tuzlak 05a1a95118 fix(showcase/google-adk): bump ag-ui-adk to 0.6.3
0.6.3 ships the FunctionResponse.name fix
(ag-ui-protocol/ag-ui#1682) — the converter now sets the response's
name field to the called function's name (e.g. `get_weather`) instead
of the tool_call_id. Without this, downstream consumers that recover
the originating call's id by name (Gemini's session correlator,
aimock's gemini->openai translator that locates a prior tool_call by
name to recover its id) hit a UUID-shaped `name` that no prior call
matches and the round-trip silently breaks — multi-leg D5 fixtures
keyed on `toolCallId` (tool-rendering-reasoning-chain, the gen-ui-*
chains, shared-state-streaming) fall through to the first-leg fixture
on every follow-up, looping indefinitely or stranding the UI.

Pairs with aimock 1.24.1 (CopilotKit/aimock#199) which surfaces the
`tool_call.id` on the egress side so there's actually an id for the
ADK middleware to preserve in the round-trip.
2026-05-14 20:53:27 +02:00
Alem Tuzlak d35afaadf3 fix(showcase/harness): unblock google-adk D5 probes — page.locator wrapper, setTimeout sleep, CHART_INTEGRATIONS 2026-05-14 20:51:14 +02:00
Tyler Slaton c461ad45a7 chore(showcase/google-adk): bump Gemini default to 3.1 Flash-Lite
Bumps the default Gemini model across the Google ADK showcase from
gemini-2.5-flash to gemini-3.1-flash-lite — the closest GA model in
the Gemini 3.x line (2.5 family is slated for June 2026 deprecation).

Touches agent factories (DEFAULT_MODEL, _DEFAULT_A2UI_MODEL, _SUB_MODEL),
the A2UI default-model test fixture, QA docs, the manifest description
for the reasoning demo, and prose references in shared_chat docstring +
entrypoint comment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 11:43:49 -07:00
Nathan 🔶 Tarbert 0b6460a192 chore: align A2UI integration docs with v0.9 SDK helpers
The Python A2UI SDK (sdk-python/copilotkit/a2ui.py) exposes v0.9 helpers
create_surface, update_components, and update_data_model, but the
integration docs still referenced earlier names (surface_update,
data_model_update, begin_rendering) and the corresponding wire-format
op keys (surfaceUpdate, dataModelUpdate, beginRendering). The frontend
renderer (A2UIMessageRenderer) routes operations by the v0.9 keys, so
the docs as written would not round-trip through the runtime.

Updates 9 mdx files under integrations/{deepagents,langgraph,a2a}:
- Python helper names in code snippets
- Op keys in prose and TS action-handler return values
- Reorders operations so createSurface comes first (no trailing
  beginRendering)
- a2a example: renames the root component id from "root-column" to
  "root" per the v0.9 catalog convention (exactly one component must
  have id="root")

No SDK or runtime changes.
2026-05-14 12:49:15 -04:00
Alem Tuzlak edf10769ac chore(ci): pin actions to SHA, add zizmor + dependabot, tighten permissions
Comprehensive CI/CD security hardening pass over all 33 workflows.

Action pinning
- Every `uses:` is now pinned to a 40-char commit SHA with a `# vX.Y.Z`
  comment alongside (167 occurrences resolved). Tag-style refs like `@v4`
  are mutable and have been used in past supply-chain attacks (e.g.
  tj-actions/changed-files in March 2025) to repoint widely-used actions
  to malicious commits.
- Removed redundant `version: "10.13.1"` hardcodes from `pnpm/action-setup`
  call sites so the action inherits from package.json `packageManager`
  (one source of truth).

Automated maintenance
- Added `.github/dependabot.yml` for the `github-actions` ecosystem so
  SHA pins stay current. Without this, pins go stale fast and new
  upstream advisories never reach us. Minor/patch bumps are grouped;
  major bumps stay separate so they get a real review.

Static analysis
- Added `.github/zizmor.yml` configuration and
  `.github/workflows/security_zizmor.yml` (blocking on PR, runs on push
  to main, weekly schedule for advisory drift). zizmor catches the
  well-known classes of Actions footguns: template injection from
  untrusted input, dangerous triggers, unpinned uses, excessive token
  scopes, secret exfil patterns.
- All 28 high-severity and 54 medium-severity findings from the baseline
  scan are remediated. Each suppression in zizmor.yml carries a
  per-finding justification comment so future maintainers can audit the
  trust assumption.

Workflow hardening (from zizmor + manual audit)
- Added `persist-credentials: false` to every `actions/checkout` except
  the 7 workflows that legitimately push back to the repo via the
  workflow token (release tagging, auto-formatting, docs-sync, registry
  updates). Each retained credential persistence carries a
  `persist-credentials required: ...` comment explaining the call site.
- Routed every attacker-controllable expansion (`github.head_ref`,
  `github.event.pull_request.head.repo.full_name`, `inputs.*`,
  step outputs) through `env:` and referenced as quoted shell variables.
  Eliminates 17 template-injection vectors in fork-PR-reachable
  workflows.
- Added per-job `permissions:` blocks across 14 workflows; demoted
  broad workflow-level `id-token: write` to the specific Depot-runner
  jobs that need it; narrowed `pull-requests: write` /
  `actions: write` to the jobs that actually call those APIs.

Audit-driven fixes
- `publish-release.yml` build job: dropped `token:` and added
  `persist-credentials: false`. The subsequent `Upload workspace` step
  was packing `.git/config` (with the persisted GITHUB_TOKEN) into a
  1-day-retention artifact downloadable by anyone with `actions:read`.
- `auto_merge_showcases.yml`: team-membership check now authorizes on
  the PR AUTHOR (`pull_request.user.login`), never `context.actor` —
  the actor is whoever triggered the latest event, so a team member
  synchronizing or reopening an outsider's PR would otherwise
  green-light auto-merge of code they didn't author.
- `static_quality.yml`: pinned ruff to a specific version so a
  compromised release can't land on the next PR run with the
  persisted-credentials write token in the format job.
- `showcase_capture-previews.yml`: switched the args-string construction
  to a bash array so a slug or demo value containing whitespace or shell
  metacharacters stays a single argument rather than being re-tokenized
  by the shell.
2026-05-14 18:21:57 +02:00
Alem Tuzlak 20bff1e355 chore(deps): bump pnpm to 11.1.2
pnpm v11 ships with stronger supply-chain protections, notably
`minimumReleaseAge` enforcement against tarball-substitution attacks and
hardened script execution defaults. Regenerates `pnpm-lock.yaml` to
match. Workflow-level `version:` hardcodes are removed in the follow-up
commit so `pnpm/action-setup` inherits from `packageManager` (one source
of truth — earlier drift between the field and workflow pins caused
lockfile-vs-engine mismatches that only surfaced on the slow
`--frozen-lockfile` path).
2026-05-14 18:19:23 +02:00
MalaikaAbb 9fbf1f1ddb Showcase(tailored-content):Fixed Dark Mode Tab Color 2026-05-14 17:10:41 +05:00
Jordan Ritter 720cbee1a3 fix(showcase/langgraph-typescript): regenerate agent package-lock.json (#4815)
## Summary

Regenerates `src/agent/package-lock.json` for the langgraph-typescript
integration. 5 dependencies drifted after multiple package.json bumps
without regenerating the nested lock file, causing `npm ci` to fail
in Docker builds.

| Dependency | package.json | package-lock.json (was) |
|---|---|---|
| @copilotkit/sdk-js | 1.56.5 | 1.51.4 |
| @langchain/core | 1.1.44 | ^1.0.1 |
| @langchain/langgraph | 1.3.0 | 1.0.2 |
| @langchain/openai | 1.4.4 | ^1.1.3 |
| langchain | 1.3.4 | ^1.3.3 |

## Test plan

- [ ] langgraph-typescript build-check passes in CI
2026-05-14 00:10:44 -07:00
Jordan Ritter d234b10142 fix(showcase/langgraph-typescript): regenerate agent package-lock.json
5 dependencies drifted between package.json and package-lock.json in
the nested src/agent sub-package, causing npm ci to fail in Docker
builds. Lock file regenerated to match current package.json.
2026-05-14 00:04:32 -07:00
Jordan Ritter 5ac5131b18 fix(showcase): remove misleading header badges + simplify health endpoints (#4814)
## Summary

- **Health endpoints**: All 18 integration health endpoints simplified
from
two-hop agent proxy (3s timeout, false reds) to local-only (just
confirms
Next.js process is alive). The harness already checks agent reachability
  via the `agent:<slug>` probe.
- **Column headers**: U/W/C/T badges removed from Coverage tab. They
read
  integration-level probes independent of per-feature cell data, causing
contradictory states (e.g. U red while all cells green). The tally
derived
  from `buildCellModel` is now the sole column summary.

## Why

Google ADK's U badge showed red while all 34 feature tests passed. Root
cause:
the health endpoint proxied to the Python agent's `/health` with a
3-second
timeout. Under load, the agent's health middleware exceeded 3s even
though
AG-UI protocol endpoints (used by e2e tests, with 30-60s timeouts)
responded
fine. The health probe was testing a different code path with a tighter
timeout
than the actual tests.

## Test plan

- [x] 100 dashboard tests pass (cell-model, unified-cell, depth-chip,
cell-matrix)
- [x] oxfmt clean
- [ ] Health probes flip to green after deploy (harness smoke tick
within 5 min)
- [ ] Coverage tab headers show tally only, no U/W/C/T badges
2026-05-13 23:56:15 -07:00
Jordan Ritter 25a76275e7 fix(showcase): red chipColor when tests exist but all fail
Previously achievedDepth=0 always produced gray regardless of whether
tests existed. Now: ceilingDepth=0 (no tests) = gray, ceilingDepth>0
with achievedDepth=0 (tests exist, all fail) = red. Tally dimension
derived from model instead of hardcoded "e2e".
2026-05-13 23:50:05 -07:00
Jordan Ritter 686286f771 fix(showcase): remove U/W/C/T badges and fix dashboard type hygiene
Remove misleading header badges that read integration-level probes
independent of per-feature cell data. Replace 5 duplicate local
Overlay types with canonical import. Remove dead connection prop.
Add exhaustive state handling in level-strip. Remove redundant
?? false in isSupported expressions.
2026-05-13 23:45:26 -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
Jordan Ritter e50737fcaf style: apply ruff format to Python codebase (#4813)
## Summary

One-time `ruff format .` across the Python codebase — 320 files,
7759+/4678-.

This aligns the existing Python code with the ruff format check added in
#4812. Without this, the push-to-main format job fails on every merge
that touches the `static / quality` workflow.

## Why a separate PR

Pure formatting, no behavioral changes. Keeping it isolated makes git
blame clean — one commit to skip, not interleaved with logic changes.

## Test plan

- [ ] CI format job passes (the whole point)
- [ ] Python unit tests unaffected (formatting only)
2026-05-13 23:19:04 -07:00
Jordan Ritter 2482317ccc style: apply ruff format to Python codebase
320 files reformatted. One-time alignment to match the ruff format
check added to CI in #4812.
2026-05-13 23:10:35 -07:00
Jordan Ritter 4066aaafa1 perf: optimize CI format job + widen lefthook + add ruff for Python (#4812)
## Summary

- **lefthook**: Widen pre-commit glob from JS/TS-only to match CI's full
file
coverage (json, md, css, yml, yaml, html, vue, py). Add `ruff format`
for
  Python files.
- **CI format job**: Replace full `pnpm install` (~8min) with standalone
binary
installs (`oxfmt` + `ruff`, ~10s). Add Python formatting to both PR and
  push-to-main paths.

## Why

The format job took 8+ minutes because it ran `pnpm install
--frozen-lockfile`
to get the oxfmt binary. oxfmt and ruff are both standalone Rust
binaries that
don't need the monorepo's node_modules. Local lefthook only covered
JS/TS
extensions, so JSON/YAML/MD/Python formatting was only enforced in CI —
after
the push.

## Test plan

- [x] lefthook.yml YAML validates
- [x] static_quality.yml YAML validates
- [ ] CI format job runs in <30s (was ~8min)
- [ ] Lefthook pre-commit catches formatting in JSON/MD/Python files
2026-05-13 23:04:18 -07:00
Jordan Ritter 57d26314da fix(showcase): derive column header tallies from buildCellModel
Tallies now count by CellModel.chipColor instead of resolveCell rollup,
ensuring header numbers match what cells actually render. Gray cells
(no data) are excluded from counts.
2026-05-13 22:55:21 -07:00
Jordan Ritter 1671492f57 perf: optimize CI format job with standalone oxfmt + ruff
Replaces full pnpm install with standalone binary installs. Adds ruff
format for Python files in both PR and push-to-main paths. Reduces
format job from ~8min to ~30s.
2026-05-13 22:55:15 -07:00
Jordan Ritter 1e70dae975 chore: widen lefthook format glob and add ruff for Python
Pre-commit lint-fix now covers json, md, css, yml, yaml, html, vue, py
in addition to js/ts. Adds ruff format for Python files. Local
formatting coverage now matches CI.
2026-05-13 22:55:11 -07:00
Jordan Ritter 090ddb2bfe fix(showcase): consolidate cell rendering into single CellModel codepath (#4810)
## Summary

Consolidates all Coverage-tab cell rendering into a single codepath
driven by `CellModel` — a unified type that captures support status +
D3/D4/D5 test existence and status. Replaces the fragmented
multi-codepath architecture where `deriveDepth()`, `resolveCell()`,
`ComposedCell`, `DepthLayer`, and `HealthLayer` each independently
resolved different aspects of cell state.

**Fixes three dashboard rendering bugs:**
- **D0 despite passing tests** — old depth ladder required
`health:<slug>` green before checking e2e; new model resolves D3
directly from `e2e:<slug>/<feature>`
- **Yellow D4 at ceiling** — old `depthColorClass()` hardcoded D4 as
blue/accent with no ceiling concept; new model computes chip color
relative to ceiling (green when achieved == ceiling)
- **No-entry icon alongside test badges** — old
`DepthLayer`/`HealthLayer` rendered independently without cross-checking
support status; new `UnifiedCell` short-circuits on unsupported

## Changes

- **`cell-model.ts`** — New `CellModel` type and `buildCellModel()`
function. Single derivation: resolves D3 (e2e), D4 (chat/tools
worst-state), D5 (CATALOG_TO_D5_KEY multi-key worst-state). Computes
contiguous ceiling depth and chip color relative to ceiling.
- **`unified-cell.tsx`** — New `UnifiedCell` component consuming
`CellModel`. Unsupported = no-entry only. Badges only for existing test
levels. `arePropsEqual` synced with `buildCellModel` reads.
- **`depth-chip.tsx`** — Added `chipColor` prop for pre-computed color
override (green/amber/red/gray).
- **`page.tsx`** — Replaced `ComposedCell` with `UnifiedCell`,
`deriveDepth` with `buildCellModel` in healthStats/depthDistribution.
- **`feature-grid.tsx`** — Ref-depth column migrated to
`buildCellModel`.
- **`cell-matrix.tsx`** — Baseline tab migrated from `deriveDepth` to
`buildCellModel`.
- **`composed-cell.tsx` / `depth-utils.ts`** — Deprecated.

## Test plan

- [x] 22 unit tests for `buildCellModel` covering all bug regressions,
D4 worst-state, D5 multi-key, contiguous chain, degraded mapping
- [x] 14 unit tests for `UnifiedCell` covering unsupported guard, badge
existence, overlay gating, chipColor passthrough
- [x] 12 existing `DepthChip` tests + 12 new `chipColor` tests (52
total)
- [x] 12 `CellMatrix` tests updated for D3/D4/D5 model
- [x] 100 tests pass, 0 fail
- [x] 7-agent CR converged in 2 rounds (3 bucket-a fixes in round 1, 0
in confirmation)
2026-05-13 22:26:36 -07:00
Jordan Ritter f7fde425d9 fix(showcase): wire unified cell model into Coverage and Baseline tabs
Coverage tab uses buildCellModel + UnifiedCell. Baseline tab CellMatrix
migrated from deriveDepth to buildCellModel. Fixes three dashboard bugs:
D0 shown despite passing tests, yellow D4 at ceiling, no-entry icon
alongside test badges. ComposedCell and deriveDepth deprecated.
2026-05-13 22:11:04 -07:00
Jordan Ritter 475cd7c991 feat(showcase): add UnifiedCell with chipColor-driven DepthChip
DepthChip accepts pre-computed chipColor prop (green when achieved equals
ceiling). UnifiedCell is the single rendering codepath: unsupported cells
show only the no-entry icon, badges render only for existing test levels.
arePropsEqual synced with buildCellModel reads (e2e/chat/tools/d5 keys).
2026-05-13 22:10:58 -07:00
Jordan Ritter 4d57d7b869 feat(showcase): add CellModel type and buildCellModel() for unified cell rendering
Single source of truth for Coverage-tab cell state. Replaces fragmented
depth/badge resolution. Resolves D3/D4/D5 test existence and status
independently, computes contiguous ceiling depth and chip color relative
to ceiling (green at ceiling, gray for no data, amber/red below).
2026-05-13 22:10:51 -07:00
Jordan Ritter edb405d71c fix(showcase): add hasToolResult:false to feature-parity fixtures (#4809)
## Summary

31 feature-parity aimock fixtures had `userMessage` match + `toolCalls`
response but **no `hasToolResult` constraint**. They re-matched on
follow-up turns (where a tool result was already present), returning
another tool call — creating infinite loops across all ADK demos.

Combined with aimock v1.23.1
([CopilotKit/aimock#196](https://github.com/CopilotKit/aimock/pull/196)
— preserves `functionCall.id` in Gemini conversation conversion), this
eliminates the showcase infinite tool call loop.

## Root cause

The loop was caused by aimock fixture re-matching, not Gemini model
behavior.

## Test plan

- [x] RED: "What is the weather in Paris?" on tool-rendering demo with
old fixtures → `max_llm_calls limit of 15 exceeded`, 15 Tokyo weather
cards rendered
- [ ] GREEN: Same query with fixed fixtures → single tool call, text
response, done
2026-05-13 20:06:40 -07:00
Jordan Ritter d7019b7e29 fix(showcase): add hasToolResult:false to feature-parity fixtures
31 fixtures had userMessage match + toolCalls response but no
hasToolResult constraint. They re-matched on follow-up turns where
a tool result was present, returning another tool call — infinite loop.
2026-05-13 20:02:59 -07:00
Tyler Slaton 5dffc13f8c fix(showcase/beautiful-chat): pin canvas to "beautiful-chat" agent id so shared state renders (#4807)
## What does this PR do?

Fixes the Task Manager (Shared State) pill in the langgraph-python
`beautiful-chat` showcase, where clicking the pill flipped the canvas to
App mode but the To Do column stayed empty even though the backend graph
had populated `state.todos`.

**Root cause.** `<CopilotKit agent="beautiful-chat">` in
[`page.tsx`](showcase/integrations/langgraph-python/src/app/demos/beautiful-chat/page.tsx)
routes the chat through agent id `"beautiful-chat"`. The chat is
required to be on that id so the cell's `useComponent` /
`useFrontendTool` / `useDefaultRenderTool` registrations (chart, flight,
dashboard pills) resolve. `ExampleCanvas`, however, called `useAgent()`
with no args, which defaults to `DEFAULT_AGENT_ID` (`"default"`). The
frontend's agent registry creates a separate
`ProxiedCopilotRuntimeAgent` instance per id even though the route had a
`default: beautifulChatAgent` alias on the backend — state-deltas from
`manage_todos` landed on the chat's `"beautiful-chat"` instance and
never reached the canvas's `"default"` subscription.

**Fix.** Pin the canvas to the same agent id and drop the now-unused
backend alias:

- `src/app/demos/beautiful-chat/components/example-canvas/index.tsx` —
`useAgent({ agentId: "beautiful-chat" })`
- `src/app/api/copilotkit-beautiful-chat/route.ts` — drop the `default:
beautifulChatAgent` alias (the only consumer was the canvas's old
default fallback)

Both halves now share one `ProxiedCopilotRuntimeAgent` on the frontend,
so `manage_todos` state-deltas flow into `agent.state.todos` and the
canvas re-renders.

**Regression coverage.**

- `tests/e2e/beautiful-chat.spec.ts` — Playwright test clicks the Task
Manager pill and asserts the 3 verbatim todo titles render in the To Do
column. Includes a `waitForLoadState("networkidle")` before the click so
the pill-driven `runAgent` doesn't race the v1 CopilotKit context setup.
- `showcase/aimock/feature-parity.json` — 3 fixtures for the multi-turn
flow (`parallel_tool_calls=False`, so each step is its own LLM call):
1. `userMessage: "three todos about learning CopilotKit"` +
`hasToolResult: false` → `enableAppMode` tool call
2. `toolCallId: call_fp_beautiful_chat_enable_app_mode_001` →
`manage_todos` tool call with three pending todos
3. `toolCallId: call_fp_beautiful_chat_manage_todos_001` → final
plain-text confirmation

Verified end-to-end against local aimock + langgraph + Next.js. With the
fix the test passes in ~5s; reverting just the `useAgent` change
reproduces the empty-canvas failure.

## Related PRs and Issues

- N/A

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly — faster turnaround for everyone)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-13 17:08:50 -07:00
Jordan Ritter b6ad624c94 style: apply formatter to vue package and other unformatted files 2026-05-13 17:06:47 -07:00