Commit Graph

3254 Commits

Author SHA1 Message Date
Jordan Ritter fd752ae1d8 fix(showcase): scope NODE_ENV=production to Next.js invocation only, not image-level ENV
M9: `ENV NODE_ENV=production` at the Dockerfile level propagates to every
process spawned by the entrypoint — including the Python agent. The
aimock toggle (aimock_toggle.py) refuses to apply when `NODE_ENV=production`
is set, so a Docker-based smoke test with `AIMOCK_URL` exported would
silently get a no-op toggle and hit real OpenAI instead of aimock.

Move `NODE_ENV=production` out of the global Dockerfile ENV blocks and
inline it on the `npx next start` invocation in entrypoint.sh. Next.js
still treats the server as production (that's all Next looks at), but the
Python sibling process is no longer subject to a production-guard that
only ever made sense for the JS runtime.

Affected: crewai-crews package Dockerfile + entrypoint.sh, plus the
starter template (Dockerfile.python + entrypoint.template.sh) — the
starter regen in a follow-up commit propagates this to all 17 starters.
2026-04-18 02:59:49 -07:00
Jordan Ritter fada8c9a76 refactor(showcase/crewai-crews): remove dead RELOAD/main() from agent_server.py
M7: Every execution path (package `pnpm dev`, starter `pnpm dev`, Docker
entrypoint, CI workflow) invokes `python -m uvicorn agent_server:app ...`
directly via CLI. The `main()` wrapper reading PORT/RELOAD from env was
dead code that:

- was never exercised by any CI path;
- defaulted PORT=8000 while starter dev scripts bound :8123 (drift);
- carried a RELOAD gate whose only purpose was to guard `reload=True`
  in a function that never ran.

Remove `main()` and the `if __name__ == "__main__"` dispatch entirely, plus
the now-unused `os` import. A comment at the bottom of the module documents
why no CLI entrypoint lives here so a future contributor doesn't add one
"for consistency" with other showcase packages.
2026-04-18 02:59:49 -07:00
Jordan Ritter d6658ebe8c fix(showcase/crewai-crews): prod-guard only fires when AIMOCK_URL is set; rename dummy key
M6: The prod-guard (`NODE_ENV=production` / `ENV=production` refuses to apply
the toggle) was entering its refusal branch even when AIMOCK_URL was unset
— returning a misleading `"aimock toggle refused"` reason when in fact
nothing was being applied. Move the `aimock_url` non-empty check BEFORE the
prod-guard block; the unset-URL path now falls through to the normal "not
configured" diagnostic, reserving the refusal message for actual refusals.

Regression pinned: `test_production_env_without_aimock_url_is_silent_no_op`
now asserts (a) no WARNING is logged, (b) reason text does not contain
"refused", and (c) neither OPENAI_BASE_URL nor LITELLM_API_BASE is mutated.

LOW: Rename `_AIMOCK_DUMMY_KEY` from `"sk-aimock-DO-NOT-SET-AIMOCK-URL-IN-PROD"`
to `"sk-aimock-dev-ci-only"`. The old name embedded a directive aimed at
operators but the value is never user-provided — the toggle itself injects
it when AIMOCK_URL is set and the prod-guard refuses production anyway.
Short, honest, still satisfies SDK versions that validate `sk-` prefix.
Test `test_dummy_key_does_not_mislead_with_replace_in_prod_suffix` extended
to also reject the old "DO-NOT-SET" directive.

LOW: Pin `LITELLM_API_BASE not in env` in
`test_production_env_refuses_toggle_even_with_aimock_url` so a future
regression that mutates LITELLM_API_BASE in the refusal branch (symmetric
with the existing OPENAI_BASE_URL check) fails the test.
2026-04-18 02:59:48 -07:00
Jordan Ritter 4fab2d9ff8 fix(showcase/langgraph-fastapi): point AGENT_URL at :8123 to match dev script
The package's own `pnpm dev` script binds langgraph_cli on port 8123
(via package.json "dev"), but the .env.example documented port 8000.
A contributor running `cp .env.example .env && pnpm dev` would hit
ECONNREFUSED out of the box because nothing binds :8000 in this package.

Generated starters (showcase/starters/langgraph-fastapi/.env.example)
already point at :8123; this aligns the package-side .env.example with
both its own dev script and the scaffolded starter output.
2026-04-18 02:59:47 -07:00
Jordan Ritter 76f0c13c85 feat(showcase/starters): regen with aimock + .env propagation
Regenerated from showcase/scripts/generate-starters.ts with the updated
propagation rules. Every starter whose package ships .env.example now carries
one (port-rewritten to :8123 where AGENT_URL points at localhost), and the
crewai-crews starter additionally carries aimock_toggle.py alongside the
agent_server.

OPENAI_API_KEY placeholder text in every package + starter .env.example now
reads 'replace-with-your-key' (not a fake sk-... value), so users who skip
editing get a loud 401 from real OpenAI instead of a silent aimock success
masking misconfig.
2026-04-18 02:12:08 -07:00
Jordan Ritter e308c52782 feat(showcase/scripts): propagate aimock + .env.example to starters
Extends generate-starters.ts so every starter whose package ships .env.example
gets the file copied through (not just non-langgraph Python), and ships the
aimock_toggle.py alongside agent_server.py for any Python package that has one.
The .env.example copy rewrites AGENT_URL=http://(localhost|127.0.0.1):8000 to
:8123 during propagation because starter dev scripts bind the agent on 8123
while package dev scripts bind on 8000.

The port-rewrite regex is now exported as AGENT_URL_LOCALHOST_8000_RE and
imported by the starter-consistency test, so the two sides cannot drift.
Previously the test used a broader [^:\/]+ host pattern while the generator
correctly narrowed to localhost/127.0.0.1 — a future package documenting
AGENT_URL=https://api.corp.example:8000 would have tripped the test while the
generator correctly preserved the non-localhost hostname.
2026-04-18 02:12:07 -07:00
Jordan Ritter 8f5c2ca99b feat(showcase/crewai-crews): aimock toggle via AIMOCK_URL env for dev/CI
Adds an env-controlled aimock toggle for the CrewAI Python agent so dev/CI
traffic can be redirected to a local aimock server while production (AIMOCK_URL
unset) is unchanged. When AIMOCK_URL is set, the toggle populates
OPENAI_BASE_URL + LITELLM_API_BASE and injects a dummy OPENAI_API_KEY if one
isn't already set.

- aimock_toggle.py: configure_aimock() with production-env guard — NODE_ENV /
  ENV set to prod/production refuses to apply the toggle (fail-safe WARNING)
  so a misconfigured deploy can't silently redirect real traffic through a
  mock. Dummy key renamed 'sk-aimock-DO-NOT-SET-AIMOCK-URL-IN-PROD' (was
  'sk-aimock-dev-only-REPLACE-IN-PROD' — the old name implied operators
  should substitute, but the value is never user-facing). Override warning
  now symmetric across OPENAI_BASE_URL and LITELLM_API_BASE (both are
  overwritten; both must report overrides).

- agent_server.py: uvicorn reload flag gated on RELOAD env (defaults false)
  so 'python agent_server.py' in prod doesn't spawn the reloader.

- requirements.txt: typing_extensions>=4.6; python_version < "3.11" so the
  NotRequired fallback only installs on older Pythons.

- Dockerfile: updated COPY comment to match reality (two COPY lines, not
  three — agents/ is kept separate because it churns independently).

- pytest.ini + conftest.py cleanup: src/ now on the import path via
  pythonpath= declarative config (pytest 7+), removing the sys.path.insert
  mutation that leaked past test collection.

- 55 pytest cases (was 38), including red-green proofs for: prod-env guard,
  LITELLM override warning, dummy-key rename, whitespace-wrapped falsy
  USE_AIMOCK values, and the typing_extensions fallback import path.
2026-04-18 02:12:07 -07:00
Jordan Ritter bc35c2e8ad feat(showcase): validation tooling suite (Bundle 3 consolidation) (#4018)
## Showcase validation tooling (Bundle 3)

Ships three CLI validators, a shared parsing lib, and two CI workflows
that enforce consistency across the 17 showcase packages and detect
drift before it lands on main. Consolidates four earlier tooling PRs
(#3985, #3987, #3995, #3996).

## What's in the box

### `showcase/scripts/` — three validators

| Tool | Purpose | Exit codes |
|------|---------|-----------|
| `audit.ts` | Cross-checks manifest-declared demos against
`tests/e2e/*.spec.ts` and `qa/*.md`, plus `examples/integrations/`
provenance via `SLUG_TO_EXAMPLES` / `FALLBACK_MAP` | 0 ok, 1 anomalies,
2 invalid-input, 3 unreadable, 4 internal, 5 strict-warnings |
| `validate-pins.ts` | Framework-dep pin-drift between
`showcase/packages/*/` and their dojo `examples/integrations/*/`
counterparts. Parses package.json, requirements.txt, pyproject.toml
(Poetry + PEP 621) | 0 ok, 1 drift, 2 internal, 3 unreadable |
| `validate-parity.ts` | Enforces demo ↔ spec ↔ qa coverage per package
with a monotonic demo-count floor | 0 ok, 1 warnings, 2 invalid-input, 3
unreadable, 4 internal, 5 must-failure |

### `showcase/scripts/lib/` — shared primitives

- **`slug-map.ts`** — single-source-of-truth `ENTRIES` for the showcase
slug taxonomy;
`BORN_IN_SHOWCASE`/`SLUG_MAP`/`SLUG_TO_EXAMPLES`/`FALLBACK_MAP` derived
and frozen at module load. `SlugEntry` is a discriminated union that
makes illegal states (born-in-showcase with non-empty examples)
unrepresentable. `freezeSet`/`freezeMap` helpers install throwing
replacements via `Object.defineProperty({writable:false,
configurable:false})` so `Set.add` / `Map.set` truly fail at runtime.
- **`manifest.ts`** — `parseManifest` returns a tagged `ParsedManifest`
union (`ok` | `missing` | `malformed{subkind: "syntax"|"shape"}` |
`unreadable`) with a never-throws content contract. Uses `statSync` +
errno inspection (not `existsSync`, which conflates ENOENT with EACCES).
`DemoId` is a branded string minted only via `createDemoId`.

### `.github/workflows/` — CI enforcement

- **`showcase_validate.yml`** — runs on PR and push-to-main. Enforces
the e2e-spec floor, runs the validators, and drives the pin-drift
ratchet.
- **`showcase_drift-report.yml`** — weekly Monday 10:00 UTC +
workflow_dispatch. Computes `set_status` (OK / SET DRIFTED / COUNT
DRIFTED) and posts to Slack.

Both workflows run on `depot-ubuntu-24.04-4` (Startup plan, unlimited)
for persistent pnpm/npm cache across runs.

## The pin-drift ratchet

`validate-pins.ts` currently finds **111 existing pin-drift failures**
across 12 showcase packages. Rather than block the PR on those, we
baseline them in `showcase/scripts/fail-baseline.json` and ratchet:

- `validatePinsFailCount` must not increase; CI tells you to ratchet
down when it decreases.
- `validatePinsFailHash` is SHA-256 of the sorted-uniqued `[FAIL]` set.
When the count is equal but the hash differs, a fail healed AND a new
one regressed — CI prints the diff and fails.
- `baselineDemoCount` (9) is the single source of truth for the e2e-spec
floor; consumed by both the workflow and `validate-parity.ts` with sync
enforced by a dedicated regression test.

Tracked in #4047. The 111 failures are mostly showcase packages pinning
`@copilotkit/*` to the `next` dist-tag while dojo pins concrete
versions; direction of fix (align showcase → dojo vs. bump dojo →
showcase) is a separate versioning decision outside this PR.

## Correctness posture

- **977 tests**, 13 files, covering every `Anomaly` / `PackageIssue` /
`ParsedManifest` variant in-process and via subprocess CLI for every
exit code. EACCES/ENOTDIR/TOCTOU paths are exercised via chmod probes
(with `it.skipIf` fallback when CI runs as root) and path-filtered
`vi.spyOn` fall-throughs.
- **`fs.statSync` + errno everywhere** — `fs.existsSync` silently
collapses ENOENT with EACCES and is a known anti-pattern in validation
tooling; the codebase uses structured errno discrimination throughout.
- **Tagged discriminated unions with exhaustive `switch` + `never`
guards** — `bucketFor` in `audit.ts`, `deriveMessage` in
`validate-parity.ts`. Adding a new variant without wiring every site is
a compile error.
- **Partial-report preservation** — when an infra error hits
mid-slug-loop, `UnreadableInputError.partialReport` carries
already-collected drift findings so the top-level catch prints them
before exiting 3. One bad package never orphans signal for the rest.
- **Per-slug isolation** — in `validate-parity.ts runParityImpl`, each
slug's audit is wrapped; a crash surfaces as a `crashed` `PackageIssue`
and forces `EXIT_INTERNAL` without aborting siblings.
- **Pipefail + scoped `|| true`** — every workflow step uses `set -euo
pipefail` with grep's no-match tolerance wrapped in `{ grep || true; }`
so producer failures (sort, shasum, cut) still surface.

## Diff

+16,455 / −18 across 34 files (26 source + 5 fixture trees + 2 workflows
+ 1 baseline).

Commits grouped by purpose:

1. `chore(showcase/scripts)`: vitest config + test deps
2. `feat(showcase/scripts)`: shared slug-map and manifest parsing lib
3. `feat(showcase/scripts)`: audit.ts coverage auditor
4. `feat(showcase/scripts)`: validate-pins.ts pin-drift validator
5. `feat(showcase/scripts)`: validate-parity.ts demo/spec/qa parity
validator
6. `ci(showcase)`: validation + weekly drift-report workflows (Depot
runners)

## Test plan

- [x] `pnpm vitest run` in `showcase/scripts/` — 977/977 green
- [x] Exit-code taxonomy verified end-to-end via subprocess tests for
every documented code
- [x] EACCES/ENOENT/ENOTDIR routing verified in all three validators
- [x] Partial-report preservation verified in both in-process and
subprocess paths
- [x] Per-slug crash isolation verified (one broken slug does not orphan
siblings)
- [x] Baseline sync contract (`BASELINE_DEMO_COUNT` ↔
`fail-baseline.json.baselineDemoCount`) pinned by test
- [ ] First CI run on Depot to confirm cold-cache timing (expected 5–8m
vs. 18–20m on ubuntu-latest)

Refs: [Full Action
Inventory](https://www.notion.so/3443aa38185281b5a1dfc6e0890264e1),
#4047
2026-04-17 23:07:14 -07:00
Jordan Ritter 5acbbcd633 feat(showcase/scripts): add validate-parity.ts demo/spec/qa parity validator
Audits each showcase package's manifest-declared demos for matching
spec (tests/e2e/*.spec.ts) and qa/*.md coverage, and enforces a
monotonic demo-count baseline via fail-baseline.json.

Key design:
- PackageIssue tagged union (13 variants) cleanly separates MUST
  errors from warnings; deriveMessage is the single renderer so new
  variants cannot emit mismatched prose.
- ProbeResult tagged union (missing | ok | unreadable) driven by
  statSync + errno inspection, distinguishing ENOENT from EACCES and
  surfacing ENOTDIR as a misconfiguration rather than a silent miss.
- runParityImpl isolates each slug's audit in try/catch; a crash in
  one slug surfaces as a crashed PackageIssue variant and forces
  EXIT_INTERNAL without aborting siblings.
- runParity never throws for content errors. InvalidBaselineError
  covers coerceBaseline failures; unknown errors route to
  EXIT_INTERNAL via formatErrorChain (walks .cause with cycle
  guard + depth cap).
- parseMainArgs rejects unrecognised flags and duplicate --baseline
  with EXIT_INVALID_INPUT (2), mirroring audit.ts parseArgs
  discipline.
- BASELINE_DEMO_COUNT default must match
  fail-baseline.json.baselineDemoCount; enforced by
  __tests__/baseline-sync.test.ts.
- Exit codes: 0 ok, 1 should-warnings-only, 2 invalid-input, 3
  unreadable, 4 internal, 5 must-failure.

Tests cover every PackageIssue variant, every exit code
(in-process + subprocess), per-slug crash isolation, EACCES routing,
ENOTDIR classification, cascade suppression when tests/e2e or qa
dirs are unreadable, and baseline coercion edge cases (leading
zeros, negative, float, hex, non-numeric).
2026-04-17 22:34:40 -07:00
Jordan Ritter cb0bf1c9b5 feat(showcase/scripts): add validate-pins.ts pin-drift validator
Compares framework dependency pins across showcase/packages/*/ and
the corresponding dojo examples/integrations/* trees, flagging drift
between the two and rejecting non-exact specs on the showcase side.

Key design:
- Parses package.json, requirements.txt, and pyproject.toml
  (including Poetry's [tool.poetry.dependencies] and PEP 621
  [project.dependencies] / optional-dependencies). Separate jsDeps
  and pythonDeps maps prevent cross-ecosystem name collisions.
- isExactSpec enforces exact-version pins per ecosystem (npm: no
  operators, workspace refs, or ranges; Python: ==X / ===X / ~=X
  with PEP 440 body). Symmetric rejection of bare MAJOR-only forms.
- parseRequirementsTxt and parsePyprojectToml thin wrappers throw
  when the detailed form produced skipped[] or dropped[] entries,
  preventing silent data loss in simpler callers.
- canonicalizeDepMap canonicalises names per PEP 503 and surfaces
  same-file collisions with differing specs as warnings.
- First-writer-wins at both file and package levels.
- UnreadableInputError carries an optional partialReport so an
  infra failure mid-slug-loop preserves already-collected drift
  findings for other slugs.
- Exit codes: 0 ok, 1 drift, 2 internal, 3 unreadable.

fail-baseline.json is the single source of truth for the CI ratchet
(validatePinsFailCount + validatePinsFailHash) and the demo-count
floor (baselineDemoCount, cross-checked against validate-parity.ts
in a dedicated sync test).

Test coverage spans every parser variant, EACCES routing via chmod
probe + fs spies, exit-code taxonomy subprocess tests, partial-report
preservation on mid-loop infra throws, and Poetry/PEP 503 edge cases
via committed fixture files under __tests__/fixtures/pins/.
2026-04-17 22:34:18 -07:00
Jordan Ritter bf603a6e4f feat(showcase/scripts): add audit.ts coverage auditor
Cross-checks each showcase package's manifest-declared demos against
the spec (tests/e2e/) and qa/ directory contents, plus
examples/integrations provenance via SLUG_TO_EXAMPLES / FALLBACK_MAP.

Key design:
- Discriminated Anomaly union with nine variants
  (count-mismatch, not-deployed, missing-examples, missing-manifest,
  malformed-manifest, unreadable-dir, unreadable-manifest,
  unreadable-examples, mapped-candidate-not-directory). bucketFor uses
  an exhaustive switch with a never guard so a new variant cannot
  silently escape routing.
- CountState tagged union separates known-count, legitimate-missing,
  and unreadable cases so an EACCES on tests/e2e/ cannot be
  misclassified as a real zero count.
- ExamplesSourceResult carries structured unreadableForSlug /
  nonDirectoryForSlug flags; classification never substring-matches
  the human-readable warning text.
- SHOWCASE_AUDIT_ROOT env var is validated with statSync + distinct
  error messages for ENOENT vs ENOTDIR vs EACCES.
- Text and --json output modes. Exit-code taxonomy: 0 ok, 1 anomalies,
  2 invalid-input, 3 unreadable, 4 internal, 5 strict-warnings.
- Deep-freezes AuditReport.packages and anomalies before return.

Tests cover every Anomaly variant, every exit code (in-process + CLI
subprocess), buildReport bucket exhaustiveness, EACCES routing via
path-filtered fs spies, TOCTOU ENOENT races, and the --columns filter
surface.
2026-04-17 22:33:58 -07:00
Jordan Ritter 4373629763 feat(showcase/scripts): add shared slug-map and manifest parsing lib
Two foundational modules consumed by all three validators:

- lib/slug-map.ts: single source of truth for the showcase slug
  taxonomy. ENTRIES array is the sole declaration; BORN_IN_SHOWCASE,
  SLUG_MAP, SLUG_TO_EXAMPLES, and FALLBACK_MAP are derived at module
  load and frozen via freezeSet/freezeMap/freezeMap2D helpers
  (defineProperty-based to block Set.add / Map.set at runtime).
  SlugEntry is a tagged union: born-in-showcase variants have empty
  examples and no fallback; non-born variants carry a non-empty
  tuple. Each slug passes isShowcaseSlug at module load.

- lib/manifest.ts: parseManifest returns a tagged ParsedManifest
  union (ok | missing | malformed | unreadable) with never-throws
  content contract. Uses statSync + errno inspection rather than
  existsSync to distinguish ENOENT from EACCES/ENOTDIR. DemoId is a
  branded string minted only through createDemoId. Empty-string
  dirSlug is rejected as a caller bug; undefined opts out of the
  slug-match check. Deep-freezes the returned Manifest.
2026-04-17 22:33:39 -07:00
Jordan Ritter 707cca1397 chore(showcase/scripts): add vitest config and test dependencies
Configure file-level isolation (fileParallelism: false) to prevent
cross-test env-var contamination when the three validators mutate
process.env.VALIDATE_PARITY_REPO_ROOT / VALIDATE_PINS_REPO_ROOT /
SHOWCASE_AUDIT_ROOT for fixture tmpdirs. Adds scripts test deps to
showcase/scripts/package.json.
2026-04-17 22:33:22 -07:00
Jordan Ritter 150bb151aa fix(showcase-docs): add TailoredContent component + harden upstream (#4056)
## Summary
Two showcase MDX files reference `<TailoredContent>` +
`<TailoredContentOption>` from
`@/components/react/tailored-content.tsx`, but the component file was
missing in showcase. This PR:

- Adds `showcase/shell/src/components/react/tailored-content.tsx`
(copied from upstream `docs/components/`)
- Inlines a tiny `cn()` helper to avoid pulling `classnames` into
showcase/shell deps
- Hardens BOTH copies (docs + showcase, kept byte-identical) against
real bugs found in CR review

## Bugs fixed in TailoredContent (both copies)
- **Build-breaker:** `useSearchParams()` in Next.js 14+ App Router
requires `<Suspense>` wrapper or `next build` fails. Added internal
Suspense wrapper so consumers don't need to add one.
- **State/URL desync:** `selectedIndex` was stored in useState
initialized once — back/forward nav didn't update. Now derived from
`searchParams` each render.
- **Keyboard a11y broken:** `role="tab"` + `tabIndex={0}` with no
keyboard handler. Added standard ARIA tab pattern: `role="tablist"`,
`role="tabpanel"`, Enter/Space to select, ArrowLeft/Right + Home/End to
navigate, roving tabindex.
- **`cloneElement` clobbered caller's icon className:** now merges via
`cn()`.
- **`TailoredContentOption` rendered `<div>` despite JSDoc saying "won't
render":** now returns `null`.
- **Unvalidated `defaultOptionIndex`:** clamped to `[0, options.length -
1]`.
- **Empty options silently produced broken UI:** now `return null`
(hooks-rules-safe; no throw mid-render).
- **Duplicate option IDs silently collided:** `console.warn` in dev mode
(via `useEffect`, not render body).
- **Hooks rules violation:** conditional hook ordering under state
changes (fixed by running all hooks unconditionally).
- **Side effects during render:** `console.warn` mutation moved to
`useEffect`.
- **`options`/`optionIds` unstable identities:** memoized via `useMemo`.

## Known remaining (non-blocking)
- The 2 copies of `tailored-content.tsx` must be kept in sync manually.
Proper fix is a shared package — out of scope for this PR.
- Stale `searchParams` race on rapid concurrent clicks across multiple
TailoredContent widgets on the same page (pre-existing upstream).
- `useMemo([children])` is ineffective since React.Children identity
changes per parent render (minor perf).

## Test plan
- [ ] CI green
- [ ] showcase-shell builds without Suspense errors
- [ ] Visit docs pages with `<TailoredContent>` — tabs render, keyboard
nav works, URL reflects selection
2026-04-17 22:29:43 -07:00
Jordan Ritter c8276ee923 feat(showcase): internal feature-matrix shell + canonical demo/code routes (#4039)
## Summary

Adds a new internal-facing showcase app — `showcase/shell-internal` —
that renders a **feature × integration grid**. Each cell links to one of
two new **canonical standalone routes** on the main `shell` app, or
shows a red ✗ when the feature isn't supported.

## What's new

### 1. Two canonical standalone routes in `showcase/shell`

These give every (integration × feature) pair a single, embeddable URL
for each artifact — useful for docs, marketing, and tooling.

- **`/integrations/[slug]/[demo]/preview`** — iframe-only hosted demo,
no chrome
- **`/integrations/[slug]/[demo]/code`** — code viewer only. Supports
URL params for future refinements:
  - `?file=<filename>` — which file tab to show
  - `?lines=10-20` or `?lines=10-20,35` — highlight specific line ranges

Example:
`/integrations/langgraph-python/agentic-chat/code?file=page.tsx&lines=15-22`

### 2. `showcase/shell-internal` — a new Next.js app on port 3002

- Single grid page: **rows = features**, **columns =
integrations/frameworks** (transpose of shell's existing `/matrix` page,
which has integrations as rows)
- Each cell has **two mini-links** — green `▶ demo` and blue `</> code`
— pointing at the canonical `shell` routes, or a red `✗` if not
supported
- Reads `showcase/shell/src/data/registry.json` directly via relative
import — single source of truth, no duplicate data
- `NEXT_PUBLIC_SHELL_URL` env var (default `http://localhost:3000`) to
point the cells at a deployed `shell` in non-local environments

### 3. Small fix: drop `--turbopack` from shell's dev script

`showcase/shell`'s Next.js 15.4.10 turbopack panics (`"Next.js package
not found"`) on this repo's multi-lockfile layout. Switching to webpack
dev resolves it; production builds (which don't use turbopack) are
unaffected.

## Why two apps instead of one

`shell-internal` could have hosted the demo and code pages itself, but
keeping them in `shell`:

- Makes the canonical URLs reusable outside internal ops (docs,
marketing, linking into product)
- Avoids duplicating the demo-rendering and code-viewer plumbing across
two apps

Internal shell stays a pure overview.

## Test plan

- [ ] `cd showcase/shell && npm run dev` — confirm shell starts on :3000
(webpack, no turbopack panic)
- [ ] `cd showcase/shell-internal && npm install && npm run dev` —
confirm shell-internal starts on :3002
- [ ] Open http://localhost:3002 — verify the feature × integration grid
renders
- [ ] Click a `▶ demo` cell — verify it opens
`http://localhost:3000/integrations/<slug>/<feature>/preview` with only
the iframe demo
- [ ] Click a `</> code` cell — verify it opens
`http://localhost:3000/integrations/<slug>/<feature>/code` with the code
viewer
- [ ] In the code route, try `?file=<name>` and `?lines=10-20` URL
params — verify file switches and lines highlight
- [ ] Verify red ✗ shows for unsupported (integration × feature)
combinations

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-17 19:18:59 -07:00
Martha Kelly Schumann e14b1cc487 docs-sync(needs-review): sync from main (3b8e457a1) [NEEDS REVIEW] (#4051)
⚠️ **Docs sync — MANUAL REVIEW REQUIRED**

This PR was auto-opened because the docs-sync script detected
showcase-local modifications overlapping with upstream changes.

The script attempted a best-effort 3-way merge:

- Where `git merge-file` produced a clean merge, the merged content was
written.
- Where `git merge-file` produced conflict markers, **upstream content
was written as-is** and showcase-local modifications were overridden.
**Manual review required.**

### Review items

```
Files where 3-way merge FAILED — upstream content written as-is, local modifications overridden. Manual review REQUIRED before merging this PR:
  - docs/content/docs/integrations/agent-spec/quickstart.mdx
  - docs/content/docs/integrations/aws-strands/generative-ui/state-rendering.mdx

Files auto-merged via 3-way merge (clean, no conflict markers — still worth a glance):
  - docs/content/docs/integrations/aws-strands/shared-state/in-app-agent-read.mdx
```

### Source

- Upstream ref:
[`3b8e457a1`](https://github.com/CopilotKit/CopilotKit/commit/3b8e457a1)
- Workflow run:
https://github.com/CopilotKit/CopilotKit/actions/runs/24593085026

**Review before merging.** Auto-merge is intentionally disabled
for `needs-review` PRs — confirm the upstream-wins sections
preserve any intentional showcase-local divergence you want to
keep, then merge manually.
2026-04-17 18:45:47 -07:00
claudebot ef78561281 Apply PR #3710 2026-04-17 18:36:05 -07:00
github-actions[bot] 930c10fb26 style: auto-fix formatting 2026-04-18 01:34:14 +00:00
Jordan Ritter 10c24ff1d7 fix(tailored-content): obey hooks rules, move warn to effect, memoize derived arrays 2026-04-17 18:32:12 -07:00
Jordan Ritter 62d775f6e7 fix(tailored-content): add Suspense wrapper, URL sync, keyboard a11y, className merge, bounds check 2026-04-17 18:32:12 -07:00
Jordan Ritter 562f47a954 fix(showcase-docs): add missing TailoredContent component referenced by MDX 2026-04-17 18:32:12 -07:00
claudebot c34c4232a9 Apply PR #3706 2026-04-17 18:29:46 -07:00
claudebot db99c684dc Apply PR #3757 2026-04-17 18:23:09 -07:00
Martha Kelly Schumann ee48a69055 docs(langgraph): document runAgent once via useEffect in configurable… (mirror of #3868) (#4052)
Mirror of #3868 by @Abubakar-01.

Wraps `agent.runAgent(...)` in a `useEffect` with an empty dependency
array in both the docs and showcase MDX files, and adds a prose warning
explaining why calling `runAgent` directly in the component body causes
"thread is already processing" errors.
2026-04-17 18:15:02 -07:00
Jordan Ritter 78a7f36447 docs(mastra): fix typo + resolve agent-app-context drift (#4048)
## Summary
Resolves the recurring `docs-sync` manual-review flag on
`integrations/mastra/agent-app-context.mdx` by applying the sync
script's clean-transform to bring the showcase copy in line with
upstream, plus a small typo fix.

- Typo: `useCopilotReadble` → `useCopilotReadable` (both files)
- Clean-transform sync: restores 2 code-block imports
(`useAgentContext`, `useState` — both actually used in the example on
lines 40 + 32), normalizes whitespace
- Bumps `showcase/shell/.docs-sync-sha` from `41b6eb93` to `0e7811402`

## Note
There is an existing auto-generated PR #4044 covering this same file
(plus 2 aws-strands files). Close that PR after merging this one; the
aws-strands files will be handled by a separate future sync run once the
updated workflow (see branch `ci/docs-sync-auto-pr`) is merged.

## Test plan
- [ ] CI green
- [ ] Post-merge: `npx tsx showcase/scripts/sync-docs-from-main.ts
--dry-run` no longer flags this file for review
2026-04-17 18:14:08 -07:00
claudebot d572c12f72 Apply PR #3868 2026-04-17 18:09:09 -07:00
Atai Barkai a5e962582b feat(showcase): consolidate gen-ui rows + plain-chat cleanup
Feature matrix (generative-ui category):
- Order: Controlled Gen-UI (Display) -> (Interactive) / In-Chat HITL
  -> (Interrupt) -> Declarative Generative UI (A2UI) -> MCP Apps
  -> Fully Open-Ended Generative UI -> Agentic Generative UI
  (In-Chat State Rendering) -> Tool Rendering.
- Merge `hitl-in-chat` with the Controlled Gen-UI (Interactive) idea;
  drop the unused `gen-ui-interactive` placeholder.
- Merge standalone `a2ui` entry into Declarative Generative UI (A2UI);
  drop the duplicate.
- Rename `gen-ui-agent` display to "Agentic Generative UI (In-Chat
  State Rendering)". Moved `tool-rendering` next to it.
- Rename `gen-ui-tool-based` display from "Controlled Generative UI"
  to "Controlled Gen-UI (Display)". Dropped the placeholder
  `gen-ui-display` entry (was zero-use).

Agentic chat demo (langgraph-python):
- Removed the "Weather in SF" suggestion and the associated
  `useRenderTool`/`get_weather` code. The slimmed agent has no backend
  tools, so this demo is now pure chat -- just `CopilotChat`, a user
  context tag, and one sonnet suggestion.

Regenerated registry + demo-content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 18:02:05 -07:00
Jordan Ritter e5c2023995 docs(mastra): fix title/prose hook references, null guards, highlight range, grammar 2026-04-17 18:00:32 -07:00
Jordan Ritter 804c5d0f19 docs(mastra): fix grammar, invalid model, missing imports, runtimeContext, type, highlight meta 2026-04-17 17:57:26 -07:00
copilotkit-devops-bot[bot] 727b20699b chore: docs sync from main — needs review (2026-04-18) 2026-04-18 00:57:13 +00:00
Atai Barkai f1cd005b2e chore(showcase): regenerate langgraph-python starter
Syncs the starter with the slimmed showcase package:
- Trimmed `src/agents/main.py` (create_agent + CopilotKitMiddleware,
  no backend tools).
- Removed `a2ui_dynamic_schema.py`, `a2ui_fixed_schema.py`,
  `todos.py`, `tool_wrappers.py`.

Generated via `npx tsx showcase/scripts/generate-starters.ts`.
`--check` passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:53:05 -07:00
Atai Barkai 7bec77a13a feat(showcase/langgraph-python): Controlled Gen UI with bar + pie charts
Rework the Controlled Generative UI demo to be minimal, self-contained,
and render charts via `useComponent`.

Frontend (`src/app/demos/gen-ui-tool-based/`):
- `page.tsx` -- `CopilotKit` + full-screen `CopilotChat` (no sidebar),
  two `useComponent` registrations (`render_bar_chart`,
  `render_pie_chart`), three chart-oriented suggestions.
- `bar-chart.tsx`, `pie-chart.tsx` -- ported from
  `examples/integrations/langgraph-python`. Each file reads top-to-
  bottom as imports -> schema -> props type -> component; colors and
  animation helpers are inlined inside the component. No shared
  chart-config module.
- Haiku card + schema removed.

Agent (`src/agents/main.py`):
- Rewritten using `create_agent` + `CopilotKitMiddleware()` so the
  LangGraph middleware injects the frontend `render_*_chart` tools into
  the model request at runtime.
- Deleted all backend-tool modules (`tools.py`, `todos.py`,
  `a2ui_dynamic_schema.py`, `a2ui_fixed_schema.py`). System prompt
  trimmed to a data-viz assistant.

Peripheral cleanups:
- `demos/agentic-chat/page.tsx` -- `change_background` tool + its
  suggestion removed; it had nothing to do with chat.
- New `demos/frontend-tools/` (In-App Actions) hosts
  `change_background` as its own demo with a `frontend_tools` agent
  name registered in `api/copilotkit/route.ts`.
- Stub `gen-ui-tool-based/agent.py` removed.
- `generate-starters.test.ts` no longer requires every python package
  to have backend tool imports -- a package with only frontend tools
  (like this controlled-gen-ui demo) is now valid.
- Whitelist generated shell data (`demo-content.json`,
  `search-index.json`, `starter-content.json`) in check-binaries hook
  -- they're generated artifacts like `package-lock.json`.
- Regenerated `demo-content.json` + `registry.json`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:40:04 -07:00
Atai Barkai 4e37b503cd refactor(showcase/shell-internal): light-mode grid + internal sort order
Grid polish:
- Light-mode palette (white surface, slate borders, dark text); dropped
  the dark-theme tokens.
- Rows are every declared feature, even ones with zero current support.
  Empty rows surface feature gaps we want to fill -- hiding them hides
  the TODO.
- Cells: `demo · code` as tight blue text links, `-` for supported but
  no demo, red `✗` for unsupported. No colored pill buttons.
- Sticky first column + sticky header row. Hover highlight replaces
  striped rows.

Internal sort order:
- New `src/lib/sort-order.ts` -- slug -> rank map used only by this app
  (intentionally not in the public registry). Orders columns LangChain
  first, then Google/MS/AWS, then the rest. Explicitly internal.
- `getIntegrations()` in lib/registry.ts sorts by this map with a
  fallback to the registry's `sort_order`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:38:04 -07:00
Atai Barkai 099c105272 feat(showcase): Docker-based local dev for Railway parity
Adds a single command to spin up the exact image Railway deploys,
for any of the 17 showcase packages, with a single shared .env:

  ./showcase/scripts/dev-local.sh up [<slug> ...]   # all if empty
  ./showcase/scripts/dev-local.sh down|build|logs|ps|ports

Pieces:
- `docker-compose.local.yml` with a service per package. Ports come
  from `shared/local-ports.json` (langgraph-python -> 3100, ...).
- `.env.example` as a commit-safe template. Real `.env` is gitignored
  and fed to every container via `env_file`, so keys (OPENAI_API_KEY,
  etc.) live in one place.
- `dev-local.sh` wraps `docker compose` and handles the
  `shared_python/` / `shared_typescript/` staging step that CI does
  before `docker build` (see showcase_deploy.yml).
- Staged `shared_*` dirs added to .gitignore.

Shell wiring:
- `shell/next.config.ts` reads `shared/local-ports.json` when
  `SHOWCASE_LOCAL=1` is set and injects it as a public env.
- `/integrations/[slug]/[demo]/preview` uses that map to iframe
  `http://localhost:<port>` instead of `integration.backend_url`.
  Per-slug; any slug not running locally falls back to Railway.
  Unset SHOWCASE_LOCAL -> prod behavior, unchanged.

Full workflow + prerequisites (Colima / Docker Desktop) documented in
showcase/README.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:37:37 -07:00
Atai Barkai 14537d8f3b feat(showcase): reorganize feature matrix + auto-rebundle demo content
Feature registry reorganization:
- Move `tool-rendering` to generative-ui (was agent-capabilities);
  move `interactivity` category above `agent-state`.
- Split `hitl` into `hitl-in-chat` (generative-ui) + `hitl-in-app`
  (interactivity). All 17 manifests updated: feature + demo id renamed
  `hitl` -> `hitl-in-chat`; demo routes stay `/demos/hitl` so deployed
  backends are unaffected.
- Rename `Tool-Based Generative UI` -> `Controlled Generative UI`;
  drop duplicate `controlled-gen-ui` registry entry.
- Add generative-ui rows: `declarative-gen-ui`, `open-gen-ui`,
  `a2ui` (moved from a2ui category), `mcp-apps` (moved from platform).
- Rename `Frontend Tools` -> `Frontend Tools (In-app actions)`.
- Add `frontend-tools` feature to langgraph-python manifest + register
  `frontend_tools` agent name in api/copilotkit/route.ts (noise-free
  `change_background` demo split out from agentic-chat).

Bundle script improvements:
- `bundle-demo-content.ts`: resolve demo directory from `demo.route`
  instead of `demo.id`. Decouples feature id renames from on-disk
  directory names.
- `--watch` mode using native `fs.watch` over `packages/` with a
  debounced re-bundle on edits under demos/, agents/, agent/, mastra/,
  or README.md.
- `shell/package.json` dev script runs the bundler in watch mode
  alongside `next dev` via `npx concurrently -k`.

Tests updated for the rename and new counts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:36:00 -07:00
Jordan Ritter a7fcd2da59 fix(docs-sync): emit review_items_file output, fix auto_push fast path, tighten gates 2026-04-17 17:28:20 -07:00
Jordan Ritter ae5fc2cc0f fix(docs-sync): manifest path, add-order, exit-code, marker, stripTrailingEol, dead search 2026-04-17 17:28:20 -07:00
Jordan Ritter 157cf7d4a0 fix(docs-sync): harden shell injection, add needs-review Slack, fix silent re-resolution + PR collision 2026-04-17 17:28:20 -07:00
Jordan Ritter 5bb7c19cab ci(docs-sync): auto-open PR instead of warn-and-skip on conflict 2026-04-17 17:28:20 -07:00
Jordan Ritter 4c8438e250 docs(mastra): fix useCopilotReadable typo in prose 2026-04-17 17:17:37 -07:00
Jordan Ritter feb81527f3 docs(mastra): resolve agent-app-context drift via clean-transform of main (bumps sync sha) 2026-04-17 16:50:25 -07:00
Jordan Ritter 88a0a6e594 fix(showcase-scripts): keep /ok probe for langgraph starters in generator
langgraph-python, langgraph-fastapi, and langgraph-typescript starters run
langgraph_cli dev which exposes /ok (not /health). The template now probes
/health, so the generator must rewrite this back to /ok for langgraph-* only,
otherwise drift-check fails and regenerating would break those starters'
health routes.
2026-04-17 16:29:14 -07:00
Jordan Ritter f2152f514c fix(showcase-starters): copilotkit route health probes hit /health not /ok (+ mastra /api/health) 2026-04-17 16:22:48 -07:00
Jordan Ritter 2a5632a573 fix(showcase-starters): health probe hits /health not /ok (matches agent server route) 2026-04-17 16:22:48 -07:00
claudebot fc43033efd Apply PR #3866 2026-04-17 14:51:20 -07:00
Atai Barkai 2b3b4d71ad fix(showcase): drop --turbopack from shell dev script
Next.js 15.4.10's turbopack panics ("Next.js package not found") on the
repo's multi-lockfile layout. Webpack dev works; production builds are
unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:43:21 -07:00
Atai Barkai b99963ccc7 feat(showcase): add internal feature-matrix shell with canonical demo/code routes
Introduces a new internal-facing showcase app (`showcase/shell-internal`)
that renders a feature × integration grid. Each cell links to one of two
new canonical standalone routes on the main `shell` app:

- `/integrations/[slug]/[demo]/preview` — iframe-only hosted demo
- `/integrations/[slug]/[demo]/code` — code viewer; supports `?file=<name>`
  and `?lines=<start>-<end>` URL params for future line-highlighting

Keeping the canonical pages in `shell` means they can also be embedded in
docs/marketing; `shell-internal` is a pure overview with no duplicated
content (reads `shell/src/data/registry.json` directly).

Also drops `--turbopack` from `shell`'s dev script: Next.js 15.4.10's
turbopack panics on the repo's multi-lockfile layout. Webpack dev works
fine and this doesn't affect production builds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:41:37 -07:00
Jordan Ritter 5c42907a1f fix(showcase-tests): read top-level integration.deployed in smoke filter (starter.deployed was manual generator patch) 2026-04-16 18:35:59 -07:00
Jordan Ritter 27f886e59c fix(showcase): complete open-gen-ui scrub — 5→4 count, schema enum, fixture, full regen 2026-04-16 18:30:02 -07:00
Jordan Ritter 2b996c54d0 fix(showcase): scrub open-gen-ui from constraints.yaml and regen derived JSONs 2026-04-16 18:16:55 -07:00