Commit Graph

6618 Commits

Author SHA1 Message Date
Jordan Ritter e1e163886b ci(showcase): emit red→green transition alerts for deploy + smoke workflows
Teams get pinged on every failure but never see a positive recovery
signal when these workflows flip back to passing. Mirror the per-service
transition pattern already implemented in showcase_smoke-monitor.yml.

showcase_deploy.yml (notify job):
  - Restore previous run's status from actions/cache (key pattern
    matches smoke-monitor: prefix-based restore-keys + run_id save key)
  - Classify outcome as failure | success | skip
  - failure → post existing red alert + update state
  - success AND prev=failure → post recovery + clear state
  - success AND prev=ok → silent (green→green, matches prior behavior)
  - skip (no-changes or cancellation) → no state change, no post

starter_deployed_smoke.yml:
  - Restore state before tests run
  - After test step, classify via steps.playwright.outcome
  - On red→green, post recovery message alongside existing failure path
  - On any terminal outcome, save new state to cache

First-ever run (or cache miss): state initializes to ok so we don't
emit a false recovery on the first green run after this ships.

Recovery wording:
  ✅ *Showcase deploy*: recovered (was down since <iso8601>)
  ✅ *Starter Deployed Smoke Tests*: recovered (was down since <iso8601>)

Existing red-alert wording is unchanged.
2026-04-19 14:37:38 -07:00
Atai Barkai 9733146552 fix(showcase/shell): redirect /<framework>/unselected/<path> → /<framework>/<path>
A framework-scoped URL asserting "unselected" in its path is
incoherent — you can't be both on langgraph-python AND in the
no-framework state. Collapse the redundant segment: if the framework
catch-all receives a slug that starts with unselected/, permanent-
redirect to the same path without that prefix (the framework-scoped
version serves the same content, just with Snippets resolved against
the selected framework's cells).

/docs/unselected/<path> remains a valid framework-agnostic URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:32:28 -07:00
Atai Barkai 6751bce773 refactor(showcase/shell): rename docs/built-in-agent → docs/unselected
The /built-in-agent/<page> URL prefix in 4085's docs was a holdover from
an early misnomer in the original 4084 work. 4084 has since renamed the
content directory to unselected/ to reflect what the route actually is:
the no-framework / "no agentic backend selected" docs view. "Built-in
Agent" is reserved for an upcoming integration COLUMN in the showcase
matrix and shouldn't share a name with this docs route.

- Rename content/docs/built-in-agent/ → content/docs/unselected/
- Update docs-render.tsx subpath fallback (built-in-agent/ → unselected/)
- Update seo-redirects.ts wildcards
- Update internal MDX link references in learn/, backend/, faq.mdx,
  meta.json, snippets/shared/

The integrations/built-in-agent/ legacy directory is preserved
unchanged (it's a separate concept).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:29:42 -07:00
Atai Barkai 66c917b592 docs(showcase/shell): merge 4084 code examples into prebuilt-components
The built-in-agent tree exists only in 4085, but 4084's top-level
prebuilt-components.mdx had richer content (per-variant code examples
for CopilotChat/Sidebar/Popup with labels, customization block with
slot props, Setup section). Merge those into the 4085 page while
keeping its modern Snippet-based provider-setup + suggestions pulls
from the live cell.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:16:33 -07:00
Atai Barkai d40907e050 chore(showcase): regenerate demo-content bundle after region additions
Bundler picks up the new region markers plus the extended manifest
highlights — each of the 7 affected docs pages (subagents,
shared-state-streaming, open-generative-ui, mcp-apps, a2ui dynamic and
built-in) now resolves its <Snippet> tags to a real region.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:15:54 -07:00
Atai Barkai bbf0b4888a feat(showcase/langgraph-python): add region markers for docs snippets
Wraps unified-runtime config blocks with @region[runtime-inject-tool],
@region[minimal-runtime-flag], and @region[advanced-runtime-config] so
the A2UI dynamic-schema, open-generative-ui, and built-in a2ui docs pages
resolve their <Snippet> tags.

Also extends manifest highlights for subagents, shared-state-streaming,
declarative-gen-ui, mcp-apps, open-gen-ui, and open-gen-ui-advanced so
the bundler scans the agent + route.ts files holding these regions.
Subagents and shared-state-streaming highlights previously pointed at
src/agents/main.py even though the graph lives in dedicated files,
hiding the subagent-setup, supervisor-delegation-tools, and
state-streaming-middleware regions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:14:25 -07:00
Atai Barkai 6a01eadcb3 chore(showcase/shell-internal): wire probe-docs into predev+build
Matches 4084's script topology so docs-status.json and the demo-content
bundle refresh automatically on every dev start and build. Previously
required manual invocation of the scripts after the docs-links pipeline
port.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:11:27 -07:00
Atai Barkai feb0882cf8 chore(showcase): regenerate registry + docs-status bundles
Regenerates shell/src/data/registry.json and shell/src/data/docs-status.json
after the docs-links pipeline port so the shell-internal dashboard picks up
per-column docs overrides and live probe state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:10:19 -07:00
Atai Barkai dc9811b1b7 feat(showcase/scripts): port probe-docs.ts for live docs-status checks
Ports probe-docs.ts from 4084. For each entry in shared/feature-registry.json
it HEADs the feature's og_docs_url and checks whether a matching .mdx exists
under shell/src/content/docs/<shell_docs_url>, then writes the results to
shell/src/data/docs-status.json. shell-internal's DocsRow falls back to this
probed state for (integration, feature) cells that don't have a per-column
docs-links.json override. Exposes the script as `probe-docs` in
showcase/scripts/package.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:10:06 -07:00
Atai Barkai 0df1d23cf4 feat(showcase/scripts): port loadDocsLinks() into generate-registry
Ports the loadDocsLinks() helper from 4084 into generate-registry.ts. After
schema validation, each integration gets a docs_links field merged in from its
sibling packages/<slug>/docs-links.json (best-effort: missing file or stale
shell_docs_url shape is tolerated). The shell-internal DocsRow reads this via
integration.docs_links.features[<id>] to prefer curated per-column overrides
over the per-feature defaults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:09:55 -07:00
Atai Barkai aa93004208 chore(showcase): port docs-links.json files from 4084 (per-column overrides)
Ports 16 per-package docs-links.json files (one per integration column) from
4084. These provide per-(integration, feature) curated docs overrides that the
shell-internal DocsRow component reads via `integration.docs_links.features[id]`
to render ✓ instead of ✗ in the docs-og/docs-shell badge columns. Consumed by
the loadDocsLinks() helper in generate-registry.ts which merges them into the
shell's registry.json bundle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:09:15 -07:00
Atai Barkai 72e3170969 chore(showcase/shell-internal): sync DocsRow + Integration.docs_links with 4084
Ports 4084's per-column docs link overrides into shell-internal:
- DocsRow now reads integration.docs_links.features[id] with fallback to
  feature.og_docs_url; shell URLs are built from shell_docs_path via
  ${shellUrl}/${slug}/unselected${path}.
- Integration interface gets optional docs_links map (sourced from
  packages/<slug>/docs-links.json once the 4085 registry bundler wires
  it up; falls through gracefully until then).
- a:hover underline restored in globals.css to match 4084.

No runtime behavior change in 4085 yet since docs_links is absent from
the registry bundle; once the bundler pipeline catches up, per-column
overrides will light up the docs-og/docs-shell links automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:03:02 -07:00
Atai Barkai f8ceb9ac4f chore(showcase): regenerate data bundles after registry sync
Rerun generate-registry + bundle-content so shell/src/data/*.json reflects
the prebuilt-chat feature addition and the langgraph-python manifest
copy-alignment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:02:52 -07:00
Atai Barkai 6e8a58604b chore(showcase/langgraph-python): sync manifest.yaml with 4084 demo+feature lists
Align demo-row display names, descriptions, and tag sets with 4084 so the
shell surfaces matching copy across the two workspaces. Preserves 4085-
specific divergences (single-container src/agents + src/app/demos highlight
paths, per-demo routes, cli-start command field, prebuilt-chat row).
2026-04-19 14:02:33 -07:00
Atai Barkai ff6dd2eed5 chore(showcase): sync feature-registry + constraints with 4084
- Add prebuilt-chat feature to the registry and constrained-explicit
  allowlist so the 4085 manifest's intentional prebuilt-chat wiring
  validates cleanly (4084 omits it; 4085 committed the cell earlier)
- Bump expected langgraph-python feature count in generate-registry
  test from 32 to 33 to reflect the new row

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:01:48 -07:00
Atai Barkai 111e077620 fix(showcase/langgraph-python): beautiful-chat runtime protocol + default agent alias
Two small wiring fixes discovered during smoke testing:

1. Drop `useSingleEndpoint={false}` from the `<CopilotKit>` provider.
   The canonical reference sets this to opt into the v2 multi-endpoint
   protocol (GET /info + POST /agent/{name}/connect) which requires a
   Hono-based endpoint via `createCopilotEndpoint`. 4085 uses
   `copilotRuntimeNextJSAppRouterEndpoint` (single POST), matching every
   other cell in this package. Without this change the client 404s on
   /agent/beautiful-chat/connect.

2. Alias the `default` agent to the same graph in the route's agents map.
   `ExampleCanvas` and `HeadlessChat` call `useAgent()` with no args, which
   resolves to agentId "default". Previously this threw "Agent 'default'
   not found after runtime sync". Aliasing matches the canonical's
   `agents: { default: defaultAgent }` shape.

Smoke-tested: Pie Chart pill click now renders a real styled doughnut chart
from query_data + controlled generative UI; zero console / page errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:15:29 -07:00
Atai Barkai a66d8d2d0c fix(showcase/langgraph-python): beautiful-chat missing deps + showcase.json path
- Add `@radix-ui/react-checkbox` and `@radix-ui/react-separator` to
  package.json (ported frontend's ui/checkbox.tsx + ui/separator.tsx import
  these; the showcase package didn't pin them yet).
- Place `showcase.json` inside the cell directory (where it semantically
  belongs — the canonical had it at the project root alongside `src/hooks/`
  at depth 2, so `../../showcase.json` resolved to the root; in 4085 the
  hooks live two levels deeper, so we colocate the tiny config with the
  cell and adjust the import path to `../showcase.json`).

Without these, `next build` errors with "Module not found: Can't resolve
'@radix-ui/react-checkbox'" and "Can't resolve '../../showcase.json'".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:05:10 -07:00
Jordan Ritter b680fbaeff chore(showcase/starters): regenerate to pick up #4101 fixes for langgraph + entrypoint (#4102)
## Summary

PR #4101 updated the resolution-aware import rewriter and the entrypoint
`$!` -> agent PID fix, but the regeneration in that merge didn't include
all affected files. After merge, `origin/main` at `2087950ee` still had
stale output — and `showcase-starter-langgraph-fastapi-production` has
been returning `503 {"agent":"down"}` on `/api/health` as a result.

Root cause:
- `showcase/starters/langgraph-fastapi/src/agents/tools/*.py` still
imported `from src.agents.types` / `src.agents.get_weather` / etc. (old
flat-rewrite output). `src/agents/src/agent.py` imports
`src.agents.tools`, which loads `tools/__init__.py`, which fails with
`ModuleNotFoundError: No module named 'src.agents.types'`. The agent
subprocess crashes during langgraph_cli's graph import step;
`/api/health` flips to 503.
- langgraph-python has the same broken imports in its tools/ barrel.
- All 15 generated `entrypoint.sh` files still used `2>&1 | sed
's/^/[agent] /' &`, so `$!` (used for `kill -0 $AGENT_PID` and `wait
-n`) tracked `sed`, not the agent. Stack traces also got line-buffered
inside the pipe and never reached the container log.

Fix: rerun `pnpm -C showcase/scripts generate-starters` (the script
already on main from #4101). Pure regeneration — no source changes.

Verified locally:
- `tools/__init__.py` now emits `from src.agents.tools.types import ...`
(resolution-aware rewrite finds `<agentDest>/tools/types.py` one parent
away).
- `entrypoint.sh` now emits `&> >(awk '{print "[agent] " $0;
fflush()}')`.

Once merged, the Railway drift rebuild will pick up the new image for
langgraph-fastapi and `/api/health` should return green within one
redeploy cycle.

## Test plan
- [ ] CI green
- [ ] After merge + drift rebuild, `curl
https://showcase-starter-langgraph-fastapi-production-c7d2.up.railway.app/api/health`
returns `200 {"agent":"up"}`
- [ ] langgraph-python health stays green (same tools/ fix applied, same
container architecture)
2026-04-19 13:04:43 -07:00
Jordan Ritter 55b1445f9d chore(showcase/starters): regenerate to pick up #4101 tool-import + entrypoint fixes
PR #4101 updated both the resolution-aware import rewriter and the
entrypoint `$!` -> agent PID fix, but the regeneration in the merged
commit didn't include all affected files. `origin/main` at 2087950ee
still contained:

- langgraph-fastapi + langgraph-python: `src/agents/tools/*.py` importing
  `from src.agents.types`, `from src.agents.get_weather`, etc. — the
  old flat-rewrite output, which crashes with
  `ModuleNotFoundError: No module named 'src.agents.types'` at agent
  import time. langgraph-fastapi on Railway was failing its health probe
  with `agent: down` for this reason.
- All 15 generated entrypoint.sh files still had the old
  `2>&1 | sed 's/^/[agent] /' &` pattern, meaning `$!` pointed at `sed`
  instead of the agent subprocess. Every `kill -0 $AGENT_PID` /
  `wait -n` check was monitoring the wrong process, and Python crash
  output was also line-buffered inside the pipe so tracebacks never hit
  the container log.

Re-running `pnpm -C showcase/scripts generate-starters` with #4101's
resolution-aware rewriter produces the correct `src.agents.tools.*`
imports for both langgraph starters and the intended
`&> >(awk '{print "[agent] " $0; fflush()}')` process-substitution form
for every entrypoint.sh. No generator changes — purely regenerated
output catching up to the script that's already on main.
2026-04-19 12:59:49 -07:00
Atai Barkai 9f15e66b2a feat(showcase/langgraph-python): add beautiful-chat backend graph + data + wiring
Inlines the canonical starter's agent/main.py + agent/src/{todos,query,
a2ui_fixed_schema,a2ui_dynamic_schema}.py into a single `beautiful_chat.py`
graph (same shape as the 4084 clone), registers it in langgraph.json, and
colocates its data files (db.csv + flight schema JSON) under
`beautiful_chat_data/` so the shared `a2ui_schemas/` dir stays owned by
a2ui_fixed.py.

Adds a dedicated `/api/copilotkit-beautiful-chat` runtime endpoint that
mirrors the canonical's combined config (openGenerativeUI: true,
a2ui.injectA2UITool: false, mcpApps) — scoped to this one cell so the other
cells on `/api/copilotkit` keep their isolated per-demo `useFrontendTool` /
`useComponent` registrations. Removes `beautiful-chat` from the main route's
neutral-assistant fallthrough list now that it has a dedicated graph.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:49:28 -07:00
Atai Barkai 463a72e6b2 feat(showcase/langgraph-python): port beautiful-chat frontend tree from 4084 canonical
Ports the full 28-file Beautiful Chat cell frontend tree (components, hooks,
A2UI declarative catalog, UI primitives, theme CSS) from the 4084 demos clone
into the unified 4085 showcase layout. Imports rewired to relative paths.
Provider wrappers (CopilotKit + ThemeProvider) moved from the canonical's
root layout.tsx into the cell's own page.tsx since 4085 has no per-cell
layout. runtimeUrl points to a dedicated `/api/copilotkit-beautiful-chat`
endpoint (wiring follow-up).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:49:07 -07:00
Jordan Ritter 2087950eea fix(showcase/starters): restore langgraph-{fastapi,typescript} agent subprocess (#4101)
## Summary

After #4099 both `starter-langgraph-fastapi` and
`starter-langgraph-typescript` returned `/api/health` =
`{"status":"degraded","agent":"down"}` on Railway. Three interlocking
regressions in `generate-starters.ts`:

- **Import rewrite was flat, not resolution-aware.** langgraph-fastapi's
`agent.py` lives at `<agentDir>/src/agent.py` and imports `.tools`, but
`tools/` lives at `<agentDir>/tools/` (one level up). Both the flat
`<agentDir>.tools` rewrite and the file-dir-based `<agentDir>.src.tools`
rewrite pointed at nonexistent paths. langgraph_cli crashed with
`ModuleNotFoundError: No module named 'src.agents.src.tools'` before
binding 8123.
- **langgraph-typescript root `package.json` missing agent deps.** The
TS Dockerfile deletes `agent/package.json` to collapse the ESM package
boundary, but there was no mechanism to lift the agent's runtime deps
(`@langchain/openai` et al.) into the root `package.json`. `npx
@langchain/langgraph-cli dev` died with `Cannot find module
'@langchain/openai'`.
- **`AGENT_LOG_PREFIX` was accidentally reverted** to `cmd 2>&1 | sed
…`. After a pipeline `$!` points at `sed`, so `kill -0 $AGENT_PID` /
`wait -n $AGENT_PID` monitor the prefixer, not the agent. `sed` also
line-buffers so crash output can be lost.

Fix all three in the generator and regenerate the two affected starters.
Committed starter entrypoint.sh files across the fleet are already on
`awk &> >(…)` (they were regenerated at some earlier point) — this PR
re-aligns the generator with their committed state, so future regens
stay consistent.

## Verification

- `docker build` + `docker run` on both starters locally:
- fastapi:
`{"status":"ok","integration":"langgraph-fastapi","agent":"ok"}`
- typescript:
`{"status":"ok","integration":"langgraph-typescript","agent":"ok"}`
- `entrypoint` logs show `Agent server started (PID: N)` with N
belonging to the agent, not an awk/sed prefixer.
- `pnpm test` in `showcase/scripts/`: 1075/1075 pass.
- `tsc --noEmit` on the generator: clean.
- No changes to `langgraph-python` output (resolution-aware rewriter is
a superset of the prior subdir-aware behavior when all imports already
resolve).

## Test plan

- [ ] Merge + wait for showcase deploy workflow to redeploy both
services
- [ ] `curl https://starter-langgraph-fastapi.up.railway.app/api/health`
returns `agent: "ok"`
- [ ] `curl
https://starter-langgraph-typescript.up.railway.app/api/health` returns
`agent: "ok"`
- [ ] Smoke-test a chat turn on each starter to confirm the agent
actually responds
2026-04-19 12:41:14 -07:00
Atai Barkai 1c340b5644 docs(showcase/langgraph-python): restore @region markers for docs snippets + port shared-state-streaming frontend
Regions were stripped during the initial port. Restore them verbatim
from the 4084 source so MDX snippet extraction continues to work:

- agentic-chat: provider-setup, configure-suggestions, render-chat
- agentic-chat-reasoning: reasoning-block-render
- frontend-tools: frontend-tool, frontend-tool-registration,
  frontend-tool-handler
- gen-ui-tool-based: bar-chart-renderer, pie-chart-renderer
- chat-customization-css (+ theme.css): theme-css-import, css-variables
- chat-slots: register-welcome-slot, register-disclaimer-slot,
  register-assistant-message-slot (with the named-locals pattern)
- prebuilt-sidebar: sidebar-basic-setup, sidebar-configuration
- prebuilt-popup: popup-basic-setup
- headless-simple: use-agent-simple, headless-hooks, message-list-simple
- interrupt_agent.py: backend-interrupt-tool

Also ports the shared-state-streaming frontend (page.tsx +
document-view.tsx), replacing the TODO stub. Includes the
frontend-use-coagent-state region marker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:34:47 -07:00
Atai Barkai 853966b987 feat(showcase/langgraph-python): port subagents + headless-complete frontends + reset open-gen-ui minimal
- subagents: port 4084 delegation-log.tsx + page.tsx (reads
  agent.state.delegations, renders a live delegation log alongside
  CopilotChat). Drops the TODO stub that previously lived under
  demos/subagents/.
- headless-complete: port the full 4084 frontend — tool-renderers.tsx
  (useRenderTool for get_weather + get_stock_price, useComponent for
  highlight_note, useDefaultRenderTool catch-all), weather-card.tsx,
  stock-card.tsx, highlight-note.tsx, use-rendered-messages.tsx
  (manual render-tool-call / render-activity-message / render-custom-
  messages composition mirroring CopilotChatMessageView), plus chrome
  updates to assistant-bubble.tsx, user-bubble.tsx, message-list.tsx,
  page.tsx. Routed through /api/copilotkit-mcp-apps so the headless
  cell exercises Excalidraw MCP activity rendering too.
- open-gen-ui: reset to 4084's minimal version (plain <CopilotChat />
  against /api/copilotkit-ogui). Drops sandbox-functions.ts + suggestions.ts
  which belonged to open-gen-ui-advanced.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:31:39 -07:00
Atai Barkai 0918c5a77c fix(showcase/langgraph-python): mcp-apps + a2ui-fixed-schema + prebuilt-chat wiring
- mcp-apps page.tsx: route through /api/copilotkit-mcp-apps (split runtime
  that has Excalidraw MCP wired) and drop the manual
  useRenderActivityMessage + renderActivityMessages registration —
  CopilotKitProvider auto-registers MCPAppsActivityRenderer; plain
  <CopilotChat /> is enough. Replace generic suggestions with 4084's
  Excalidraw-specific ones.
- a2ui-fixed-schema page.tsx: fix the stale `./catalog` import to
  `./a2ui/catalog`, and delete the orphaned top-level catalog.ts +
  flight-card.tsx (the authoritative versions live under ./a2ui/).
- prebuilt-chat: add to features list + demos list in manifest.yaml so
  the shell surfaces it (runtime wiring already landed in the previous
  commit as a neutral-assistant cell).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:26:47 -07:00
Atai Barkai 7c74646c5a feat(showcase/langgraph-python): dedicated graphs for basic cells instead of sample_agent fallthrough
Before this commit, main.py carried the Tool-Based Generative UI chart
system prompt, and a long list of cells (agentic-chat, frontend-tools,
gen-ui-agent, tool-rendering-frontend-tools, gen-ui-tool-based) fell
through to that graph — so they all inherited the wrong "data
visualization assistant" prompt.

Split each cell into its own dedicated graph, mirroring 4084's per-cell
backends. main.py is now a neutral "helpful, concise assistant" used
only by UI/chrome demos (prebuilt-sidebar, chat-slots, headless-simple,
beautiful-chat, prebuilt-chat, etc.).

- agentic_chat, frontend_tools, gen_ui_agent: neutral variants with
  minor system-prompt tweaks from 4084
- tool_rendering_frontend_tools: weather-assistant prompt; frontend owns
  the tool via useFrontendTool
- gen_ui_tool_based: chart-viz system prompt (moved out of main.py)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:25:28 -07:00
Atai Barkai fe0a1cfb09 feat(showcase/langgraph-python): port missing backends for stub cells
Ports 4084 backend agents for shared-state-streaming, subagents, and
headless-complete into 4085's consolidated src/agents/ layout, registers
the new graphs in langgraph.json, wires them into the main and
copilotkit-mcp-apps routes.

- shared_state_streaming: StateStreamingMiddleware write_document tool
- subagents: supervisor + research/writing/critique sub-agents with
  delegation log shared state
- headless-complete: get_weather + get_stock_price + MCP Apps routing;
  routed through /api/copilotkit-mcp-apps to match 4084 pedagogy

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:24:01 -07:00
Jordan Ritter d7522137d1 chore(showcase/starters): regenerate all starters after #4098 (#4100)
## Summary

Hotfix for drift-check on main after #4098 merged.

#4098 landed two generator-level changes that affect every starter slug:
1. `rewritePythonImports` now strips `import sys` when the
`sys.path.insert` block is removed and no other `sys` reference
survives.
2. `starters/template/entrypoint.template.sh` switched from
pipeline-with-sed to process substitution so `$!` captures the real
agent PID, not sed's.

Only langroid was regenerated in #4098. This PR regenerates the other 16
starters so drift-check passes.

No source logic change.

## Test plan
- [x] `npx tsx showcase/scripts/generate-starters.ts` — clean regen
- [x] `npx tsx showcase/scripts/generate-starters.ts --check` — no drift
- [ ] CI drift-check green

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-19 12:23:39 -07:00
Jordan Ritter c6b1617bef chore(showcase/starters): regenerate all starters post-generator fix 2026-04-19 12:17:50 -07:00
Jordan Ritter 70f8df05a4 chore(showcase/starters): regenerate langgraph-{fastapi,typescript} after generator fix
langgraph-fastapi/src/agents/src/agent.py now imports
`src.agents.tools.*` (module exists) rather than `src.agents.src.tools.*`
(nonexistent path) -- fixes the ModuleNotFoundError crash that held
/api/health at agent: "down".

langgraph-typescript/package.json now includes @langchain/core,
@langchain/langgraph, @langchain/langgraph-checkpoint,
@langchain/langgraph-cli, @langchain/openai, and @copilotkit/sdk-js so
the agent subtree can resolve its runtime imports after the Dockerfile
deletes agent/package.json.

Local docker build + run verified: both /api/health return
{"status":"ok","agent":"ok"} and their entrypoint logs show
`Agent server started` with the captured PID belonging to the agent,
not an awk/sed prefixer.
2026-04-19 12:13:40 -07:00
Jordan Ritter 710da8cc30 fix(showcase/scripts): restore langgraph starter subprocess boot path
Three interlocking fixes to generate-starters.ts that together restore
langgraph-fastapi and langgraph-typescript /api/health to "ok" after
#4099 shipped an entrypointOverride feature that accidentally reverted
earlier fixes and left gaps for the TS starter.

1. Resolution-aware python import rewrite for langgraph starters.

   langgraph_cli loads agent modules standalone (not as packages), so the
   generator rewrites `from .X import ...` to absolute form. The previous
   flat rewrite produced `from <agentDir>.X import ...`, and the
   subsequent subdir-aware variant used the file's OWN dir as the
   package. Both assume sibling targets sit alongside the importing file.

   langgraph-fastapi violates that: agent.py lives at
   `src/agents/src/agent.py` but the `tools/` it imports lives at
   `src/agents/tools/` -- one level up, not inside `src/`. Either prior
   rewrite produced `from src.agents.src.tools import ...`, a path that
   doesn't exist, and langgraph_cli crashed on module import with
   `ModuleNotFoundError: No module named 'src.agents.src.tools'` before
   ever binding 8123.

   Walk UP from the file's own dir toward agentDest and rebase the
   absolute import on the shallowest directory that actually contains
   `<firstSeg>/` or `<firstSeg>.py`. Correct both for co-located imports
   (`tools/get_weather.py` importing `.types`) and for sibling-directory
   imports (`src/agent.py` importing `.tools` from `../tools`).

2. Merge langgraph-typescript agent runtime deps into root package.json.

   The TS Dockerfile deliberately deletes `agent/package.json` to
   collapse the ESM package boundary between the Next.js frontend and
   the agent subtree. Without merging the agent's runtime deps up into
   the root package.json, the langgraph-cli's runtime import of
   graph.ts fails with `Cannot find module '@langchain/openai'` and
   the agent never binds 8123.

   Add `extraDependencies` to the langgraph-typescript framework def
   with @langchain/core, @langchain/langgraph,
   @langchain/langgraph-checkpoint, @langchain/langgraph-cli,
   @langchain/openai, and @copilotkit/sdk-js.

3. Restore AGENT_LOG_PREFIX process-substitution helper.

   #4099 inadvertently replaced `cmd &> >(awk … fflush …)` with
   `cmd 2>&1 | sed …` across every getEntrypointBlock branch. After a
   pipeline `$!` points at `sed`, not the agent, so `kill -0 $AGENT_PID`
   and `wait -n $AGENT_PID` monitor the wrong process and mask real
   crashes; `sed` also line-buffers so crash output can be lost.
   Restore the helper so the committed starter entrypoint.sh files and
   regenerated output stay consistent.
2026-04-19 12:13:32 -07:00
Atai Barkai c3d105ae00 feat(showcase/langgraph-python): port 4084 cells into 4085 demos layout
Port 15+ cells from PR 4084 (per-demo workspace) into PR 4085's
shared-column layout (src/agents/*.py + src/app/demos/<cell>/*.tsx).

New cells:
- beautiful-chat (port scaffold — full component tree deferred)
- declarative-gen-ui-hardcoded (single-file catalog variant)
- interrupt-headless (useHeadlessInterrupt from primitives)
- open-gen-ui-advanced (sandbox functions + app-tool-calling)
- readonly-state-agent-context (useAgentContext one-way channel)
- reasoning-default-render (built-in CopilotChatReasoningMessage)
- shared-state-read-write (preferences write + notes read)
- tool-rendering-reasoning-chain (reasoning emitter + chaining loop)

Restructured cells:
- declarative-gen-ui: BYOC with 3-file a2ui/{definitions,renderers,catalog}
- a2ui-fixed-schema: compositional tree with Title/Airport/Arrow/
  AirlineBadge/PriceTag + 3-file catalog; search_flight renamed
  display_flight
- mcp-apps: simplified to mcpApps.servers runtime config targeting
  Excalidraw; drops custom MCPAppsStubMiddleware
- open-gen-ui: minimal provider + openGenerativeUI runtime flag
- tool-rendering + 3 variants: per-tool WeatherCard + FlightListCard
  plus useDefaultRenderTool wildcard

Runtime wiring:
- /api/copilotkit: registers new agents + a2ui.injectA2UITool for
  declarative + fixed-schema cells
- /api/copilotkit-ogui: adds open-gen-ui-advanced
- /api/copilotkit-mcp-apps: NEW dedicated endpoint for mcpApps

Backend graphs:
- shared_state_read_write.py (PreferencesInjectorMiddleware + set_notes)
- readonly_state_agent_context.py
- hitl_in_chat_agent.py (tools=[] + tailored prompt)
- a2ui_dynamic_hardcoded.py (secondary-LLM dynamic schema)
- open_gen_ui_advanced_agent.py
- tool_rendering_reasoning_chain_agent.py (reason→tool loop)

Flight fixed-schema JSON now assembles Card>Column>[Title,Row,Row,Button].

All `@region[...]` markers ported to drive docs <Snippet> resolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:45:21 -07:00
Jordan Ritter 6e1aa87072 chore(showcase/starters): regenerate all starters after #4098
#4098 landed two generator-level changes that affect every starter slug but only
langroid was regenerated in that PR:

1. rewritePythonImports now strips `import sys` when sys.path.insert is removed
   and no other `sys` reference survives in the file (paired with existing
   osUsed detection).
2. starters/template/entrypoint.template.sh switched from pipeline
   (`2>&1 | sed 's/^/[agent] /'`) to process substitution
   (`&> >(awk '{print "[agent] " $0; fflush()}')`) so $! captures the real
   agent PID, not sed's — prior pattern masked uvicorn crashes behind sed's
   exit code.

Regenerate the remaining 16 starters so drift-check passes on main.

No source logic change.
2026-04-19 11:41:50 -07:00
Jordan Ritter 09d08b1e43 fix(showcase/langroid): route A2UI planner through langroid LLM abstraction (#4098)
## Summary

langroid is provider-agnostic by design — operators pick a chat model
via `LANGROID_MODEL`. But `GenerateA2UITool` hardcoded `openai.OpenAI()`
+ `gpt-4.1`, forcing non-OpenAI users to keep an `OPENAI_API_KEY` around
just for the A2UI dashboard demo.

This PR routes the A2UI planner through `lm.OpenAIGPT` (langroid's
universal LLM abstraction) and hardens the deploy/boot path around it.

## Core fix

- **Provider-agnostic A2UI planner.** `GenerateA2UITool` now uses
`lm.OpenAIGPT` keyed on `A2UI_MODEL` (override) → `LANGROID_MODEL`
(inherit) → `gpt-4.1` (default, bare name — `openai/` prefix is NOT
langroid-native and silently breaks at request time).
- **Structured error surface.** `_A2uiError` TypedDict with
`_A2uiErrorKind` enum (values pinned to sibling adapters), `_a2ui_error`
factory with non-empty-string validation at construction, runtime
`ValueError` (not `assert`) so `python -O` can't strip it.
- **`_ARGS_MISSING` sentinel** distinguishes "no tool call" from "tool
call with degraded shape" — different remediations for the frontend.
- **Narrow re-raise tuple** propagates programmer errors
(`AttributeError`, `TypeError`, `NameError`, `ImportError`,
`ModuleNotFoundError`, `AssertionError`, `NotImplementedError`,
`pydantic.ValidationError`) while wrapping recoverable SDK errors into
`a2ui_llm_error`.
- **Backend tool handlers** now wrap impls in try/except →
`_tool_error(kind: _ToolErrorKind, ...)` JSON surfaces, preventing
unhandled exceptions from escaping to langroid's tool machinery.
- **Boundary validation** after `build_a2ui_operations_from_tool_call`
return.

## Deploy / entrypoint hardening

- **Provider-aware credential guard.** Detects `LANGROID_MODEL` prefix
(`openai/` → warns it's not routable, `gemini/` → `GEMINI_API_KEY`,
`litellm/anthropic/` → `ANTHROPIC_API_KEY`,
`ollama/`/`local/`/`vllm/`/`llamacpp/` → no-key-required,
`langdb/`/`litellm-proxy/`/`litellm/<other>/` → config-resolved) and
fails fast under `REQUIRE_LANGROID_API_KEY=1` only when credentials are
genuinely missing.
- **Real PID capture** for uvicorn + Next.js via process substitution
(prior `| sed` pattern captured the sed PID, masking crash diagnostics).
- **Graceful shutdown:** trap cleanup with `set +e` safety + 5s
SIGTERM→SIGKILL grace window, survivor-kill with EPERM diagnostics.
- **Package Dockerfile** now runs as non-root with `ENV PORT=10000` /
`ENV HOSTNAME=0.0.0.0` parity with starter.

## Generator + CI

- **`entrypointOverride`** mechanism in `generate-starters.ts` so the
langroid starter's provider-aware entrypoint survives regeneration.
Reads canonical from `STARTERS_DIR/<slug>/` (not `outDir`) so `--check`
mode doesn't false-flag drift.
- **Fail-loud** on missing required inputs (agent_server.py, extraFiles,
PIN_OVERRIDES stale deps, missing override file) instead of silent
warn+skip.
- **Regression test** pins the `entrypointOverride` preservation
behavior.
- **`.gitattributes`** enforces LF on `.sh` for Windows contributor
safety.

## Review

5 full CR rounds (7 agents each) + 6 fix rounds. Load-bearing bugs
converged:
- Round 1: R1 → 47 findings, most resolved
- Round 2: R2 → 30+ findings, critical (lru_cache keying, build_a2ui
wrapper, starter parity, `_A2uiError` hardening)
- Round 3: R3 → sed-PID bug (production-blocking), `--check` drift, file
mode, `entrypointOverride` hard-error, `saw_modern_call` logic gap
- Round 4: R4 → `google/*` FATAL, bare-prefix FATAL, RecursionError test
naming, caplog ambiguity, ClassDef walker, `_ToolErrorKind` enum
- Round 5: R5 → **`openai/gpt-4.1` default empirically broken**
(langroid doesn't strip the prefix → OpenAI SDK rejects), fail-fast
refusing ollama/local/vllm/llamacpp, missing regression test for
entrypointOverride, rootful package Dockerfile
- Round 6: R6 → `langdb/`/`litellm-proxy/`/`litellm/<non-anthropic>/`
refused under fail-fast, starter `wait -n` pid quoting, cleanup trap
`set -e` safety

Deferred as design-scope follow-ups (not load-bearing, current code is
correct):
- `_A2uiError` TypedDict → frozen dataclass / pydantic model (stronger
encapsulation, cross-sibling alignment required)
- `_ARGS_MISSING: object` → named sentinel class (cleaner narrowing)
- `list[dict]` tool fields → TypedDict / pydantic models for schema
enforcement at ingestion
- Comment rot around "Identical TypedDicts live in siblings" (sibling
adapters diverged on the Literal)
- Frontend-tool `handle()` server-side regression path returns benign
string (explicit UX tradeoff)

## Tests

- 109 passed, 1 skipped (integration test gated by
`LANGROID_INTEGRATION_TESTS=1`)
- Module-import hygiene via subprocess isolation (no more stale
`importlib.reload` state)
- AST walker catches top-level + `try/except` `import openai` (including
ClassDef bodies)
- LRU eviction pinned at `maxsize=4`
- Forced-function-call kwargs + `stream=False` planner assertion
- Parametrized error propagation (both re-raise and wrap tuples)
- Backend tool handle happy + error paths across all 6 tools
- `create_agent` factory: stream=True + enable_message(ALL_TOOLS)

## Test plan
- [x] `pytest showcase/packages/langroid/tests/python/` — 109 pass, 1
skipped
- [x] `npx tsx showcase/scripts/generate-starters.ts --check` — no
langroid drift
- [x] `bash -n` clean on both entrypoints
- [x] Manual: `REQUIRE_LANGROID_API_KEY=1` + various `LANGROID_MODEL`
values — bare anthropic/ FATALs,
langdb/litellm-proxy/litellm-non-anthropic INFO-pass, ollama/local
no-key-required INFO-pass
- [ ] CI green (watching)
- [ ] Railway deploy of showcase-langroid once merged

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-19 11:40:39 -07:00
Jordan Ritter ede34dabc1 chore(showcase/langroid): regenerate starter after source+generator updates 2026-04-19 11:39:06 -07:00
Jordan Ritter e862feb63b feat(showcase/scripts): per-slug entrypointOverride + fail-loud on missing inputs
generate-starters.ts:
- Add entrypointOverride?: boolean to FrameworkDef so slugs whose boot sequence
  diverges from the shared template (e.g. langroid's provider-aware credential
  guard) can preserve their committed entrypoint.sh through regeneration.
- Snapshot the override from STARTERS_DIR/<slug>/entrypoint.sh (canonical
  committed path), NOT outDir — so --check mode (which passes a temp outDir)
  doesn't false-flag the override as drift.
- Force mode: 0o755 on the restored file regardless of source mode so editors
  that strip the executable bit can't silently ship a broken starter.
- Throw (not warn) when an entrypointOverride slug is missing the override
  file, when declared extraFiles / agent_server.py / Dockerfile are missing,
  and when PIN_OVERRIDES references a stale dep. These are repo-integrity
  failures — silent-warn-and-continue ships broken starters.
- Strip unused `import sys` after sys.path.insert removal (pair with the
  existing osUsed detection).

Opt langroid in via entrypointOverride: true.

Also adds a regression test in __tests__/generate-starters.test.ts that
calls generateStarterToDir against a tmp dir and asserts the emitted
entrypoint.sh byte-equals the committed langroid starter entrypoint,
plus a negative test that a non-override slug does NOT preserve its file.
2026-04-19 11:38:59 -07:00
Jordan Ritter 2dea75a5ab fix(showcase/langroid): non-root Dockerfile + pin direct Python deps
Package Dockerfile:
- Create unprivileged app:app user (UID/GID 1001) matching starter Dockerfile
- USER app drop with --chown=app:app on COPY for security parity
- ENV PORT=10000 / ENV HOSTNAME=0.0.0.0 so child processes inherit defaults
- Preserves PYTHONPATH=/app/shared/python for shared-tools imports

requirements.txt (package + starter): pin httpx, pydantic, openai directly
rather than relying on transitive resolution from langroid / fastapi.
agui_adapter.py imports these symbols directly — the module's contract
shouldn't depend on upstream pin discipline we don't control.
2026-04-19 11:38:44 -07:00
Jordan Ritter c2234312b8 fix(showcase/langroid): provider-aware entrypoint credential guard + graceful shutdown
Replace the OPENAI_API_KEY-hardcoded credential guard with a provider-aware
_check_key that inspects LANGROID_MODEL's prefix and probes the correct env
var for that provider:

- openai/ → WARN (not a langroid-native prefix; use bare model names)
- anthropic/ → WARN (not routable; suggest litellm/anthropic/<model>)
- litellm/anthropic/ → ANTHROPIC_API_KEY
- gemini/ → GEMINI_API_KEY
- openrouter/, groq/, cerebras/, glhf/, minimax/, portkey/, deepseek/ → dedicated keys
- ollama/, local/, vllm/, llamacpp/ → NO_KEY_REQUIRED (local inference)
- langdb/, litellm-proxy/, litellm/<non-anthropic>/ → NO_KEY_REQUIRED_* (credentials
  resolved via config, not env)

Under REQUIRE_LANGROID_API_KEY=1 a missing credential FATALs the boot; the
default is warn-and-continue so dev containers boot cleanly.

Process lifecycle hardening:
- Use process substitution `> >(sed ...)` instead of pipelines so $! captures
  the real python/next PID (not sed's) — prior pipeline pattern would mask
  uvicorn crashes behind sed's exit code
- Trap cleanup with `set +e` at entry (trap may fire from FATAL `exit 1` path
  where set -e would otherwise abort the cleanup loop)
- 5s SIGTERM→SIGKILL grace window on the surviving child
- Extended exit-code case statement (0, 1, 2, 126, 127, 130, 137, 139, 143, 255)
- Survivor-kill diagnostics distinguish EPERM from ESRCH
- wait -n with explicit positional PIDs so unrelated subshell reaps can't
  satisfy the wait

.env.example updates document the multi-provider options so operators
discover them from the file itself, not entrypoint.sh.

.gitattributes enforces LF on *.sh so Windows contributors regenerating
the starter don't silently ship CRLF entrypoints.
2026-04-19 11:38:32 -07:00
Jordan Ritter 65f3790653 fix(showcase/langroid): route A2UI planner through langroid LLM abstraction
The secondary GenerateA2UITool previously hardcoded openai.OpenAI() + gpt-4.1,
forcing non-OpenAI users to keep an OPENAI_API_KEY around just for the A2UI
dashboard demo even when LANGROID_MODEL pointed at another provider.

Route the planner through lm.OpenAIGPT (langroid's universal LLM abstraction)
keyed on A2UI_MODEL (override) → LANGROID_MODEL (inherit) → gpt-4.1 (default).
Default uses the bare model name because `openai/` is NOT a langroid-native
prefix — langroid passes it literally to the OpenAI SDK which rejects it.

Additional hardening:
- _A2uiError TypedDict with _A2uiErrorKind enum, factory with non-empty-string
  validation that raises ValueError (not assert, so python -O can't strip it)
- _ARGS_MISSING sentinel distinguishes "no tool call" from "degraded shape"
  so the frontend gets correct remediation
- Narrow re-raise tuple propagates programmer errors (AttributeError, TypeError,
  NameError, ImportError, ModuleNotFoundError, AssertionError, NotImplementedError,
  pydantic.ValidationError) while wrapping recoverable SDK errors into _a2ui_error
- _ToolErrorKind enum for backend tool error codes — typo-safe parity with _A2uiErrorKind
- Boundary validation after build_a2ui_operations_from_tool_call return
- Backend tool handlers wrap impls in try/except so exceptions don't escape
  to langroid's tool machinery
- @lru_cache(maxsize=4) on _get_a2ui_llm keyed on resolved model string
- FRONTEND_TOOL_NAMES canary raises RuntimeError at import time on drift
- No top-level import of openai (AST walker test pins this contract)

Covered by 109 tests (integration test gated by LANGROID_INTEGRATION_TESTS=1).
2026-04-19 11:38:06 -07:00
Atai Barkai 5eb4da7db9 chore(showcase): regenerate shell/src/data bundles after port
Regenerate registry.json (41 features, 11 categories, 17 integrations),
demo-content.json (152 demos bundled with region markers support +
dual-path highlight resolution), constraints.json (new allowlists),
and status.json (no variants field) so the shell + shell-internal
dashboards render the ported state without stale cached inputs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:25:29 -07:00
Atai Barkai 2a52cf05ba chore(showcase/scripts): drop variants mock-seeding from generate-status
Port the 4084 simplification of the status generator: remove the
MOCK_VARIANTS seeding table + mockVariantTest / mockVariantQA /
mockVariantHealth helpers + Variant type. Informational demos (no
route) are skipped from health probing. The status JSON no longer
carries per-demo `variants[]` — the shell-internal dashboard renders
one row per demo without variant expansion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:25:08 -07:00
Atai Barkai 18ed9dbdbd chore(showcase/scripts): port bundle regions + parity dual-location
Port the 4084 scripts-layer enhancements so 4085's showcase toolchain
matches the new feature shape:

- lib/manifest.ts: ManifestDemo gains optional `command` field; parser
  accepts + validates it (non-empty string, frozen).
- bundle-demo-content.ts: inline `@region[name]` / `@endregion[name]`
  comment-marker extraction; informational-only demos (no route, e.g.
  cli-start) are skipped; markers stripped from bundled content;
  regions: { file, startLine, endLine, code, language } emitted per
  demo. External-highlight-file merging (4085-specific) preserved, so
  backend agents under src/agents/*.py still flow into the bundle.
- validate-parity.ts: accepts demos at BOTH demos/<cell>/ (4084 layout)
  and src/app/demos/<cell>/ (4085 layout); informational demos
  (command field) are excluded from the parity audit.
- tests: bundle-demo-content.test.ts expectedDemos updated for the
  shared-state rename; generate-registry.test.ts feature count 25→32;
  validate-parity.test.ts missing-demo-dir message updated to match
  the new dual-location wording.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:24:55 -07:00
Atai Barkai fb062d3750 chore(showcase): port shared schema + feature-registry + constraints
Port the 4084 internal-showcase-followups state of the shared showcase
schema to 4085 (no Docker restructure):

- feature-registry.json: new Dev Ex category, category reorder
  (Dev Ex → Chat & UI → Platform → Controlled → Declarative → Open →
  Operational → Interactivity → Agent State → Multi-Agent → BYOC);
  +8 new features (beautiful-chat, cli-start, interrupt-headless,
  reasoning-default-render, tool-rendering-reasoning-chain,
  open-gen-ui-advanced, declarative-gen-ui-hardcoded,
  readonly-state-agent-context); renames (shared-state-write →
  shared-state-read-write, shared-state-agent-readonly →
  readonly-state-agent-context); removals (shared-state-read,
  state-rendering, a2ui-*, shared-state-io, shared-state, readables,
  a2a-chat, deep-agents, vnext-chat, byoc-a2ui, byoc-tambo);
  gen-ui-agent → kind: testing.
- constraints.yaml: allowlists updated to reference the new IDs.
- manifest.schema.json: `route` is optional; `command` field added for
  informational demos (e.g. cli-start).
- All 17 column manifests: shared-state-read removed,
  shared-state-write renamed to shared-state-read-write.
- langgraph-python manifest: full 4084 features list + demos entries
  with 4085-appropriate highlight paths (src/agents/*.py +
  src/app/demos/<cell>/* rather than backend/ + frontend/).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:24:33 -07:00
Atai Barkai beb42019d4 docs(showcase/shell): port ~70 MDX pages from 4084 into shell
Port the MDX content delta between the 4085 base branch
(atai/2026-04-18/feature-port-no-docker-restructure) and the 4084
follow-ups branch (atai/2026-04-17/internal-showcase-followups):

- built-in-agent tree (ag-ui, coding-agents, copilot-runtime,
  frontend-tools, inspector, prebuilt-components, programmatic-control,
  custom-look-and-feel/{headless-ui,slots}, generative-ui/{a2ui,
  tool-rendering,your-components/{display-only,interactive}},
  premium/{headless-ui,observability,overview},
  troubleshooting/{common-issues,error-debugging,migrate-to-*})
- top-level feature docs (agentic-chat-ui, frontend-tools, headless,
  human-in-the-loop, inspector, shared-state, programmatic-control,
  ag-ui-middleware, coding-agents, coding-agent-setup)
- custom-look-and-feel (css, reasoning-messages, slots)
- generative-ui (a2ui, a2ui/dynamic-schema, a2ui/fixed-schema,
  mcp-apps, open-generative-ui, reasoning, tool-based, tool-rendering)
- human-in-the-loop (headless, useInterrupt)
- prebuilt-components (index, popup, sidebar) — replaces the single
  prebuilt-components.mdx
- shared-state (agent-readonly, streaming)
- troubleshooting (common-issues, debug-mode, error-debugging,
  migrate-to-*, observability-connectors)
- learn (connect-mcp-servers)
- multi-agent/subagents
- integrations/built-in-agent/custom-agent,
  integrations/langgraph/generative-ui/tool-rendering
- meta.json updates across backend, custom-look-and-feel,
  generative-ui, generative-ui/a2ui, prebuilt-components,
  troubleshooting, root docs

These pages use the new Snippet / InlineDemo / FrameworkTabs
components shipped in the preceding infrastructure commit, plus the
FrameworkGuardedContent pattern that only applies when a page has a
defaultCell frontmatter. Framework-agnostic pages (/learn/*,
/troubleshooting/*, /premium/*) keep rendering their body
unconditionally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:22:57 -07:00
Atai Barkai c1b595596e feat(showcase/shell): port /docs routing + framework-scoped routes from 4084
Port the full docs routing + rendering infrastructure from the 4084
branch (atai/2026-04-17/internal-showcase-followups):

- New [framework]/[[...slug]] catch-all that validates the first
  segment against the registry and renders framework-scoped docs
  with a "not available for this framework" banner when the page's
  defaultCell is not tagged in the framework's cells.
- FrameworkProvider + selector: framework is strictly URL-derived,
  storedFramework is an advisory localStorage signal. No
  auto-redirect from localStorage.
- /docs/[[...slug]] rewritten as a thin wrapper around DocsPageView
  with a new DocsOverview landing: framework picker + topic cards.
- New lib/docs-render.tsx centralising snippet inlining,
  frontmatter parsing, nav tree + breadcrumb builders.
- New lib/mdx-registry.tsx consolidating the ~700-line component
  shim used by both routes.
- Server <Snippet> component with demo-content regions + syntax
  highlighting via highlight.js.
- Per-feature <InlineDemo> iframe embedder pointing at the
  integration's backend (single-container shape
  http://localhost:3100/demos/<cell>).
- FrameworkTabs, docs-callout, docs-steps, docs-tabs, router-pivot,
  stored-framework-highlight components for the MDX registry.
- Global typography + color pivot in globals.css: Plus Jakarta
  Sans body, Spline Sans Mono code, cool-gray background, purple
  accent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:22:28 -07:00
Atai Barkai 218a356256 feat(showcase/shell-internal): port enriched cell chrome + command cell from 4084
- Drop the 5 experimental variant-presentation routes + SingleCell helper;
  the variant layouts no longer match the enriched cell chrome.
- Rename variant-pieces.tsx -> cell-pieces.tsx; expose a shared
  <CellStatus ctx={ctx} /> that renders the docs-og/docs-shell row +
  E2E/Smoke/QA/health badges so both the runnable-demo cell and the
  informational CommandCell share the same bottom section.
- Add CommandCell (client component): takes the full CellContext, renders
  <code> + Copy button for ctx.demo.command, then the same CellStatus row.
- page.tsx branches on ctx.demo.command so the CLI Start row renders a
  copy-pasteable command in place of Demo/Code links while keeping the
  matrix visually consistent.
- registry.ts: Feature gains kind + og_docs_url/shell_docs_url; Demo.route
  is optional and Demo.command is the new informational field. Feature-grid
  passes the full demo onto CellContext.
- status.ts: drop variant helpers / types (no longer used).
- Add docs-status.ts reader + a stub docs-status.json so the enriched
  DocsRow renders without blowing up the build before the schema agent
  lands the generated bundle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:22:02 -07:00
Jordan Ritter 3be1bda487 fix(showcase/starters): chown /app to app user to prevent CLI cache-dir crashes (#4099)
## Summary

**Root cause:** PR #4092 replaced a blanket `RUN chown -R app:app /app`
with per-COPY `COPY --chown=app:app` lines. That covers the copied
files, but `WORKDIR /app` at the top of the runner stage creates `/app`
as root BEFORE the `app` user exists, and `COPY --chown=` only reassigns
the copied files — not the parent dir. Result: `/app` stays owned by
root.

**Symptom:** `starter-mastra` deploy CRASHED on Railway with:

```
Error: EACCES: permission denied, mkdir '/app/.mastra'
```

`npx mastra dev` tries to create its cache dir under CWD at runtime as
user `app`, and fails.

**Likely co-victims:** any starter whose runtime invokes a Node CLI that
writes to CWD. `starter-langgraph-typescript` (uses
`@langchain/langgraph-cli dev`) fits the exact same signature — same
class of bug, would have hit the same wall once traffic forced a cache
write.

**Fix:** add `RUN chown app:app /app` immediately before `USER app` in
all four Dockerfile templates (typescript, python, dotnet, java),
applied uniformly to all 17 generated starters via
`showcase/scripts/generate-starters.ts`. Surgical, cheap, idempotent.

## Evidence — local docker build + run

**starter-mastra:**

```
$ docker exec starter-mastra-test ls -la /app | head
drwxr-xr-x 1 app  app  4096 .          ← WORKDIR now owned by app
drwxr-xr-x 1 root root 4096 ..
drwxr-xr-x 4 app  app  4096 .mastra    ← created successfully by mastra dev
...
$ curl http://localhost:13010/api/health
{"status":"ok","integration":"mastra","agent":"ok",...}  ← HTTP 200
```

**starter-langgraph-typescript:**

```
$ docker ps --filter name=starter-langgraph-ts-test
starter-langgraph-ts-test Up 8 minutes             ← stable, not crashlooping
$ docker exec starter-langgraph-ts-test touch /app/test-write && echo OK
OK
$ curl http://localhost:13020/api/health
{"status":"degraded","integration":"langgraph-typescript","agent":"down",...}
                                                    ← HTTP 503 (dummy key) — NOT a crash
```

## Scope

- 17 starter Dockerfiles regenerated
- 4 template Dockerfiles updated (the source of truth)
- Generator TS untouched — the fix is purely in the Dockerfile templates
that the generator copies verbatim
- `showcase/scripts` vitest: 1073/1073 green

## Test plan

- [x] `pnpm run generate-starters` regenerates without errors
- [x] `pnpm test` in `showcase/scripts` — 1073 tests green
- [x] `docker build` + `docker run` starter-mastra — container stays up,
`/api/health` 200
- [x] `docker build` + `docker run` starter-langgraph-typescript —
container stays up 8+ min, `/api/health` 503 degraded (expected on dummy
key)
- [ ] Railway redeploy of starter-mastra after merge — expect container
to boot and reach `running`
- [ ] Railway redeploy of starter-langgraph-typescript after merge —
expect container to boot and reach `running`

Independent of #4096 — branched from `origin/main`, no dependency.
2026-04-19 10:56:22 -07:00
Jordan Ritter 98841aaba5 fix(showcase/starters): chown WORKDIR to app user in Dockerfiles
Root cause: `WORKDIR /app` at the top of the runner stage creates /app
owned by root BEFORE the unprivileged `app` user is created. The
`COPY --chown=app:app` lines added in #4092 only reassign the files
being copied, NOT the /app directory itself.

Symptom: starter-mastra CRASHED on Railway with
  EACCES: permission denied, mkdir '/app/.mastra'
when `npx mastra dev` tried to create its cache dir under CWD as user
`app`. Likely co-victim class: any starter whose runtime invokes a Node
CLI that writes to CWD (e.g. langgraph-typescript via @langchain/langgraph-cli dev).

Fix: add `RUN chown app:app /app` immediately before `USER app` in all
four Dockerfile templates (typescript, python, dotnet, java), applied
uniformly to all 17 generated starters via the generator.

Verified locally:
 - docker build + run starter-mastra → container stays up, /app owned
   by app:app, /app/.mastra created successfully, /api/health returns 200.
 - docker build + run starter-langgraph-typescript → container stays up
   (8+ min), write to /app succeeds, /api/health returns 503 degraded
   (expected on dummy OPENAI_API_KEY) — NOT a crash.

All 17 starter Dockerfiles regenerated via
  pnpm run generate-starters
and the existing showcase/scripts vitest suite stays green (1073 tests).
2026-04-19 10:40:12 -07:00
Jordan Ritter 692c57db01 fix(showcase/starters): restore /api/health accuracy across 15 degraded agent starters (#4096)
## Summary

15 of 17 showcase starters were reporting `{status: "degraded", agent:
"error" | "down"}` from `/api/health`. Root-caused to two compounding
bugs that hid each other.

### Cause 1 — FastAPI route shadowed by mount catch-all

Python FastAPI starters registered `@app.get("/health")` but then
installed an AG-UI adapter at `/` (either `app.mount("/",
stream.build_asgi())` or
`add_agent_framework_fastapi_endpoint(path="/")`). Starlette's `Mount`
at `/` is a prefix match and swallows every subsequent request including
`/health`, so the decorated handler never fired and the runtime saw a
non-JSON agent response and flagged the starter as "degraded".

Repro (reduced, before):
```python
app = FastAPI()
app.mount("/", mounted)  # or adapter that mounts at "/"

@app.get("/health")
def health():
    return {"status": "ok"}

# curl /health -> "agent-saw:/health"  (wrong — mount won)
```

Fix: install a `HealthMiddleware` (BaseHTTPMiddleware) that
short-circuits `GET /health` above the routing layer, which runs before
any Mount can claim the path. Agent mount stays intact so AG-UI traffic
at `/` is unaffected.

Applies to 10 Python agent starters: ag2, agno, claude-sdk-python,
crewai-crews, google-adk, langroid, llamaindex, ms-agent-python,
pydantic-ai, strands.

### Cause 2 — `$!` after a pipeline points to `sed`, not the agent

The entrypoint template used:
```bash
cmd 2>&1 | sed 's/^/[agent] /' &
AGENT_PID=$!
```
After a pipeline, `$!` is the last command (`sed`), not the agent. Every
`kill -0 $AGENT_PID` and `wait -n $AGENT_PID` therefore monitored `sed`,
which stays alive until its stdin closes — long after the agent crashed.
Compounding that, `sed` buffers by default and Python agents buffer
their own stdout, so a stack trace at crash time was discarded when the
pipe closed.

Fix: process substitution instead of pipeline, plus `PYTHONUNBUFFERED=1`
at the entrypoint level:
```bash
cmd &> >(awk '{print "[agent] " $0; fflush()}') &
AGENT_PID=$!
```
Process substitution doesn't create a pipeline, so `$!` stays the
agent's PID. `awk` with `fflush()` line-flushes prefixed output
immediately.

Applied to all 17 starters via `generate-starters.ts` + the template.

### Cause 2a — hidden langgraph-fastapi crash

`generate-starters.ts` rewrites relative imports to absolute for
langgraph starters (langgraph_cli loads modules standalone, not as
packages). The rewrite was flat: `from .X import ...` -> `from
<agentDir>.X import ...`. For a file at
`<agentDir>/tools/get_weather.py`, `from .types import ...` resolves to
`tools.types` (the CURRENT package), not `<agentDir>.types`. The flat
rewrite dropped the `tools` segment and produced:
```
ModuleNotFoundError: No module named 'src.agents.types'
```
at import time. The agent crashed; the `sed` pipe bug swallowed the
traceback; the 2-3s sleep guard caught the window while `sed` was still
alive; `/api/health` reported `agent: "error"`.

Fix: make the rewrite subdir-aware — compute the file's containing
Python package from its relative path under `agentDest` and prepend that
to the relative import target. So `from .types import ...` inside
`src/agents/tools/get_weather.py` becomes `from src.agents.tools.types
import ...`.

langgraph-python had the same broken imports in `tools/__init__.py` but
doesn't crash at runtime because `main.py` doesn't import from `tools`
(dead path). Regenerating fixes the dead code too.

## Verification

### Middleware logic (reduced reproduction)

```python
# With HealthMiddleware installed above the routing layer:
app = FastAPI()
app.add_middleware(HealthMiddleware)
app.mount("/", mounted)

c.get("/health")      # 200 {"status": "ok"}   <- short-circuited
c.get("/anything")    # 200 agent-saw:/anything <- reaches mount
c.get("/")            # 200 agent-saw:/         <- reaches mount
```

### Tests
- `showcase/scripts` vitest: 1061/1061 passing
- `generate-starters.test.ts` (258) and `starter-consistency.test.ts`
(306) both still green — no test updates required

### Starters touched
- Cause 1 (HealthMiddleware): ag2, agno, claude-sdk-python,
crewai-crews, google-adk, langroid, llamaindex, ms-agent-python,
pydantic-ai, strands (10)
- Cause 2 (entrypoint PID): all 17 starters via generator + template
- Cause 2a (langgraph import): langgraph-fastapi (crash path),
langgraph-python (dead path)

## Commits

1. `fix(showcase/starters): serve /health via middleware to bypass
FastAPI mount shadow` — Cause 1
2. `fix(showcase/starters): capture real agent PID in entrypoint.sh +
unbuffer stderr` — Cause 2
3. `fix(showcase/starters/langgraph-fastapi): correct src.agents.tools.*
imports` — Cause 2a

## Test plan

- [ ] Docker build + run ag2: `curl -i http://localhost:3000/api/health`
returns 200 `{"status":"ok",...}`
- [ ] Docker build + run langgraph-fastapi: health OK, agent imports
succeed, no ModuleNotFoundError in logs
- [ ] Docker build + run langgraph-typescript: health OK
(entrypoint-only fix)
- [ ] Post-merge Railway: monitor all 17 starter health endpoints return
`status: "ok"` after redeploy
- [ ] Post-merge: inspect logs for any starter that still reports
`degraded` — with awk+fflush+PYTHONUNBUFFERED, the real import/crash
error should now surface in container logs

## Safety notes

- No `.github/workflows/*.yml` edits
- No force-push, no amend
- Author: Jordan Ritter <jordan@copilotkit.ai>
- Do NOT merge until reviewer approves
2026-04-19 10:39:15 -07:00
Jordan Ritter 05f181891d chore(showcase): ratchet validate-pins baseline for main (post-4095) (#4097)
## MERGE ASAP — main is RED

`Showcase validate` / `Run validate-pins (ratchet)` is failing on main
after PR #4095 (agno SDK upgrade) merged. This PR unblocks main CI.

## What drifted

Pure **set drift** — count unchanged, hash differs:

| field | before | after |
| --- | --- | --- |
| `validatePinsFailCount` | 110 | **110** (unchanged) |
| `validatePinsFailHash` | `c87ecdd6…a45560` | `958bcf24…4ae17` |

From failing run
[24632821166](https://github.com/CopilotKit/CopilotKit/actions/runs/24632821166):

```
validate-pins FAIL: actual=110 baseline=110
validate-pins HASH: actual=958bcf24c27cef69d7856e12deafe92073af7ad716289b2f6e4418827264ae17 baseline=c87ecdd6cc0829f8ef93c6e3cc4bb30aa3a577f99c5c8e9349b7c2dc78a45560
```

## Why

PR #4095 (`fix(showcase/agno): upgrade agno SDK to 2.5.17`) ratcheted
the hash against its own branch state, but other PRs merged in between
(#4094 google-adk, #4092 chown, etc.) shifted the baseline further. End
result: one `[FAIL]` healed while another regressed — net zero on the
counter but the failing tuples changed, so the hash no longer matches.

## What this PR does

Re-ratchets `showcase/scripts/fail-baseline.json` to the hash currently
produced by main. Count stays at 110.

## Risk

Minimal. Single field change in a JSON baseline file. No workflow edits.
No source changes. Does not hide new regressions — if any NEW failure
appears after this merges, the count (not just the hash) will bump and
CI will catch it.

## Test plan

- [x] Extracted actual hash from failing run output, not guessed
- [ ] CI green after merge (unblocks main)
2026-04-19 10:38:25 -07:00