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.
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.
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.
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.
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.
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.
* 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.
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>
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>
Documentation companion to the BIA D6 readiness work:
- PARITY_NOTES.md: tracks built-in-agent feature parity vs LGP +
a 'Known Issues' section documenting 3 D6 demos that remain red
due to downstream renderer/state gaps in @copilotkit/react-core
(a2ui renderer host doesn't mount Card; STATE_DELTA → useAgent
state-subscription gap; declarative-gen-ui renderer host shares
the same class). All three require fixes outside this PR's scope.
- feature-registry.json: adds threadid-frontend-tool-roundtrip
feature entry covering the new gen-ui-agent STATE_DELTA wiring.
Adds the set_steps tool definition to state-tools and wires it through
the tanstack factory so the gen-ui-agent demo emits STATE_DELTA events
on its agent-plan stream the same way the LGP integration does.
Extracts the inline subagents page DelegationCard into three reusable
components that mirror the LGP integration layout, enabling D6 testid
coverage:
- subagent-activity-card.tsx: per-subagent activity panel
- delegation-log.tsx: cumulative delegation event log
- supervisor-activity-banner.tsx: supervisor-level status banner
The subagents page now composes these components instead of inlining
the markup, with data-testid hooks for D6 selectors.
Adds inline comments next to the data-testid="headless-message-{user,assistant}"
markers in assistant-bubble.tsx, user-bubble.tsx, and headless-simple/page.tsx
explaining that the testids intentionally repeat once per message — mirroring
the canonical LGP implementation — and that role discrimination for the D6
conversation-runner is via data-message-role, not unique testids.
Backfills the data-testid markers the D6 probes assert against across the
auth, headless-simple, headless-complete, a2ui-fixed-schema,
declarative-gen-ui, and gen-ui-interrupt demos; aligns the python
a2ui_fixed agent + a2ui definitions/renderers with the canonical LGP
shapes; and switches the gen-ui-interrupt CopilotKit provider import to
@copilotkit/react-core/v2 so the demo mounts under the V2 runtime that
the D6 probe drives.
Adds the chart-card renderer and wires it into the headless-complete
tool-renderers map so the D6 probe for the headless-revenue-chart feature
can mount and assert against a real chart component.
Replaces useLangGraphInterrupt with useInterrupt (LangGraph-specific hook
not exported from the V2 React core) and switches the CopilotKit provider
import to @copilotkit/react-core/v2 so the demo mounts under the V2
runtime that the D6 probe drives.
Annotates 14 integration manifests with d6_not_supported_features entries
and aligns d6_supported_features with what each backend actually implements,
so the D6 fleet probe only enumerates demos that the backend can serve.
Align showcase integration requirements.txt files (strands,
langgraph-fastapi, langgraph-python, pydantic-ai, google-adk,
crewai-crews) to the fleet pin standard, including an accurate
typing_extensions comment in crewai-crews and a trailing newline in
langgraph-python.
Replace floating "beta" dist-tags with exact versions for @ag-ui/mastra,
@mastra/{client-js,core,libsql,memory}, and mastra in both the examples
and showcase mastra packages. Showcase mastra also raises its zod floor
^3.24.0 -> ^3.25.0. The examples mastra package additionally carries the
fleet-wide @ag-ui/client 0.0.55 bump and single-tree overrides here, since
its manifest mixes both changes.
## Summary
Combined landing of three browser-verified showcase work waves (37
commits, per-integration grouping preserved), plus a full multi-round
code review with all mandatory fixes folded in.
**Wave 1 — @ag-ui currency (9/9 integrations).** Bump `@ag-ui/*`
frontend deps to exact `0.0.55` for: llamaindex, agno,
claude-sdk-python, pydantic-ai, strands, claude-sdk-typescript,
ms-agent-python, ms-agent-dotnet, google-adk. Exact pins land across 13
`package.json` files.
**Wave 2 — reasoning emission ports (4/4, ref #76).** Port
reasoning-message emission to ag2, crewai-crews, langroid, and spring-ai
(each also bumped to `@ag-ui` 0.0.55). Adds per-integration
`reasoning_agent` (Python) / `ReasoningController` (spring-ai Java) and
wires the copilotkit route.
**Wave 3 — google-adk demo parity (3/4).** Port `hitl`,
`threadid-frontend-tool-roundtrip`, and `gen-ui-interrupt` demos to
google-adk for parity with the gold reference, plus d6/aimock fixtures.
The `interrupt-headless` demo is intentionally kept `not_supported`
(needs aimock `customEvents` support + an ADK interrupt route — tracked
as a known upstream gap).
## Code review
A 5-round unbiased multi-agent CR loop ran against the combined diff and
converged at zero mandatory findings; the bucket-(c) promotion audit
came back clean. Key fixes folded into the branch:
- **Client error-leak hardening** in the crewai, langroid, and spring-ai
reasoning routes — internal exception details no longer leak to the
client, with `errorId` correlation between client response and server
logs (also applied to google-adk).
- **Protocol-correct reasoning error paths** — on failure the emitters
now close any open frames, emit a generic `RUN_ERROR`, and never emit
`RUN_FINISHED` after `RUN_ERROR`; verified against `@ag-ui/client`
`verifyEvents` semantics, with red-green tests.
- **`x-aimock-context` propagation** across spring-ai's async hop, so
fixture replay stays correct through the thread boundary.
- **Bounded reasoning executor** (no unbounded thread growth) and
**parse-failure observability** (failures surface in logs instead of
being swallowed).
- **Full multi-turn history threading** in the reasoning agents — prior
turns are now forwarded to the LLM, with single-turn byte-equality
preserved so existing aimock fixtures stay valid; covered by tests.
- **Phantom deps declared** — `@copilotkit/shared`/`@ag-ui` deps that
were imported but undeclared in claude-sdk-python and
ms-agent-dotnet/python are now in their `package.json`.
- **`@copilotkit/core` `"latest"` overrides pinned** to `1.59.4`.
- **Reasoning parity token-identity test** across the 3 ported Python
integrations (ag2/crewai-crews/langroid) so their reasoning streams
can't silently drift.
- **Ratchets tightened/updated**: shadow-collision ceiling ratcheted
down 151 → 123 (actual count), duplicate-fixture ceiling 288 → 290 (new
google-adk fixtures reuse standard prebuilt-probe pills,
runtime-disambiguated by demo route), and the `validate-pins` baseline
drops 57 → 48 (currency bumps retire 9 exact-pin FAIL lines).
The final commit is the `style: auto-fix formatting` bot commit
(formatting on the new Python test files).
## Test plan
- [x] Per-integration browser verification (each touched integration's
demos exercised end-to-end) with aimock fixtures added/updated.
- [x] crewai pytest — 113/113 pass.
- [x] `showcase/scripts` vitest — 1780/1780 pass.
- [x] `validate-parity` MUST checks — 19/19 pass, 0 fail.
- [x] `validate-pins` ratchet — exits 0 against the updated baseline
(FAIL-set hash matched).
- [x] D6 `gen-ui-custom` cells verified live (google-adk + agno).
- [x] CI fully green — per-integration Depot Docker `build-check`,
Python unit tests (3.10 + 3.12), commitlint, format, oxlint, Validate
Showcase, production-pinning lint.
## Follow-ups
Consolidated follow-up ledger (bucket c/d items):
https://www.notion.so/copilotkit/37b3aa38185281e5b871d0b907aaef71
_extract_user_input in the ag2, crewai-crews, and langroid reasoning agents
documented a str return but passed AG-UI message content straight through.
Multimodal content can be a list of parts, which would flow unmodified into
the single caller in each file (_run_reasoning_agent ->
messages=[{"role": "user", "content": user_input}]) sent to the OpenAI
chat-completions API. Coerce: str passes through, a list joins its text
parts (dict or attr form), anything else falls back to str().
Callers (one per file):
- ag2/src/agents/reasoning_agent.py:104 -> chat message at :119
- crewai-crews/src/agents/reasoning_agent.py:108 -> chat message at :123
- langroid/src/agents/reasoning_agent.py:103 -> chat message at :118