Commit Graph

4771 Commits

Author SHA1 Message Date
Lukas Moschitz e4bf77f4e9 fix(showcase): stop langgraph-fastapi open-gen-ui D6 loop (fixture shadowing)
open-gen-ui and open-gen-ui-advanced (both probes load gen-ui-open.json) hung
with done-signal-missing (~12 agent runs, 1.3MB tool-call payload each turn).
Cause: two files (gen-ui-open.json + gen-ui-tool-based.json) both defined leg-1
generateSandboxedUi tool-call fixtures for the SAME userMessages ('3D axis…',
'Inline expression evaluator') under the same context but different toolCallIds.
aimock pools every d6/<slug>/*.json into one substring-match set, and the
turnIndex:0 fixture in gen-ui-tool-based.json got served on follow-up turns too
(turnIndex-relaxed), so the toolCallId-anchored terminal never won → no
finish_reason:stop → loop.

Fix (fastapi fixtures only, aligned to GOTCHAS 'canonical fixtures have no
turnIndex' + toolCallId-terminal-before-userMessage-leg1):
- gen-ui-tool-based.json: strip spurious turnIndex:0 from leg-1 tool-call
  fixtures; add chunkSize:9999 so the large args JSON-parse in one chunk. Now
  the single source for all open-gen-ui pills.
- gen-ui-open.json: empty its fixtures (keep a documenting _note) to remove the
  duplicate leg-1/terminal for the 2 probed pills.
- gen-ui-open-advanced.json: delete orphan (no probe declares it; both open
  probes use gen-ui-open.json).

D6 green + stable (two ~4s runs each); regression-checked gen-ui-custom
(gen-ui-tool-based route) still green. NOTE: LGP + likely all integrations have
the same open-gen-ui loop (fleet-wide fixture-shadow bug) — no sibling was green.
2026-07-24 15:35:12 +02:00
Lukas Moschitz 1dde897af3 fix(showcase): stop langgraph-fastapi frontend-tools-async D6 loop
fixture[8] (userMessage:"project planning", turnIndex:0) returned a
query_notes toolCall. aimock matches userMessage by substring, so
"project planning" also matched the test prompt "Find my notes about
project planning"; as a turnIndex:0 'scripted turn' it beat the correct
terminal fixture[2] (toolCallId-keyed, content-only) on the follow-up turn,
so the agent kept getting another tool call and looped ~30x, never emitting
the done signal (D6 done-signal-missing).

Remove turnIndex:0 from fixture[8] so it's a plain fallback that loses to
the terminal fixture by registration order (matching the langgraph-typescript
shape). D6 now green: two real ~6s runs (was a 120s timeout).

Note: langgraph-python has the identical bug (still red) — same one-line fix
applies there; tracked separately.
2026-07-24 15:04:04 +02:00
Lukas Moschitz cd8c94a492 feat(showcase): make fe-parity exception-aware via PARITY_NOTES allowlist
fe-parity.ts now reads a per-integration allowlist from
integrations/<slug>/PARITY_NOTES.md (an <!-- fe-parity-allow --> block of
'src-relative-path | reason' lines). Listed files report as ALLOWED
(sanctioned per-integration divergence), not DRIFT; the gate passes on zero
UNSANCTIONED drift instead of zero diffs. This stops the byte-identical goal
from being impossible for demos that legitimately must differ (e.g.
a2ui-recovery's per-slug prompt, which has no aimock context routing).

Add langgraph-fastapi/PARITY_NOTES.md documenting the a2ui-recovery frontend
divergence with reasons. D6 remains the correctness gate; fe-parity is the
'where to look' map.
2026-07-24 13:53:14 +02:00
Alem Tuzlak a486015563 feat(showcase/built-in-agent): real beautiful-chat backend (query_data + A2UI + OGUI + MCP)
The flagship beautiful-chat cell was a stub (generic all-tools agent on a bare
route) that only passed local aimock D6 because fixtures scripted the tool
calls; against a real LLM (prod) it said query_data/Excalidraw/etc. 'not
available'. Port the real backend mirroring langgraph-python's beautiful_chat:

- New createBeautifulChatAgent() with server tools query_data (sales data),
  manage_todos, get_todos, search_flights (A2UI fixed-schema flight cards), and
  declaration of the runtime-injected tools (render_a2ui, generateSandboxedUi,
  Excalidraw MCP) so the model can actually call them; manage_todos result ->
  STATE_DELTA /todos for the app-mode board. Model gpt-5.4.
- Route configures the combined runtime: openGenerativeUI:true,
  a2ui.injectA2UITool:true (catalog copilotkit://app-dashboard-catalog),
  mcpApps (Excalidraw).

VERIFIED against a real OpenAI LLM (not aimock): all 6 flows fire the tool +
render the component (pie/bar via query_data, calculator OGUI iframe, flight
A2UI cards, Excalidraw MCP iframe, todo board). Shared factory defaults
unchanged. Also gitignore .env/.env*.local (local real-key testing).
2026-07-24 12:36:45 +02:00
Alem Tuzlak eedea568a2 fix(showcase/built-in-agent): use gpt-5.4 (staging returns empty on gpt-5.5)
Staging D4 chat probe returned 'empty assistant response' for every cell,
capping all cells at D3. Root cause: the factories used gpt-5.5 (agentic-chat +
generic createBuiltInAgent) and leftover gpt-4o/gpt-4o-mini (a2ui, byoc, mcp-apps,
ogui, subagents). gpt-5.5 is unique to built-in-agent; every other integration —
including the LGP reference that works on staging — uses gpt-5.4, which staging's
OpenAI account serves. aimock ignores the model id, so this was invisible locally.

Switch all built-in-agent openaiText() calls to gpt-5.4 (matches LGP, unblocks
staging). reasoning-factory keeps gpt-5.2 (reasoning-capable, its demos are
NSF-quarantined). Note: deviates from the general gpt-5.5 house rule because this
is an LGP-parity integration and staging only serves gpt-5.4.
2026-07-24 11:21:48 +02:00
Lukas Moschitz eaa49e55b3 feat(showcase): port langgraph-fastapi declarative-gen-ui to canonical sales-analyst demo
Task 2 of OSS-582. Replace fastapi's old generic 'chart-picker' declarative-gen-ui
with langgraph-python's canonical sales-analyst demo, so it matches the shared D6
probe (which asserts sales-dashboard / DataTable / StatusBadge / InfoRow per pill):
- backend src/agents/src/a2ui_dynamic.py: generic prompt -> LGP sales-analyst graph
  (persona + dataset grounding + composition rules + generate_a2ui tool)
- frontend definitions.ts/renderers.tsx/chat.tsx/suggestions.ts byte-identical to LGP,
  add sales-context.ts (fictional Vantage Threads dataset + composition rules)
- d6 fixtures gen-ui-declarative.json + render-a2ui.json: LGP's, re-keyed to
  context=langgraph-fastapi

Verified D6 green via control-plane (real 12s browser run, canonical testids asserted).
a2ui-recovery intentionally NOT aligned: its fixtures have no context routing, so each
integration must keep a unique pill prompt (sanctioned per-slug divergence).
2026-07-24 11:10:22 +02:00
Tyler Slaton 831cfc0745 feat(showcase/built-in-agent): LGP parity — byte-identical frontends + named-agent backend (#6106)
## What & why

Brings the **built-in-agent** showcase integration to parity with the
**LangGraph-Python (LGP)** reference: byte-identical demo frontends + a
named-agent backend registry (BuiltInAgent + TanStack AI), so every demo
climbs the D0–D6 ladder against the LGP gold standard.

## Changes (4 commits)

1. **P0 pattern** — `agentic-chat` byte-identical + named agent
(`agentic_chat`); proven D6-green locally. Fixed `gpt-4o` → `gpt-5.5` in
the shared factory.
2. **Frontend migration (all demos)** — every LGP `src/app/demos/*`
copied verbatim (`diff -r` clean), plus shared `components/ui` (25
shadcn primitives) + `lib/utils`, byte-identical. Added the 5 demos BIA
lacked (`a2ui-recovery`, `declarative-hashbrown`,
`declarative-json-render`, `shared-state-read`,
`threadid-frontend-tool-roundtrip`); added the frontend deps the copied
UI needs (radix-ui, cmdk, embla-carousel-react, react-markdown,
remark-gfm, yaml, …).
3. **Named-agent backend** — `/api/copilotkit` registers 22 named agents
(generic all-tools, fixture-driven; reasoning trio via the reasoning
adapter). 8 dedicated routes re-keyed `default` → LGP agent id;
`mcp-apps` also serves `headless-complete`; `ogui` serves both
open-gen-ui ids; `byoc-*` routes renamed to `declarative-*`; new
`a2ui-recovery` + `beautiful-chat` routes reuse existing agents. Dropped
BIA-only extras (`byoc-*`, `hitl-in-chat-booking`).
4. **Reconcile** — `manifest.yaml` (37 features / 40 demos;
`generate-registry` + `validate-parity` pass) + `PARITY_NOTES.md`.

> **Note on "byte-identical":** frontends are verbatim LGP **modulo
BIA's `consistent-type-imports` ESLint rule** (type imports split into
`import type {}`) — required for a green lint/PR, semantically & DOM
identical.

## D6 status (local sweep)

- **~33/40 demos GREEN** on the first sweep — byte-identical frontends +
named agents + existing fixtures work broadly.
- **4 RED locally are an aimock-infra issue, not this integration:** the
deployed `ghcr.io/copilotkit/aimock:latest` has no
`context`/`--context-field` fixture scoping, so cross-slug `userMessage`
collisions let earlier-loaded (`ag2`/`d4`) fixtures shadow BIA's own.
BIA's fixtures are **correct** and converge under a context-aware aimock
(present on aimock `origin/main`). Affects
`tool-rendering-custom-catchall`, `headless-complete`, `gen-ui-agent`,
`frontend-tools`. **Action for infra: redeploy aimock from a
context-aware build.** Details in `PARITY_NOTES.md`.
- **2 downstream-host RED (kept as features, informational — mirrors
LGP):** `declarative-gen-ui` (A2UI renderer host) and `mcp-apps` (MCP
iframe host).
- Quarantined NSF unchanged: `gen-ui-interrupt`, `interrupt-headless`,
`shared-state-streaming`, reasoning-trio.

D6 is informational/weekly (not a merge gate); these are documented for
parity tracking.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-23 16:43:46 -07:00
Alem Tuzlak bffb119091 fix(showcase): allowlist ms-agent-dotnet headless-complete custom-bubbles multi-file region
Restoring frontend parity re-added the @region[custom-bubbles] markers in both
message-assistant.tsx and message-user.tsx (matching the langgraph reference and
every other integration). Add the ms-agent-dotnet::headless-complete::custom-bubbles
key to the multi-file-region allowlist so the demo-content bundler accepts it.
2026-07-23 19:12:21 +02:00
Alem Tuzlak d35935b35f fix(showcase): repoint ms-agent-dotnet manifest highlights to existing files
The stale-file cleanup removed chat-slots/custom-welcome-screen.tsx, the
top-level headless-complete/{message-list,use-rendered-messages}.tsx, and the
top-level gen-ui-interrupt/time-picker-card.tsx, but their manifest highlight
entries still pointed at them, failing the registry bundler (shell/shell-docs/
shell-dojo builds). Repoint to the real files (slot-wrappers, chat/chat,
hooks/use-tool-renderers, _components/time-picker-card).
2026-07-23 18:56:16 +02:00
Mike Ryan 98711fbefb fix(showcase): stage Angular artifacts in deployment images 2026-07-23 09:46:29 -07:00
Alem Tuzlak 1ab3fba04e feat(showcase): restore ms-agent-dotnet frontend parity with the langgraph reference
Restore the root shell (globals.css theme+brand, manifest-driven index, layout,
middleware x-pathname, tsconfig), the declarative-gen-ui demo subtree, doc-snippet
region markers, import-style, and subagents to match the langgraph-python reference;
remove stale orphaned files. Load-bearing .NET adaptations (parse-json 3-layer
unwrap, multimodal shim, tool-based hitl, agent-config properties) are preserved.
2026-07-23 18:43:25 +02:00
Alem Tuzlak b70b6913f7 feat(showcase): wire ms-agent-dotnet D6 routing, manifest, and threadid demo
Add the per-token createSharedStateStreamingAgent route shim, register the
threadid-frontend-tool-roundtrip agent (frontend_tools passthrough) and its demo,
drop shared-state-streaming from not_supported_features, and add the a2ui-recovery
feature + demo entry to the manifest.
2026-07-23 18:43:24 +02:00
Alem Tuzlak 55b4da3005 feat(showcase): add a2ui-recovery cell for ms-agent-dotnet
Implement the render/validate/retry recovery loop with a2ui_recovery_exhausted
hard-fail as a raw-SSE endpoint (RecoveryAgent.cs, mounted in Program.cs), add
the demo frontend + API route, the deterministic aimock fixture, and the unique
per-slug PROMPTS entry in the shared d5-a2ui-recovery probe.
2026-07-23 18:43:23 +02:00
Alem Tuzlak dac30ed9f1 feat(showcase): stream shared-state document per-token for ms-agent-dotnet
Replace the final-snapshot-only shared-state-streaming behavior with a
write_document tool whose document arg streams; per-token state.document
emission is bridged on the copilotkit route (see the routing commit).
2026-07-23 18:43:22 +02:00
Lukas Moschitz db296afd91 fix(showcase): stop harness services racing on shared image tag
harness-control-plane and harness-pool-worker both declared a build: block
AND the same image: showcase-harness:local. Under the parallel docker buildx
bake path (default in recent Docker Compose) both targets build and race to
tag the identical image, failing the whole 'bin/showcase up' with
'image "...showcase-harness:local": already exists'. It only surfaces on a
cold parallel bake build (Colima/Homebrew, fresh clone), which is why it is
intermittent across toolchains.

Give the image a single build owner: harness-pool-worker now reuses the
image built by harness-control-plane (worker vs control-plane role is chosen
at runtime via HARNESS_ROLE) instead of declaring its own build:.
2026-07-23 18:27:21 +02:00
Mike Ryan 053b00e846 fix(angular): match React MCP Apps sandbox 2026-07-23 08:51:34 -07:00
Mike Ryan c4919f9f79 ci(showcase): remove broad Angular proof workflow 2026-07-23 08:51:24 -07:00
Mike Ryan 1c0c769562 docs(angular): add task guides 2026-07-23 08:10:21 -07:00
Mike Ryan 06df1ea155 docs(angular): improve standalone documentation 2026-07-23 07:51:53 -07:00
Lukas Moschitz f3d01b83c7 fix(showcase): align langgraph-fastapi frontend chrome with langgraph-python
Task 1 of OSS-582 (frontend parity). Bring the app chrome + beautiful-chat
byte-identical to the langgraph-python north star:
- globals.css: adopt LGP theme (@theme inline tokens + green palette)
- middleware.ts: add (was missing) — sets x-pathname like LGP
- layout.tsx: adopt LGP structure; keep FastAPI in title/log (identity carve-out)
- beautiful-chat/page.tsx: sync stale doc comment

Also fix a Dockerfile parity gap: fastapi was missing the COPY manifest.yaml
that LGP has. demos/layout.tsx reads manifest.yaml at request time via
generateMetadata (headers() -> dynamic), so without it every /demos/* route
crashed with an RSC render error (ENOENT /app/manifest.yaml).
2026-07-23 16:26:52 +02:00
Mike Ryan 7ccd34a05d feat(showcase): checkpoint 5 - hardening and final exposure 2026-07-23 07:14:55 -07:00
Mike Ryan 4d32d941eb feat(showcase): checkpoint 4 - all supported features and docs 2026-07-23 07:14:55 -07:00
Mike Ryan 637845bb7c feat(showcase): checkpoint 3 - shared build and proof pair 2026-07-23 07:14:55 -07:00
Mike Ryan fec70d086f feat(angular): checkpoint 2 - core and package 2026-07-23 07:14:55 -07:00
Mike Ryan 873cbb8b6c feat(showcase): checkpoint 1 - baseline and registry 2026-07-23 07:12:53 -07:00
Mark 9855a81072 fix(showcase/mastra): sanitize OpenAI Responses input[].id so multi-turn chat stops 400-ing (OSS-381) (#6117)
## What

Fixes multi-turn chat on every mastra showcase demo, which 400s on the
2nd turn:

> `AI_APICallError: Invalid 'input[3].id': 'msg-92Y7BhMpWBhXt7dm'.
Expected an ID that contains letters, numbers, underscores, or dashes,
but this value contained additional characters.` (`INCOMPLETE_STREAM`)

## Root cause

OpenAI's Responses API actually **rejects dashes** in `input[].id`. Its
400 message misleadingly lists dashes as allowed, but empirically only
`[A-Za-z0-9_]` is accepted:

| `input[].id` | result |
|---|---|
| *(omitted)* | ✅ 200 |
| `msg_92Y7BhMpWBhXt7dm` (underscore) | ✅ 200 |
| `msg-92Y7BhMpWBhXt7dm` (**the failing client id**) | ❌ 400 |

CopilotKit mints message ids like `msg-…`, and `@ag-ui/mastra` + the AI
SDK forward them straight into `input[].id` when replaying prior-turn
history — so turn 1 works (no prior ids) and every turn after dies.

## Fix

The mastra provider already routes every outbound LLM call through
`forwardingFetch` (the header-forwarding shim). This rewrites dashes
(and any other non-`[A-Za-z0-9_]` char) in each outbound `input[].id` to
`_` there.

**Why here, not in the bridge's message conversion:** it touches only
the bytes sent to OpenAI. Mastra's in-memory `CoreMessage.id` — which
drives its upsert-by-id history **dedup** — is untouched, so dedup is
unaffected. OpenAI-issued ids (`msg_…`, `rs_…`, no dashes) pass through
unchanged, preserving server-side conversation-state references. Chat
Completions bodies (no `input[]` array) are untouched.

This **supersedes ag-ui-protocol/ag-ui#2227** — a bridge-layer charset
munge that *kept* dashes (`[^A-Za-z0-9_-] → -`), making it a no-op on
the real failing ids. That PR is being reverted.

## Tests

`tests/vitest/header-forwarding-id-sanitize.test.ts` — 8 cases: the real
failing id, valid-id no-op, full-charset mapping, in-body rewrite,
no-op/passthrough, and chat-completions-untouched. All green.

## Verification status

- ✅ Transform verified against the exact failing id; `msg_…` form
confirmed accepted by the real OpenAI Responses API.
- ✅ 8 unit tests pass in-module.
- ⚠️ Full end-to-end wasn't run locally (the showcase runtime OOMs a 16
GB box), but **every** showcase OpenAI call flows through this wrapper,
so **staging is the final check** — deploy and re-run a two-click
multi-turn on `/demos/agentic-chat`.

## Refs

- Linear **OSS-381** (mastra refresh umbrella).
- Supersedes ag-ui-protocol/ag-ui#2227 (revert incoming).
- Follow-up worth filing upstream: `@ag-ui/mastra` / AI SDK shouldn't
forward non-provider message ids into `input[].id` at all.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-23 06:54:07 -07:00
Mark cd37325ff3 fix(showcase/mastra): D6 follow-ups to #5798 — gen-ui-agent step cap + useComponent probe path (OSS-381) (#6103)
## What

Two mastra showcase D6 follow-ups to #5798 (v1 bridge alpha). Both cells
went red the moment #5798 took them out of `not_supported_features` —
they were claimed supported before actually passing. **Neither is a
v1-bridge streaming regression.**

## Commits

**1. gen-ui-agent completes all 3 steps (raise step cap)** — `57afed6dd`
"Generative UI: Agent State" (gen-ui-agent) stalled at 2/3 steps:
`genUiAgent` set no stop condition, so the AI SDK default halted the
agentic loop before the 3rd step completed. Adds
`defaultOptions.stopWhen = stepCountIs(12)`. Verified 6/6 on the Node-22
+ `next start` + aimock replay rig; tool-rendering / gen-ui-tool-based
unaffected.

**2. useComponent (gen-ui-tool-based) — probe took the wrong path** —
`4640d6304`
The D5 `gen-ui-custom` probe omitted `mastra` from `CHART_INTEGRATIONS`,
so it sent the *haiku* prompt and hunted for a haiku card. mastra's demo
is the LGP-style `useComponent` chart demo (`render_pie_chart` /
`render_bar_chart`) with no haiku tool, so the assistant bubble came
back empty (*"haiku card [data-testid=copilot-assistant-message]
rendered but has no text content"*).
- Add `"mastra"` to `CHART_INTEGRATIONS`.
- Add `aimock/d6/mastra/gen-ui-custom.json` (mirrors langgraph-python;
identical pie schema `{title, description, data:[{label,value}]}`) so
the cell is deterministic under replay instead of falling through to the
live upstream.
- Repoint the probe unit test's haiku-empty-card case from `"mastra"` →
`"agno"` (a genuine haiku integration).

## Verification

- gen-ui-agent: 6/6 on the faithful rig.
- useComponent: logic-only harness + fixture changes; harness unit tests
run in CI (sparse local checkout has no vitest).

## Refs

- Follow-on to #5798. Linear **OSS-381** (mastra refresh umbrella).
- Companion `@ag-ui/mastra` PR — multi-turn Responses-API message-id 400
fix: ag-ui-protocol/ag-ui#2227.
- Sibling from the same triage (separate, not fixed here): **PNI-100** —
hitl-in-app follow-up-run gap.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-23 06:53:32 -07:00
Alem Tuzlak ca5773b3df feat(showcase/built-in-agent): close final D6 backend gaps (a2ui-recovery exhaust + multimodal PDF)
- a2ui-recovery: add opt-in createA2UIRecoveryAgent() — generate_a2ui runs a
  validate->retry loop and, once the attempt cap is hit with only invalid
  surfaces, returns the { code: 'a2ui_recovery_exhausted', error, attempts }
  envelope the A2UI middleware paints as the graceful failure card. Wired only
  into the a2ui-recovery route; createDeclarativeGenUIAgent behavior unchanged.
  D6 EXHAUST turn now green.
- multimodal: add opt-in createMultimodalAgent() that flattens PDF document
  parts to text server-side via unpdf (TS equivalent of LGP's pypdf) through a
  new opt-in preprocessMessages hook on createBuiltInAgent (default pass-through,
  other demos byte-identical). D6 PDF turn now green.
- deps: add unpdf for server-side PDF text extraction.

Both fixes opt-in; shared factory defaults unchanged. next build + Docker
rebuild + D6 probes all green.
2026-07-23 15:35:14 +02:00
Lukas Moschitz fa0392f3e5 feat(showcase): add fe-parity.ts frontend parity checker
Diffs an integration's frontend surface (all src/** UI files except
src/agents/** and src/app/api/**, tests, qa) against a reference
integration (default langgraph-python) byte-for-byte, normalizing
integration identity (manifest name/slug) so name-only differences
report as IDENTITY rather than DRIFT. Exits 0 when the frontend is
byte-identical modulo the integration's own name. Supports --md
(markdown audit), --full, --all (fleet ranking), --verbose, --ref.

Complements the structural-only validate-parity.ts. Zero-dependency;
runs on node 23+ directly or via tsx.
2026-07-23 14:43:45 +02:00
Alem Tuzlak dc0ee47f4c fix(showcase): D6 red fixes for built-in-agent (shared-state-read green; recovery/multimodal partial)
- shared-state-read: remove spurious turnIndex:0 on the turn-2 fixture entry
  (turnIndex counts assistant msgs = 1 on turn 2, so the constraint could never
  match -> turn 2 dom-missing). Now D6 GREEN.
- a2ui-recovery: register built-in-agent heal/exhaust prompts in the shared
  probe PROMPTS (new demo BIA lacked) + add its aimock fixture. HEAL turn now
  GREEN; EXHAUST still red pending a backend factory change (emit the
  a2ui_recovery_exhausted envelope) — tracked, not fixable at fixture layer.
- multimodal: fix conversation-runner skipSend baseline (snapshot run-start
  BEFORE preFill, since preFill issues the run on skipSend turns; fast
  in-process runtimes else false-red done-signal-missing). Image turn now
  GREEN; PDF turn still red (BIA runtime has no document/PDF flattening path).

NOTE: conversation-runner.ts is a SHARED harness helper — change is guarded to
skipSend turns (non-skipSend byte-identical) and only corrects the baseline;
flagged for harness-owner review.
2026-07-23 14:28:29 +02:00
Alem Tuzlak 94a23c6bf4 fix(showcase/built-in-agent): byte-identical globals.css (theme tokens for shadcn/AI-Elements)
BIA's globals.css was a 17-line stub missing LGP's @theme inline Tailwind-v4
token map + the :root design-token palette (--background/--card/--primary/
--muted/--accent/--radius + CopilotKit brand vars). Without it every shadcn /
AI-Elements / prompt-kit primitive fell back to unstyled — most visible on
beautiful-chat. Copy LGP's globals.css verbatim so the byte-identical demo
frontends render with the correct theme.
2026-07-23 12:01:15 +02:00
Mark Fogle ad67eb068c fix(showcase/mastra): sanitize OpenAI Responses input[].id so multi-turn chat stops 400-ing
Multi-turn chat on every mastra demo fails on the 2nd turn:

  AI_APICallError: Invalid 'input[3].id': 'msg-92Y7BhMpWBhXt7dm'.
  Expected an ID that contains letters, numbers, underscores, or dashes,
  but this value contained additional characters. (code: INCOMPLETE_STREAM)

Root cause: OpenAI's Responses API actually REJECTS dashes in `input[].id`
(its 400 message misleadingly lists dashes as allowed — empirically only
`[A-Za-z0-9_]` is accepted; `msg-92Y7…` 400s, `msg_92Y7…` succeeds).
CopilotKit mints message ids like `msg-…`, and @ag-ui/mastra + the AI SDK
forward them straight into `input[].id` when replaying prior-turn history, so
the whole request fails. Turn 1 works (no prior ids); every turn after dies.

Fix at the HTTP boundary: the mastra provider already routes every outbound
LLM call through `forwardingFetch` (header-forwarding shim). Rewrite dashes
(and any other non-`[A-Za-z0-9_]` char) in each outbound `input[].id` to `_`
there.

Why here and not in the @ag-ui/mastra message conversion: this touches ONLY
the bytes sent to OpenAI. Mastra's in-memory `CoreMessage.id` — which drives
its upsert-by-id history dedup — is left untouched, so dedup is unaffected.
OpenAI-issued ids (`msg_…`, `rs_…`) contain no dashes and pass through
unchanged, preserving server-side conversation-state references. Chat
Completions bodies (no `input[]` array) are untouched.

Supersedes the ineffective ag-ui-protocol/ag-ui#2227 (a bridge-layer charset
munge that kept dashes — a no-op on the real failing ids; being reverted).

Tests: tests/vitest/header-forwarding-id-sanitize.test.ts (8 cases — the real
failing id, valid-id no-op, full-charset mapping, body rewrite, no-op/passthrough,
chat-completions untouched). All green.

--no-verify: sparse showcase checkout has no monorepo lefthook/commitlint binaries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 00:40:52 +00:00
Mark 9c7e0b37ea feat(showcase): add "Show unique" filter to dashboard feature grid (#6115)
## What

Adds a **"Show unique"** filter to the Showcase Dashboard feature grid,
mirroring the existing **"Show deprecated"** toggle. A demo is
**common** when ≥ 2 frameworks ship it; single-framework (and
zero-framework) demos are **unique**.

Both toggles default **OFF**, so the default view is **common ∩
non-deprecated** — the cross-framework gold-standard surface. Each
toggle independently widens the set (AND-combined).

This makes room for framework-specific demos (e.g. the planned Mastra
browser-use / observational-memory demos): once added they'll be hidden
by default and revealed via "Show unique".

## Why the "ships a demo" signal

"Framework supports a demo" is defined as `integration.demos.some(d =>
d.id === feature.id)` (the grid's existing `isWired` signal). The two
alternatives were rejected:
- `integration.features[]` — stale in the data (e.g.
`interrupt-headless` has demos in ~19 integrations but 0 `features[]`
declarations).
- `not_supported_features` — a brand-new single-framework demo never
appears in another integration's `not_supported_features`, so it would
be wrongly classified as common. This is exactly the Mastra case that
motivated the feature.

## UI

- `Show unique (N)` checkbox next to `Show deprecated`, rendered only
when `N > 0`. Tooltip: "N demos supported by fewer than two frameworks —
hidden by default…".
- Subtitle shows the **exact distinct hidden-row count** — `(N hidden)`
— rather than an additive per-category breakdown (a feature can be both
deprecated and unique; the per-category badges provide attribution,
faceted-filter style).

## Testing

- 6 new behavioral tests in `feature-grid.test.tsx` (default-hidden,
reveal-on-toggle, count label, accurate tooltip wording, exact distinct
subtitle count, note-drop when both filters enabled). Suite: **37/37
green**.
- `tsc --noEmit` clean; `oxlint` clean (on the changed files); `next
build` succeeds.

## Notes / follow-up

- **Column-header tallies** count the full matrix regardless of
row-visibility filters. This is pre-existing (unchanged by this PR) and
arguably correct-by-design (a coverage metric over the whole matrix, per
the `computeColumnTally` docstring). Flagged in review, deferred.
- The "unique" count uses `frameworkCount < 2`, intentionally grouping
zero-demo features with single-framework ones (approved design
decision); tooltip wording reflects this.

## Scope

Client-side view state only — no registry, catalog, props, or SSE
changes; all edits internal to `FeatureGrid`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-22 17:28:22 -07:00
Mark Fogle d67693a809 fix(showcase): show exact distinct hidden-row count in grid subtitle
Per-category subtitle counts overlapped (a feature can be both deprecated
and unique), overstating hidden rows. Show the distinct total instead;
per-category counts remain on the toggle badges. CR round 1 finding F2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 00:02:31 +00:00
Mark Fogle 3bf2d50c67 fix(showcase): correct Show-unique tooltip wording for <2 framework count
Tooltip said 'only one framework' but uniqueCount is frameworkCount<2,
which includes zero-framework demos. CR round 1 finding F3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 00:02:31 +00:00
Mark Fogle 27ed872cad test(showcase): decouple unique-hidden subtitle assertion from segment order
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 00:02:31 +00:00
Mark Fogle 75a313360e feat(showcase): note unique-hidden count in feature grid subtitle
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 00:02:31 +00:00
Mark Fogle 74f4bb1684 feat(showcase): add Show unique toggle to feature grid
Hides single-framework (non-common) demo rows by default, mirroring the
Show deprecated toggle. Common = shipped by >=2 frameworks (demos[]).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 00:02:31 +00:00
Sam Julien cd349a8940 fix: avoid the PostHog import lint warning 2026-07-22 15:47:08 -07:00
Sam Julien d72c03e7b9 docs: track Rich Threads conversion actions 2026-07-22 15:46:32 -07:00
Sam Julien 21eede7d12 docs: finalize the Rich Threads journey 2026-07-22 15:46:19 -07:00
Sam Julien e00435a7da docs: apply Rich Threads review feedback 2026-07-22 11:56:04 -07:00
Sam Julien 827003e7c8 test: verify Rich Threads navigation contracts 2026-07-22 11:20:47 -07:00
Sam Julien 2b72479da2 docs: fix Rich Threads onboarding guidance 2026-07-22 11:03:01 -07:00
Sam Julien a715e1f70b docs: align Rich Threads support boundaries 2026-07-22 10:57:07 -07:00
Sam Julien 45ce56b729 docs: clarify thread history synchronization 2026-07-22 10:45:51 -07:00
Sam Julien 540a980abb docs: fix Rich Threads review findings 2026-07-22 10:36:08 -07:00
Sam Julien 68ab0740c6 docs: introduce Rich Threads overview journey 2026-07-22 10:30:43 -07:00
Alem Tuzlak 8f4e0b97a2 docs(showcase/built-in-agent): declarative-gen-ui + mcp-apps confirmed D6-green
Both were suspected downstream-host RED; per-demo probes against a context-scoped
aimock confirm GREEN. declarative-gen-ui: cross-slug shadowing was the sole cause
(a2ui-fixed-schema passes on the same host). mcp-apps: fixed via the create_view
elements JSON-string fixture correction. Update manifest note + PARITY_NOTES to
the resolved state.
2026-07-22 16:09:14 +02:00
Alem Tuzlak 14f0af7dd5 fix(showcase/built-in-agent): mcp-apps create_view elements arg must be a JSON string
Excalidraw's MCP create_view tool declares `elements` as a string (JSON-encoded
array) in its inputSchema; the fixtures emitted a raw JSON array. BIA declares
the injected MCP tool locally via jsonSchemaToZod -> z.string(), so the array
failed input validation, the tool never executed against excalidraw, no
ACTIVITY_SNAPSHOT fired, and the MCP Apps iframe never mounted (D6 red).
Stringify the elements arg to match the inputSchema. Verified D6 green.
Same latent fix applied to the flowchart pill in mcp-apps.json.
2026-07-22 16:06:02 +02:00