Commit Graph

12110 Commits

Author SHA1 Message Date
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 83fd617f94 feat(showcase/harness): rewrite d5 smoke probes to genuine assertions
Rewrites 10 D5 smoke probes from keyword-match-on-transcript checks
to side-effect / DOM-mount / network-payload assertions per
Phase-2B of .claude/specs/lgp-test-genuine-pass.md:

- d5-frontend-tools: 3 per-pill turns (Sunset/Forest/Cosmic) asserting
  the page background data-attribute mutated to the pill's family-
  specific gradient and differs from the prior pill's gradient.
- d5-frontend-tools-async: notes-card testid mount + settled-state
  detection (list items OR empty-state copy).
- d5-agent-config: 3 knob pairs (tone/expertise/responseLength) sent
  as 6 turns; assertion compares value-A vs value-B response text or
  character-count delta. Aimock fixtures key on prompt-encoded knob
  tokens since JSON fixtures don't expose context-keyed predicates.
- d5-gen-ui-agent: 3 per-pill turns asserting agent-state-card mounts
  with ≥ 2 agent-step rows whose text fingerprint differs across
  pills (catches a regression where fixtures stop differentiating).
- d5-gen-ui-declarative: 4 per-pill turns asserting at least one
  catalog testid (declarative-card / metric / status-badge /
  pie-chart / bar-chart) mounted.
- d5-gen-ui-a2ui-fixed: pill prompt + a2ui-fixed-card testid mount
  assertion.
- d5-gen-ui-interrupt: 2 per-pill turns; click first time-picker-slot
  after time-picker-card mounts; assert time-picker-picked appears.
- d5-gen-ui-open: pill prompt; iframe[srcdoc] mounts with srcdoc
  length ≥ 100 chars.
- d5-shared-state-streaming: 3 per-pill turns asserting
  document-content text length ≥ STREAMING_MIN_FINAL_CHARS.
- d5-readonly-state-context: seeds [data-testid=ctx-name] with a
  sentinel; installs page.route() interceptor on /api/copilotkit;
  asserts the captured outgoing request body contains the sentinel.

Adds _genuine-shared.ts with the structural Page extension
(GenuinePage), pill-click helper, testid waiter, and runtime guard
that mirrors the _beautiful-chat-shared.ts pattern.

All 10 *.test.ts files updated with focused assertions over fakes —
none rely on the production page being live, all 63 unit tests pass.
2026-05-07 18:15:02 +02:00
Alem Tuzlak 7b1f43fd9f chore(showcase/aimock): add d5 probe fixtures keyed on context values
Adds per-pill aimock fixtures backing the Phase-2B genuine D5 probes:

- agent-config: 6 fixtures (3 knob pairs) so concise vs detailed
  responses differ deterministically; satisfies the new probe's
  text-diff + length-diff assertions.
- frontend-tools: 3 per-pill fixtures (sunset/forest/cosmic) emitting
  change_background tool calls with family-specific gradient hexes.
- frontend-tools-async: query_notes tool call so the NotesCard mounts.
- gen-ui-agent: 3 per-pill set_steps tool calls with distinct step
  content so the per-pill content-fingerprint assertion catches
  fixture-drift.
- gen-ui-declarative: 4 per-pill generate_a2ui calls + render_a2ui
  fixture for the secondary LLM call that paints the catalog.
- gen-ui-a2ui-fixed: SFO/JFK display_flight tool call.
- gen-ui-interrupt: 2 per-pill schedule_meeting tool calls with
  distinct time-slot payloads.
- gen-ui-open: generateSandboxedUi tool call with a non-trivial
  HTML payload so the iframe[srcdoc]-mount assertion has ≥ 100 chars
  to observe.
- shared-state-streaming: 3 per-pill write_document tool calls with
  substantive content payloads (≥ 100 chars each).
- readonly-state-context: pill-prompt fixture; the probe's network-
  payload assertion checks the request body, not the response.

d5-all.json is updated with the new entries prepended so first-match
precedence routes specific pill prompts to their per-pill fixtures
ahead of the generic adjacent matches.
2026-05-07 18:14:35 +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 b0f0947ae3 chore(showcase/aimock): add tool-rendering pill fixtures with priority
Add 14 fixtures at the top of d5-all.json so they win precedence over
the existing 'weather in Tokyo' / 'd5 beautiful-chat probe: search
flights' substring matches:

- Chain tools: 3 toolCalls in one assistant turn (get_weather Tokyo +
  search_flights SFO->Tokyo + roll_d20=11) plus follow-up text.
- Weather in SF: get_weather(San Francisco) + text (deterministic).
- Find flights: dedicated search_flights(SFO,JFK) fixture, no longer
  leaks the a2ui beautiful-chat shape.
- Stock price: get_stock_price(AAPL) returning $338.37 / -2.96%.
- Roll a 20-sided die: 5 sequential roll_d20 fixtures with
  turnIndex 0..4 (stateless across runs), values [7,14,3,19,20].
2026-05-07 17:54:43 +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
Sam Julien 59a8a71a61 docs(shell-docs): give quickstart CLI section two clear paths (interactive vs flag)
Restructure the "Run our CLI" step in all eight framework quickstarts to surface
two paths: the upstream interactive flow (which now covers the Enterprise
Intelligence Platform prompt and sign-up) and the `--framework <id>` flag fast
path. LangGraph and Microsoft Agent Framework keep both language variants in the
flag block.
2026-05-07 08:52:31 -07:00
Alem Tuzlak e67fcfbf84 feat(showcase/harness): add d5-gen-ui-open-advanced probe
Phase-2A wrong-target split. The old d5-gen-ui-open probe claimed BOTH
open-gen-ui and open-gen-ui-advanced via the same gen-ui-open literal,
which meant a regression on the advanced demo's iframe sandbox would
never surface (the basic-tier assertion didn't read iframe state). The
advanced demo now owns its own probe asserting iframe presence as the
distinguishing signal:

- d5-gen-ui-open-advanced: drives /demos/open-gen-ui-advanced, asserts
  the [data-testid="gen-ui-open-advanced-iframe"] testid (with a
  generic iframe fallback).

d5-gen-ui-open: scoped to the basic /demos/open-gen-ui route only;
preNavigateRoute no longer branches on the demos[] context.

d5-feature-mapping.ts: open-gen-ui-advanced now points at the new
gen-ui-open-advanced literal; d5-registry.ts adds the literal.
2026-05-07 17:52:31 +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 e6644338d5 feat(showcase/harness): add d5-tool-rendering-default-catchall and d5-tool-rendering-custom-catchall probes
Phase-2A wrong-target split. Both registry IDs previously pointed at
d5-tool-rendering, which asserts a per-tool WeatherCard — the wrong
signal for catchall renderers. Each catchall surface now owns a probe
that asserts its own testid contract:

- d5-tool-rendering-default-catchall: drives the built-in default
  catchall renderer, asserts [data-testid="copilot-tool-render"] +
  [data-tool-name="get_weather"] + a tool-status-* lifecycle pill.
- d5-tool-rendering-custom-catchall: drives the user-supplied wildcard
  renderer, sends 2 distinct prompts (get_weather + get_stock_price)
  and asserts BOTH render through the same [data-testid="custom-catchall-render"]
  testid (cross-tool signature snapshot — the wildcard truly catches
  all tools, not just one).

Mapping in d5-feature-mapping.ts now points each registry ID at its
own probe; d5-registry.ts adds the two new D5FeatureType literals.
2026-05-07 17:52:16 +02:00
Alem Tuzlak 276161d0bd chore(showcase/aimock): add fixtures for hitl-in-app and frontend-tools-async pills
Adds deterministic fixtures to d5-all.json (loaded before feature-parity.json
so it wins match precedence) for the Phase 1A genuine-pass cells:

- hitl-in-app refund #12345 and escalate #12347 pills: each emits a
  request_user_approval tool call on the first turn, then branches via
  sequenceIndex on the second turn (0 = approve response, 1 = reject
  response). Test ordering (serial mode in the spec) drives which branch
  is claimed first per pill pair.

- frontend-tools-async project-planning, auth, and reading pills: each
  emits a query_notes tool call so the async client-side handler runs
  against NOTES_DB and renders project-planning / auth / reading-tagged
  matches. The reading pill's 2nd-turn narration locks the canonical
  leading phrase per spec test #4.

Replaces nothing — purely additive. The dedicated pill-prompt entries
beat the broad 'plan' and showcase-assistant catch-all entries that were
silently winning before.
2026-05-07 17:52:09 +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 2b7d93a157 feat(showcase/harness): split d5-mcp-subagents into d5-mcp-apps and d5-subagents
Phase-2A wrong-target split. The old d5-mcp-subagents probe claimed both
mcp-apps and subagents feature types but routed both to /demos/subagents,
leaving mcp-apps wrong-targeted. Each feature now has its own probe:
- d5-mcp-apps: drives /demos/mcp-apps, asserts iframe presence via the
  [data-testid="mcp-app-iframe"] testid (with iframe[sandbox] fallback).
- d5-subagents: drives /demos/subagents, asserts the 3 Phase-1D
  subagent-card testids (researcher, writer, critic), enforces the
  one-critic invariant, and rejects boilerplate placeholder text.

d5-feature-mapping.ts: comment block updated to reflect the split.
d5-registry.ts: no new literals needed (mcp-apps + subagents already
existed).
2026-05-07 17:51:36 +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 72342e1543 chore(showcase/aimock): add open-gen-ui pill fixtures with priority over showcase-assistant catch-all
The 5 of 7 open-gen-ui pill prompts (3D axis, neural network, quicksort,
calculator, ping-the-host) currently match the broad userMessage: 'hi'
catch-all in feature-parity.json (substring match on 'hi' inside 'Say hi
to the host', 'this', etc.) and resolve to the showcase-assistant
boilerplate greeting instead of emitting the generateSandboxedUi tool
call. That kills the iframe path on 5/7 of the pills.

Add 7 high-priority verbatim-prompt fixtures in d5-all.json (and the
source-of-truth showcase/harness/fixtures/d5/gen-ui-open.json) that emit
deterministic generateSandboxedUi tool calls with inline HTML + CSS in
the tool result. d5-all.json loads BEFORE feature-parity.json so the
first-match-wins ordering naturally beats the catch-all. Pill fixtures
appear at the top of the file so they also win against intra-bundle
specifics. Inline HTML is intentionally minimal — the assertion bar is
iframe presence + non-empty srcdoc, not iframe DOM introspection
(cross-origin blocked under sandbox=allow-scripts only).
2026-05-07 17:50:53 +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 38d327d9af chore(showcase/aimock): add headless-complete highlight fixture
Adds high-priority verbatim-prompt fixtures for the headless-simple and
headless-complete pill prompts so the deterministic leading phrases stay
locked under aimock:

- headless-simple: 'Say hello in one short sentence' / 'Tell me a one-line
  joke' / 'Give me a fun fact' lock the greeting, joke, and fun fact.
- headless-complete: 'Highlight: ship the demo on Friday' is a NEW
  high-priority entry that emits a highlight_note tool call with text
  'ship the demo on Friday' plus a deterministic narration. Without it
  the showcase-assistant catch-all in feature-parity.json wins and the
  pill never paints a Highlight card.
- headless-complete: 'chart of revenue over the last six months' emits a
  get_revenue_chart tool call plus a deterministic narration leading
  phrase 'Here is the chart of revenue over the last six months'.

Weather Tokyo and AAPL fixtures already lock the leading phrases the
headless-complete spec asserts on; they remain unchanged.
2026-05-07 17:46:02 +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
Nathan 🔶 Tarbert 620e69998a chore(README): Update video asset the the "What is CopilotKit" section
Updated AG-UI Protocol link and asset URL in README.
2026-05-07 11:27:02 -04: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
Ran Shemtov 0f90638c5f chore(release): include @copilotkit/agentcore-runner in monorepo scope
The package was added to the repo but never wired into release.config.json,
so the release / create-pr and release / publish workflows skipped it. Adding
it here lets the next monorepo release bump and publish it like its siblings
(e.g. @copilotkit/sqlite-runner). sharedVersion=true means the existing
1.56.2 in package.json will be overwritten with the monorepo's next version.
2026-05-07 15:15:50 +00:00
Alem Tuzlak 90c38bdb91 docs(showcase/langgraph-python): genuine-pass test spec
Design doc for the lgp-test-genuine-pass blitz: Phase 0 cleanup,
Phase 1 family rewrites for 11 cells, Phase 2A wrong-target
D5 probe splits, Phase 2B smoke→genuine D5 probe rewrites.
2026-05-07 17:04:06 +02:00
Markus Ecker 60db1b7a8e feat(core): registerProxiedAgent — explicit multi-agent mounting against one runtime agent (#4629)
## Summary

Replaces the implicit per-thread agent cloning from #3525 / #3630 with
an explicit registration API. Three commits:

1. **revert** — strips the cloning machinery (`useAgent({ threadId })`
per-thread clones, `getThreadClone`, `globalThreadCloneMap`,
`cloneForThread`), the inspector hooks added only to handle clones
(`onAgentRunStarted` from #3869, the connect-time emission from #3872,
the `agentRunThreadId` map), the state-manager `isClone` composite-key
path, and the `consumerAgent` parameter on `SuggestionEngine`. Restores
`agent.threadId = resolvedThreadId` in `CopilotChat` (pre-#3525
behavior). Re-opens issue #2957 (CPK-7155): two `<CopilotChat>`
instances sharing an `agentId` will share state again.

2. **feat** — adds `CopilotKitCore.registerProxiedAgent({ agentId,
remoteAgentId })` which mints a `ProxiedCopilotRuntimeAgent` under a
local registry id and routes its outbound HTTP requests to the named
runtime agent. Returns `{ agent, unregister }` for React `useEffect`
cleanup. Throws on duplicate `agentId` (collisions with
`agents__unsafe_dev_only` or another `registerProxiedAgent` are loud,
not silent).

`ProxiedCopilotRuntimeAgent` gains a `remoteAgentId` field used only for
outbound routing — URL paths (`/agent/<id>/run`, `/connect`, `/stop`),
single-route envelopes, and the `IntelligenceAgent` delegate's
`agentId`. The local `agentId` remains the registry key and source of
truth for state-manager subscriptions, `useAgent` lookups, and
`onAgentsChanged`. So multiple proxies (`chat-1`, `chat-2`) targeting
the same runtime agent (`default`) don't cross-talk in any subscriber
bookkeeping.

3. **test** — re-adds the isolation coverage that the revert deleted,
rewritten against the explicit-registration model (10 tests total).

## Usage

```tsx
const { copilotkit } = useCopilotKit();
useEffect(() => {
  const { agent, unregister } = copilotkit.registerProxiedAgent({
    agentId: "chat-1",          // local registry id (subscriber bookkeeping)
    remoteAgentId: "default",   // runtime id (URL routing only)
  });
  return unregister;
}, [copilotkit]);
// then <CopilotChat agentId="chat-1" />
```

## Test plan

- [x] `nx run @copilotkit/core:test` — **424 passed** (was 409 + 15 new
across feat & test commits)
- [x] `nx run @copilotkit/react-core:test` — **1151 passed** (was 1150 +
1 new)
- [x] `nx run @copilotkit/web-inspector:test` — **7 passed**
- [x] Build: `core`, `react-core`, `web-inspector` all clean

### New tests cover

- routing — proxy at `agentId` routes outbound to `remoteAgentId`; URL
path encodes the remote id, body envelopes use the remote id
- duplicate-throw — register twice with same `agentId` throws (whether
against another registered proxy or an `agents__unsafe_dev_only` entry)
- idempotent `unregister` — calling twice doesn't throw or re-emit;
stale handles don't strip replacements
- `onAgentsChanged` notification on register and unregister
- header inheritance from core
- two proxies → same `remoteAgentId` are distinct instances with
isolated messages, isolated state, independent threadIds, but shared
outbound URL
- `getAgent` returns the same proxy instance across calls (no per-call
clone)
- registering before runtime connects yields a proxy that's still usable
for in-memory ops
- registering with a `remoteAgentId` the runtime doesn't yet expose
still works for local bookkeeping
- re-register after unregister yields a fresh proxy (no carry-over)
- regression: activity renderers receive the agent under the local
`agentId`, never another agent in the registry (replaces the deleted
clone-vs-registry trap test)

## Caveats

- Issue #2957 (CPK-7155) is re-opened by the revert. The new API is the
supported path forward — callers that previously relied on `useAgent({
threadId })` for isolation should move to `registerProxiedAgent`.
- Runtime `/info` sync still uses last-write-wins, not throw, on
collisions with manually-registered ids. Easy follow-up if we want
strict throw there too.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-07 15:27:00 +02:00
Markus Ecker 61e4292be6 feat(runtime): configurable MCP server on BuiltInAgent (Bearer + per-call user header) (#4420)
## Summary

Closes [CPK-7526](https://linear.app/copilotkit/issue/CPK-7526).

`@copilotkit/runtime/v2`'s `BuiltInAgent` already supported MCP servers,
but only with **static** headers set at client construction. CopilotKit
Intelligence's `/mcp` endpoint requires a two-axis auth contract that
breaks under static headers:

1. **Static project Bearer** — `Authorization: Bearer
cpk-{projectId}_{shortToken}_{longToken}`. Same on every call.
2. **Per-call end-user header** — `X-Cpki-User-Id`. Fresh per outbound
MCP HTTP request — never cached. Determines which user's persistent bash
sandbox + `/threads` view a call sees.

Without per-call user-id, every demo session for a given project would
share one bash sandbox, breaking the user-isolation contract that
`cpki.shell_contexts` and `ThreadsFs` enforce on the platform side.

This PR adds the missing per-call resolver hook and is the precondition
for [CPK-7527](https://linear.app/copilotkit/issue/CPK-7527) (Phase 4b
SL integration), which wires it into `Intelligence/demos/simple-agent`.

## What's in here

### Public API surface

```ts
import {
  BuiltInAgent,
  INTELLIGENCE_USER_ID_HEADER,
  // re-exported from @ai-sdk/mcp:
  type MCPClient,
  type MCPTransport,
  type OAuthClientProvider,
} from "@copilotkit/runtime/v2";

new BuiltInAgent({
  model: "openai/gpt-4o",
  mcpServers: [{
    type: "http",
    url: `${process.env.INTELLIGENCE_API_URL}/mcp`,
    authToken: process.env.INTELLIGENCE_API_KEY!,
    getHeaders: ({ requestHeaders }) => {
      const userId = requestHeaders[INTELLIGENCE_USER_ID_HEADER]?.trim();
      if (!userId) throw new Error("missing user-id");
      return { [INTELLIGENCE_USER_ID_HEADER]: userId };
    },
  }],
});
```

- Unified `MCPClientConfig` shape mirrors `@ai-sdk/mcp`'s
`MCPTransportConfig` (single discriminated `type: "http" | "sse"`,
`url`, `headers`, `authProvider`) plus two CopilotKit extensions:
**`authToken`** (static Bearer shorthand) and **`getHeaders`** (per-call
resolver invoked on every outbound HTTP request — initialize,
tools/list, tools/call, reconnects).
- **`MCPRequestContext`** carries `requestHeaders` (snapshot of the
agent's per-run forwarded headers), `input`, and `mcpServerUrl`.
- **`MCPHeaderResolverError`** wraps resolver throws so `RUN_ERROR`
attributes the failure to the resolver via ES2022 `Error.cause`.
- **`BuiltInAgent.headers: Record<string, string> = {}`** is now
declared on the class. The runtime's existing
`extractForwardableHeaders` feature-detect (`if (agent.headers)` in
`configureAgentForRequest`) only forwards headers to agents that already
declare a truthy field — initializing to `{}` activates that path so the
BFF's per-request headers reach the resolver via context.
- **`INTELLIGENCE_USER_ID_HEADER`** constant exported as the canonical
header name (`"x-cpki-user-id"`) — re-exported through both
`intelligence-platform` and `v2/runtime` barrels.

### Architecture

The agent's MCP layer now sits directly on `@ai-sdk/mcp`'s stable
surface (`createMCPClient`, `MCPClient`, `MCPTransport`) instead of
bypassing it to `@modelcontextprotocol/sdk`. The agent module no longer
imports `@modelcontextprotocol/sdk` at all — that's confined to a small
`CopilotKitMCPTransport` class that implements Vercel's `MCPTransport`
interface and is only instantiated when a `getHeaders` resolver is
present.

For static-only configs (no per-call hooks), the config is handed
straight to `createMCPClient` and Vercel's built-in `HttpMCPTransport` /
`SseMCPTransport` handle the wire.

`MCPClient`, `MCPTransport`, `OAuthClientProvider`, `OAuthTokens`, and
`UnauthorizedError` are re-exported from `@copilotkit/runtime/v2` so
consumers don't need a direct `@ai-sdk/mcp` dependency.

### Side-effect bug fix: SSE static headers

The pre-existing direct-SDK construction passed `serverConfig.headers`
as the wrong-shape options arg to `SSEClientTransport`, and the SDK
silently ignored it — auth on SSE simply didn't work. Vercel's
`SseMCPTransport` correctly applies `headers` via its `commonHeaders()`
pipeline. The new architecture inherits the fix; a regression test in
`mcp-servers-integration.test.ts` proves static `headers` now reach the
wire on the SSE path.

### What's intentionally NOT in here

- **Demo wiring** in `Intelligence/demos/simple-agent` (CPK-7527).
- **MCP support for LangGraph / Mastra** runtimes — different
integration points; not this ticket.
- **Server-side `/mcp` route changes** in Intelligence (already shipped
on `mme/integrate-sl`).

## Notes for reviewers

- **Public-API addition:** `BuiltInAgent.headers` is a real public
field, not just an ad-hoc property. It's load-bearing for the runtime's
existing header-forwarding feature-detect.
- **Test header inspection:** `aimock` redacts `Authorization` to
`[REDACTED]` in its journal, so tests that need to verify the actual
outgoing Bearer use a `vi.spyOn(globalThis, "fetch")` recorder instead
of the journal. The `x-cpki-user-id` header isn't redacted, so per-call
user-id assertions read from the journal directly.
- **No `toMCPServer()` helper.** Earlier iterations of this PR shipped a
`CopilotKitIntelligence.toMCPServer()` shortcut. It conflated thread
management (the class's actual job) with MCP transport configuration and
baked in opinionated behavior that not every deployment will want;
dropped in favor of the inline pattern shown above using the exported
`INTELLIGENCE_USER_ID_HEADER` constant. Same line count as the
helper-call form, more flexible.
- **Pre-existing `tsc --noEmit` OOM:** `pnpm nx run
@copilotkit/runtime:check-types` runs out of heap on `main` at 8GB.
Reproduces on a clean checkout without any changes from this PR. Worth
tracking as a separate issue. Build (`tsdown`) is unaffected; the full
vitest suite (1419 tests, 101 files) passes.

## Test plan

- [x] `pnpm nx run @copilotkit/runtime:test -- mcp-servers-integration`
— 15 cases pass (8 existing + 6 per-call/static-header + 1 new SSE
regression test)
- [x] `pnpm nx run @copilotkit/runtime:test -- mcp-clients` — 8 cases
pass (existing user-managed-clients suite, including `MCPClient` ↔
`MCPClientProvider` type-compat check)
- [x] `pnpm nx run @copilotkit/runtime:test --skip-nx-cache` — full
suite 1419/1419
- [x] `pnpm nx run @copilotkit/runtime:build` — `tsdown` clean
- [x] `oxlint` on changed files — 0 errors
- [ ] Manual end-to-end against a local Intel server + simple-agent BFF
— deferred to CPK-7527 since the demo wiring lives there
2026-05-07 15:26:13 +02:00
Markus Ecker 5dad3de7f3 Merge branch 'main' into lukas/cpk-7526-copilotkitruntimev2-configurable-mcp-server-on-builtinagent 2026-05-07 14:43:23 +02:00
Alem Tuzlak b3463f8995 fix(showcase/langgraph-python): copy manifest.yaml into runtime image (#4696)
## Summary

- Production deploys of the `showcase-langgraph-python` image were
crashing on every `/demos/*` route with "An error occurred in the Server
Components render" — backed by ENOENT on `/app/manifest.yaml`.
- Root cause: the demos layout's `generateMetadata` calls `await
headers()` (forces dynamic rendering) and `fs.readFileSync(process.cwd()
+ "/manifest.yaml")` for per-demo titles. The Dockerfile's runner stage
copied `.next`, `node_modules`, `package.json`, `public/`,
`langgraph.json`, `src/agents/`, `tools/`, and `entrypoint.sh` — but
never the manifest.
- The home page (`/`) was unaffected because it has no dynamic APIs, so
Next prerenders it statically at build time when the manifest is
available.
- All cells in the langgraph-python column on the showcase dashboard
were stuck at D2/D3 because the chat/tools probes can't pass against a
Server-Components error.

## Fix

One line in the Dockerfile: `COPY --chown=app:app manifest.yaml ./` in
the runner stage, with a comment explaining the runtime dependency.

## Test plan

- [x] Rebuilt local image with `bin/showcase build langgraph-python`
- [x] Recreated the local container and verified `/app/manifest.yaml` is
present
- [x] Hit `/demos/agentic-chat`, `/demos/headless-complete`,
`/demos/auth` — all load with zero console errors and the correct
manifest-driven page titles ("LangChain - Python - Prebuilt:
CopilotChat", etc.)
- [ ] Once merged, next Railway deploy of `showcase-langgraph-python`
should clear the column on the showcase dashboard
2026-05-07 14:37:33 +02:00
github-actions[bot] 657077b4f2 style: auto-fix formatting 2026-05-07 12:35:14 +00:00
Markus Ecker 12f2c0e734 refactor(runtime): rename cki → cpki and use INTELLIGENCE_USER_ID_HEADER constant
Two CR comments addressed:

- Rename the local destructure of forwardedProps.auth.copilotkitIntelligence
  from 'cki' to 'cpki' so it matches the project-wide abbreviation already
  used in metadata fields (cpki_event_id, cpki_event_seq, etc).

- Replace the inline 'X-Cpki-User-Id' string literal with the existing
  INTELLIGENCE_USER_ID_HEADER constant exported from intelligence-platform/client.
  Applies to the runtime auto-attach in agent/index.ts and to the three
  test sites in intelligence-mcp-helper.test.ts so the user-side and
  runtime-side stay in sync.
2026-05-07 14:31:59 +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
Markus Ecker 3e7449dc4c Merge remote-tracking branch 'origin/main' into lukas/cpk-7526-copilotkitruntimev2-configurable-mcp-server-on-builtinagent 2026-05-07 14:28:27 +02:00
Markus Ecker 79fb5af452 Merge remote-tracking branch 'origin/main' into mme/register-proxied-agent
# Conflicts:
#	packages/react-core/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx
#	packages/react-core/src/v2/hooks/use-agent.tsx
#	packages/web-inspector/src/styles/generated.css
2026-05-07 14:20:55 +02:00
Alem Tuzlak 95f957d7c2 fix(showcase): register reasoning-default + reasoning-custom feature IDs
PR #4694 renamed langgraph-python's reasoning demos
(agentic-chat-reasoning → reasoning-custom, reasoning-default-render →
reasoning-default) but didn't update the central feature-registry.json /
constraints.yaml, so generate-registry validation rejected the new
manifest IDs. Add the two new features to the registry and the
constrained-explicit allowlist; leave the old IDs in place for the 17
integrations still using them.
2026-05-07 14:10:50 +02:00
Alem Tuzlak 45cc89dc99 chore(showcase): ratchet validate-pins baseline 97→98
Pre-existing drift on main (mastra/ms-agent/llamaindex/pydantic-ai/strands)
that the langgraph-python Dockerfile fix is unrelated to. Bump the
baseline in this PR to unblock CI.
2026-05-07 14:03:39 +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
Alem Tuzlak d446b29fe1 feat(showcase/langgraph-python): demo pass — rebuild headless, pivot agent-config, simplify, retag (#4694)
## What does this PR do?

A wholesale demo pass on the `langgraph-python` showcase. The full diff
is +20,639 / −22,881 across 273 files; rebased into 14 thematic commits,
each scoped to one demo cluster or one cross-cutting concern. Build is
green at 54 routes; every demo round-trips with the local LangGraph dev
server.

### Per-demo headlines

- **Headless UI: Simple** — minimum-viable shadcn-only chat (`useAgent`
+ `useCopilotKit`) across 5 small files. Backend wiring corrected (was
borrowing the Complete demo's MCP runtime).
- **Headless UI: Complete** — modular hand-rolled `<CopilotChat>`
replacement. `page.tsx` enumerates capabilities; `chat/`, `hooks/`,
`tools/`, `attachments/` split by responsibility. Bug fixes folded in:
tool-cards no longer stuck "running" (passes `ToolMessage` to
`useRenderToolCall`), empty state no longer hugs the top (rendered
outside Radix `ScrollArea`), suggestion bar hidden on first paint.
- **Chat Customization: CSS** — HALCYON, a warm-paper editorial theme.
Two layers: v2 token overrides on `[data-copilotkit]` + class-targeted
styling. Demonstrates CSS-only customization without touching
components.
- **Chat Customization: Slots** — every overrideable slot wrapped;
labels are click-to-copy badges showing the PascalCase component path
(`Input.TextArea`, `MessageView.AssistantMessage`, …).
- **Reasoning: Default + Custom** — paired demos sharing one reasoning
graph (gpt-5-mini via Responses API). Default uses the built-in slot;
Custom overrides `messageView.reasoningMessage`.
`agentic-chat-reasoning` directory renamed to `reasoning-custom`
(manifest, route, e2e, docs-links updated together).
- **Prebuilt: CopilotChat / Sidebar / Popup** — centered content,
sidebar genuinely pushes the page (root-cause fix in `globals.css` —
body wasn't allowed to shrink with `marginInlineEnd`).
- **Multimodal + Voice + Beautiful Chat** — `LegacyConverterShim` (until
ag-ui/langgraph ships an updated converter), V2 runtime for voice (V1
drops `transcriptionService`), beautiful-chat ports parity from
`examples/integrations/langgraph-python`. Fixed `gpt-5.4-mini` typo that
would have 4xx'd every call.
- **Frontend Tools (in-app + async) + HITL family (in-chat / in-app /
interrupt-based)** — full coverage of agent→client tool calls and the
three HITL patterns.
- **Generative UI tool-rendering family** (5 demos sharing one backend)
— opt-in chaining via a "Chain tools" suggestion. The previous
always-chain bias generated extra unsolicited tool-call cards on every
turn.
- **Declarative UI + BYOC + Open Generative UI** — A2UI dynamic + fixed,
MCP Apps, Hashbrown, json-render, Open Generative UI default + advanced.
`a2ui-fixed-schema` simplified: dropped `BOOKED_SCHEMA` +
`booked_schema.json` since the SDK doesn't yet expose `action_handlers`.
8 `(props as Record<string, any>)` casts collapsed into one shared `s()`
helper.
- **Shared State + Sub-Agents** — streaming, read+write, frontend
context sharing, multi-agent supervisor with delegation log (tightened
type to drop unused `"running" | "failed"` legs).
- **Auth + Agent Config (platform)** — Auth defaults UNAUTHENTICATED
with a sign-in card; the chat doesn't mount until the user signs in, so
`<CopilotChat>`'s 401-on-mount crash never fires (`ChatErrorBoundary`
workaround removed). Agent Config pivoted from broken `<CopilotKit
properties={...}>` (silently dropped values in @ag-ui/langgraph 0.0.31)
to `useAgentContext`, the LangGraph 0.6+ idiom.

### Cross-cutting

- **Manifest curator pass** — every `Thing - Subthing` / `Thing
(Subthing)` normalized to `Thing: Subthing`. Retags: Auth → `platform`,
HITL → `interactivity`, Reasoning → `chat-ui`, Generative UI: Tools →
`generative-ui`. New tags surfaced in the registry: `platform`,
`agent-state`, `multi-agent`. Highlight paths corrected for the rebuilt
headless demos. Hitl entry now points at the working
`/demos/hitl-in-chat` route.
- **v1 → v2 import sweep** — every demo imports only from
`@copilotkit/react-core/v2`. Fixed silent breakage in beautiful-chat
where `useFrontendTool` was importing from bare v1, making
`enableAppMode` / `enableChatMode` invisible to the v2 agent.
- **page.tsx convention** — every demo's `page.tsx` reads as imports +
provider + suggestions hook + JSX. `useConfigureSuggestions` extracted
to a sibling `suggestions.ts`. Inline component definitions extracted.
- **Scaffolding** — manifest-driven landing page, per-demo titles via
middleware + demos layout, Tailwind v4 `@theme inline` block (without it
shadcn utilities compile to nothing), v2 catch-all route at
`[[...slug]]/route.ts`.
- **Dead-dep prune** — removed 17 deps with zero importers
(`@copilotkit/react-ui`, `@rive-app/react-webgl2`, `@xyflow/react`,
`@streamdown/{cjk,code,math,mermaid}` + `streamdown`, `ai`,
`use-stick-to-bottom`, `ansi-to-react`, `marked`, `react-jsx-parser`,
`media-chrome`, `motion`, `nanoid`, `remark-breaks`, `shiki`,
`tokenlens`, `@radix-ui/react-use-controllable-state`). Net: −5,000
lines on the lockfile. Every shadcn primitive in `src/components/ui/` is
intact.

### Things removed (the iteration arc)

This branch went through several reversals during development. The
rebase erased them from history; cataloguing the consequential ones for
context:
- AI Elements + prompt-kit headless demos (added then removed when the
spec narrowed to shadcn-only)
- Headless: 4-tab → 5-separate → trim to Simple+Complete
- `hitl-in-app-interrupt` (added then removed pending Atai's
`useInterrupt` resolver API)
- `BOOKED_SCHEMA` schema-swap branch in a2ui-fixed-schema (no SDK
support yet)
- `ChatErrorBoundary` for the auth demo (no longer needed once chat is
gated behind `isAuthenticated`)
- `read_properties()` / `build_system_prompt()` in agent_config_agent.py
(one static prompt now that toggles arrive via `useAgentContext`)
- `[A2UI-DEBUG]` print scaffolding in beautiful_chat.py
- 5 stub `agent.py` files in demo dirs (real graphs in `src/agents/`)

### Follow-ups

- `tool-rendering-default-catchall` registers a `useDefaultRenderTool`
despite the manifest claiming "zero frontend renderers" — either drop
the renderer or rewrite the description.
- Upstream: fix `@ag-ui/langgraph` 0.0.31's silent drop of `properties`
(would let agent-config use the typed transport instead of
`useAgentContext`).
- Upstream: `<CopilotChat>` shouldn't throw on transport 401 at first
paint (auth demo currently sidesteps).
- Upstream: relax `WithSlots` typing or ship an `asSlot<T>()` helper —
would erase the 9 `as unknown as` casts in chat-slots +
reasoning-custom.
- Upstream: published `CopilotRuntime` type rejects `Record<string,
LangGraphAgent>` — every dedicated runtime route ships the same
`@ts-ignore`.

## Test plan

- [x] `pnpm exec next build` — green, 54 routes generated
- [x] Every demo route resolves without crashing
- [x] Headless: Simple — `useAgent` + `useCopilotKit` round-trip;
suggestions in empty state work
- [x] Headless: Complete — tool cards advance from "running" to
"complete"; chart-card renders; attachments round-trip; suggestion bar
appears after first message
- [x] Chat Customization: CSS — HALCYON theme renders end-to-end; user
bubble gradient bound to inner bubble (not full-row); inputs /
suggestions / scrollbar all themed
- [x] Chat Customization: Slots — every slot label visible on hover;
click copies the PascalCase path with ✓ flash
- [x] Reasoning: Custom — `messageView.reasoningMessage` slot fires;
ReasoningBlock renders with "Thinking…" → "Agent reasoning" transition
- [x] Prebuilt: Sidebar — sidebar pushes the page (not overlapping) when
toggled
- [x] Frontend Tools — agent's `change_background` tool repaints the
indigo canvas
- [x] HITL: in-chat — TimePickerCard renders inline; user pick resumes
the agent
- [x] HITL: in-app — modal renders OUTSIDE the chat via `createPortal`;
decision resolves the pending Promise
- [x] Tool Rendering trio — single-tool default, "Chain tools"
suggestion fires multiple tool calls
- [x] Auth — first paint is the sign-in card; signing in mounts the chat
with `Authorization: Bearer …`
- [x] Agent Config — toggles change agent style per turn (tone /
expertise / responseLength routed through `useAgentContext`)

## Related PRs and Issues

Tracking notes: [Showcase - LangGraph Python
Notes](https://www.notion.so/copilotkit/Showcase-LangGraph-Python-Notes-3583aa3818528036ac0ddd1353f3e354)

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked
2026-05-07 11:26:59 +02:00
Markus Ecker 6ed400c776 refactor(runtime): nest Intelligence MCP credentials under forwardedProps.auth.copilotkitIntelligence
Move the per-request Intelligence MCP bag from
forwardedProps.copilotkitIntelligence to
forwardedProps.auth.copilotkitIntelligence so the Intelligence-side
redaction policy strips it. The 'auth' namespace is the convention for
credentials; persistence sinks (Postgres, Redis, S3) and FE replay
paths in apps/realtime-gateway already strip everything under it.

Updates:
- Emitter (handlers/intelligence/run.ts): merge the bag into a single
  forwardedProps.auth object alongside any upstream auth keys, and
  only emit the auth namespace when there is something to put in it.
- Reader (agent/index.ts): read from forwardedProps.auth.copilotkitIntelligence
  instead of forwardedProps.copilotkitIntelligence.
- Tests (intelligence-mcp-helper.test.ts): three fixtures rewritten
  to the nested shape.
2026-05-07 10:55:02 +02:00
github-actions[bot] f9cef5048d style: auto-fix formatting 2026-05-07 08:35:24 +00:00
Alem Tuzlak 593895c55a Merge remote-tracking branch 'origin/main' into feat/langgraph-python-demo-pass
# Conflicts:
#	pnpm-lock.yaml
2026-05-07 10:32:07 +02: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