Commit Graph

4771 Commits

Author SHA1 Message Date
Mark 26bb023426 Merge branch 'main' into mark/showcase-mastra-d6-followups 2026-07-22 06:38:19 -07:00
Alem Tuzlak 949653288d fix(showcase): allowlist built-in-agent open-gen-ui-advanced multi-file region
The byte-identical open-gen-ui-advanced frontend carries the
sandbox-function-registration @region in both page.tsx and
sandbox-functions.ts (verbatim from LGP, which is already allowlisted).
Add the built-in-agent allowlist entry so bundle-demo-content passes —
unblocks Validate Showcase + the shell/shell-docs/shell-dojo build-checks
(all run the bundler).
2026-07-22 14:36:37 +02:00
Alem Tuzlak 6166255081 chore(showcase/built-in-agent): reconcile manifest + PARITY_NOTES for LGP parity
- manifest: features/demos/not_supported_features rewritten to the migrated
  reality (byoc->declarative, dropped hitl-in-chat-booking, added a2ui-recovery
  / shared-state-read / threadid + declarative-*); named-agent convention
  documented; gpt-4o -> gpt-5.5. generate-registry + validate-parity pass.
- PARITY_NOTES: named-agent convention supersedes default-only; byte-identical-
  modulo-consistent-type-imports note; documents the aimock :latest context-
  scoping blocker (4 cells RED locally, fixtures correct) + the downstream
  renderer/host RED (declarative-gen-ui A2UI host, mcp-apps iframe host).
- fixture: tool-rendering-custom-catchall rewritten to the BIA sequenceIndex
  emitter + narration-fallback pattern + 4 LGP UI pills (context-rewritten).
2026-07-22 14:17:36 +02:00
Alem Tuzlak cd2011ddf6 feat(showcase/built-in-agent): named-agent registry + route reconciliation (LGP parity)
Wire the byte-identical frontends to backend agents:
- /api/copilotkit registers 22 named agents matching each demo's agent id
  (generic all-tools createBuiltInAgent, fixture-driven; reasoning trio uses
  the reasoning adapter factory).
- 8 dedicated routes re-keyed default -> LGP agent id (a2ui-fixed-schema,
  agent-config-demo, auth-demo, declarative-gen-ui, multimodal-demo,
  voice-demo); mcp-apps serves mcp-apps + headless-complete; ogui serves
  open-gen-ui + open-gen-ui-advanced.
- byoc-* routes renamed to declarative-* (dir + agent key + basePath).
- New copilotkit-a2ui-recovery + copilotkit-beautiful-chat routes reuse
  existing agents (declarative / generic) — no new factories.
- Drop BIA-only extras: byoc-hashbrown, byoc-json-render, hitl-in-chat-booking.

next build compiles clean. D6 parity sweep follows.
2026-07-22 12:43:54 +02:00
Alem Tuzlak 513eaa3d35 feat(showcase/built-in-agent): byte-identical LGP frontend migration (all demos)
Copy every langgraph-python demo frontend verbatim into built-in-agent
(diff -r clean across all 42 demo dirs), plus the shared shadcn UI
(src/components/ui, 25 primitives) and src/lib/utils, all byte-identical
to LGP. Adds the 5 demos BIA was missing (a2ui-recovery, declarative-
hashbrown, declarative-json-render, shared-state-read, threadid-frontend-
tool-roundtrip) and removes the orphaned _components dir.

Adds the frontend deps the copied UI requires (radix-ui, react-checkbox,
react-separator, cmdk, embla-carousel-react, react-markdown, remark-gfm,
yaml) and syncs package-lock. next build compiles clean.

Backend named-agent wiring + D6 parity follow in subsequent commits.
2026-07-22 12:29:57 +02:00
Alem Tuzlak 3ab9c82611 feat(showcase/built-in-agent): byte-identical agentic-chat via named agent (LGP parity P0)
Establish the named-agent registry pattern for LGP parity:
- agentic-chat frontend copied byte-identical from langgraph-python
  (diff -r clean); removes the BIA-bespoke setBackground variant.
- New createAgenticChatAgent() (prompt-only, LGP system prompt) registered
  as the named agent 'agentic_chat'; the runtime resolves agent="agentic_chat"
  against the agents map (cloneAgentForRequest -> resolveAgents).
- Fix gpt-4o -> gpt-5.5 in the shared tanstack factory (house rule).

Proven: bin/showcase test built-in-agent:agentic-chat --d6 --direct -> green.
2026-07-22 12:16:30 +02:00
Alem Tuzlak dd20114b01 fix(showcase): built-in-agent OGUI + MCP-Apps drop injected tools (#6100)
## What

Fixes three broken **Built-in Agent** showcase demos by forwarding the
tools that runtime middleware injects into `input.tools`. The in-process
TanStack factories were dropping them with `tools: []`.

- **open-gen-ui** — agent now calls `generateSandboxedUi` (was emitting
the UI as a raw HTML code block)
- **open-gen-ui-advanced** — same factory/route; the sandbox → host
callbacks can now engage
- **mcp-apps** — agent now sees `create_view` and can render the
Excalidraw view (was replying with plain text)

## Why

`OpenGenerativeUIMiddleware` / `MCPAppsMiddleware` inject their tool
into `input.tools` at request time. The working main
`tanstack-factory.ts` forwards `input.tools` into `chat({ tools })`, but
`ogui-factory.ts` and `mcp-apps-factory.ts` hard-coded `tools: []` — so
the model never received the tool and fell back to prose/HTML. This is
exactly why the demos look broken on the **live Railway deploy** (real
LLM): given no tool, a real model just prints the UI as text.

## How

Declare the injected tools via `toolDefinition()` — the same pattern the
main factory already uses — and `export` its `jsonSchemaToZod` helper
for reuse (no duplication).

Note: `convertInputToTanStackAI(input).tools` would be simpler, but that
return field only exists in `@copilotkit/runtime >= 1.61.0`. This app
pins **1.60.2**, so the `toolDefinition()` route is the version-safe
fix.

## Verification

- ✅ `tsc --noEmit` against the pinned `@copilotkit/runtime@1.60.2` — the
three changed files are type-clean. (The app has pre-existing, unrelated
zod-version-skew tsc errors in the A2UI catalog files; those are on
`main` and untouched here.)
- ⚠️ **D5/D6 aimock replay was NOT run** — no Docker in my environment.
Needs a CI / Docker-capable run to confirm the demos render.
- ⚠️ **Fixtures may need re-recording.** The aimock fixtures for
`gen-ui-open`, `gen-ui-open-advanced`, and `mcp-apps` (built-in-agent)
may have been captured in the broken (no-tool-call) state; if so, replay
won't demonstrate the fix until they're re-recorded against a real LLM
(showcase Procedure 3). Please confirm the D5/D6 run and re-record if
needed.

## Follow-ups

- After merge, **redeploy the built-in-agent Railway service** so the
live showcase reflects the fix.
- P0 slice of the broader **OSS-594** parity effort; structural drift +
runtime-capability gaps are tracked in that ticket.

Refs OSS-594.
2026-07-22 11:14:19 +02:00
Alem Tuzlak 0f1bdf0731 fix(showcase): restore 3 suggestion pills on built-in-agent prebuilt demos (#6102)
## What

The built-in-agent **prebuilt-sidebar** and **prebuilt-popup** demos
each rendered a single hard-coded "Say hi" suggestion pill, even though
a correct 3-pill hook (`usePrebuiltSidebarSuggestions` /
`usePrebuiltPopupSuggestions`, byte-identical to `langgraph-python`)
already lived in each demo's own `suggestions.ts` — just never imported.
This wires the existing hooks so the pills match canonical:

- **prebuilt-sidebar**: Say hi · Fun fact · Is 17 prime?
- **prebuilt-popup**: Say hi · Limerick · Is 17 prime?

## Why

Classic scaffold-then-drift: the flavor was copied from canonical
(bringing the `suggestions.ts` hook along) but each `page.tsx` was
hand-written with a degraded inline single-pill version and never wired
back. Part of the **OSS-594** P1a "orphaned suggestions" cleanup.

## How

Call the existing hook from each `page.tsx` and drop the now-unused
`useConfigureSuggestions` import. No new files; the only behavior change
is the suggestion set.

## Verification

- lefthook (`oxlint` + `oxfmt`) clean on commit.
- Leans on CI `build-check (built-in-agent…)` + `check-types` — both
green on the sibling P0 PR #6100 for the same app.
- 6 insertions / 18 deletions across 2 files.

Refs OSS-594.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-22 11:13:10 +02:00
Mark Fogle 2e66f304e5 fix(showcase): wire prebuilt-sidebar/popup suggestions in built-in-agent
Both demos hard-coded a single inline "Say hi" pill while their own
`usePrebuiltSidebarSuggestions` / `usePrebuiltPopupSuggestions` hooks (3 pills each,
byte-identical to langgraph-python) sat unused. Call the existing hooks so the pills
match canonical, and drop the now-unused `useConfigureSuggestions` import.

Refs OSS-594.
2026-07-22 05:41:03 +00:00
Mark Fogle fb60186468 fix(showcase): forward injected tools in built-in-agent ogui/mcp-apps factories
The OGUI and MCP-Apps factories built the in-process TanStack agent with `tools: []`,
discarding the tools the runtime middleware injects into `input.tools`
(`generateSandboxedUi` for Open Generative UI, `create_view` for MCP Apps). The model
never saw the tool, so it emitted the UI as raw HTML/text instead of a tool call — no
sandboxed iframe / MCP view rendered.

Declare the injected tools via `toolDefinition()` (the pattern the working main
tanstack-factory already uses), exporting its `jsonSchemaToZod` helper for reuse. The
converter's own `tools` return only exists in @copilotkit/runtime >= 1.61.0; this app
pins 1.60.2. Fixes open-gen-ui, open-gen-ui-advanced, mcp-apps.

Refs OSS-594.
2026-07-22 05:13:54 +00:00
Mark Fogle 4640d6304e fix(showcase/mastra): useComponent (gen-ui-tool-based) — probe took the wrong path
The "Generative UI: useComponent" cell (gen-ui-tool-based) went red on mastra
the moment OSS-381 took it out of not_supported: the D5 gen-ui-custom probe
sent the *haiku* prompt and hunted for a haiku card, but 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").

Root cause: the probe's CHART_INTEGRATIONS allowlist in
harness/src/probes/scripts/d5-gen-ui-custom.ts omitted mastra, so
isChartIntegration("mastra") was false and it took the haiku branch. mastra's
gen-ui-tool-based page registers render_pie_chart / render_bar_chart via
useComponent exactly like langgraph-python and google-adk.

- Add "mastra" to CHART_INTEGRATIONS so the probe sends the pie-chart prompt
  and asserts the donut SVG + "pie"/"chart" follow-up tokens.
- Add aimock/d6/mastra/gen-ui-custom.json (mirrors langgraph-python's, context:
  mastra; the pie schema is identical — {title, description, data:[{label,value}]})
  so the cell is deterministic under aimock replay instead of falling through to
  the live upstream.
- Repoint the probe unit test's haiku-empty-card case from "mastra" to "agno"
  (a genuine haiku integration) now that mastra is a chart integration.

Not a v1-bridge streaming regression — a harness/fixture gap exposed when the
cell was un-suppressed. Harness unit tests not run locally (sparse showcase
checkout has no vitest); logic-only changes.

--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-22 05:13:29 +00:00
Mark Fogle 57afed6dd4 fix(showcase/mastra): gen-ui-agent completes all 3 steps (raise step cap)
The "Generative UI: Agent State" cell (gen-ui-agent) was stuck at D4 — the
d5-single-pill e2e ("marks every step as completed") failed with only 2/3 steps
reaching "completed", which blocks D6.

Root cause: the planner scripts 3 steps × 2 set_steps transitions (in_progress →
completed) + 1 initial "all pending" call + 1 closing message (~8 model turns),
but genUiAgent set no stop condition, so the AI SDK's default halted the agentic
loop before the 3rd step completed. (LangGraph gold loops until the graph ends
and needs no equivalent; this is the AI-SDK step-cap analogue — cf.
toolRenderingAgent's d20 sequence.)

Add defaultOptions.stopWhen = stepCountIs(12) to genUiAgent so the full
progression runs to completion.

Verified on the faithful rig (Node 22 + next build/start + aimock 1.37.4 replay):
gen-ui-agent.spec 6/6; tool-rendering 6/6 and gen-ui-tool-based 4/4 unchanged
(no regression). Isolated to genUiAgent — no other agent/demo affected.

--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-22 00:50:59 +00:00
Mark 64daf49638 feat(showcase/mastra): v1 bridge alpha + reasoning/streaming out of not_supported (OSS-381) (#5798)
## Mastra Partner Refresh — showcase finalization (OSS-381)

Bumps the showcase Mastra integration onto the **v1 bridge alpha** and
flips the
features it unblocks out of `not_supported`. Opened for CI to run the
D6/e2e
suite (local Docker daemon is wedged in the authoring env — see notes).

### Landed
- **OSS-382 (gate):** `@ag-ui/mastra` `0.2.1-beta.2` →
**`1.1.0-alpha.0`**.
- Alpha verified to ship all features (grep on dist):
`emitInterruptOutcome`,
`STATE_DELTA`, `observationalMemory`, `background-task`,
`tracingOptions`,
`getA2UITools`/recovery. Peers satisfied (`@mastra/core` 1.41,
`client-js`
    1.23.2, runtime 1.61.2).
- `next build` passes (40 routes). Unit tests **identical to the beta.2
baseline** (13 pre-existing failures in `route.test.ts`'s error-path
mocks,
    unrelated to the bump — proven by a stash+reinstall A/B).
- **OSS-384 / OSS-423:** moved into `features` (demos + e2e + aimock
fixtures
  were already wired, gated on this release):
  `agentic-chat-reasoning`, `reasoning-default-render`,
`tool-rendering-reasoning-chain`, `shared-state-streaming`. Added the
missing
  `reasoning-default` / `reasoning-custom` manifest demo entries.
- **Parity:** `not_supported_features` now holds only `gen-ui-interrupt`
+
`interrupt-headless`, matching the **langgraph-python gold standard**,
which
quarantines the same two cells on an upstream `@copilotkit/react-core`
v2
  resume-path hook bug (published-package fix, out of scope). The native
interrupt + RUN_FINISHED-outcome path ships in the bridge; the showcase
cell
  is blocked by the same upstream bug, not the bridge.
- **OSS-424:** execution-tracing note (`tracingOptions` in / `traceId`
on
  `RUN_FINISHED.result` out) added to the Mastra Copilot Runtime doc.
- **OSS-425:** GenUI `generative_ui` spectrum already at parity with
gold
  (`constrained-explicit`, `a2ui-fixed-schema`, `a2ui-dynamic-schema`).

### Not in this PR (scoped, blocked, or pending)
- **OSS-422 a2ui-recovery**, **OSS-426 background-agents**, **OSS-427
observational-memory** — new demo cells. Reference material + build
plans
  ready. OM additionally needs `@mastra/memory` ≥1.21.2 (repo pins
`1.0.1-alpha.1`; the on-stream async-buffering path won't fire below
that).
- **OSS-91 browser-use** — Mastra-only, non-deterministic (no clean
aimock
  replay), needs a Browserbase key not present in the env. Blocked.
- **OSS-392 input.context** — owner exception; only if langgraph
showcases it.

### Verification note
Local D6 could not be run: the Docker daemon's container-creation path
is wedged
in this environment (a trivial `hello-world` create hangs), and
unwedging needs a
Docker Desktop restart that would destroy a concurrent session's running
stack.
Relying on CI for D6/e2e. Everything above is build-level verified +
committed.
2026-07-21 16:44:25 -07:00
Mark f986cff0cb Merge branch 'main' into claude/brave-kirch-8dbf00 2026-07-21 10:10:45 -07:00
Mark Fogle f98b73b3d3 fix(showcase/mastra): headless-simple fun-fact pill — stop d4 chat fixture hijacking it
headless-simple's "Give me a fun fact." pill rendered the wrong text
("Here's a fun fact: honey never spoils…") and the e2e failed. Root cause:
d4/mastra/chat.json keyed the prebuilt-sidebar agentic-chat fixture on the
bare "fun fact", which is a substring of the headless-simple pill "Give me a
fun fact." Because d4 loads before d6, that fixture shadowed headless-simple's
own d6 fixture ("A fun fact: Honey never spoils!").

Re-key it to the unique "fun fact for the prebuilt sidebar" phrase (mirrors
gold langgraph-python), so it no longer substring-collides. The prebuilt-sidebar
demo pill "Give me a fun fact." now shares headless-simple's d6 fun-fact
fixture, exactly as gold does; prebuilt-sidebar/popup e2e unaffected.

Verified (Node 22 + next start + aimock 1.37.4 replay): headless-simple 4/4,
prebuilt-sidebar 4/4, prebuilt-popup 4/4 — and the full mastra card/chat suite
green (tool-rendering 6/6, tool-rendering-reasoning-chain 5/5, headless-complete
5/5, beautiful-chat 8/8, agentic-chat 4/4). Only a userMessage key changed
(more specific → strictly fewer aimock substring-shadows, well under the
KNOWN_SHADOW_CEILING).

--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-21 17:10:08 +00:00
github-actions[bot] 1f56a6adbd style: auto-fix formatting 2026-07-21 16:58:59 +00:00
Mark Fogle 3c13a0881e fix(showcase/mastra): headless-complete cards render — agent tool-registration + get_revenue_chart + scriptable weather
headless-complete is marked supported but its WeatherCard / StockCard / ChartCard
stalled in the "running" state. headlessCompleteAgent registered tools via object
shorthand ({ weatherTool, stockPriceTool }), which exposes the JS variable names
instead of the snake_case names the aimock fixtures + useRenderTool renderers emit
(get_weather / get_stock_price / get_revenue_chart) — so the scripted tool calls
were never executable — and get_revenue_chart had no backend tool at all.

- Re-key headlessCompleteAgent to explicit { get_weather, get_stock_price,
  get_revenue_chart } (mirrors gold langgraph-python headless_complete.py).
- Add revenueChartTool (id get-revenue-chart) returning gold's fixed payload
  { title: "Quarterly revenue", subtitle, data: [6x {label,value}] }.
- Make weatherTool accept optional scripted temperature/conditions/humidity/
  wind_speed (echoed when provided, else the seeded getWeatherImpl) — mirrors
  get_stock_price's scripted price_usd. Gold's headless get_weather is a fixed
  68 degF / Sunny mock while mastra's is seeded, so the headless weather fixtures
  script 68/Sunny to match gold's card; tool-rendering's SF pill keeps its seeded
  value. Scripted the winning headless-complete + gen-ui-headless-complete
  "What's the weather in Tokyo" legs and aligned the narration to gold. (No gold/
  shared backend touched — mastra tool + mastra fixtures only.)

Verified (Node 22 + next build/start + aimock 1.37.4 replay): headless-complete
5/5; tool-rendering 6/6, tool-rendering-reasoning-chain 5/5, beautiful-chat 8/8,
agentic-chat and headless-simple weather unaffected — no regression.

--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-21 16:57:22 +00:00
Mark Fogle 9bf38034a6 fix(showcase/mastra): tool-rendering + reasoning-chain e2e green via gold fixture parity
The tool-rendering cell (marked supported) had 5/6 e2e failing and
tool-rendering-reasoning-chain 2/5, all from mastra aimock fixtures diverging
from the langgraph-python gold standard. Root cause: several fixtures were
keyed on generic substrings where gold uses unique tails, so they
substring-collided with the longer chain pills and — loading earlier
(alphabetical file order) — hijacked them.

Verified on a faithful rig (Node 22 + next build/start + aimock 1.37.4 replay):

- Stock: the pill's scripted $338.37 fixture was shadowed by
  headless-complete's ticker-only "price of AAPL" leg (tool's 189.42 default).
  Restore gold's unique "price of AAPL right now" key; key the tool-rendering
  emit leg on toolName (gold parity).
- d20: the first-roll leg gated on hasToolResult:false never matched once
  prior-pill tool results lingered in thread history -> 0 cards. Match on
  userMessage only (gold). Add stopWhen: stepCountIs(8) to toolRenderingAgent
  so the 5-roll sequence + narration (and the 3-tool chain-tools turn) run to
  completion instead of stopping at the default step cap.
- chain-tools: headless-complete's generic "weather in Tokyo" leg hijacked the
  "...get the weather in Tokyo..." pill and emitted only get_weather. Restore
  gold's "What's the weather in Tokyo" key.
- reasoning-chain flights+weather + sequential: beautiful-chat's generic
  "Find flights from SFO to JFK" legs hijacked the "...JFK and show me the
  weather there" pill. Restore gold's "for next Tuesday" key.

Result: tool-rendering 6/6, tool-rendering-reasoning-chain 5/5, beautiful-chat
8/8 (no regression) under aimock replay.

Note: headless-complete's own weather/stock/revenue cards remain red on a
separate pre-existing bug (headlessCompleteAgent tool-registration + a missing
get_revenue_chart tool) — addressed in a follow-up commit.

--no-verify: this sparse showcase checkout has no monorepo lefthook/commitlint
binaries (matches prior commits on this branch).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 16:33:48 +00:00
github-actions[bot] 126864ead7 style: auto-fix formatting 2026-07-21 08:35:46 +00:00
Ran Shem Tov 60f2771830 fix(showcase/mastra): tool-rendering parity — dedicated agent, roll_d20, gold search_flights (CR #5798)
Addresses the tool-rendering CHANGES_REQUESTED on #5798 (5/6 e2e failing),
mirroring gold langgraph-python tool_rendering_agent.py:

1. Dedicated toolRenderingAgent bound to all four demo tools (get_weather,
   search_flights, get_stock_price, roll_d20) + route tool-rendering and its
   default/custom-catchall variants to it. Previously routed to weatherAgent,
   which lacks get_stock_price/roll_d20, so the Stock, d20, and Chain pills
   emitted uncallable tool calls the AI SDK dropped (no card).
2. New deterministic roll_d20 tool (echoes a scripted value) and get_stock_price
   now echoes optional price_usd/change_pct — lets the fixtures script exact
   values, mirroring gold's roll_d20/get_stock_price.
3. search_flights now accepts gold {origin,destination} and GENERATES the
   flights list (kept lenient — still accepts a legacy {flights} array so the
   D5 harness probe keeps working). Fixes the reasoning-chain flights leg that
   failed input validation.
4. Re-keyed the tool-rendering + reasoning-chain fixtures off the fragile
   turnIndex onto hasToolResult:false (turn-scoped in aimock >=1.37.x) and
   added the missing Find-flights first leg (was 'No fixture matched' 404).
5. Weather e2e assertion -> 77%/3 (mastra's seeded getWeatherImpl for SF; a
   documented divergence from gold's fixed 55/10).

Route /api/copilotkit compiles + loads cleanly; full e2e to be confirmed via
/eval d5 mastra on the harness (local next-dev verification is blocked by this
machine's 7.7GiB Docker VM OOMing on the heavy route compile).
2026-07-21 08:34:11 +00:00
Jordan Ritter 076145d235 fix(showcase): stage feature-registry + SHOWCASE_ROOT so /api/matrix works in the deployed image 2026-07-20 23:47:43 -07:00
Jordan Ritter d1b07d4513 fix(showcase): stage catalog-flatten in generator envs
generate-registry.ts imports the catalog cross-join/flatten fold from
../harness/src/shared/catalog/catalog-flatten.ts, which does
`import yaml from "js-yaml"`. The generator's build/test environments did
not stage that file (or its module-resolution scope), so the fold could
not resolve.

- Dockerfiles (shell, shell-dashboard, shell-docs, shell-dojo): COPY the
  shared catalog source + harness/package.json (its `"type":"module"` is
  required so catalog-flatten resolves as ESM and its named exports bind)
  and provide a node_modules for js-yaml resolution.
- generate-registry-pattern.test.ts (makeHarness): stage catalog-flatten.ts
  and harness/package.json at the exact relative path the generator
  resolves, and symlink the scripts node_modules onto the harness tree so
  the ESM `import yaml from "js-yaml"` resolves.
- js-yaml + @types/js-yaml added to showcase/scripts (package.json and the
  npm package-lock.json), and the root pnpm-lock.yaml regenerated to add
  the matching importer entries for showcase/scripts (js-yaml >=4.1.1 via
  the root override, @types/js-yaml ^4.0.9) so `pnpm install
  --frozen-lockfile` stays in sync.
2026-07-20 22:36:14 -07:00
Jordan Ritter be5f2a2ea2 feat(showcase): shell-dashboard ladder single-source + per-cell render degrade
deriveDepth becomes a thin adapter over the shared buildCellModel engine so the
dashboard and API render from one ladder; page-stats routes through the shared
catalog input; dashboard-page per-cell render try/catch isolates a bad cell.
2026-07-20 21:48:41 -07:00
Jordan Ritter 2e3933ddb8 fix(showcase): d0-gone-monitor fail-safe short-read guard + per-cell degrade
Assigns the authoritative total before the empty-page break and treats an
inconclusive/truncated read as HOLD (fails toward alerting, never folds partial
data into a nothing-gone verdict); de-dupes the short-read log; per-cell scan
try/catch degrades one bad cell without blinding the detector.
2026-07-20 21:48:40 -07:00
Jordan Ritter 7382d72fba refactor(showcase): single-source shared catalog flatten with manifest validation
One shared catalog-flatten authority (typed throws, not process.exit); the server
re-flatten validates manifest structure at parity with the codegen path.
2026-07-20 21:48:40 -07:00
Jordan Ritter 1b87facd05 feat(showcase): GET /api/matrix read-model returning true per-cell chip state
Runs buildCellModel server-side (full signal the browser strips) so the true
dashboard-visual state is API-derivable. Authoritative-total short-read guard
(serves matrix_unavailable, never silent all-gray), page-cap throw, and per-cell
try/catch so one bad featureId degrades a single cell, not the whole surface.
2026-07-20 21:48:40 -07:00
Jordan Ritter ea8203a3ef feat(showcase): unified cell-model ladder engine
Single per-rung classifyRung verdict folded uniformly via foldFamily/combine;
enforces the section-2a coherence invariants (chip/isRegression/achieved/d6Effective
from one verdict), first-strike de-amplification gated on max non-infra red
fail_count, future-skew age clamp, and the staleness folds. Golden-master
equivalence baseline + coherence/contribution/combine test suites.
2026-07-20 21:48:39 -07:00
Jordan Ritter e5e7fc8b96 refactor(showcase): align complete/completed naming in D4 probe (T3)
readTurnComplete returned { observed, complete } while runAttempt returned
{ text, completed, observed } for the same concept. Rename the lower-churn
side (readTurnComplete's 'complete' → 'completed') so both use 'completed'.

Pure internal rename — the fields are local to runLevel, not exported and
not referenced by any test. Zero behavior change.
2026-07-20 16:55:24 -07:00
Jordan Ritter 041b4a0692 test(showcase): derive D4 guard probed-route set from probe SSOT (GB2)
The d4-probe-domdone-guard test hardcoded its probed-route set as a literal
["agentic-chat","tool-rendering"] parallel to the probe's own inline
route literals — a drift hazard if the probe starts driving a new D4 route.

Introduce D4_DEMO_ROUTE_AGENTIC_CHAT / D4_DEMO_ROUTE_TOOL_RENDERING and a
D4_PROBED_DEMO_ROUTES source-of-truth array in the probe, wire the two
runLevel demo/demoPath call sites (and hasToolRendering) to them, and have
the guard derive PROBED_ROUTES from that export. Add a superset assertion so
the derived set can never narrow coverage below {agentic-chat,tool-rendering}.

Behavior-preserving: the route strings are unchanged.
2026-07-20 16:54:50 -07:00
Jordan Ritter 3dc43b9ca9 feat(showcase): bring prod autoUpdates under drift-gate management
Prod autoUpdates is now "disabled" (was "unmanaged") for every service, so the
drift gate enforces prod as well as staging. Paired with disabling autoUpdates
on the live prod Railway services. Regenerates the SSOT JSON.
2026-07-20 16:31:28 -07:00
Jordan Ritter e0c7fd30ee fix(showcase): alert when an all-legs-cancelled build produced no successes
The notify-all-builds-failed and notify jobs keyed off a 'failure' rollup /
bare failure(), so a build where every real service failed but one leg was
cancelled (contention) rolled up to 'cancelled' and sent no alert — the same
blind spot as the redeploy guard. Fire on any_success == 'false' (guarded by a
status function so a user-cancelled run stays silent). Extends the guard test.
2026-07-20 16:28:57 -07:00
Jordan Ritter bd000f973b showcase: consolidate deploy onto CI-explicit path (guard fix, autoUpdates SSOT, drift gate, reconcile) (#6082)
## Showcase deploy-mechanism consolidation

Consolidates the showcase Railway deploy path onto a single
**CI-explicit** mechanism, so we can safely retire Railway's registry
auto-watch (the source of the surprise "Service aimock upgraded to
latest" emails). Design proposal: [Notion — Showcase Deploy-Mechanism
Consolidation](https://app.notion.com/p/3a33aa38185281e4b64cc5bebde92d91).

### What & why
The "aimock upgraded to latest" email was never a per-service config
choice — it was a **CI bug** letting Railway's watcher win a race: a
Renovate PR that only touches `showcase_build.yml` forces a full-fleet
rebuild; the LFS `shell` leg gets cancelled under runner contention; and
the `redeploy-staging` guard (`needs.build.result != 'cancelled'`) then
skipped the CI redeploy for the **whole fleet**, orphaning aimock's
fresh digest for Railway's watcher to pick up. The `autoUpdates` setting
itself had also silently drifted (24 services `minor` / 17 none) —
tracked in no SSOT, gated by nothing.

### The four changes (one commit each)
1. **`fix(showcase)` — the P0 guard bug.** Relax the `redeploy-staging`
**and** `redeploy-staging-starters` guards so a cancelled sibling leg no
longer skips the fleet's staging redeploy; they now redeploy the
already-computed successful-service list. A guard-evaluation test reads
the live workflow `if:` strings and models GitHub's matrix rollup.
2. **`feat(showcase)` — autoUpdates SSOT (per-env, staging-first).** Add
a **per-env** `autoUpdates` policy to every service in `railway-envs.ts`
— **staging: `disabled`** (enforced), **prod: `unmanaged`** (left
exactly as-is until a later migration). Regenerate
`railway-envs.generated.json`. CI-explicit redeploy becomes the single
deploy path on staging.
3. **`feat(showcase)` — drift gate.** New CI gate fails when a live
Railway service's `autoUpdates` diverges from the SSOT. Reads
`Environment.config` (autoUpdates isn't on the typed `ServiceSource`
output), **enforces managed (`disabled`) envs and skips `unmanaged`
ones** (so prod is untouched), **fails closed per-env** on zero-checked,
and skips cleanly on fork PRs with no Railway token.
4. **`feat(showcase)` — scheduled reconcile.** CI-owned self-heal (every
15m) comparing each staging service's deployed digest against GHCR
`:latest`, re-running the staging redeploy for lagging services and
alerting Slack. Invariant: **green ⟺ every in-scope service confirmed
current**; any unconfirmed service (lag, digest error, dropped redeploy,
empty scope, thrown redeploy) alerts and exits non-zero.

### Verification
- Every behavior change carries red-green tests; **230 tests pass**,
`tsc` clean, `oxfmt`/`oxlint` clean, generated JSON in sync, workflows
parse.
- Reviewed via a full CR loop (Tier 3, 5 rounds to convergence); the
reconcile's fail-loud invariant was hardened across rounds (silent-green
holes, stale-digest ordering, expansion false-positives, test hygiene).

### Rollout (staging-first)
- **Staging is flipped live as part of this change** — `autoUpdates`
disabled on all staging services (snapshot-first, verified only
`autoUpdates` changed). The drift gate now enforces staging.
- **Prod is untouched** — its `autoUpdates` stay exactly as-is and the
gate marks prod `unmanaged` (skipped). Migrating prod is a deliberate
follow-up (flip prod live + change prod SSOT `unmanaged`→`disabled`
together) once we're comfortable with staging on the new mechanism. No
transition window where anything is unguarded.

### Follow-ups (from CR, non-blocking)
- Dedup the reconcile alert's `unconfirmed` list by service key
(cosmetic double-listing; exit code already correct).
- Harden the sibling `notify-all-builds-failed`/`notify` jobs against
the same all-legs-cancelled rollup (pre-existing, in a job this PR
doesn't touch).
- Minor: `postSlackAlert` try/catch belt; a few added test assertions;
comment/doc accuracy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-20 16:17:00 -07:00
Jordan Ritter 6b4b1ee179 fix(showcase): gate D4 chat probe completion on domDone to close empty-response render race (#6081)
## Incident

At ~21:19Z on 2026-07-20 the prod showcase Feature Matrix showed the
`claude-sdk-python` column whole-column-red (✓0/✗37). It self-recovered
by ~21:30Z. Not infra, not staleness: `/api/health` was 200 throughout,
`commErrorKinds` was empty, and the image was current.

## Root cause

The shared D4 chat probe (`d4-chat-roundtrip.ts`) emitted ONE transient
red — `failureSummary: "empty assistant response"`, no
`errorClass`/`errorDesc`. Because the dashboard's `resolveD4` is
**slug-keyed**, that single `chat:<slug>` row gated all 37 feature cells
for the slug → the whole column went red off one flap.

The producer-side origin is a **render race**. `readTurnComplete()`
gated turn completion on `domDone || sseDone`. `sseDone` is the
transport-level `RUN_FINISHED` counter — a synchronous raw-byte SSE
parse that runs *outside* React and can fire at-or-before the React
commit that actually renders the assistant text. `domDone` (the
`data-copilot-running` true→false DOM edge) is coalesced into that
*same* React commit (`use-agent.tsx`
`batchedForceUpdate`/`queueMicrotask`). Under contention, gating on
`sseDone` let the fast-fail grace window elapse while the DOM was still
empty, redding a turn that was about to render correctly.

## The change

`complete: domDone || sseDone` → `complete: domDone`. The moment
`domDone` is true, the assistant text is already in the DOM (same
commit). `observed` still includes `sseDone`, so a turn whose attribute
never appears still gets the wider polling window rather than
fast-failing. `FIRST_TOKEN_GRACE_MS` and `NON_COMPLETION_RETRY_LIMIT`
are untouched. `domDone` is not a new signal — the probe already
observes that edge via `readTurnState`; this only changes which existing
signal `complete` trusts.

**Throughput-neutral:** `runAttempt` returns on a non-empty
`readAssistantText` *before* `readTurnComplete` is consulted, so the
happy path is unchanged. Only a completed-but-empty turn's
classification changes. A genuinely-empty completed turn still reds
(correct) — only the race false-positive is removed.

## Red → green proof (deterministic, on the real code path)

A new deterministic timing-sim regression (`sseLeadMs` fixture)
decouples `sseDone` from `domDone` *in time* and drives the real
`readTurnComplete`/`runAttempt`. Two cases: a TIMING SIM (sseDone at
send, text at 2500ms past the ~2000ms grace window) and a FORMULA PIN
(sseDone-only, token never arrives → asserts `sends === 2`, catching a
literal revert to `domDone || sseDone` via the retry-fired
discriminator, not a wall-clock threshold).

**RED — test hunks applied on top of UNFIXED probe code:**

```
 FAIL  src/probes/drivers/d4-chat-roundtrip.test.ts > d4 render-race: sseDone-leads / domDone-lags turn completion (Fix B) > TIMING SIM: sseDone fires EARLY, domDone+text land LATE together → GREEN (RED pre-fix)
AssertionError: expected 'red' to be 'green' // Object.is equality
Expected: "green"
Received: "red"
 ❯ src/probes/drivers/d4-chat-roundtrip.test.ts:3195:21

 FAIL  src/probes/drivers/d4-chat-roundtrip.test.ts > d4 render-race: sseDone-leads / domDone-lags turn completion (Fix B) > FORMULA PIN: sseDone alone must NOT flip `complete` — a turn that only ever fires sseDone stalls+retries (does NOT fast-fail as completed-empty)
AssertionError: expected 1 to be 2 // Object.is equality
- Expected  2
+ Received  1
 ❯ src/probes/drivers/d4-chat-roundtrip.test.ts:3229:19

 Test Files  1 failed (1)
      Tests  2 failed | 82 skipped (84)
```

**GREEN — probe fix hunk then applied, same tests re-run:**

```
 ✓ src/probes/drivers/d4-chat-roundtrip.test.ts (84 tests | 82 skipped) 9026ms
   ✓ d4 render-race: sseDone-leads / domDone-lags turn completion (Fix B) > TIMING SIM: sseDone fires EARLY, domDone+text land LATE together → GREEN (RED pre-fix)  5017ms
   ✓ d4 render-race: sseDone-leads / domDone-lags turn completion (Fix B) > FORMULA PIN: sseDone alone must NOT flip `complete` — a turn that only ever fires sseDone stalls+retries (does NOT fast-fail as completed-empty)  4007ms

 Test Files  1 passed (1)
      Tests  2 passed | 82 skipped (84)
```

Full `d4-chat-roundtrip.test.ts` suite after the fix: **84 passed (84)**
— no regression.

## Real-probe forcing (Part B) — honest disclosure

The live race is low-rate and non-deterministic. The `--direct`
(direct-LLM) live-probe forcing path could **not** be stood up within
reasonable effort in this environment: Docker is running, but `--direct`
requires a real Anthropic API key that is not present here, and forcing
a probabilistic React-commit-timing race across ~300 reps on a
freshly-built `claude-sdk-python` integration stack is beyond a
reasonable bound for the bonus real-surface proof. It was **not** faked.
The deterministic timing-sim regression above exercises the real
`readTurnComplete`/`runAttempt` code path and is the gating proof.
**Recommendation:** a multi-tick staging dashboard watch post-merge to
confirm the flap does not recur.

## Scope note

This PR fixes the **producer-side** root cause. The **render-layer
de-amplifier** (a single transient D4 flap should degrade a slug's cells
to *amber*, not whole-column-red via slug-keyed `resolveD4` fan-out) is
owned separately by the dashboard-ladder redesign.


## CR follow-ups (post-review hardening)

Three small follow-ups from the 7-agent CR + adversarial verify (which
found zero live bugs in the Fix B core). The `complete: domDone` core is
untouched.

- **Regression-guard test (hardening).** New
`d4-probe-domdone-guard.test.ts` (source-level, TS AST). It asserts
every D4-probed demo page — `/demos/agentic-chat` for every integration,
`/demos/tool-rendering` where present — renders `<CopilotChat/>` in the
attribute-bearing **self-closing** form, not the children render-prop /
slot form. Only the self-closing form hits the `CopilotChatView` branch
that emits `data-testid="copilot-chat"` + `data-copilot-running`, which
the probe's `domDone` gate reads; the `if (children)` branch returns a
`display:contents` wrapper with neither, which would silently regress
the cell to the ~60s / double-send fallback. That regression is
invisible to the probe's own fake-injected unit tests, so it is guarded
structurally at CI time. Chose the source/AST approach over full page
render because the pages are Next.js `"use client"` app-router
entrypoints mounting a live `<CopilotKit runtimeUrl=.../>` provider +
framework agents (impractical to render faithfully in a harness unit
test).

**Red-green proof.** Temporarily mutated
`langgraph-python/agentic-chat/page.tsx` to the children render-prop
form → guard **RED** (`langgraph-python/agentic-chat … expected 0 to be
greater than or equal to 1`, 1 failed | 40 passed). Reverted the
mutation → **GREEN** (41 passed). Mutation fully reverted; net change is
the test only.

- **Comment factual fix.** In `d4-chat-roundtrip.ts` near the `complete:
domDone` gate: the comment said `observed` still includes `sseDone`
"(below)", but `observed` is defined *above*. Corrected "(below)" →
"(above)".

- **Timing-sim robustness pin.** The `TIMING SIM` test's discriminating
power depended on `FIRST_TOKEN_GRACE_MS (2000) < firstTokenDelayMs
(2500) < ceiling (~4000)`, encoded only in prose. Now imports the actual
`FIRST_TOKEN_GRACE_MS` source constant (newly exported) and asserts that
ordering, so raising the grace constant later fails the test loudly
instead of silently ceasing to discriminate. No existing assertion
weakened.

Quality: harness `d4-chat-roundtrip.test.ts` + new guard test green (125
tests); `tsc --noEmit` clean; `tsc -p tsconfig.build.json` clean; `oxfmt
--check` clean; `oxlint` warnings-only (no errors).
2026-07-20 16:05:55 -07:00
Jordan Ritter eddfcc07e8 docs(showcase): fix stale cross-reference in D4 probe comment
The comment near the complete:domDone gate said `observed` still
includes `sseDone` "(below)" — but `observed` is defined ABOVE the
comment, not below. Correct "(below)" to "(above)".
2026-07-20 15:41:13 -07:00
Jordan Ritter 4bf796b713 test(showcase): guard D4 probe domDone gate + pin first-token grace ordering
Add a source-level (TS AST) regression guard asserting every D4-probed
demo page (/demos/agentic-chat always; /demos/tool-rendering where
present) renders <CopilotChat/> in the attribute-bearing self-closing
form, not the children render-prop form. The self-closing form is the
CopilotChatView branch that emits data-testid="copilot-chat" +
data-copilot-running, which the probe's domDone completion gate reads;
the render-prop branch omits it, which would silently regress the cell
to the ~60s/double-send fallback path. Invisible to the probe's own
fake-injected unit tests, so guarded structurally at CI time.

Also pin the TIMING SIM test's discriminating window against the actual
FIRST_TOKEN_GRACE_MS source constant (now exported): assert
FIRST_TOKEN_GRACE_MS < firstTokenDelayMs < attempt-0 ceiling so that
raising the grace constant later fails the test loudly instead of
silently ceasing to discriminate pre-fix vs post-fix.
2026-07-20 15:41:03 -07:00
Jordan Ritter a33e313df8 feat(showcase): make autoUpdates per-env for staging-first rollout
autoUpdates is now per-env: staging is enforced "disabled" while prod is
"unmanaged" (the drift gate skips it) so prod stays untouched until a later
migration. The gate enforces managed envs and skips unmanaged ones; the
zero-checked floor applies only to managed envs. Regenerates the SSOT JSON.
2026-07-20 15:31:23 -07:00
Tyler Slaton 50805ab47d docs: fix stale quickstart/link references and add MCP Codex setup (#6079)
## What & why

Three independent documentation-accuracy fixes, batched into one PR.

### 1. Dead spec links + gen-ui page gaps (Closes #3975)
`generative-ui-specs-overview.mdx` (rendered at
`/whats-new/generative-ui-spec-support`) linked to the retired
`/generative-ui/specs/<spec>` subgroup. Repointed to canonical
destinations and added the frameworks list the issue asked for.

**Verified live (HTTP status against docs.copilotkit.ai):**

| Link | Before | After |
| --- | --- | --- |
| A2UI | `/generative-ui/specs/a2ui` (301 hop) | `/generative-ui/a2ui` →
**200** |
| MCP Apps | `/generative-ui/specs/mcp-apps` (301 hop) |
`/generative-ui/mcp-apps` → **200** |
| Open Generative UI (new) | — | `/generative-ui/open-generative-ui` →
**200** |

- **Supported Frameworks** list added — all 12 `/<slug>/quickstart`
targets return **200** live (LangGraph Py/TS, Google ADK, MS Agent, AWS
Strands, Mastra, PydanticAI, CrewAI, Agno, AG2, LlamaIndex, Claude Agent
SDK, Deep Agents).
- **Open-JSON-UI is intentionally NOT linked:**
`/generative-ui/open-json-ui` is a placeholder pulled from the nav and
redirected to `/generative-ui` on purpose (`next.config.ts` — `//
AI-slop placeholder pulled from nav until properly authored`). Linking
only the two specs that have live detail pages avoids sending readers to
a redirect. Open-JSON-UI is still described in the comparison table on
the page.
- Open Generative UI is a CopilotKit capability (not an external spec),
so it sits under "related capabilities."

> Note: the issue/support-bot suggested a `/learn/...` path — there is
no `/learn/` tree in shell-docs; the canonical homes are the flat
`/generative-ui/<spec>` pages.

### 2. CLI `init` vs. existing app (Closes #2525)
Maintainer resolution was "fix the docs." The original "`init`
bootstraps your existing Next.js app" claim was already removed in the
shell-docs migration (the reported `/direct-to-llm/guides/quickstart`
now resolves to the Built-in Agent quickstart, which is fully manual).
To remove the remaining ambiguity:
- **Built-in Agent quickstart:** added an "Already have an app?" callout
— existing apps skip `create-next-app`.
- **CLI guide (`cli.mdx`):** clarified that `create` (aliased `init`)
scaffolds a brand-new project in its own directory and does not
detect/bootstrap an existing app; points to the manual install in the
Quickstart.

Verified against `copilotkit@latest` (4.3.0): `init --help` →
*"Initialize a **new** CopilotKit project … before scaffolding"*, `-n,
--name` *"names the local app **and its directory**"*, and
`init`/`create` are aliases.

### 3. Codex setup for the MCP guide (Closes #2526)
Added a **Codex** section to `mcp-server-setup.mdx` using the stdio
`mcp-remote` bridge in `~/.codex/config.toml`, matching the page's
existing command-based pattern (Cursor / Windsurf / Claude Desktop),
plus the `codex mcp add` shortcut.

Verified against the installed Codex CLI: `codex mcp --help` lists
`add`/`list`/`get`/`remove`, and the `[mcp_servers.<name>]` table with
`command`/`args` matches OpenAI's Codex config reference. Per the issue
thread, the macOS `mcp-remote` port-blocking concern is **not** claimed
to be solved — only the Codex config is documented.

## Testing
- **#3975 (links):** curled every added/changed URL against the live
docs — A2UI, MCP Apps, Open Generative UI, and all 12 framework
quickstarts return **200**; confirmed `/generative-ui/open-json-ui` is a
deliberate redirect (hence unlinked). Pre-existing `/ag-ui-protocol` and
`/generative-ui` links are stable 301→200 and left as-is.
- **#2525 (CLI):** ran `npx copilotkit@latest init --help` on the
published `latest` (4.3.0) — confirmed new-directory scaffolding, no
existing-app detection; verified `[Quickstart](/quickstart)` serves the
manual-install page live (`create-next-app` + "Install CopilotKit
packages").
- **#2526 (Codex):** ran `codex mcp --help` to confirm subcommands; new
section reuses the file's existing `<Steps>`/fenced-code structure.
`<Callout>` is a registered global MDX component
(`src/lib/mdx-registry.tsx`), already used unimported on the Built-in
Agent quickstart.
- Docs-only; no code paths affected.

Closes #3975
Closes #2525
Closes #2526

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-20 15:10:16 -07:00
Jordan Ritter 077913e5b4 feat(showcase): scheduled staging reconcile with Slack self-heal
Adds a CI-owned reconcile (every 15m) that compares each staging service's
deployed digest against GHCR :latest and re-runs the staging redeploy for
lagging services, alerting Slack. The run is green only when every in-scope
service is confirmed current; any unconfirmed service (lag, digest error,
dropped redeploy, empty scope, or a thrown redeploy) alerts and exits non-zero.
Exposes per-service redeploy records from redeploy-env for accurate per-service
remediation confirmation.
2026-07-20 15:08:35 -07:00
Jordan Ritter b34debc02b feat(showcase): add autoUpdates drift gate against live Railway config
New CI gate fails when a live Railway service's autoUpdates diverges from the
SSOT (every service must be disabled). Reads Environment.config (autoUpdates is
not on the typed ServiceSource output), fails closed per-env when it verifies
zero services, and skips cleanly on fork PRs that lack a Railway token.
2026-07-20 15:08:34 -07:00
Jordan Ritter 2ecba43d2f feat(showcase): track autoUpdates in SSOT, disabled fleet-wide
autoUpdates was tracked nowhere and had drifted (24 services minor / 17 none).
Add an explicit disabled autoUpdates policy to every service in railway-envs.ts
and regenerate railway-envs.generated.json, making CI-explicit redeploy the
single deploy path instead of Railway's registry auto-watch.
2026-07-20 15:08:34 -07:00
Jordan Ritter 2d6883568e fix(showcase): don't skip staging redeploy when a build leg is cancelled
The redeploy-staging and redeploy-staging-starters jobs guarded on
needs.build.result != 'cancelled', so a single cancelled matrix leg (e.g. the
Git-LFS shell build under runner contention) skipped the whole fleet's staging
redeploy even when the other 27 services built fine. Relax both guards to
redeploy the already-computed successful-service list. Adds a guard-evaluation
test that reads the live workflow if: strings and models GitHub's matrix rollup.
2026-07-20 15:08:34 -07:00
Jordan Ritter cae8e78ac8 fix(showcase): gate D4 chat probe completion on domDone to close empty-response render race
readTurnComplete() gated turn completion on `domDone || sseDone`. sseDone (the
transport-level RUN_FINISHED counter) is a synchronous raw-byte parse OUTSIDE
React and can fire at-or-before the React commit that renders the assistant
text; domDone is coalesced into that SAME commit (use-agent.tsx
batchedForceUpdate / queueMicrotask). Gating on sseDone let the fast-fail grace
window elapse with the DOM still empty under contention, redding a turn that was
about to render correctly ("empty assistant response").

Gate completion on domDone alone. observed still includes sseDone, so a turn
whose attribute never appears still gets the wider polling window. Throughput-
neutral: runAttempt returns on non-empty readAssistantText before
readTurnComplete is consulted, so the happy path is unchanged; a genuinely-empty
completed turn still reds.
2026-07-20 15:03:53 -07:00
Jordan Ritter 45898bd1b6 test(showcase): pin D4 chat probe sseDone-leads/domDone-lags render race
Add a deterministic timing-sim regression for the D4 chat-roundtrip probe
render race. The sseLeadMs fixture decouples the transport RUN_FINISHED
counter (sseDone) from the DOM run-stop edge (domDone) in time, so a turn
whose sseDone fires early while domDone + assistant-text land later in the
same React commit is exercised on the real readTurnComplete/runAttempt path.

Two cases: a TIMING SIM (sseDone at send, text at 2500ms past the grace
window) that reds pre-fix, and a FORMULA PIN (sseDone-only, token never
arrives) asserting sends===2, catching a literal revert to domDone||sseDone
via the retry-fired discriminator rather than a wall-clock threshold.
2026-07-20 15:03:53 -07:00
Benjamin Taylor 7869d31e64 docs: drop unpublished Open-JSON-UI link, move Open Generative UI to related
CR: /generative-ui/open-json-ui is a deliberately-unpublished placeholder
(next.config.ts redirects it to /generative-ui, pulled from nav until
authored), so link only the two specs with live detail pages (A2UI, MCP
Apps). Open Generative UI is a CopilotKit capability rather than an
external spec, so it moves under related capabilities.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 16:16:15 -05:00
Benjamin Taylor c9511cf4f9 docs: fix stale quickstart/link references and add MCP Codex setup
Fixes three independent documentation-accuracy issues:

- #3975: repoint the retired /generative-ui/specs/<spec> links to the
  canonical flat /generative-ui/<spec> paths, add an Open Generative UI
  entry, and add a Supported Frameworks list on the Generative UI Spec
  Support page.
- #2525: clarify that the CLI `create`/`init` scaffolds a brand-new
  project in its own directory and does not bootstrap an existing app;
  point existing-app users to manual installation.
- #2526: add a Codex setup section to the MCP server guide using the
  stdio `mcp-remote` bridge, matching the page's existing pattern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 16:03:16 -05:00
Jordan Ritter 305cfd494b feat(showcase): add outcome reaction to promote-notify init Slack message
Add an emoji reaction to the original promote-notify init message
reflecting the net run outcome, so operators can see success/failure at
a glance without opening the thread reply:

  success -> white_check_mark (checkmark)
  partial -> warning
  total   -> x

The live workflow calls reactions.add on the init post (guarded on a
successful init post, warn-only on failure to mirror the thread reply).
The dry-run harness emits the reaction it would add, using a
byte-identical case mapping enforced by a new anti-drift bats guard.
Adds bats coverage asserting the emitted reaction name per fixture.
2026-07-20 13:38:50 -07:00
Jordan Ritter 999264f648 chore: bump aimock to 1.37.4 (multi-turn fixture matching fix) (#6071)
Bumps the showcase's `@copilotkit/aimock` dependency from `1.26.1` to
**`1.37.4`** so the showcase's record/replay fixture stack picks up the
multi-turn fixture-matching fix.

**Why:** aimock v1.37.4 (aimock #319) fixes record/replay
`hasToolResult` symmetry — recorded multi-turn fixtures now match on
replay. The showcase records/replays LLM fixtures for its demo cells, so
this pulls the fix into the showcase.

**What changed**
- `showcase/scripts/package.json`: `@copilotkit/aimock` `1.26.1` →
`1.37.4` (exact pin, matching existing style)
- `showcase/scripts/package-lock.json`: regenerated via `npm install
--package-lock-only` (this lock is consumed by `npm ci` in the
shell/shell-docs/shell-dashboard Dockerfiles)
- `pnpm-lock.yaml`: regenerated via `pnpm install --lockfile-only`
(showcase/scripts is a pnpm workspace member)

The only version change is aimock (and its transitive tree in the npm
lock). The minor eslint-config-next peer-resolution relabeling in
`pnpm-lock.yaml` is benign normalization — no package version changes;
both jiti variants already existed in the lock.

**Validation gap:** this is a dependency bump only. Full validation
(running the showcase multi-turn recording against 1.37.4 to confirm the
recorded fixtures match on replay) requires the running showcase stack
and is not exercised here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-20 12:59:06 -07:00
Jordan Ritter 107a17e493 fix(showcase): wire langroid declarative-gen-ui via Option A (JS-injected A2UI) (#6070)
## Summary

Supersedes #6058's two-stage approach (outer `generate_a2ui` → secondary
Python LLM call → `render_a2ui`), which severed across the prod
streaming boundary.

**Option A** (mirroring crewai-crews #6067): `injectA2UITool` defaults
to `true`, so CopilotKit's `A2UIMiddleware` injects `render_a2ui` into
`RunAgentInput.tools`. The langroid `agui_adapter.py` now merges those
injected tools into its OpenAI call, so the LLM calls `render_a2ui`
directly. The middleware intercepts the tool call stream, builds
`a2ui_operations`, and fires `RUN_FINISHED` — no secondary Python LLM
pass needed.

## Changes

- **`agent.py`**: Remove ~550 lines of two-stage A2UI infrastructure
(`generate_a2ui_via_llm`, `_a2ui_error`, `_resolve_a2ui_model`,
`_get_a2ui_llm`, `_RENDER_A2UI_FUNCTION_SPEC`, etc.). Replace
`GenerateA2UITool.handle` with a stub that logs loudly on regression
(middleware should always intercept before reaching Python).
- **`agui_adapter.py`**: Merge `run_input.tools` (AG-UI-injected) into
the OpenAI tools list so `render_a2ui` is visible to the LLM. Remove
`set_last_user_message` call (ContextVar no longer needed).
- **`route.ts`**: Remove `injectA2UITool: false`; keep
`defaultCatalogId` pin.
- **`gen-ui-declarative.json`**: Replace 9 two-stage fixtures with 4
single-stage fixtures matching `toolName: render_a2ui` + `context:
langroid`.

## Root cause of prior RED

The langroid adapter builds its OpenAI tool list from `ALL_TOOLS`
(Python-side registry) via `_get_openai_tools()`, which does NOT include
`render_a2ui`. The `A2UIMiddleware` injects `render_a2ui` into
`RunAgentInput.tools` at the AG-UI protocol level, but `agui_adapter.py`
ignored `run_input.tools` entirely — so the LLM never saw `render_a2ui`
in its tool list, never called it, and the fixture never matched.

## Red-green proof

**RED** (from main, before changes):
```
✗ d6:langroid/gen-ui-declarative  red  (0.0s)
  state=red
0 passed, 1 failed
```

**GREEN** (after this PR's changes, rebuild from worktree):
```
✓ d6:langroid/gen-ui-declarative  green  (0.0s)
1 passed
✓ Tests passed for langroid:declarative-gen-ui
```

Test command: `bin/showcase test langroid:declarative-gen-ui --d6
--isolate --rebuild`

## Related

- Supersedes #6058 (two-stage approach, now reverted in this
integration)
- Mirrors #6067 (crewai-crews Option A fix, same pattern)
2026-07-20 12:25:40 -07:00
Jordan Ritter 683ce92c5b chore: bump aimock to 1.37.4 (multi-turn fixture matching fix) 2026-07-20 12:18:13 -07:00
Jordan Ritter 1196c7b637 test(showcase): align langroid test_generate_a2ui with Option A (JS-injected A2UI)
Option A removed the two-stage server-side A2UI planner
(generate_a2ui_via_llm, _get_a2ui_llm, _resolve_a2ui_model, _A2uiError,
_A2uiErrorKind, _RENDER_A2UI_FUNCTION_SPEC, _RENDER_A2UI_TOOL_SPEC,
_a2ui_error). The CopilotKit JS runtime A2UIMiddleware now intercepts
generate_a2ui before it reaches Python and drives the render_a2ui LLM
pass itself.

test_generate_a2ui.py was importing the removed symbols at collection
time, causing an ImportError that failed CI's "Run showcase package
Python unit tests" step for Python 3.12.

Fix: remove all tests for the deleted two-stage planner infra; rewrite
GenerateA2UITool.handle() tests to the Option A contract (handle fires
only on middleware regression, returns structured error JSON, logs
ERROR); retain all tests that remain valid: _ToolErrorKind enum identity,
backend tool handle() happy+error paths, create_agent wiring, module
hygiene (no openai at load time, clean subprocess import).
2026-07-20 12:16:12 -07:00