Commit Graph

11311 Commits

Author SHA1 Message Date
Jordan Ritter e457a41c00 fix(react-core): await runAgent in useInterrupt::resolve
resolve() previously called copilotkit.runAgent(...) without await and
without return, so callers had no handle to sequence against the resume
run's settle. The harness DOM-settle check timed out for any consumer
awaiting the assistant confirmation bubble.

Add regression test: resolve returns a Promise that settles only after
runAgent settles.
2026-06-15 15:10:00 -07:00
Jordan Ritter c43ed08e7b ci(e2e-dojo): run dojo suites on 4-vCPU runner (−40% wall-clock) (#5452)
Bumps the dojo e2e matrix from `depot-ubuntu-24.04` (2 vCPU) to
`depot-ubuntu-24.04-4` (4 vCPU) and `NX_PARALLEL: 4` so the build uses
the extra cores. This is the non-serializing way to cut dojo wall-clock
(the build-once dedup tried in #5450 regressed wall-clock and was
reverted).

## Result: −40% wall-clock (measured on CI)

Dojo wall-clock = the single slowest suite (the 15 run in parallel).
Comparison vs the 2-vCPU baseline:

| metric | 2-vCPU baseline | 4-vCPU | Δ |
|---|---|---|---|
| **wall-clock** (long pole `langgraph-python`) | 623s (10.4m) | **373s
(6.2m)** | **−40%** |
| runner-minutes (wall summed, 15 suites) | 105m | 76m | −28% |
| **billed compute** (vCPU-min; 4-vCPU ≈ 2× rate) | ~210 | ~304 |
**+45%** |

Every suite got faster; the long-pole suites benefited most:

| suite | 2-vCPU | 4-vCPU |
|---|---|---|
| langgraph-python | 623s | 373s |
| langgraph-typescript | 547s | 362s |
| langgraph-fastapi | 500s | 337s |
| adk-middleware | 414s | 286s |
| (… all 15 faster …) | | |

Long-pole `langgraph-python` step breakdown:

| phase | 2-vCPU | 4-vCPU |
|---|---|---|
| Build cpk | 82s | 48s |
| Prep dojo | 94s | 52s |
| **Run tests (Playwright)** | **271s** | **117s** |
| total | 623s | 373s |

**Key finding:** the Playwright phase more than halved → the e2e suites
are **CPU/worker-bound, not LLM-latency-bound**. A bigger runner is the
right lever; test sharding is not needed to reach ~6 min.

## Trade-off
−40% wall-clock for **~+45% billed compute** (4-vCPU costs ~2×/min,
partly offset by finishing 28% sooner). If the cost bump isn't worth it
across all 15 suites, a follow-up can scope `-4` to just the slow suites
via a per-matrix `runner` field (wall ~6.5m, smaller cost increase).

Companion to #5450 (unit-test `nx affected`).
2026-06-15 12:49:19 -07:00
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
Benjamin Taylor 8de9ac5f5b ci(e2e-dojo): bump dojo suites to 4-vCPU runner (experiment)
Measure wall-clock impact of a larger Depot runner on the e2e suites.
The long pole (langgraph-python, ~10.4min) spends ~50% on build/prep
(CPU-bound) and ~43% on the Playwright run. 2->4 vCPU + NX_PARALLEL 4
should speed build/prep; the test-phase gain reveals whether it is
CPU-bound (big win) or LLM-latency-bound (then sharding is the lever).
2026-06-15 12:07:29 -05: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
Jordan Ritter 51d2775940 fix(showcase/aimock): BIA tool-rendering cross-pill shadow on hasToolResult narration (#5446)
## Summary

The `built-in-agent:tool-rendering-custom-catchall` probe sends
`"weather in Tokyo"` then `"What's the current price of AAPL?"` in one
session. 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 `get_stock_price`. The
custom-catchall assertion (both tools rendered through the wildcard
testid) then fails with missing `get_stock_price`.

The bug was structural: the (hasToolResult:true narration +
hasToolResult:false/turnIndex:0 emitter) layered fallbacks were authored
as if hasToolResult tracked the CURRENT pill's tool, but the matcher
checks for ANY tool result in history.

## Fix

Replace the layered hasToolResult 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. The toolCallId-keyed
narration above each block is retained for the non-BIA fast path.

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 earlier partial fix to `tool-rendering-custom-catchall.json` is kept
— those fixtures never match real probe traffic (they use unique `"check
Tokyo weather forecast"` substring) but the reordering is consistent
with the cross-file pattern.

## Verification

- `./bin/showcase test built-in-agent:tool-rendering --d6 --direct` →
green
- `./bin/showcase test built-in-agent:tool-rendering-custom-catchall
--d6 --direct` → green (turn 2 emits get_stock_price; cross-tool
signature pass)
- `./bin/showcase test built-in-agent:tool-rendering-default-catchall
--d6 --direct` → green
- `pnpm vitest run __tests__/aimock-fixtures.test.ts` (showcase/scripts)
→ 737 pass; collision/shadow ceilings unchanged.

## Test plan

- [x] tool-rendering local green
- [x] tool-rendering-custom-catchall local green
- [x] tool-rendering-default-catchall local green
- [x] aimock-fixtures.test.ts collision/shadow ceilings unchanged
- [ ] CI green
2026-06-15 00:25:19 -07: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
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
Ben Taylor 0ce40b2292 fix(react-core): refresh thread headers on provider updates (#5300)
## What does this PR do?

Fixes #5282.

Provider header updates already reach the core instance via
`setHeaders`, but React consumers of `useCopilotKit()` were only
re-rendered for runtime connection status changes. That left
`useThreads()` with stale context after the provider `headers` prop
changed, so subsequent `/threads` requests could miss headers such as
`X-CSRF`.

This subscribes the React context hook to `onHeadersChanged` and adds a
provider-level regression test that verifies `/threads` is refetched
with the updated header.

## Related PRs and Issues

- Fixes https://github.com/CopilotKit/CopilotKit/issues/5282

## Testing

- `pnpm install --frozen-lockfile`
- `pnpm --dir packages/react-core exec vitest run
src/v2/hooks/__tests__/use-threads-provider-headers.e2e.test.tsx`
(failed before the production change, passed after)
- `pnpm --dir packages/react-core exec vitest run
src/v2/hooks/__tests__/use-threads.test.tsx
src/v2/hooks/__tests__/use-threads-provider-headers.e2e.test.tsx`
- `pnpm exec oxlint packages/react-core/src/v2/context.ts
packages/react-core/src/v2/hooks/__tests__/use-threads-provider-headers.e2e.test.tsx`
- `pnpm exec oxfmt --check packages/react-core/src/v2/context.ts
packages/react-core/src/v2/hooks/__tests__/use-threads-provider-headers.e2e.test.tsx`
- `pnpm nx run @copilotkit/react-core:build`
- `pnpm nx run @copilotkit/react-core:test`
- `git commit -m "fix(react-core): refresh thread headers on provider
updates"` (pre-commit ran `pnpm run test && pnpm run check:packages`;
commit-msg ran `pnpm commitlint --edit`)

Also checked: `pnpm nx run @copilotkit/react-core:check-types` currently
fails before checking this package because dependency package type/build
errors are reported in `@copilotkit/shared` and
`@copilotkit/a2ui-renderer`; I did not change those packages.

Note: I used Codex while preparing this change, reviewed the final diff,
and ran the listed checks locally.

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [ ] If the PR changes or adds functionality, I have updated the
relevant documentation (not applicable: internal header propagation bug
fix)
- [x] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly - faster turnaround for everyone)
2026-06-12 13:18:25 -05:00
jinhyuk9714 9639b8d4d6 fix(react-core): refresh thread headers on provider updates 2026-06-12 12:47:32 -05: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
Tyler Slaton 930e182d41 fix(react-core): stabilize pin-to-send scrolling (#5386)
## What does this PR do?

Fixes `pin-to-send` scrolling in the v2 chat view.

- Re-attaches the non-autoscroll scroll listener after the real scroll
element mounts by depending on `nonAutoScrollEl`, not the stable
`scrollRef` object.
- Lets the `usePinToSend` spacer adjust in both directions as content
below the pinned user message changes, so the user message stays
anchored after streaming finishes and layout height changes.
- Adds regression coverage for the scroll-to-bottom button and spacer
adjustment behavior.

## Related PRs and Issues

Fixes #5355

## Tests

- `corepack pnpm -C packages/react-core exec vitest run
src/v2/hooks/__tests__/use-pin-to-send.test.tsx
src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.tsx`
- `corepack pnpm exec oxfmt --check
packages/react-core/src/v2/components/chat/CopilotChatView.tsx
packages/react-core/src/v2/hooks/use-pin-to-send.ts
packages/react-core/src/v2/hooks/__tests__/use-pin-to-send.test.tsx
packages/react-core/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.tsx`
- `git diff --check`

Attempted:

- `corepack pnpm -C packages/react-core run check-types`
- This failed in the local workspace on existing/type-resolution issues
outside this diff, including `react-markdown` JSX namespace errors,
missing `@copilotkit/runtime-client-gql` declarations, and existing e2e
mock `AbstractAgent` private member mismatches.

## 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 (N/A: bug fix only, no API/docs change)
- [x] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly — faster turnaround for everyone)
2026-06-12 10:34:38 -07:00
Jordan Ritter dfdb5e60ae fix(showcase): BIA D6 followups — PARITY_NOTES NSF naming + STATE_DELTA op:add (#5421)
## Summary

Small followups to PR #5413 (BIA D6 readiness, merged 2026-06-12).

- **`PARITY_NOTES.md` NSF naming**: corrected `hitl` (which is supported
in BIA via Strategy-B `useFrontendTool`) to call out the actual
NSF-quarantined demos `gen-ui-interrupt` and `shared-state-streaming`
per the manifest. PR #5413's NSF banner commit (`3585c33b8`) mounted the
banners on the correct demos.
- **Sub-Agents TODO removed**: post-merge staging dashboard showed
sub-agents RED; diagnose confirmed code on `5e828aed9` is correct (local
`--direct` D6 PASSES). The staging RED was stale dashboard image /
fixture cache, not code. PARITY_NOTES no longer claims sub-agents is a
known-issue.
- **gen-ui-agent STATE_DELTA op fix**: BIA's `set_steps` tool emission
used RFC-6902 `op: "replace"` on path `/steps`, but the agent's initial
state is `{}` and `fast-json-patch` rejects unresolvable paths in strict
mode (`@ag-ui/client@0.0.57` swallows the throw with `console.warn`).
Changing to `op: "add"` creates the path on first emission and
idempotently overwrites on subsequent calls. Single-line fix in
`tanstack-factory.ts`.

## Out-of-scope (tracked separately)

- **a2ui-fixed-schema + declarative-gen-ui** (PR #5413 documented
known-issues): root cause is in `@copilotkit/runtime/v2` v2-stack
pipeline OR `@ag-ui/a2ui-middleware@0.0.8` JSON.parse gap — one upstream
fix likely unblocks both. Diagnose reports at
`/tmp/cr/bia-rxr-diagnose/{a2ui-fixed-schema,declarative-gen-ui}.md`.
Needs separate packages PR.
- **tool-rendering port + headless-complete missing components**: BIA
needs StockCard, ChartCard, `get_revenue_chart` server tool, UI
primitives. Separate component-port PR.
- **shadcn catchall**: product/design call pending (escalate to PM).

## Test plan

- [x] Local `--direct` D6 verify on `gen-ui-agent` after the JSON-Patch
op fix
- [x] CI green on PR
2026-06-12 10:32:01 -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