Commit Graph

4305 Commits

Author SHA1 Message Date
Jordan Ritter 4791c86923 fix(showcase/harness): override LOCAL_SERVICES_JSON in --isolate generator to target the requested slug (#5454)
## Summary
- `showcase/docker-compose.local.yml:262` hardcodes
`LOCAL_SERVICES_JSON` to `showcase-langgraph-python` (intentional N=1
demo default).
- `showcase/bin/showcase test <slug> --d6 --isolate` was inheriting that
value verbatim into the iso1 stack, so the iso1 control-plane discovered
`showcase-langgraph-python` instead of `showcase-<requested-slug>`.
- Result: iso1 probes targeted the wrong service. Visible in iso1
harness logs as `discovery.railway-services.local-injection count:1
names:["showcase-langgraph-python"]` regardless of CLI arg.
- This PR teaches the iso1 compose generator (`apply_isolation` in
`showcase/scripts/cli/_common.sh`) to inject a per-slug
`LOCAL_SERVICES_JSON` override built from the slug's manifest.yaml demos
list. Fallback to `["agentic-chat"]` if manifest absent.

## Scope
Two files, ~55 LOC added: `showcase/scripts/cli/cmd-test.sh` (pass slug
arg), `showcase/scripts/cli/_common.sh` (inject regex sub in python
rewriter). Bash + embedded python only; no TypeScript changed.

## Verification
- **Local `--isolate` discovery confirmed correct:**
`showcase/bin/showcase test ms-agent-python --d6 --isolate` — iso1
harness log now shows `discovery.railway-services.local-injection
names:["showcase-ms-agent-python"]` (was `showcase-langgraph-python`
before this PR).
- Persistent stack default behavior (langgraph-python N=1) preserved via
fallback when no slug arg provided.
- **Heredoc hardening scope:** commit edc77f809 moves `$slug` from
bash-interpolation into the python rewriter to an env var. This is a
slug-only carve-out — `$slug` is the only value that originates from the
CLI arg path. The other bash-interpolated `$VAR`s embedded in the
heredoc (`$PORTS_FILE`, `$COMPOSE_FILE`, `$name`, `$SHOWCASE_ROOT`,
`$ISOLATE_PORT_OFFSET`) remain script-internal: each is constructed
inside `_common.sh` from validated sources (manifest reads, computed
offsets, fixed roots), not from user input, and CR Round 1 + Round 2
slot 5 both verified they are not user-tainted. A broader
env-var-pass-all-vars refactor would be a separate concern and is out of
scope for this PR.

## Out of scope
- Worker heartbeat clock-skew issue (`fleet.health.worker-unhealthy
lastHeartbeatAt N min stale`) is a separate bug; not touched.
- `buildLocalServicesJson` in `cli/control-plane-run.ts` has a similar
comment-vs-code disagreement (JSDoc says "filter", code returns env
verbatim) — flagged but not auto-fixed, as iso1 override is the correct
insertion point.
- Generalized env-var-pass for all heredoc-embedded $VARs (see
Verification) — separate refactor concern.
2026-06-15 11:38:26 -07:00
Jordan Ritter 318bd9e45f fix(showcase/aimock): align D6 tool-rendering catchall userMessage to D5 probe input (#5453)
## Summary
- D5 e2e-deep probes for `tool-rendering-{default,custom}-catchall` send
`"forecast for Tokyo"` as the test input (see
`showcase/harness/src/probes/scripts/d5-tool-rendering-{default,custom}-catchall.ts`).
- aimock uses substring match on `userMessage`.
- The catchall fixtures on main had a stale `"check Tokyo weather
forecast"` string that couldn't substring-match the probe input →
fixture miss → probe falls through to live LLM → CV ✗ red D4 on the
dashboard.
- This PR renames the userMessage to the canonical `"forecast for
Tokyo"` across 28 catchall fixture files in 16 integrations.

## Scope
28 files × ~2 userMessage occurrences each = 67 line changes. **No code,
no agent, no page.tsx changes.** Pure fixture-data alignment.

Integrations covered (default-catchall and/or custom-catchall): ag2,
agno, built-in-agent, claude-sdk-python, claude-sdk-typescript,
crewai-crews, google-adk, langgraph-python, langroid, llamaindex,
mastra, ms-agent-dotnet, ms-agent-python, pydantic-ai, spring-ai,
strands.

## Commit history note
Commit b1f19bdc8 changes the rename target from the original `"weather
in Tokyo"` (commit 388c69e68) to `"forecast for Tokyo"`. This was a CR
Round 1 catch: `"weather in Tokyo"` was a substring of the chain pill
prompt (`"weather forecast chain in Tokyo"` / similar), which would have
caused the catchall fixture to incorrectly match chain-pill traffic.
`"forecast for Tokyo"` has no such substring collision with any other
probe input.

## Verification
- **Live red-green proof** was performed on the prior `"weather in
Tokyo"` rename (commit 388c69e68) against `ms-agent-python` via
`showcase/bin/showcase test ms-agent-python --d6 --isolate`:
- Before (origin/main): catchall featureTypes red (fixture miss → live
LLM → flaky)
- After: `d6:ms-agent-python/tool-rendering-default-catchall=green`,
`d6:ms-agent-python/tool-rendering-custom-catchall=green`
- **The current HEAD's `"forecast for Tokyo"` rename (b1f19bdc8) has NOT
been re-run live.** It is verified by static analysis only: substring
math (no collision with any known D5 probe input or chain pill prompt)
and a clean CR Round 2 across all reviewing agents.
- Post-merge dashboard re-probe will be the final runtime verification.

## Out of scope (separate follow-ups)
- LG-TS / LG-FastAPI catchall fixtures don't have the stale string — use
pill-aligned userMessages; need different fix
- `tool-rendering` (non-catchall) and `tool-rendering-reasoning-chain`
featureTypes have separate failure modes
- Other red cells in the dashboard (frontend-tools-cosmic timeout,
agent-config, auth, etc) are unrelated
2026-06-15 11:33:34 -07:00
Jordan Ritter edc77f8090 fix(showcase/harness): pass slug via env var to python rewriter instead of bash interpolation
The python rewriter in apply_isolation previously interpolated $slug
directly into the inline python source via bash. A slug containing a
single quote would break the python literal. Internal-tool risk only
(slug is developer-typed), but cheap to harden.

Pass slug via SHOWCASE_ISO_SLUG env var and read os.environ.get(...)
inside the python heredoc. Defense-in-depth; no behavior change for
valid slugs.
2026-06-15 11:16:24 -07:00
Jordan Ritter b1f19bdc80 fix(showcase): rename catchall userMessage to 'forecast for Tokyo' to avoid chain pill substring collision
The previous 'weather in Tokyo' rename (388c69e68) was a substring of the
main tool-rendering chain pill prompt 'Chain a few tools in this single
turn: get the weather in Tokyo, search flights from SFO to Tokyo, and roll
a d20.' Because aimock loads fixtures alphabetically per integration dir
and uses substring match with first-match-wins, the catchall fixture
(loaded before tool-rendering.json) was intercepting chain pill matches
across 16 integrations.

Rename catchall fixture userMessage to 'forecast for Tokyo' — a phrase
not contained in any other pill prompt. Update the corresponding D5
catchall probe inputs in d5-tool-rendering-{default,custom}-catchall.ts
and the test assertions that pin those inputs.

Call-Site Enumeration: 'weather in Tokyo' remains intentionally in
page.tsx suggestions.ts pills (user-visible UX) and inside the chain
pill prompt itself — neither is in the substring-match path now.
2026-06-15 11:14:57 -07:00
Jordan Ritter 5e641d88c9 fix(showcase/harness): override LOCAL_SERVICES_JSON in --isolate generator to target the requested slug
The persistent stack's docker-compose.local.yml hardcodes LOCAL_SERVICES_JSON
to the langgraph-python sample for fast N=1 local demos. When --isolate
spawns an iso1 stack with a different slug (e.g. ms-agent-python), the
iso1 harness container inherited that hardcoded value, causing
discovery.railway-services.local-injection to enumerate the wrong service
(showcase-langgraph-python instead of showcase-<requested-slug>). The iso1
probe then targeted the wrong container, broke red-green verification, and
left D5 cells unwritten.

Inject a per-slug LOCAL_SERVICES_JSON override into the iso1 compose
generator so iso1 always probes the slug passed via --isolate.
2026-06-15 10:38:06 -07:00
Jordan Ritter 87b369fdb4 feat(showcase): declarative gen-UI demo as a sales-analyst dashboard (OSS-136) (#5396)
## Summary
- Reworks the `declarative-gen-ui` demo (LangGraph Python + Google ADK)
to feel like Beautiful Chat's sales dashboard, per
[OSS-136](https://linear.app/copilotkit/issue/OSS-136/declarative-gen-ui-demo-rework-to-feel-like-beautiful-chats-sales)
- Suggestion pills are natural business questions; chart-type steering
moved from user prompts into the agent system prompt + frontend context
(`sales-context.ts`, shared verbatim by both integrations)
- Every pill renders a dashboard-grade surface:
- **Show my sales dashboard** — bare KPI strip + regional revenue donut
+ 6-month revenue bars (no surrounding card)
  - **Team performance** — rep table + quota-attainment bar chart
- **Anything at risk?** — risk KPI strip over three severity cards (icon
badges, reason + next action)
  - **Top account details** — account fact card + product-line donut
- Renderers ported to beautiful-chat's visual language: card chrome,
metric typography, recharts donut/bars, shared palette, lucide severity
icons
- Test triad synced: D5 probe (per-pill newly-mounted testid
assertions), Playwright e2e (incl. click-dispatch guard), aimock
fixtures **captured from live model responses**, QA docs

## Verification
- Fixture validation: 738/738 · harness probe unit tests: 17/17
- Container e2e (fixture replay, both integrations rebuilt): LGP 6/6 ·
ADK 6/6
- Live-LLM iteration on LGP: all four pills produce the steered
composition consistently (11/11 captured runs + repeated interactive
verification)

## Test plan
- [ ] `pnpm exec nx run @copilotkit/showcase-harness:test --
d5-gen-ui-declarative`
- [ ] `pnpm --filter @copilotkit/showcase-scripts test aimock-fixtures`
- [ ] `BASE_URL=<container> npx playwright test
declarative-gen-ui.spec.ts` per integration
- [ ] Post-deploy:
https://dashboard.showcase.copilotkit.ai/#matrix:links,health row
"Declarative UI: Dynamic A2UI" still reaches D5 (CV badge) for
langgraph-python and google-adk
2026-06-15 09:42:45 -07:00
Jordan Ritter d5152eaa83 fix(showcase/e2e+qa): composition exclusions + KPI=4 contract alignment
- Scope clickPill locator to data-message-role='user' bubble so the pill
  button itself can no longer satisfy the dispatch guard
- Dedup clickPill retry: skip click if the user bubble already exists
- Hero pill: assert declarative-card count=0 (OSS-136 no-Card rule),
  metric count >=4 (was >=3 — KPI strip is 4 tiles per composition rule)
- At-risk pill: assert no chart and no table testids (composition rule)
- Top-account pill: assert no data-table and no status-badge testids
- Rename hero test title to 'KPI strip + pie + bar (no surrounding card)'
  so the title no longer falsifies the body
- QA docs: replace 'card + metrics + pie + bar' Expected Results with
  '4 KPI metrics + 1 PieChart + 1 BarChart, no surrounding Card per OSS-136'
- Probe responseTimeoutMs derived from FIRST_SIGNAL_TIMEOUT_MS so it
  matches the e2e 90s budget
2026-06-15 09:35:46 -07:00
Jordan Ritter 3ec2432964 fix(showcase/harness): newly-mounted gate + minCounts delta + per-pill chart asserts
- Migrate readDeclarativeTestIds from booleans to counts so leftover vs
  newly-mounted is distinguishable
- everyNewlyMounted gate uses current[k] > baseline[k] (was boolean
  !baseline[k] against a count, which falsely blocked at non-zero baseline)
- minCounts enforce newly-mounted delta, not raw current count
  (fixes the cross-pill bleed: at-risk metric:3 floor used to pass on
  hero's 3 leftover metrics with no fresh mount)
- Per-pill minCounts add the chart sibling asserts D5 was missing:
  hero=4 metric+1 pie+1 bar, team=1 table+1 bar, top-account=1 info-row+1 pie
- 31/31 harness tests green
2026-06-15 09:35:45 -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
Jordan Ritter df48df3587 fix(showcase/google-adk): align aimock fixture + suggestions comment
- Correct suggestions.ts file-path reference (was pointing at LP a2ui_dynamic.py)
- Tighten userMessage matchers to full pill prompts
- Strip unschema'd weight/variant fields from Metric/Card/Chart/Text payloads
2026-06-15 09:35:44 -07:00
Jordan Ritter e57ea6b864 fix(showcase/langgraph-python): align agent + aimock with ADK parity
- Replace fake gpt-5.4 with env-overridable real model (default gpt-4o)
- Register generate_a2ui tool matching SYSTEM_PROMPT + ADK structure
- Stub tool raises RuntimeError if middleware bypassed (fail-loud)
- Reorder LP fixture entries: inner render_a2ui before outer generate_a2ui
  to match ADK first-match-wins ordering
- Tighten userMessage matchers to full pill prompts (no substring hijack)
- Drop dead _design_a2ui_surface mirrors; strip unschema'd weight/variant fields
- Honest SYSTEM_PROMPT comment cross-referencing ADK _INSTRUCTION
2026-06-15 09:35:43 -07:00
Jordan Ritter 388c69e684 fix(showcase): align D6 tool-rendering catchall userMessage to D5 probe input
The D5 e2e-deep probe for tool-rendering-{default,custom}-catchall sends
"weather in Tokyo" as the test input (harness/src/probes/scripts/
d5-tool-rendering-{default,custom}-catchall.ts). The fixture userMessage
matcher uses substring match. Main's catchall fixtures had a stale
"check Tokyo weather forecast" string that could not substring-match
the probe input, causing the fixture to miss and the probe to fall
through to the live LLM — surfacing as CV x red D4 on the dashboard.

Rename to the canonical "weather in Tokyo" string across affected
integrations' tool-rendering-{default,custom}-catchall.json files.

No agent or page.tsx changes; fixture content otherwise unchanged.
2026-06-15 09:17:42 -07:00
Alem Tuzlak 21e4b87a43 docs(shell-docs): add WhatsApp bot guide 2026-06-15 17:08:27 +02:00
Alem Tuzlak a925e33be9 docs(bot-slack): document assistant pane + native streaming; enable in slack example
Update package READMEs + ARCHITECTURE for the assistant pane, native streaming,
and the new onThreadStarted / setSuggestedPrompts / setTitle surface. Reverse
the slack.mdx callout that told users to delete the assistant scopes (now
required), and enable the pane in the examples/slack manifest (assistant_view +
assistant:write + assistant_thread_* events) with a dev-ex onThreadStarted
greeting and the assistant config.
2026-06-15 15:47:46 +02:00
Jordan Ritter 97031e54e1 fix(showcase/aimock): break BIA tool-rendering cross-pill shadow on hasToolResult fallback
The custom-catchall probe sends 'weather in Tokyo' then 'AAPL'. After the
weather tool runs in turn 1, hasToolResult is true across the rest of the
thread — which fires tool-rendering.json's AAPL 'hasToolResult:true' narration
prematurely on turn 2 iteration 1, returning prose without ever emitting the
get_stock_price tool. The custom-catchall assertion (both tools rendered
through the wildcard testid) then fails with missing get_stock_price.

Replace the (hasToolResult:true narration + hasToolResult:false/turnIndex:0
emitter) layered fallbacks with a sequenceIndex:0 emitter ordered before a
bare userMessage+context narration. The per-test fixture-match counter resets
each run, so the emitter fires exactly once on iteration 1 regardless of
prior pills' tool history, then falls through to the narration on
iteration 2. Applied symmetrically to the two AAPL blocks in
tool-rendering.json (the 'What\'s the current price of AAPL?' block at the
top and the legacy 'current price of AAPL' alias block lower down). The
toolCallId-keyed narration above each block is retained for the non-BIA
fast path.

The earlier partial fix to tool-rendering-custom-catchall.json is kept (it
adds toolCallId-scoped narration legs ordered before the existing
hasToolResult:true narrations); those fixtures never match real probe
traffic (the probe sends 'weather in Tokyo' / 'current price of AAPL', not
the unique 'check Tokyo weather forecast' substring in this file) but the
reordering is consistent with the cross-file pattern and harmless.

Verified locally: built-in-agent:tool-rendering and
built-in-agent:tool-rendering-custom-catchall both green via
`./bin/showcase test ... --d6 --direct`; built-in-agent:tool-rendering-default-catchall
also green; aimock-fixtures.test.ts (collision/shadow ceilings) unchanged.
2026-06-15 00:18:53 -07:00
Jordan Ritter cb9fbe4c55 feat(showcase/built-in-agent): D6 BIA component port — tool-rendering + headless-complete + LGP-canonical naming (#5427)
## Summary

BIA D6 component port (#4 from PR #5413 followup list). Companion to PR
#5407 (claude-sdk-python), PR #5413 (initial BIA D6), PR #5421 (BIA D6
small follow-ups). Brings BIA closer to LGP gold-standard parity.

### What's in

- **tool-rendering**: 5 LGP-mirrored companion components
(`weather-card`, `flight-list-card`, `stock-card`, `d20-card`,
`custom-catchall-renderer`) + extracted `tool-renderers.tsx` wiring.
**D6 GREEN.**
- **headless-complete**: 2 new components (`stock-card`, `chart-card`) +
`get_revenue_chart` server tool + LGP-aligned 4 pill suggestions +
`data-message-role` on bubble cascade + `get_weather` tool name fix in
tool-renderers. Turns 1 (weather) + 2 (stock) GREEN.
- **roll_dice → roll_d20 rename** across BIA backend + reasoning-chain
references (LGP canonical naming).
- **aimock fixtures**: BIA-namespaced `tool-rendering.json` updated +
`tool-rendering-reasoning-chain.json` realigned to the rename.
- **PARITY_NOTES**: documents the server-tool reprompt loop
architectural gap blocking turns 3+4 of headless-complete.

### Known issue (documented in PARITY_NOTES.md, out-of-PR-scope)

headless-complete turns 3 (highlight_note) and 4 (revenue_chart) RED due
to BIA's TanStack multi-turn server-tool reprompt cycle + aimock
userMessage-keyed fixtures looping until timeout. Three remediation
options identified — all require changes outside this PR's scope (BIA
agent architecture / aimock matcher precedence / fixture matcher
gating).

### Test plan

- [x] Local `--direct` D6 on tool-rendering: GREEN (2.8s)
- [x] Local `--direct` D6 on headless-complete: turns 1+2 GREEN, turns
3+4 RED (documented)
- [x] CI green on PR
2026-06-14 20:15:30 -07:00
Timothy Asiimwe b19db9f966 docs: fix recurring spelling typos in README and tutorials
- README: 'procuct' -> 'product'
- agentic-protocols/a2a: 'recieved' -> 'received'
- ai-travel-app/step-5: 'Recieving'/'manaully'/'recieve' -> 'Receiving'/'manually'/'receive'
- ai-travel-app/step-6: 'recieve'/'recieves' -> 'receive'/'receives'

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 23:15:52 -04:00
Tyler Slaton f655013dd2 fix(showcase): harden built-in-agent root rollout 2026-06-12 17:17:18 -07:00
Tyler Slaton 88de23324a Merge remote-tracking branch 'origin/main' into codex/bia-root-review-fix 2026-06-12 16:47:25 -07:00
Tyler Slaton 1adaf1b839 fix(shell-docs): harden built-in-agent root migration 2026-06-12 16:41:13 -07:00
Tyler Slaton 6d6a65c531 docs: testing that previews are up
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-06-12 16:27:57 -07:00
Tyler Slaton 5c8c56071b feat(shell-docs): serve Built-in Agent docs at the docs root
The default framework's docs now live at bare root URLs (/quickstart,
/server-tools, ...) instead of under /built-in-agent/. The root
catch-all resolves BIA-authored pages first, /built-in-agent/:path*
permanently redirects to /:path*, and sidebar/landing/selector hrefs
are root-relative.

The whole root surface shares ONE sidebar: the Built-in Agent IA with
the agnostic root sections (Concepts, Runtime, Deploy, Platforms, Other)
folded in via buildRootSurfaceNav. Empty ---Section--- placeholders in
the BIA meta.json position each folded-in section; appendSharedRootSections
fills them, dropEmptySections clears any that stay empty, and route-group
nodes (e.g. the (other) tree) are excluded so the fold never emits a bogus
/(other)/... href. Without this, navigating from a BIA page to an agnostic
page (/concepts/*, /backend/*) swapped the sidebar between two overlapping
IAs. The fold is scoped to the root surface only — deepagents keeps
Platforms-only and generated frameworks are untouched.

Duplicate pages that the fold would otherwise double up are consolidated
onto their canonical root homes:
- The three BIA backend wrappers (copilot-runtime, custom-agent, ag-ui)
  are retired; the folded-in Runtime section is their single home. This
  resolves the /backend/ag-ui collision (the wrapper had shadowed the
  real root page). The bare /ag-ui segment belongs to the AG-UI protocol
  docs, so old /built-in-agent/ag-ui links redirect to /backend/ag-ui.
- The BIA troubleshooting wrappers are retired in favor of the canonical
  /troubleshooting/* pages surfaced by the folded-in Other section, so
  Troubleshooting appears once.

Stale redirect R25 (/runtime-server-adapter -> /backend/copilot-runtime)
is removed: runtime-server-adapter is a distinct, current 'Deploy to any
runtime' page linked from the sidebar, and the redirect had made it
unreachable at its own URL.

Middleware rules that would shadow or loop against the new surface
(M2 /quickstart, BIA_DEFAULT_ROOT_REDIRECTS, MV-telemetry) are retired,
and remaining live destinations move off the old prefix. The sitemap,
llms.txt, per-page .md/.mdx, and OG image routes resolve the same
content the pages serve. The client-side RouterPivot bounce is removed
since root URLs now render real content in place.
2026-06-12 16:08:35 -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 667114cfa4 test(showcase): assert pill clicks dispatched in declarative-gen-ui e2e
Click a pill, then require the user-message bubble before asserting on
the surface; retry the click if it was swallowed. On slow dev-server
hydration the first click can land before the chat send pipeline is
wired, which previously burned the full surface-assertion budget and
masked the real failure point.
2026-06-13 00:14:49 +02:00
Maxim a558adc2d8 test(showcase): source gen-ui-declarative fixtures from captured live responses
Replaces the hand-authored surface payloads with real gpt-5.4 responses
captured via the langgraph dev threads API during OSS-136 prompt
iteration (catalogId injected, since the replay path resolves the catalog
from recorded tool args). Verified: fixture suite 738/738, LGP container
e2e 6/6, ADK container e2e 6/6.
2026-06-13 00:14:48 +02:00
Maxim 513bf87234 test(showcase): regenerate gen-ui-declarative aimock fixtures for the new pills
Same three-call choreography per pill (outer generate_a2ui, inner design
toolcall discriminated by toolName, narration matched by toolCallId), now
keyed to the sales-analyst prompts and emitting Vantage Threads payloads:
composed hero dashboard, rep DataTable, at-risk StatusBadge cards, and
top-account InfoRows. Verified by the LGP Playwright run against the
aimock-backed container (6/6).
2026-06-13 00:14:48 +02:00
Maxim 7c68e95b04 test(harness): sync gen-ui-declarative D5 probe to the sales-analyst pill set
Hero pill asserts the composed dashboard conjunctively (card + metric +
pie + bar); pills 2-4 each require a testid the hero is steered not to
mount (data-table / status-badge / info-row), preserving the
newly-mounted anti-masking gate.
2026-06-13 00:14:48 +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
Jordan Ritter 8b6052ac7e fix(showcase/scripts): ratchet aimock-fixtures ceilings + close BIA headless-complete reprompt-loop known-issue
* duplicate ceiling 290→291: tool-rendering.json's tightened 'current
  price of AAPL' matchers now share two match keys with the existing
  tool-rendering-custom-catchall.json entries in the same BIA context,
  runtime-disambiguated by feature route.
* shadow ceiling 134→132 (ratchet down): the bare 'AAPL' vs 'current
  price of AAPL' shadow pair on the tool-rendering.json side is gone.
* PARITY_NOTES: replaces the 'headless-complete turns 3+4 server-tool
  reprompt loop' known-issue section with a resolved-via-sequenceIndex
  description; the architectural reprompt loop now converges via the
  sequenceIndex-gated emitter + narration-fallback pattern in
  gen-ui-headless-complete.json.
2026-06-12 14:50:47 -07:00
Jordan Ritter 89a2dd52ef fix(showcase/aimock): gate gen-ui-headless-complete emitters with sequenceIndex to break BIA reprompt loop
BIA registers headless-complete's tools (get_weather, get_stock_price,
get_revenue_chart, highlight_note) as server-executed via TanStack's
chat() engine. After the LLM returns a tool call, TanStack runs the
server tool and reprompts the LLM with the result. The userMessage-keyed
toolcall fixtures fired again on every reprompt because the original
user pill text stays in conversation history — and the toolCallId-keyed
narration fallback never matched because BIA's /v1/responses endpoint
rewrites the assistant tool_call_id to a runtime-generated fc-… value.
Net effect: turns 3+4 (highlight, revenue chart) ballooned to 70+
assistant messages within the 60s timeout window.

Restructured each pill as a (sequenceIndex:0 emitter, narration
fallback) pair. The emitter matches the FIRST request for the pill
prompt (counter starts at 0) and emits the tool call; subsequent BIA
reprompt iterations fall through the now-exhausted emitter to the
narration fallback (no tool call), so the loop converges. sequenceIndex
is chosen over hasToolResult:false because hasToolResult is computed
across the entire thread — any earlier pill's tool result would
permanently disable a hasToolResult:false emitter, breaking multi-turn
sessions where turn 2+ would have hasToolResult=true globally.
2026-06-12 14:50:26 -07:00
Jordan Ritter ab05464c5e fix(showcase/aimock): tighten built-in-agent tool-rendering matchers to avoid shadowing gen-ui-headless-complete pills
The legacy bare 'AAPL' userMessage matchers in tool-rendering.json were
substrings of gen-ui-headless-complete's 'price of AAPL right now'
pill prompt, so when the BIA TanStack server-tool reprompt loop hit
iteration 2 (toolCallId chain broken by /v1/responses id rewriting),
the request fell through to tool-rendering.json's loose 'AAPL'
matchers and leaked wrong-card content. Tightened all four bare 'AAPL'
match keys to 'current price of AAPL' — preserves matching for the
tool-rendering 'Stock price' pill ("What's the current price of
AAPL?") and the custom-catchall probe's second prompt ("What's the
current price of AAPL?") while no longer matching the headless
probe's "What's the price of AAPL right now?".
2026-06-12 14:50:26 -07:00
Mark 60d39eae82 fix(showcase): pin page-registered A2UI catalog as defaultCatalogId fleet-wide (#5425)
## Problem

Asking for a sales dashboard in the beautiful-chat demo (reported on
`dojo.showcase.copilotkit.ai/?integration=langgraph-python&demo=beautiful-chat`)
fails with:

> A2UI render error: Catalog not found:
https://a2ui.org/specification/v0_9/basic_catalog.json

## Root cause

**Introduced by #5245** ("chore(showcase): upgrade langgraph A2UI to
stable releases + rewrite dynamic-schema docs", merged 2026-06-05): it
flipped the beautiful-chat routes to `injectA2UITool: true` — switching
them onto the runtime-injected `render_a2ui` tool — without adding the
`defaultCatalogId` the middleware contract expects the host to provide.
/cc @ranst91

The runtime-injected `render_a2ui` tool guide explicitly tells the model
**not** to send a `catalogId` ("the catalog id is set by the host, not
by you" — `@ag-ui/a2ui-middleware` `tools.ts`), and integrations whose
backend owns `generate_a2ui` see real models omit or late-stream the
argument. When the streamed `createSurface` is emitted without a
configured `defaultCatalogId`, the middleware falls back to the spec
basic catalog URL — which no showcase page registers, so the renderer
throws "Catalog not found".

The middleware contract expects the host to pin the catalog via
`a2ui.defaultCatalogId`; none of the showcase routes did. The pinned
`@ag-ui/a2ui-middleware@0.0.6` (resolved via
`@copilotkit/runtime@1.59.4` in the integration lockfiles) already
prefers the configured value over streamed args, so this is config-only.

## Fix

Add `defaultCatalogId` matching the catalog each page registers:

- 17 × `copilotkit-beautiful-chat` routes →
`copilotkit://app-dashboard-catalog` (every beautiful-chat page
registers this id)
- 14 × `copilotkit-declarative-gen-ui` routes →
`declarative-gen-ui-catalog` (all declarative catalogs use this id)

Left untouched: the 3 declarative routes with no `a2ui` block (ag2,
claude-sdk-typescript, strands) — `isA2UIEnabled` is false there, the
middleware never attaches, so the fallback path can't fire.
`copilotkit-a2ui-fixed-schema` routes are also untouched (direct tools
carry their catalog in the result envelope).

## Verification

- RUNBOOK-canonical D6 isolate run (`bin/showcase test langgraph-python
--d6 --isolate ...`) on this branch: **all A2UI pills green**
(`gen-ui-declarative`, `gen-ui-a2ui-fixed`, all five beautiful-chat
pills) — these stream through the middleware with the new
`defaultCatalogId` active (config preference). Aggregate green; the only
non-green features are pre-existing and unrelated (2×
`crypto.randomUUID` insecure-context in headless demos, 1× agent-config
fixture-length assertion).
- All 31 patched files parse-checked clean; full `tsc --noEmit` on
langgraph-python shows zero errors in the patched routes.
- Confirmed published middleware 0.0.6 (what the integration lockfiles
resolve) contains the host-preference logic for `defaultCatalogId`.
- Caveat: the Sales Dashboard pill itself could not be manually verified
end-to-end — its aimock fixture chain is broken by a pre-existing
fixture-shadowing collision from the `1e66a5f8d` fixture reorg (a
`userMessage: "First"` substring catch-all shadows the pill prompt;
three overlapping fixture chains mismatch on `toolCallId`
mid-conversation → `404 no_fixture_match` → `RUN_ERROR`). Broken
identically on `main`; tracked as a follow-up issue.

## Follow-ups (not in this PR)

- The canonical `examples/integrations/langgraph-python` route has the
same gap (`a2ui: { injectA2UITool: false }`, no `defaultCatalogId`,
pages register `copilotkit://app-dashboard-catalog`) — needs the same
fix through the parity sync flow.
- Test gap that let this ship: the D5 declarative fixture is a text-only
stub and beautiful-chat's D5 mapping reuses the agentic-chat
conversation, so no fixture exercises a `generate_a2ui` call that omits
`catalogId` the way real models do.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-12 13:58:09 -07:00
Austin Merrick 018b957305 docs(shell-docs): add @copilotkit/react-native reference documentation (#5397)
Adds a **React Native** SDK to the reference docs at
`/reference/react-native`, covering the full `@copilotkit/react-native`
public API. Modeled on the existing React/Core/Bots reference sections.

**Nav:** register `react-native` in `reference-items.ts`, add the SDK
selector label + an overview card.

**Content (22 pages, written from package source):** index, 8
components, 13 hooks. `CopilotChat` and `CopilotModal` exist in both a
headless (root) and prebuilt-UI (`/components`) form; each page
documents both, split by import path.

**Verified:** `next build` passes, all pages render, `oxlint` + `tsc`
clean, and content appears in `llms.txt` / `llms-full.txt`.

Out of scope per the issue: guide content and new demos.


---

## Preview

**Overview + SDK nav** — `/reference/react-native` (left sidebar shows
the new “React Native” SDK selector and all 8 components + 13 hooks)

![React Native reference
overview](https://raw.githubusercontent.com/CopilotKit/CopilotKit/0ce40a7546eeb5556580882a0b6ecf8923284490/pr-screenshots/rn-01-overview.png)

**Component page — `CopilotChat`** —
`/reference/react-native/components/CopilotChat` (headless + prebuilt-UI
split by import path)

![CopilotChat reference
page](https://raw.githubusercontent.com/CopilotKit/CopilotKit/0ce40a7546eeb5556580882a0b6ecf8923284490/pr-screenshots/rn-02-component-copilotchat.png)

**Hook page — `useAgent`** — `/reference/react-native/hooks/useAgent`
(re-export callout, react-native code examples)

![useAgent reference
page](https://raw.githubusercontent.com/CopilotKit/CopilotKit/0ce40a7546eeb5556580882a0b6ecf8923284490/pr-screenshots/rn-03-hook-useagent.png)
2026-06-12 13:20:35 -07:00
github-actions[bot] 43fed818f1 style: auto-fix formatting 2026-06-12 19:23:14 +00:00
Jordan Ritter 0ddf1c029b docs(showcase/built-in-agent): PARITY_NOTES known-issue for headless-complete server-tool reprompt loop 2026-06-12 12:22:13 -07:00
Jordan Ritter 07ce13a83c fix(showcase/aimock): BIA aimock fixtures for tool-rendering + tool-rendering-reasoning-chain + shadow-ceiling 128→134 2026-06-12 12:22:09 -07:00
Jordan Ritter 81e64bba3a fix(showcase/built-in-agent): align headless-complete bubbles with D6 conversation-runner cascade (data-message-role + get_weather wiring) 2026-06-12 12:13:12 -07:00
Jordan Ritter 0e3f7e3fa6 feat(showcase/built-in-agent): port headless-complete stock-card + chart-card + get_revenue_chart server tool + LGP-aligned suggestions 2026-06-12 12:13:07 -07:00
Jordan Ritter 9f4fd4c189 fix(showcase/built-in-agent): rename roll_dice → roll_d20 to match LGP canonical naming 2026-06-12 12:12:57 -07:00
Jordan Ritter 0009aff9cd feat(showcase/built-in-agent): port 5 LGP tool-rendering companion components (weather, flight, stock, d20, custom-catchall) + tool-renderers wiring 2026-06-12 12:12:11 -07:00
Mark Fogle 53801f8e04 test(showcase): make sales-dashboard e2e reproduce real-model catalogId omission
The injected/streamed a2ui fixtures all included catalogId, so aimock
replay never exercised the basic-catalog fallback that broke production
(real models omit catalogId per the tool-usage guide). Strip catalogId
from the langgraph-python sales-dashboard secondary-call fixtures and
hard-assert "Catalog not found" is absent outside the charts-rendered
soft branch, so the spec fails without a route defaultCatalogId.

Also repoint the on-demand e2e workflow at the d4/d5-recorded/d6/shared
fixture dirs — it still referenced feature-parity.json, deleted in the
1e66a5f8d fixture reorg, so every /test-aimock run died at aimock start.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 18:47:16 +00:00
Austin Merrick cf5126a04e docs(shell-docs): add @copilotkit/react-native reference documentation
Adds a "React Native" SDK to the reference section, documenting the full
public surface of @copilotkit/react-native at /reference/react-native.

Navigation wiring:
- Register `react-native` in REFERENCE_VERSIONS / VERSION_SUBDIRS
- Add the "React Native" label to the SDK version selector
- Add a React Native card to the reference overview page

Content (22 pages, sourced from package source for accuracy):
- index: install, polyfills, provider setup, and the headless vs prebuilt
  two-tier model
- components: CopilotKitProvider, CopilotChat, CopilotModal, CopilotSidebar,
  CopilotPopup, CopilotMarkdown, AssistantMessage, UserMessage — disambiguating
  the headless (root) and prebuilt-UI (/components) variants of CopilotChat and
  CopilotModal by import path
- hooks: RN-specific useAttachments and useRenderTool, plus the platform-
  agnostic hooks re-exported from react-core/v2 adapted to RN imports and
  primitives (useAgent, useCopilotKit, useFrontendTool, useAgentContext,
  useThreads, useCapabilities, useComponent, useHumanInTheLoop, useInterrupt,
  useSuggestions, useConfigureSuggestions)

Content is picked up automatically by llms.txt / llms-full.txt via the
reference content walker.

OSS-250
2026-06-12 11:37:55 -07: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
Jordan Ritter 4e4180bf88 fix(showcase/harness): redefine family lastSuccessAt — terminal-completion, not all-green (#5422)
## Symptom

Dashboard banner false alarm: *"Worker family E2E demos has not
completed successfully since 2h 40m ago"* (and the same on D5/D6) firing
while workers were healthy and emitting results every cycle.

## Triage (already done)

The D5/D6 family-silence banner fires because:

- `lastSuccessAt` is computed via `maxFinishedAtIso(completed)` where
`completed` requires the §5.2.1 `deriveOutcome` to return `"completed"`
(all jobs `done`, zero cell failures) — see
`showcase/harness/src/fleet/control-plane/run-view.ts` (pre-fix
`findCompletedBatch` + the `lastSuccessAt` line in `projectFamily`).
- With chronic content-reds present, every batch lands with
`jobs.done=1, jobs.failed=17` (cells failing inside the probes). The
outcome derives `"failed"`, no batch satisfies `outcome ===
"completed"`, and `findCompletedBatch` returns null.
- The family-silence monitor falls back to oldest-batch-`enqueuedAt` and
fires after `now − oldest > 3 × period` (see
`family-silence-monitor.ts`).
- The worker is fine: per-job `commError: null`, jobs completing with
real cell results, just `<100%` pass-rate.

This is a DEFINITIONAL bug. The worker is healthy; the definition of
"success" was conflating worker-completion with cells-all-green.

## The fix

Redefine "success" as **terminal-state accounting**, not pass-rate.

A batch counts as a terminal completion when:
1. Every job is in a terminal status (`done` or `failed`), AND
2. No job carries a `result.commError` (i.e. no worker-crashed-mid-job,
lease-expired, or other comm-level outage signal).

Cells red without a `commError` IS a terminal completion — the worker
reached the pool, ran the probe, and returned a result. Chronic content
reds become "known bad" instead of "stalled."

The strict §5.2.1 `outcome=="completed"` all-green semantic is unchanged
— it still drives `lastRun.outcome` and §6.2 dashboard rendering. No
external caller of run-view consumed the old strict `lastSuccessAt` for
logic beyond the banner and monitor (grep verified — every reference
outside this file is either a test fixture or the silence-banner display
surface), so renaming was unnecessary; only the definition was
redirected.

The fallback path in `family-silence-monitor.ts`
(oldest-batch-enqueuedAt when `lastSuccessAt` is null) is intentionally
**untouched** — with the new semantics, `lastSuccessAt` advances every
sweep on a healthy family, so the fallback only fires on true
never-completed envs (the rule it was designed for).

## Affected files

- `showcase/harness/src/fleet/control-plane/run-view.ts` — new
`isTerminalCompletionBatch` + `findTerminalCompletionBatch` predicates;
`projectFamily` now sources `lastSuccessAt` from terminal completion;
doc comment on the type updated.
- `showcase/harness/src/fleet/control-plane/run-view.test.ts` — 3 new
tests; 1 existing walk-back fixture updated to add a `commError` so its
original intent (skip non-completion batches) survives the new
predicate.
-
`showcase/harness/src/fleet/control-plane/family-silence-monitor.test.ts`
— 2 new tests: chronic-reds stays silent; real outage still fires.
- `showcase/harness/src/http/fleet-runs.test.ts` — T5 multi-page
walk-back fixture updated to flag its 20 "outage" batches with a
`commError` (so the walk-back still has to extend to page 2);
`batchFixture` gained an optional `resultFor` parameter.

## Tests (RED → GREEN)

Confirmed the 2 net-new predicate tests fail under the old
implementation and pass under the new:

- `lastSuccessAt advances when all jobs reach a terminal state with no
commError, even if cells failed` — old: `null`, new: newest finishedAt
- `lastSuccessAt does NOT count a batch where any job carries a
commError (worker-outage signal)` — old: `null` (walk-back to prior
worked but for the wrong reason — strict all-green semantics), new:
walks back past the comm-erroring batch to the terminal-completion batch

Negative cases preserved:
- `lastSuccessAt is null when every batch in the capped window has a
commError` — real outage stays loud
- `lastSuccessAt does NOT count a batch with non-terminal jobs` —
stall/abandon still excluded
- Family-silence monitor still alerts on real outages

Final test counts: harness `2700/2700` green, fleet/control-plane +
fleet-runs slice `355/355` green; format / lint / typecheck / build all
clean.

## Follow-up

Per the minimize-PRs directive, the D5+D6 banner remediation and
`redsCleared` semantic refresh are tracked separately in the coordinate
channel handoff — this PR is scoped to the `lastSuccessAt` definitional
fix.
2026-06-12 10:40:29 -07:00
Jordan Ritter 34ca7f1292 fix(showcase/harness): redefine family lastSuccessAt as terminal-completion, not all-green
Chronic content-reds in the D5/D6 worker families left `lastSuccessAt`
pinned to null on /api/runs, which tripped the dashboard "worker family X
has not completed successfully since Yh ago" silence banner even though
the workers were healthy. Each batch landed with jobs.done=1,
jobs.failed=17 (cells failing inside the probes), the §5.2.1 outcome
precedence derived "failed", findCompletedBatch returned null, and the
§9 family-silence monitor fell back to oldest-batch-enqueuedAt and fired
after 3 x period.

The fix is definitional: a batch counts as a "terminal completion" for
lastSuccessAt purposes when every job reaches a terminal state (done |
failed) with no `result.commError` on any row. Cell-level reds (rollup
counts) no longer block the timestamp; only worker-level outages
(crashed / reclaimed / lease-expired, surfaced via commError) do.

The strict §5.2.1 outcome=="completed" all-green semantic is unchanged
(it still drives lastRun.outcome and §6.2 dashboard rendering). No
caller of run-view consumed the old strict lastSuccessAt for logic
beyond the banner and monitor (grep verified — every external reference
is either a test fixture or the silence-banner display surface).

Tests added (RED -> GREEN):
- run-view.test.ts: lastSuccessAt advances when all jobs reach a terminal
  state with no commError, even if cells failed (the regression case)
- run-view.test.ts: lastSuccessAt does NOT count a batch where any job
  carries a commError (worker-outage signal stays loud)
- run-view.test.ts: lastSuccessAt does NOT count a batch with non-terminal
  jobs (stalled / abandoned still excluded)
- family-silence-monitor.test.ts: does not alert when the family runs every
  cycle with cell-level reds but no commError
- family-silence-monitor.test.ts: still alerts when the family stops
  emitting results entirely (real outage)

Two existing tests updated to add commError to their "no completion"
fixtures so their original intent (walk-back across non-completion
batches) survives the new predicate:
- run-view.test.ts: lastSuccessAt walk-back through a commError batch
- fleet-runs.test.ts: T5 multi-page walk-back coverage
2026-06-12 10:31:17 -07:00
Jordan Ritter bf37f3808d fix(showcase/built-in-agent): emit STATE_DELTA with op:add (not replace) so first /steps patch creates the path 2026-06-12 10:24:54 -07:00