Commit Graph

251 Commits

Author SHA1 Message Date
Alem Tuzlak 247f061456 fix(showcase/langgraph-python): disable inspector on voice demo for D5 parity
The voice demo's <CopilotKit> didn't pass enableInspector, so
shouldShowDevConsole(undefined) defaulted to isLocalhost(), which
auto-mounts <cpk-web-inspector> on any local Docker host
(localhost:3100 in showcase compose). The inspector overlay
intercepts pointer events on top of the voice sample-audio button,
so dev/D5 probe runs can't click it through Playwright.

Production isn't localhost, so the inspector never mounts there —
voice is D5 in prod and D4 locally for this reason alone. Set
enableInspector={false} explicitly so the demo behaves the same in
both environments.

Probe result: d5:langgraph-python/voice flips green.
2026-05-08 13:54:05 +02:00
Tyler Slaton 197c588c32 fix(showcase/langgraph-python): auth e2e spec uses v2 testid not v1 data-message-role
CR Round 3 final: my auth.spec.ts e2e was asserting on
[data-message-role="assistant"] which is the v1 react-ui RenderMessage
attribute. The auth demo uses v2 CopilotChat — its
CopilotChatAssistantMessage only emits data-testid="copilot-assistant-message".
The selector would never have matched and both tests would have
timed out at 30s when actually run.

Verified via grep:
- packages/react-core/src/v2/components/chat/CopilotChatAssistantMessage.tsx:192
  emits data-testid="copilot-assistant-message" (no data-message-role)
- packages/react-ui/src/components/chat/messages/RenderMessage.tsx:32,41
  emits data-message-role="user"/"assistant" (v1 path)
- All sibling specs in langgraph-python/tests/e2e/ correctly use
  data-testid="copilot-assistant-message"

One-character switch from data-message-role to data-testid with the
canonical v2 testid value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 19:47:22 -07:00
github-actions[bot] deb0b7394d style: auto-fix formatting 2026-05-08 00:52:19 +00:00
Tyler Slaton 8d39b53f6e fix(showcase): rework auth probe and e2e for unmount-based sign-out flow
The auth demo refactor flipped its lifecycle: unauthenticated is now
the default state, <CopilotKit> only mounts after sign-in, and
sign-out unmounts the entire chat tree (instead of leaving stale
auth headers in a still-mounted chat). The old probe + e2e spec
chased a 401-error-banner surface that no longer exists in the new
demo, plus a brittle 500ms hardcoded `useEffect` flush wait.

Probe rewrite (`d5-auth.ts` + tests):
- Add `buildAuthPreFill` that clicks the SignInCard's sign-in button
  before turn 1, then waits for the chat textarea to mount (proves
  <CopilotKit> handshook with the runtime).
- `buildAuthAssertion` now clicks sign-out, then waits for SignInCard
  to re-mount. The unmount marker IS the proof — no chat-send-and-401
  dance is needed (or possible — there's no chat to send into).
- Drop the hardcoded 500ms setTimeout, the unauth-banner wait, and
  the error-surface poll. None apply to the new flow.

E2E rewrite (`tests/e2e/auth.spec.ts`):
- "page loads unauthenticated with SignInCard visible"
- "signing in mounts the chat surface with AuthBanner"
- "authenticated send produces an assistant response"
- "signing out unmounts the chat tree and re-renders SignInCard"
- "signing back in re-mounts a fresh chat surface"

Fixture comment updated to reflect the new flow. The user message
("auth check turn 1") and content response are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:55:35 -07:00
Tyler Slaton 4f26734b4d fix(showcase): rewrite d5-gen-ui-headless-complete probe + fixture for new chip set
The headless-complete refactor replaced the old 5-chip set
(Weather/AAPL/Highlight/Sketch/Largest continent) with a new 4-chip
set wired through `useConfigureSuggestions`/SuggestionBar:

  Weather       → "What's the weather in Tokyo?"      → WeatherCard
  Stock price   → "What's the price of AAPL right now?" → StockCard
  Highlight a note → "Highlight this note for me: 'ship the demo on Friday'."
                                                       → HighlightNote
  Revenue chart → "Show me a chart of revenue over the last six months."
                                                       → ChartCard

Probe rewrite:
- Drop the wrapper-scoped chip selector (`[data-testid=
  "headless-suggestions"] >> text=...`) — the new SuggestionBar
  doesn't have that container testid. Click via plain `button >>
  text="<chip title>"` instead.
- Per-turn assert the matching tool card testid mounts
  (headless-weather-card, headless-stock-card, headless-highlight-card,
  headless-revenue-chart) plus a distinguishing text token. Driven
  off a TURN_EXPECTATIONS table so adding a chip is one entry.
- Drop the readMessagesText helper that scoped to a missing
  `[data-testid="headless-complete-messages"]` container; collect
  text by concatenating all `headless-message-assistant` bubbles.

Fixture rewrite:
- Drop the Excalidraw + Largest-continent entries (no longer in the
  chip set). Weather is already covered by feature-parity.json.
- Add a Revenue chart fixture for `get_revenue_chart` with inline
  data so ChartCard renders without backend.
- Stock + Highlight fixtures preserved (still match the new chip
  messages via substring).

Also restore `data-message-role` attributes on the headless-complete
UserBubble + AssistantBubble so the runner's settle plateau cascade
can resolve them — matches the runner's documented headless-template
contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:52:04 -07:00
Tyler Slaton 2d78a0f409 fix(showcase): rename gen-ui-headless D5 type to headless-simple and rewrite probe
The headless-simple demo was refactored to a deliberately minimal
"two hooks, one shadcn shell" template — text-in/text-out only, no
gen-UI. The D5 type literal `gen-ui-headless` no longer described
what the probe tests, and the old probe (Profile-card useComponent
+ continent fallback) was asserting against UI that no longer exists.

Three coordinated changes:

1. Rename `gen-ui-headless` D5FeatureType to `headless-simple` so the
   slug matches the demo. Updated d5-registry, REGISTRY_TO_D5,
   CATALOG_TO_D5_KEY (dashboard), and dependent tests/comments.
   `headless-complete` keeps its existing literal because that demo
   still drives the full gen-UI surface.

2. Replace d5-gen-ui-headless.{ts,test.ts,fixture} with
   d5-headless-simple.ts + headless-simple.json fixture. New probe
   clicks the "Say hello in one short sentence." chip and asserts the
   `[data-testid="headless-message-assistant"]` bubble mounts with
   non-empty content.

3. Restore `data-message-role` attributes on the headless-simple
   UserBubble + AssistantBubble. The runner's chat-input cascade
   documents these as the headless-template contract; the refactor
   dropped them, breaking the runner's settle plateau detection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:48:43 -07:00
Tyler Slaton 4e03a3f105 fix(showcase): expose data-slot-label on SlotMarker and use it in d5-chat-slots
The chat-slots refactor replaced the explicit `data-testid="custom-assistant-message"`
attribute with a SlotMarker wrapper component. The probe still asserted
the old testid which no longer exists, so the cell stuck at D4.

Add `data-slot-label={label}` to SlotMarker's outer span — idiomatic
data attribute that mirrors the existing `label` prop and gives the
probe a stable contract without restoring the legacy testid pattern.
The marker was already passing label="MessageView.AssistantMessage";
this just surfaces it in the DOM.

Update d5-chat-slots probe + test to assert
`[data-slot-label="MessageView.AssistantMessage"]`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:43:53 -07:00
Tyler Slaton c7be72308e fix(showcase): harden beautiful-chat toggleTheme against page-close races
Two related changes targeting the fc=97 'Target page closed' D5 failure
on `beautiful-chat-toggle-theme`:

1. Probe (`_beautiful-chat-shared.ts:assertToggleTheme`) — replace the
   manual 200ms `page.evaluate` poll over 30s with Playwright's
   `waitForFunction`. The native polling is event-driven inside the
   browser context, disconnects cleanly on page-close, and avoids
   ~150 round-trip evaluates per probe. The catch branch now checks
   `page.isClosed()` first and surfaces a diagnostic message naming
   the renderer-crash case explicitly, so operators don't have to
   guess what 'Target page closed' meant.

2. Demo (`use-generative-ui-examples.tsx`) — drop `[theme, setTheme]`
   from the `useFrontendTool` deps array. The handler reads `document`
   directly and the setter is stable across renders, so the deps
   array forced a re-registration after every theme flip. That race
   could collide with an in-flight tool result and surface as a
   renderer error during multi-turn sequences. Removing deps keeps
   the tool registration stable for the duration of the conversation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:33:27 -07:00
Alem Tuzlak 5d95e8e102 Merge branch 'main' into blitz/lgp-genuine-pass/integration 2026-05-07 21:17:15 +02:00
github-actions[bot] b13129b319 style: auto-fix formatting 2026-05-07 19:08:48 +00:00
Alem Tuzlak b7ac944315 fix(showcase/langgraph-python): surface explicit sentinel for empty sub-agent results
_invoke_sub_agent's last-resort branch silently returned '' or a
Python repr like \"[{'type': 'text', ...}]\" for block-list content,
which the UI would render as a blank/garbled card. Return a stable
SUB_AGENT_EMPTY_SENTINEL ('<sub-agent produced no output>') instead
so the d5-subagents probe can match it against its boilerplate-marker
list and fail the genuine-pass test loudly when a sub-agent produces
no usable output.
2026-05-07 20:55:13 +02:00
Alem Tuzlak 447c3d415f fix(showcase/langgraph-python): make get_stock_price deterministic via optional args
The get_stock_price tool returned randint-based price/change every
call, so e2e specs asserting $338.37 / -2.96% would only pass when
aimock short-circuited the entire call. The Python tool body still
runs server-side under aimock — only the LLM call is mocked.

Mirror the deterministic-`value` pattern on roll_d20: accept optional
price_usd / change_pct arguments and echo them back when present.
Defaults to random mock data when the args are omitted, preserving
the legacy live-LLM behaviour.
2026-05-07 20:54:49 +02:00
Alem Tuzlak abfbb803b8 fix(showcase): assert non-boilerplate hello in headless-simple spec
The HELLO_LEADING phrase was the showcase-assistant catch-all
boilerplate ('I can help you with weather lookups...') that other
tests in this PR explicitly guard AGAINST. The dedicated d5-all.json
fixture for 'Say hello in one short sentence' now returns a distinct
non-boilerplate greeting; the spec asserts that distinct phrase, so a
fixture-priority misroute fails loudly instead of passing by accident.
2026-05-07 20:54:36 +02:00
Alem Tuzlak ddb248034d fix(showcase/langgraph-python): restore useDefaultRenderTool() in default catchall cell
The blitz removed the explicit useDefaultRenderTool() call expecting a
framework-level fallback to handle zero-hook registrations, but the
integration uses the published @copilotkit/react-core@1.56.5 which does
not yet ship that fallback. Without the call, useRenderToolCall has no
'*' renderer and tool calls render invisibly — the user only sees the
agent's final text summary instead of the OOTB tool card.

Restore the explicit useDefaultRenderTool() invocation. The framework
fallback (committed in this PR but inert until react-core publishes a
release that includes it) becomes a no-op once that ships.
2026-05-07 19:57:48 +02:00
Alem Tuzlak 6ad6dfbbd1 Merge slot B8 into blitz/lgp-genuine-pass/integration
Resolved conflicts:
- d5-all.json: appended B8's 26 new fixture entries to the existing 131
- gen-ui-open.json: kept ours (B3's verbatim pill messages match the suggestions.ts pills); dropped B8's paraphrased fixtures
- d5-gen-ui-open.ts: kept B7's basic-only routing + B8's iframe-presence assertion logic; updated PILL_PROMPT_PREFIX to '3D axis visualization (model airplane)' so it matches the actual pill message
2026-05-07 18:22:52 +02:00
Alem Tuzlak 06989b977b Merge slot B6 into blitz/lgp-genuine-pass/integration
Resolved d5-all.json conflict by appending B6's headless-simple/complete fixtures (Say hello, joke, fun fact, Highlight, chart) before the tool-rendering and open-gen-ui entries already on integration.
2026-05-07 18:20:15 +02:00
Alem Tuzlak e8eaacee14 Merge slot B5 into blitz/lgp-genuine-pass/integration 2026-05-07 18:18:23 +02:00
Alem Tuzlak 4097b166eb Merge slot B4 into blitz/lgp-genuine-pass/integration 2026-05-07 18:18:22 +02:00
Alem Tuzlak d5615fed90 Merge slot B3 into blitz/lgp-genuine-pass/integration 2026-05-07 18:17:58 +02:00
Alem Tuzlak 92e405946d Merge slot B2 into blitz/lgp-genuine-pass/integration
Resolved d5-all.json conflict by appending B2's readonly-state-agent-context fixtures after B1's hitl-in-app and frontend-tools-async fixtures.
2026-05-07 18:17:42 +02:00
Alem Tuzlak 63aef191ff feat(showcase/langgraph-python): add testids and pills required by d5 probes
Adds production-code testids needed by the Phase-2B genuine D5 probes:

- frontend-tools/background.tsx: data-testid='frontend-tools-background'
  + data-background-value mirror so the probe can read the live gradient
  off the DOM without computing styles.
- declarative-gen-ui/a2ui/renderers.tsx: data-testid for Card,
  StatusBadge, Metric, PieChart, BarChart so per-pill probes can assert
  the expected catalog component painted.
- a2ui-fixed-schema/a2ui/renderers.tsx: data-testid='a2ui-fixed-card'
  on the Card override so the fixed-schema component-tree mount is
  observable without keyword-matching the transcript.

Each cell's Layer 1 spec is already green; this is purely additive — no
spec rewrites.
2026-05-07 18:14:13 +02:00
Alem Tuzlak 05395937fe test(showcase/langgraph-python): rewrite tool-rendering trio to pill-driven 6-test plans
All three tool-rendering cells now drive the suggestion pills directly
instead of typing free-form prompts that race fixture matchers:

- tool-rendering: 6 tests (page loads + 5 pills) — Weather in SF
  asserts SF city + deterministic temp/humidity/wind; Find flights
  asserts >=2 flight rows from the dedicated fixture; Stock price
  asserts AAPL $338.37 / -2.96%; Roll a d20 asserts exactly 5 d20
  cards with the 5th=20; Chain tools asserts weather+flights+d20
  cards mount from a single pill click.
- tool-rendering-default-catchall: 6 tests asserting the OOTB default
  tool-call renderer paints every tool call with data-testid=
  copilot-tool-render plus data-tool-name. Branded sibling-cell
  testids stay at zero. Test 6 asserts every card matches the
  built-in renderer DOM signature.
- tool-rendering-custom-catchall: 6 tests asserting the same
  custom-wildcard-card testid renders for every tool. Test 6 is the
  cross-tool snapshot — every tool kind paints via the same shell.
2026-05-07 17:55:20 +02:00
Alem Tuzlak ba60df5d33 feat(showcase/langgraph-python): add per-tool testids
Add stable testids and rendering surfaces for the three tool-rendering
cells so the e2e suite can distinguish each cell's strategy:

- tool-rendering: register useRenderTool for get_stock_price and
  roll_d20; new StockCard / D20Card components with testids
  stock-card / d20-card / stock-price / stock-change / d20-value.
  Rename FlightListCard testid flight-list-card -> flights-card.
- tool-rendering-default-catchall: drop the custom shadcn
  useDefaultRenderTool registration so the cell is truly zero
  custom-render-hooks. The framework's built-in
  DefaultToolCallRenderer now paints every tool call, with stable
  data-testid='copilot-tool-render' wrapper plus data-tool-name,
  data-args, and data-result attributes for inspection without
  expanding the card.
- tool-rendering-custom-catchall: rename the wildcard renderer's
  testids from custom-catchall-* to custom-wildcard-* so the cell
  is distinguishable from the (now-OOTB) default-catchall demo.
- packages/react-core: when no per-tool / wildcard renderer is
  registered, useRenderToolCall now falls back to the built-in
  DefaultToolCallRenderer instead of returning null.
2026-05-07 17:55:02 +02:00
Alem Tuzlak 7747033d68 fix(showcase/langgraph-python): mock d20 as 5 deterministic rolls
Replace the random roll_dice tool with roll_d20(value), which echoes
the LLM-supplied value back as the result. Aimock fixtures script the
five sequential calls returning [7, 14, 3, 19, 20] so the e2e suite can
assert exact values rather than rolling until 20 lands.

Update SYSTEM_PROMPT to allow multi-tool chaining when the user
explicitly asks for it (Chain tools pill emits 3 tool calls in one
turn).
2026-05-07 17:54:26 +02:00
Alem Tuzlak 6ce43eeaf6 test(showcase/langgraph-python): rewrite hitl-in-app and frontend-tools-async to genuine assertions
hitl-in-app — 7 explicit tests (1 skip):

- Page-load and pill-render tests retained.
- New refund #12345 approve/reject pair asserts the deterministic
  fixture leading phrases ("I am processing the $50 refund" vs
  "refund request was not approved").
- New escalate #12347 approve/reject pair asserts "Escalated ticket
  #12347" vs "Not escalated".
- The describe block runs in serial mode so the approve test
  (sequenceIndex 0 in the fixture) always runs before the reject test
  (sequenceIndex 1) for each pill.
- Downgrade #12346 stays skipped per spec (broken upstream as of
  2026-05-07).

frontend-tools-async — 4 explicit tests:

- Page-load test asserts composer + 3 pills.
- Project-planning, auth, and reading pills each click and assert the
  Notes DB card renders with the correct keyword heading and the
  per-note testid rows that the async handler returned. Anti-regression
  assertions catch the previous fixture-priority bugs (generic-plan
  boilerplate, showcase-assistant catch-all).
- Reading pill locks the full canonical shape per spec test #4: keyword,
  match count, note title, content lines, tag chip, and the assistant
  narration leading phrase.

No production-code testid changes — the existing dialog and notes-card
testids cover every assertion. Fixture work lives in d5-all.json (prior
commit).
2026-05-07 17:52:30 +02:00
Alem Tuzlak 390ab6fbbc test(showcase/langgraph-python): rewrite subagents to 5 deterministic 3-card tests
- Drop the 8 stale tests that asserted travel-planner shapes
  (Current Itinerary / supervisor-indicator / .bg-gray-50). They
  predated the supervisor + 3-subagent rewrite and could not catch
  the 3 production bugs.
- New suite (5 tests, 0 skipped):
    1) page loads with composer + 3 verbatim suggestion pills + 3
       subagent role indicators (testid-based).
    2-4) one test per pill (Write a blog post / Explain a topic /
       Summarize a topic). Each clicks the pill, waits for all
       three role-scoped subagent cards to reach data-status=
       "complete", then asserts each card's subagent-result is
       non-empty AND does not contain the showcase-assistant
       boilerplate fragments. Test 4 also serves as a regression
       gate on the delegations reducer fix — without it, that pill
       returns HTTP 400 and the cards never reach complete.
    5) clicks any pill, waits for terminal state, then asserts the
       critic-card count is exactly 1 and stays at 1 with status
       complete across a 5s dwell — catches any return of the
       supervisor -> critic loop.
- Aimock fixtures: 3 verbatim pill chains (cold exposure training,
  LLM tool calling, reusable rockets) added to both d5-all.json and
  the harness source d5/mcp-subagents.json. Each chain drives the
  full supervisor flow (turnIndex 0..3) plus three nested sub-agent
  fixtures so every Researcher/Writer/Critic card surfaces real
  prose instead of showcase boilerplate.
2026-05-07 17:52:02 +02:00
Alem Tuzlak a6f1076cf5 test(showcase/langgraph-python): rewrite open-gen-ui and open-gen-ui-advanced to iframe-presence assertions
Drop the 5 cross-origin contentFrame() / page.on('console', ...) skipped
assertions across the two specs — sandbox=allow-scripts only blocks host
introspection of the iframe DOM, and console-spying on the host page
catches no inner-iframe logs. Replace with iframe-presence assertions:
each pill click must produce iframe[sandbox*='allow-scripts'] with a
non-empty srcdoc (or src) attribute. That is the load-bearing signal
that the open-generative-ui pipeline mounted SOMETHING.

Rewrite each suggestion message string as a short verbatim label that
doubles as a deterministic aimock fixture key (paired with the new
fixtures in showcase/aimock/d5-all.json). Drop pill-title parentheticals
per the cosmetic note in lgp-test-genuine-pass.md so titles read as
natural human prompts; keep the message field aligned with the fixture
key.

Final test counts: 5 minimal (page-load + 4 pill-iframe), 4 advanced
(page-load + 3 pill-iframe). All .skip() removed. The sandbox-function
round-trip (evaluateExpression / notifyHost) is intentionally not
asserted here — that requires a same-origin sandbox option or a
host-side spy on the runtime's sandbox-function-call event, both
deferred to a follow-up.
2026-05-07 17:51:44 +02:00
Alem Tuzlak 9b3d64dda4 feat(showcase/langgraph-python): add subagent-card and subagent-result testids
- subagent-activity-card: emit data-testid="subagent-card-<role>" on
  each card wrapper (researcher | writer | critic), data-testid=
  "subagent-result" on the Result content div, and data-testid=
  "subagent-status" on the status pill. The previous testids
  (subagent-activity-card, subagent-activity-result) collapsed across
  roles, so the e2e suite couldn't count or content-assert per role.
- delegation-log: render a fixed row of 3 always-visible role
  indicators (data-testid="subagent-indicator-<role>") so the page
  exposes a stable hook for the load-state assertion regardless of
  whether the supervisor has delegated yet.
2026-05-07 17:51:40 +02:00
Alem Tuzlak 527e46c5d9 fix(showcase/langgraph-python): fix subagents delegations reducer, single-critic cap, and Result-echo boilerplate
- Annotate AgentState.delegations with operator.add reducer so concurrent
  sub-agent emissions in one supervisor step accumulate instead of
  raising INVALID_CONCURRENT_GRAPH_UPDATE (HTTP 400 on the Summarize pill).
- Update _delegation_update to return only the new entry (the reducer
  concatenates) instead of echoing the full prior list, which would
  duplicate entries each step under operator.add.
- Cap supervisor -> critique_agent loop at _MAX_CRITIQUE_ITERATIONS
  (default 1). Re-entrant critique calls short-circuit with a finish-now
  ToolMessage and do not append a second delegation, so the UI shows
  exactly one critic card per supervisor run.
- _invoke_sub_agent now walks messages newest-first and returns the
  first non-empty AIMessage content (handles list-of-content-blocks
  shape too). Prevents the previous failure mode where a final empty
  AIMessage made the card Result blank or echoed the showcase-assistant
  intro.
- Strengthen supervisor system prompt: each sub-agent must be called
  exactly once, with no further calls after critique returns.
2026-05-07 17:51:19 +02:00
Alem Tuzlak c7b65e9ec7 test(showcase/langgraph-python): rewrite headless-simple and headless-complete to deterministic pill-driven tests
Rewrites both headless specs to the pill-driven plan from
.claude/specs/lgp-test-genuine-pass.md (Family-1F).

headless-simple (4 tests):
1. page loads with custom composer + 3 pills visible
2. hello pill -> assistant bubble starts with the greeting leading phrase
3. joke pill -> assistant bubble contains the deterministic joke
4. fun fact pill -> assistant bubble contains 'Honey never spoils!'

headless-complete (5 tests):
1. page loads with custom composer + 4 pills visible
2. weather pill -> WeatherCard with Tokyo / Sunny / 68F + narration
3. AAPL pill -> StockCard with AAPL / $189.42 / +1.27% + narration
4. highlight pill -> HighlightNote with 'ship the demo on Friday' + narration
5. revenue chart pill -> ChartCard with 'Quarterly revenue', subtitle,
   month labels Jan-Jun + narration

Each test asserts on the headless-specific testids introduced in the
preceding commit, so a regression that demotes the headless surface
back to the default CopilotChat surface fails every tool test. Each
pill exercises a different render-hook path so regressions surface
test-by-test.

No .skip() — all 9 tests are live.
2026-05-07 17:46:47 +02:00
Alem Tuzlak cb1b8bfaf6 feat(showcase/langgraph-python): add headless surface testids
Adds stable data-testid hooks on the hand-rolled headless chat surface
shared by headless-simple and headless-complete so e2e specs can target
the headless surface (and not the default CopilotChat surface) by
selector.

Shared:
- 'headless-message-assistant' on the custom assistant bubble
- 'headless-message-user' on the custom user bubble
- 'headless-composer' on the composer container

headless-complete only:
- 'headless-weather-card' on the WeatherCard rendered via useRenderTool
- 'headless-stock-card' on the StockCard
- 'headless-highlight-card' on the HighlightNote rendered via useComponent
- 'headless-revenue-chart' on the ChartCard

If the headless surface ever silently regresses to the default
CopilotChat surface, the headless-specific testids are absent and the
spec fails. Each tool-card testid is scoped per-component so a regression
in a single render hook fails only that test.
2026-05-07 17:46:25 +02:00
Alem Tuzlak c3d8fdc14f test(showcase/langgraph-python): rewrite readonly-state-agent-context to 5 deterministic tests
Replace the previous 4-test (2 active, 2 skipped) suite with a
5-test deterministic plan keyed off the demo's actual published
context defaults and pill verbatim prompts.

Tests:
1. page loads — context-card + composer render
2. edits propagate to JSON — type into name/timezone, JSON updates
3. "Who am I?" pill — assistant reply leads with "I see you're Atai"
   and the identity card has name=Atai, timezone=America/Los_Angeles,
   avatar text=A (defaults from page.tsx)
4. activity checkboxes default-checked — "viewed the pricing page"
   and "watched the product demo video" are checked on first paint
5. "Suggest next steps" pill — assistant reply leads with "Since
   you recently viewed the pricing page and watched the product
   demo video"

Tests 3 and 5 rely on the deterministic aimock fixtures added in
the previous commit. Tests 4 uses the new activity-<slug> testids.
0 .skip() remaining.
2026-05-07 17:46:11 +02:00
Alem Tuzlak f1d55a40f5 feat(showcase/langgraph-python): add identity testids and aimock fixtures for readonly-state-agent-context
Add four production-code testids on demo-layout.tsx:
- identity-name on the user-name display
- identity-timezone on the timezone display
- identity-avatar on the first-letter avatar circle
- activity-<slug> on each activity <label>, kebab-case of activity name

These let Playwright lock the identity card against the published
context defaults (Atai, America/Los_Angeles, A) and assert the
default-checked activity rows ("Viewed the pricing page", "Watched
the product demo video") without depending on assistant text.

Add two verbatim-prompt aimock fixtures to showcase/aimock/d5-all.json
for the demo's suggestion pills:

- "What do you know about me from my context?" leading phrase
  "I see you're Atai, and you're in the America/Los_Angeles timezone.
  Recently, you viewed the pricing page and watched the product demo
  video."
- "Based on my recent activity, what should I try next?" leading phrase
  "Since you recently viewed the pricing page and watched the product
  demo video, ..."

Pinned to the verbatim message bodies so they don't contend with the
showcase-assistant catch-all fixture.
2026-05-07 17:45:34 +02:00
Alem Tuzlak 265c1567bf chore(showcase/langgraph-python): Phase 0 cleanup of orphans and dead probes
- delete orphan e2e specs (hitl, interrupt-headless,
  tool-rendering-reasoning-chain)
- rename reasoning-default-render → reasoning-default (route + describe)
- delete dead D5 probes (hitl-steps, interrupt-headless,
  tool-rendering-reasoning-chain)
- update d5-feature-mapping: rename agentic-chat-reasoning →
  reasoning-custom and reasoning-default-render → reasoning-default;
  repoint hitl + hitl-in-chat-booking to hitl-text-input (still used by
  ag2/agno/built-in-agent)
- update d5-registry: drop hitl-steps, interrupt-headless,
  tool-rendering-reasoning-chain feature types
- update d5-reasoning-display preNavigateRoute branch logic and tests
- update probes.test.ts and e2e-deep.test.ts to use surviving feature
  types
2026-05-07 17:18:21 +02:00
Alem Tuzlak bbe128ca65 fix(showcase): repair langgraph-python manifest highlight paths and bump test snapshots
Three highlight paths in langgraph-python's manifest pointed at files
that don't exist after the PR #4694 reorganization:
  - hitl-in-chat → src/agents/hitl_in_chat.py (actually hitl_in_chat_agent.py)
  - chat-slots → custom-welcome-screen.tsx (file doesn't exist; use slot-wrappers.tsx)
  - mcp-apps → copilotkit-mcp-apps/route.ts (actually .../[[...slug]]/route.ts)

The bundler walks every highlight at build time; one missing path aborts
the whole CI step. Fix all three.

Test snapshot counts in generate-catalog and generate-registry hardcoded
40 features / 720 cells / 702 total. With the two new feature IDs added
to the registry (reasoning-default + reasoning-custom), counts shift to
42 / 756 / 738; the LGP-specific cell distribution moved from
39 wired + 1 stub + 0 unshipped to 35 wired + 1 stub + 6 unshipped, and
the registry-side LGP feature/demo count drops to 36 (PR #4694 trimmed
4 items from the manifest's features list).
2026-05-07 14:30:45 +02:00
Alem Tuzlak 621c4e3bd1 fix(showcase/langgraph-python): copy manifest.yaml into runtime image
The demos layout's `generateMetadata` calls `headers()` (forces dynamic
rendering) and reads `manifest.yaml` at request time for per-demo titles.
The Dockerfile's runner stage didn't include the manifest, so every
`/demos/*` route in production threw a Server Components render error
(ENOENT on /app/manifest.yaml). The home page was unaffected because it
has no dynamic APIs and gets statically prerendered at build time.

Add a single COPY of `manifest.yaml` into the runner stage.
2026-05-07 13:55:39 +02:00
github-actions[bot] f9cef5048d style: auto-fix formatting 2026-05-07 08:35:24 +00:00
Tyler Slaton f85c1f8328 chore(showcase/langgraph-python): prune dead dependencies
The branch's iteration arc went through several headless-demo
implementations (CSS Modules, AI Elements, prompt-kit, shadcn) and a
streaming-markdown experiment with `streamdown`. After the spec
narrowed to shadcn-only and `react-markdown` for assistant rendering,
those component libraries and their satellite packages were left
installed but unused.

Removed (zero importers across `src/`):
- @copilotkit/react-ui (v1 UI; the showcase consumes /v2 hooks only)
- @rive-app/react-webgl2 (animations, never wired)
- @streamdown/cjk, /code, /math, /mermaid + streamdown (replaced by
  react-markdown for assistant content)
- @xyflow/react (graph viz, never wired)
- ai (Vercel AI SDK, was the AI Elements demo's transport)
- ansi-to-react (terminal output, never wired)
- marked (alternative markdown parser, never wired)
- media-chrome (media player UI, never wired)
- motion (animation library, was a prompt-kit demo dep)
- nanoid (we use crypto.randomUUID())
- react-jsx-parser (never wired)
- remark-breaks (markdown extension, never wired)
- shiki (syntax highlighting, never wired)
- tokenlens (never wired)
- use-stick-to-bottom (was an AI Elements dep)
- @radix-ui/react-use-controllable-state (no importers)

Kept everything actually imported: shadcn primitive surface intact
(class-variance-authority, cmdk, embla-carousel-react, lucide-react,
radix-ui umbrella + per-package @radix-ui/react-checkbox /
react-separator for beautiful-chat's local components), CopilotKit v2,
Hashbrown + json-render BYOC catalogs, recharts, react-markdown +
remark-gfm, openai (voice route), yaml (manifest parsing), zod.

Build still green at 54 routes. Lockfile updated. tsconfig.json
`jsx: "preserve"` — Next 15 reset this from `react-jsx` automatically
on build.
2026-05-06 23:32:47 -07:00
Tyler Slaton ebad989855 chore(showcase/langgraph-python): manifest, runtime, e2e, cleanup
Cross-cutting changes that don't belong with any one demo: manifest +
landing-page tags, runtime route adjustments, e2e + QA notes that
follow the demo renames, and a few small cleanups.

Manifest (manifest.yaml + src/app/page.tsx tag labels):
- Naming convention: every demo uses `Thing: Subthing` (Generative UI:
  Tool Rendering - Default / Custom Default / Specific; Open Generative
  UI: Default / Advanced; Shared State: Streaming / Read + Write;
  Reasoning: Default / Custom; Frontend Tools: In-App Actions / Async;
  Human in the Loop: In-chat / In-App / Interrupt based; Chat
  Customization: CSS / Slots; Headless UI: Simple / Complete).
- Retags: Auth → `platform`; HITL Step Selection + Interrupt-based →
  `interactivity`; Reasoning Default + Custom → `chat-ui`; Generative
  UI: Tools → `generative-ui`.
- Renames: Readonly State (Agent Context) → Frontend Context Sharing.
- HITL slot points at /demos/hitl-in-chat (working
  useHumanInTheLoop+interrupt path) instead of the previous
  /demos/hitl that had no backend `interrupt()` calls.
- Highlight paths corrected for the rebuilt headless demos (root-level
  paths replaced with hooks/, chat/, tools/, attachments/ subdirs).
- Descriptions rewritten where they had drifted from the implementation
  (gen-ui-agent: dropped useCoAgentStateRender claim;
  headless-simple: shadcn primitives, not raw Tailwind;
  headless-complete: enumerates the actual hooks wired).

Runtime / route:
- src/app/api/copilotkit/route.ts — 30 agents registered (incl. the
  reasoning-custom rename from agentic-chat-reasoning).
- copilotkit-mcp-apps/route.ts replaced with [[...slug]]/route.ts so v2
  subpath POSTs (/v2/agent/run) resolve.
- src/app/api/copilotkit-voice/[[...slug]]/route.ts — env var standardized
  (was `AGENT_URL || LANGGRAPH_DEPLOYMENT_URL`, now matches the rest
  of the showcase with just LANGGRAPH_DEPLOYMENT_URL); trailing `/`
  removed from deploymentUrl.

Tests / QA:
- e2e specs renamed and paths updated for the demo renames.
- qa notes for a2ui-fixed-schema (booked-state checklist removed) and
  byoc-json-render (Wave 4a residue removed).
- docs-links.json key renamed for reasoning-custom.

Cleanup:
- Removed remaining stub agent.py files in demo dirs (real graphs in
  src/agents/); removed dead beautiful-chat/components/headless-chat.tsx
  (zero importers); removed [A2UI-DEBUG] / [A2UI-RESPONSE] print
  statements from beautiful_chat.py; gpt-5.4-mini → gpt-5-mini typo
  fix in beautiful_chat.py:249 (would have 4xx'd every model call);
  stripped iframe-restriction LLM-prompt copy bleed from
  open-gen-ui-advanced suggestion titles.

The convention pass that ran across ~28 demos earlier in this branch is
already reflected in their per-demo commits — every page.tsx reads as
imports + provider + suggestions hook + JSX, with `useConfigureSuggestions`
extracted to a sibling suggestions.ts.
2026-05-06 23:19:57 -07:00
Tyler Slaton 7a380ecbeb feat(showcase/langgraph-python): Platform — Auth + Agent Config
Two demos that showcase how a platform team integrates CopilotKit:
auth gating and runtime config injection.

Auth — defaults UNAUTHENTICATED. First paint is a centered shadcn Card
with the demo token visible (`demo-token-123`) and a "Sign in" button.
<CopilotKit> doesn't mount until the user signs in; clicking the button
stores the token in localStorage and triggers a re-render that mounts
the chat with `Authorization: Bearer <token>` header attached. Reload
preserves the token; sign-out clears it and returns to the card.

Earlier drafts of this demo defaulted to authenticated with a
ChatErrorBoundary + onError-driven banner to recover from <CopilotChat>
's 401-on-mount crash. Both have been removed — gating the chat behind
`isAuthenticated` means it never mounts with bad creds, so the boundary
has no purpose.

Backend route uses `createCopilotRuntimeHandler` from
@copilotkit/runtime/v2 directly because the Next.js adapter does not
forward `hooks`. The `onRequest` hook validates the bearer token and
throws a Response(401) on missing/wrong tokens.

Agent Config — typed knobs (tone / expertise / responseLength) that
change the agent's behavior per turn. Pivoted to `useAgentContext` from
the original `<CopilotKit properties={...}>` transport, which silently
dropped the values in @ag-ui/langgraph 0.0.31 — those payloads landed
at the top level of the LangGraph stream and weren't routed into
RunnableConfig["configurable"]. A prior workaround that repacked them
there triggered LangGraph 0.6's "cannot specify both configurable and
context" 400.

useAgentContext is the supported LangGraph 0.6+ path for "frontend →
agent runtime context." A small ConfigContextRelay component sits inside
the provider and publishes the live toggles. The Python graph collapses
to a single static system prompt with three rulebooks; CopilotKitMiddleware
injects the context entry into the model's prompt automatically.
2026-05-06 23:19:16 -07:00
Tyler Slaton a78e6bddc7 feat(showcase/langgraph-python): Shared State + Sub-Agents
Four state-flow demos plus the multi-agent demo, all sharing the
page-as-entry-point convention with extracted suggestions.

- shared-state-streaming (Shared State: Streaming) —
  StateStreamingMiddleware(state_key="document", tool="write_document",
  tool_argument="document"). The argument name MUST match the state_key
  for the partial-JSON streamer to index correctly. Fixed in this pass
  (previous version had a name mismatch). Frontend renders `LIVE` badge
  + char counter so per-token streaming is visible.
- shared-state-read-write (Shared State: Read + Write) — bidirectional.
  UI writes preferences via `agent.setState`; agent writes notes via a
  `set_notes` tool that returns Command(update={...}). PreferencesInjector
  middleware reads the state on every turn and injects it as a system
  message. CopilotPopup layout, 2-col card UI, "Agent Scratch pad"
  copy.
- shared-state-read (deprecated route stub) — kept for back-compat with
  any external links; the canonical demo is shared-state-read-write.
- readonly-state-agent-context (Frontend Context Sharing) — frontend
  publishes read-only context via useAgentContext (the LangGraph 0.6+
  idiom). Backend has tools=[] and only CopilotKitMiddleware; read-only
  is enforced by the absence of any state-write tool, not a flag.

- subagents (Sub-Agents) — supervisor + research / writer / critic
  sub-agents. Per-tool useRenderTool registrations surface delegation
  events to the chat. State has a delegations[] log; the Python side
  only writes status="completed" so the type was tightened (dropped
  unused "running" / "failed" legs from both Python TypedDict and the
  TypeScript shape). Frontend infers active sub-agent from in-flight
  tool calls via a defensive structural probe over agent.messages.
2026-05-06 23:18:51 -07:00
Tyler Slaton a7a6a5c6fd feat(showcase/langgraph-python): Declarative UI + BYOC + Open Generative UI
A single commit for the "agent-authored UI" cluster — five distinct
strategies, all sharing a common shape (declare a catalog, let the
agent pick + populate components):

- declarative-gen-ui (Declarative UI: A2UI) — A2UI dynamic schema. The
  agent calls `generate_a2ui` (not the runtime's auto-injected
  `render_a2ui`) which secondary-binds an internal render tool with
  forced tool_choice, then returns operations via `a2ui.render(...)`.
  Custom catalog (Card / StatusBadge / Metric / InfoRow / PrimaryButton
  / PieChart / BarChart) wired via `a2ui.catalog` on the provider.
- a2ui-fixed-schema (Declarative UI: A2UI Fixed Schema) — fixed
  server-side schema. The "Book flight" button is an inert label; the
  earlier draft tried a schema swap to a booked-confirmation but the
  SDK doesn't yet expose `action_handlers` from Python. Removed
  BOOKED_SCHEMA + booked_schema.json since they were dead weight.
  Cleaned 8 (props as Record<string, any>) casts down to a single
  shared `s()` helper.
- mcp-apps — MCP server-driven UI via activity renderers. The runtime's
  `mcpApps.servers` config wires Excalidraw; agent has tools=[] and
  the middleware emits activity events that the built-in
  MCPAppsActivityRenderer auto-mounts as a sandboxed iframe.
- byoc-hashbrown (Declarative UI: Hashbrown) — streaming structured
  output via @hashbrownai/react. Agent prompt locks output to JSON via
  `response_format: json_object` with a `{ ui: [{ tag: { props } }] }`
  contract. Custom slot override on messageView.assistantMessage parses
  the streaming JSON.
- byoc-json-render (Declarative UI: json-render) — streaming hierarchical
  JSON UI spec via @json-render/react with a Zod-validated catalog.
  Catalog (defineCatalog) + registry (defineRegistry) split keeps the
  schema as the single source of truth.
- open-gen-ui (Open Generative UI: Default) — runtime's
  `openGenerativeUI` config injects a sandboxed UI tool; design-skill
  override steers the agent toward educational visualizations. Built-in
  OpenGenerativeUIActivityRenderer auto-mounts.
- open-gen-ui-advanced (Open Generative UI: Advanced) — adds frontend
  sandboxFunctions registered on the provider; each Zod-typed handler
  is exposed to the iframe via the host bridge. Suggestion titles read
  as normal user prompts (no iframe-restriction LLM-prompt copy bleed).

Backends sit at src/agents/{a2ui_fixed,byoc_hashbrown_agent,
byoc_json_render_agent}.py and the MCP runtime at
src/app/api/copilotkit-byoc-hashbrown/route.ts.
2026-05-06 23:18:18 -07:00
Tyler Slaton 8ad38cfdf2 feat(showcase/langgraph-python): Generative UI tool-rendering family
Five demos exercising the per-tool / catch-all / agent-state rendering
patterns. The three tool-rendering cells share the tool_rendering_agent
graph; they differ only in how the frontend renders the same tool
calls.

- tool-rendering (Tool Rendering - Specific) — per-tool useRenderTool
  for get_weather + search_flights, plus a useDefaultRenderTool wildcard
  for everything else.
- tool-rendering-default-catchall (Tool Rendering - Default) — single
  shadcn-styled wildcard via useDefaultRenderTool. Without registering
  *some* renderer the runtime has no `*` entry and tool calls render
  invisibly; this demo shows the minimum-viable shape.
- tool-rendering-custom-catchall (Tool Rendering - Custom Default) —
  same single-wildcard shape, branded with a custom card.

Backend system prompt (src/agents/tool_rendering_agent.py) defaults to
ONE tool per user question. Chaining is opt-in via a "Chain tools"
suggestion that triggers an explicit-ask exception in the prompt — the
previous default-on-chaining generated extra unsolicited tool-call
cards on every turn.

- gen-ui-tool-based (Generative UI: useComponent) — useComponent for
  render_bar_chart + render_pie_chart with Zod schemas; backend has
  tools=[] and the runtime injects the tools.
- gen-ui-agent (Generative UI: Agent State) — agent-state-driven step
  list. The Python graph plans steps via a `set_steps` tool that
  returns Command(update={"steps": …}); the frontend reads via
  useAgent({updates: [OnStateChanged]}) + a custom MessageList that
  renders steps inside CopilotChat's messageView.children slot.

Removed: src/app/demos/{tool-rendering,gen-ui-agent}/agent.py — TODO
stubs; real graphs live in src/agents/.
2026-05-06 23:17:45 -07:00
Tyler Slaton 9e40b1bf64 feat(showcase/langgraph-python): Frontend Tools + HITL family
Frontend Tools (in-app + async) demonstrate the spectrum of agent →
client tool calls:

- frontend-tools — useFrontendTool with a synchronous handler that
  mutates page state. The agent calls `change_background` with any CSS
  background value and the canvas re-paints. <CopilotSidebar /> layout;
  default background is solid indigo so the canvas reads as a clean
  start.
- frontend-tools-async — useFrontendTool with an async handler. The
  agent calls `query_notes`, the handler awaits a 500ms simulated DB
  query, and the agent uses the returned notes in its reply. Pure
  frontend tool — backend has tools=[].

HITL family — three patterns for human-in-the-loop, all keyed on the
useHumanInTheLoop / useInterrupt primitives:

- hitl — step-feedback variant rendering inside the chat via
  useHumanInTheLoop + useInterrupt (the v2 replacement for
  useLangGraphInterrupt, which is not exported in v2).
- hitl-in-chat — time-slot picker variant. Backend graph (hitl_in_chat)
  calls `interrupt({slots, …})` and resumes when the user picks. This
  is the canonical "in-chat HITL" demo; the manifest entry points here.
- hitl-in-app — async useFrontendTool with an app-LEVEL approval modal
  (rendered via createPortal OUTSIDE the chat). The completion callback
  resolves the pending tool Promise with the user's decision. This is
  HITL where the human surface is your app's UI, not the chat.
- gen-ui-interrupt — the lower-level useInterrupt primitive. Backend
  (src/agents/interrupt_agent.py) has a real `schedule_meeting` tool
  that emits an interrupt with topic / attendee / slots, and the
  frontend renders an inline TimePickerCard.
2026-05-06 23:17:21 -07:00
Tyler Slaton 3e157a1e02 feat(showcase/langgraph-python): Multimodal + Voice + Beautiful Chat
Three "production-feel" chat demos that exercise the same convention
(page.tsx as entry point + suggestions extracted) and add their own
specialized hooks:

- multimodal — image + PDF uploads via CopilotChat attachments. Includes
  a LegacyConverterShim (until @ag-ui/langgraph ships an updated
  converter), magic-byte + LFS-pointer guard for safe content sniffing,
  and sample-attachment-buttons that inject test images via DataTransfer
  + dispatch `change` event so screenshots / Playwright reproduce.
- voice — speech-to-text via @copilotkit/voice. Uses the V2 runtime
  directly with [[...slug]] catch-all because `transcriptionService` is
  V2-only. A guarded sample-audio-button injects deterministic sample
  text via the textarea's native value setter (CopilotChat has no
  controlled-input prop today). useSingleEndpoint={false} opts into the
  V2 multi-endpoint protocol.
- beautiful-chat — flagship polished starter chat with brand fonts,
  theme tokens, suggestion pills, generative-UI charts, and
  enableAppMode / enableChatMode tools. Backend
  (src/agents/beautiful_chat.py) wires query_data, manage_todos,
  search_flights, and an A2UI dynamic generator (generate_a2ui) that
  hits a secondary LLM for schema design. Model: gpt-5-mini.

The convention pass extracted suggestions into separate files for each
demo and slimmed page.tsx down to imports + provider + render.
2026-05-06 23:17:00 -07:00
Tyler Slaton 4737eb46f1 feat(showcase/langgraph-python): Prebuilt — CopilotChat / Sidebar / Popup
Three demos showing the prebuilt component formats. All three share the
neutral assistant graph and follow the page-as-entry-point convention:
each page.tsx slimmed to imports + provider + the suggestions hook
mount + JSX, with `useConfigureSuggestions` extracted to its own file.

- agentic-chat (Prebuilt: CopilotChat) — full-page CopilotChat. Plain
  text suggestions (joke / fun fact / limerick) — earlier drafts had a
  "Weather in Paris" prompt but the agent has no weather tool; trimmed
  to non-tool prompts so suggestions actually work.
- prebuilt-sidebar (Pre-Built: Sidebar) — <CopilotSidebar /> docked to
  the edge of the viewport. Page content centered in mx-auto max-w-2xl
  column with icon + heading + paragraph. The sidebar genuinely PUSHES
  the page now — see the body width fix in src/app/globals.css from the
  scaffolding commit.
- prebuilt-popup (Pre-Built: Popup) — <CopilotPopup /> with a floating
  launcher. Same centered content shape as the sidebar demo.

Removed: src/app/demos/agentic-chat/agent.py — TODO stub with a
misleading docstring; the real graph is at src/agents/agentic_chat.py.
2026-05-06 23:16:40 -07:00
Tyler Slaton ac89b11efd feat(showcase/langgraph-python): Reasoning - Default + Custom
A pair of demos that exercise the same backend reasoning graph but
differ only in whether the frontend overrides the
`messageView.reasoningMessage` slot.

Backend (src/agents/reasoning_agent.py): uses a reasoning-capable OpenAI
model (gpt-5-mini by default, override via OPENAI_REASONING_MODEL) routed
through the Responses API so the model's chain-of-thought streams as
AG-UI REASONING_MESSAGE_* events with `role: "reasoning"`. The prompt
asks for a concrete physics answer, which reliably triggers reasoning;
meta-prompts like "show your reasoning step by step" produce no
reasoning summary because the model recognizes those as a request to
reveal chain-of-thought (which it refuses).

Frontend:
- reasoning-default/ — no slot override; built-in
  CopilotChatReasoningMessage renders the "Thinking… / Thought for X"
  header with an expandable content region.
- reasoning-custom/ — overrides `messageView.reasoningMessage` with a
  ReasoningBlock (amber banner with `data-testid="reasoning-block"`).
  The label flips from "Thinking…" while streaming to "Agent reasoning"
  once the stream settles.

Suggestions live in their own files (per the page-as-entry-point
convention). Both demos share `agent="reasoning-default"` /
`agent="reasoning-custom"` against the same `reasoning_agent` graph,
registered in api/copilotkit/route.ts.

Removed:
- src/app/demos/agentic-chat-reasoning/ — replaced by reasoning-custom/
  for naming clarity.
- src/app/demos/reasoning-default-render/ — earlier draft of the Default
  demo with a slightly different page name.
- tests/e2e/agentic-chat-reasoning.spec.ts — replaced by
  reasoning-custom.spec.ts.
2026-05-06 23:16:13 -07:00
Tyler Slaton 4ff8dd608c feat(showcase/langgraph-python): chat customization (CSS + Slots)
Two paired demos showing the spectrum of "change the look" without
rewriting components:

CSS theming (chat-customization-css/) — HALCYON, a warm-paper editorial
brand. Two layers do the work:
  1. v2 token overrides on `[data-copilotkit]` recolor every Tailwind
     utility (cpk:bg-muted, cpk:text-foreground, …) the runtime renders.
  2. Class-targeted styling on .copilotKitChat, .copilotKitMessage*,
     .copilotKitInput, suggestions, scrollbar, welcome screen for the
     editorial details that CSS variables alone can't express.
Aesthetic: cream parchment surface, sharp 90° corners, copper-ember
accents, italic display serif (Instrument Serif) + Fraunces body +
JetBrains Mono dispatch, paper-grain noise via inline SVG, mono masthead
pinned under the top edge. All selectors namespaced under
`.chat-css-demo-scope` — no leakage.

Slot atlas (chat-slots/) — every overrideable slot wrapped in a
dashed-outline marker. Markers nest correctly: each shows ONLY its own
label on hover via `:has(.slot-marker:hover)` rather than lighting up
every nested label as the cursor enters the outermost one. Each label is
a click-to-copy button (✓ flash on success) that copies the slot's
PascalCase component path (`Input.TextArea`,
`MessageView.AssistantMessage`, …) so a developer can paste straight
into IDE search. SuggestionPill, ScrollToBottomButton, and Feather slots
are all wired. CustomFeather has its own `FeatherCopyLabel` because the
default Feather uses position:absolute and can't share SlotMarker.

Both demos use the neutral assistant graph (chat-customization-css and
chat-slots are entries in the route.ts neutralAssistantCells list).
2026-05-06 23:15:49 -07:00
Tyler Slaton bd9da67c48 feat(showcase/langgraph-python): rebuild Headless UI: Complete (modular)
Full headless surface — a hand-rolled CopilotChat replacement that wires
every render hook on top of shadcn/ui primitives. Visual chrome matches
Headless: Simple so the two read as a paired sibling demo.

Architecture is progressive-disclosure: the entry file is a 30-line
HeadlessCompleteRoot that enumerates capabilities, each registered via
a focused hook module:

  page.tsx
  hooks/
    use-tool-renderers.tsx     — useRenderTool x3, useDefaultRenderTool
    use-frontend-components.ts — useComponent (highlight_note)
    use-headless-suggestions.ts — useConfigureSuggestions
  chat/
    chat.tsx, header.tsx, empty-state.tsx, composer.tsx,
    suggestion-bar.tsx, message-list.tsx, message-user.tsx,
    message-assistant.tsx, message-activity.tsx, typing-indicator.tsx
  attachments/use-attachments-config.ts + attachment-preview.tsx
  tools/weather-card.tsx, stock-card.tsx, chart-card.tsx,
        generic-tool-card.tsx, highlight-note.tsx

Backend (src/agents/headless_complete.py): get_weather, get_stock_price,
get_revenue_chart tools; the chart tool replaces the previous Excalidraw
"Sketch a diagram" suggestion (MCP capability stays wired).

Bug fixes folded in:
- Tool-call cards stuck "running" forever — message-list.tsx indexes
  role:"tool" messages by toolCallId and passes the matching ToolMessage
  to renderToolCall so cards advance to "complete".
- Empty state was hugging the top of the viewport — Radix ScrollArea
  wraps content in a `display: table` div that breaks h-full propagation.
  Empty state now renders OUTSIDE the ScrollArea.
- SuggestionBar duplicated the empty-state prompts on first paint.
  Hidden until the conversation starts.
2026-05-06 23:15:26 -07:00
Tyler Slaton 83884b0be5 feat(showcase/langgraph-python): rebuild Headless UI: Simple
Minimum-viable headless chat that wires only `useAgent` + `useCopilotKit`,
dressed in shadcn/ui primitives. Five small single-purpose files so a
reader can grok the surface in under a minute:

  page.tsx        — provider + <Chat />, ~10 lines
  chat.tsx        — useAgent + useCopilotKit + send loop
  composer.tsx    — Textarea + send button
  empty-state.tsx — sparkles + sample prompts
  message-bubble.tsx + typing-indicator.tsx — render pieces

Wires runtimeUrl="/api/copilotkit" + agent="headless-simple" against
the neutral assistant graph registered in route.ts.

Also adds the v2 catch-all route at copilotkit-mcp-apps/[[...slug]]/route.ts
(used by Headless: Complete in the next commit). v2 hooks POST to subpaths
like /v2/agent/run; the previous flat route 404'd, leaving headless demos
stuck on "Thinking…".
2026-05-06 23:15:03 -07:00