Skip to content

Tags: mexicanamerican/CopilotKit

Tags

showcase-previews

Toggle showcase-previews's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(showcase): narrow aimock fixture patterns + add drift guardrail (C…

…opilotKit#4155)

## Summary

Showcase demos (e.g. gen-ui-tool-based's "Traffic pie chart", Beautiful
Chat's pie/bar-chart suggestions) were rendering nothing in prod because
aimock's substring-match fixtures cross-fired across demos with
different tool surfaces, returning tool names the target agent never
registered. This PR narrows the fixture patterns to fix the immediate
breakage and adds a static validator so the same class of drift fails CI
before it reaches prod.

## What broke

Aimock serves deterministic responses in prod for cost reasons. Fixtures
substring-match the user message and return hardcoded tool calls. The
`"pie chart"` pattern returned `query_data` (for Beautiful Chat's
two-step flow where it has that tool), but the same substring also fires
for gen-ui-tool-based's suggestions — which only registers
`render_pie_chart`. The returned `query_data` call dangles, no UI
renders.

Beautiful Chat also looped on the same fixture: aimock has no
conversation-turn awareness, so after `query_data` returned its tool
result, the follow-up model call had the same user-message context and
the fixture re-matched, emitting `query_data` again — infinite until
LangGraph's iteration cap.

Exposed by PR CopilotKit#4113 (showcase-ops) / the prod-mode migration cluster
that started routing prod traffic through aimock. The fixtures
themselves had been incrementally drifting for a while, but the routing
change turned silent drift into user-visible breakage across many demos
simultaneously.

## Fix #1 — narrow the fixture patterns

`showcase/aimock/feature-parity.json`:

- Replaced the generic `"pie chart"` / `"bar chart"` / `"show pie"` /
`"show bar"` patterns with **6 per-suggestion specific-phrase matches**.
gen-ui-tool-based and declarative-gen-ui get `render_pie_chart` /
`render_bar_chart` directly; Beautiful Chat gets `pieChart` / `barChart`
with real data (skipping the query_data loop).
- Narrowed `"schedule"` + `"meeting"` into one match for Beautiful
Chat's "30-minute meeting to learn about CopilotKit" → `scheduleTime`.
- Narrowed `"flight"` / `"fly"` to `"flights from SFO to JFK"`.
- Narrowed `"background"` to `"sunset-themed gradient"`.
- Removed `"trip"`, `"sales"`, `"pipeline"`, `"todo"` — too generic,
substring-false-firing across unrelated demos. Interrupt and A2UI demos
with those prompts fall through to the real LLM proxy.

## Fix #2 — static drift guardrail

New `showcase/scripts/validate-fixture-tool-surface.ts`:

- Pure `validate()` function: for each fixture with tool-call responses,
finds every demo whose suggestion prompt contains the fixture's match
substring, then asserts the fixture's returned tool names are all
registered by that demo's agent.
- CLI walks `packages/*/` collecting:
  - suggestions from `page.tsx` + sibling `hooks/*.tsx`
- frontend tools from `useComponent` / `useHumanInTheLoop` /
`useFrontendTool` / `useRenderTool` / `useDefaultRenderTool` calls
- backend tools via `api/copilotkit*/route.ts` → agentId→graphId map →
`langgraph.json` graph→Python-file → `@tool` decorators + `tools=[...]`
arrays
- 7 vitest cases written TDD-first (watched fail, then implemented)
covering: drift detection, content-only fixtures, no-matching-demo,
case-insensitivity, multi-demo cross-check, multi-tool responses.

Runs as `npx tsx showcase/scripts/validate-fixture-tool-surface.ts`.
Exit 0 = clean; exit 1 = per-fixture drift report.

Current state: **33 fixtures × 191 demos, no drift.**

Counterfactual: reverting just the pie-chart fixture fix correctly flags
`langgraph-python/gen-ui-tool-based` and
`langgraph-python/declarative-gen-ui` — i.e. the exact demos that broke
in prod.

## Also fixed — unrelated LangGraph Python Dockerfile bug

`showcase/packages/langgraph-python/Dockerfile`: `WORKDIR /app` left
`/app` owned by root; the explicit `--chown=app:app` on COPY lines
chowned *contents* but not the directory itself, so the `app` user
couldn't create `.langgraph_api` (the in-memory LangGraph runtime's
cache dir) and the agent crashed on boot with `PermissionError: [Errno
13]`. Added a non-recursive `chown app:app /app` (preserves the perf
intent of not doing a recursive chown).

## Known follow-ups (out of scope for this PR)

- Interrupt demos (`gen-ui-interrupt`, `interrupt-headless`,
`hitl-in-chat`) and A2UI demos (`declarative-gen-ui`,
`a2ui-fixed-schema`, `mcp-apps`, Calculator App) currently fall through
to the real LLM when unmatched. Faithful fakes would need per-agent
fixture keying in the aimock engine — separate upstream change.
- Python backend-tool parser uses regex; misses star-spread collections
like `tools=[query_data, *todo_tools]`. Safe failure mode — missing
tools surface as guardrail drift rather than silently pass.
- Add this validator to `.github/workflows/showcase_*.yml` so CI runs it
on every PR touching fixtures or demos.

## Test plan

- [x] `npx vitest run
showcase/scripts/__tests__/validate-fixture-tool-surface.test.ts` — 7/7
pass
- [x] `npx vitest run
showcase/scripts/__tests__/aimock-fixtures.test.ts` — 17/17 still pass
(no regression)
- [x] `npx tsx showcase/scripts/validate-fixture-tool-surface.ts` — 33
fixtures × 191 demos, 0 drift
- [x] Counterfactual: revert fixture fix, validator flags
gen-ui-tool-based + declarative-gen-ui exactly
- [x] Direct aimock probe (localhost:4010) for all 8 fixed prompts →
returns correct tool call
- [x] End-to-end through local LangGraph agent (localhost:3100) →
gen-ui-tool-based "Traffic pie chart" suggestion → `render_pie_chart`
with real data
- [ ] Merge → Railway redeploys aimock + langgraph-python → smoke cycle
on Beautiful Chat + gen-ui-tool-based + declarative-gen-ui suggestions