Commit Graph

964 Commits

Author SHA1 Message Date
github-actions[bot] 4629573f32 style: auto-fix formatting 2026-04-30 20:33:59 +00:00
Jordan Ritter a9193b2d7f fix(showcase/google-adk): align chat-customization-css theme with D5 reference
Update CSS custom properties and page layout to match the D5 probe
reference theme expectations.
2026-04-30 13:32:21 -07:00
Jordan Ritter b4361d8ea7 fix(showcase/google-adk): add SampleAttachmentButtons and multimodal attachment pipeline
Add SampleAttachmentButtons component with PDF/image sample files,
wire multimodal demo page to support file attachments matching D5
probe expectations.
2026-04-30 13:32:14 -07:00
Jordan Ritter ebcbdc5774 fix(showcase/google-adk): demo wiring fixes for D5 probe compatibility
Fix chat-slots agent name (dashes to underscores), prebuilt-popup
defaultOpen prop, auth demo defaults to unauthenticated state, and
add missing data-testid attributes to byoc renderers.
2026-04-30 13:32:07 -07:00
Jordan Ritter 69ca0c6afc fix(showcase/ag2): demo page fixes — agent-config, testids, imports, wiring
- agent-config: replace useAgent/setState pattern with CopilotKit properties
  prop (the correct way to pass config to AG2 ContextVariables)
- headless-complete: change runtimeUrl from /api/copilotkit to
  /api/copilotkit-mcp-apps so MCP Apps activity messages render
- byoc-hashbrown, byoc-json-render: re-attach data-testid="copilot-assistant-message"
  on custom assistantMessage slot overrides (harness conversation runner
  needs this to detect settled responses)
- agentic-chat-reasoning, beautiful-chat: add demo-level data-testid wrappers
- tool-rendering-reasoning-chain, voice: fix CopilotKit import path
  (import from @copilotkit/react-core, not /v2, for consistency)
2026-04-30 13:13:51 -07:00
Jordan Ritter 0f6942c5d0 fix(showcase/ag2): multimodal content flattener + attachment pipeline
Rewrite the multimodal demo's message converter from a legacy-binary-shape
rewriter to a content flattener. AG2's AGUIStream validates message content
as a plain string and rejects arrays of content parts with a 400. The new
ContentFlattenerShim extracts text from multipart user messages before the
AG-UI run dispatches them to the AG2 backend.

Also adds defensive validation to sample-attachment-buttons: magic-byte
checks, LFS pointer detection, and actionable error messages.
2026-04-30 13:13:38 -07:00
Jordan Ritter 0aef10f9a2 fix(showcase/ag2): backend wiring — mount order, @tool() decorator, route fixes
- Fix Starlette mount order: /open-gen-ui-advanced before /open-gen-ui to
  prevent prefix shadowing (open-gen-ui-advanced was unreachable)
- Fix @tool -> @tool() decorator in agent_config_agent.py (bare @tool
  silently fails to register the function as a CopilotKit tool)
- Wire headless-complete agent into copilotkit-mcp-apps route so the
  headless-complete demo can exercise MCP Apps rendering
- Update manifest to reference copilotkit-mcp-apps route for headless-complete
- Remove stale @ts-ignore in auth route
2026-04-30 13:13:27 -07:00
Jordan Ritter 2c32b48dda fix(showcase): fix spring-ai D5 failures — all 28 features green (#4525)
## Summary

- Fix TOOL_CALL_RESULT events reusing parent assistant message ID across
StreamingToolAgent, SharedStateReadWriteController, and
SubagentsController —
React's deduplicateMessages() Map overwrote assistant messages with tool
  messages when they shared the same ID
- Add `data-testid="copilot-assistant-message"` to BYOC hashbrown
renderer so
  the D5 test harness can detect assistant messages
- Register AG-UI Jackson mixins via JacksonConfig postConfigurer,
normalize
array-format content via ContentNormalizingModule, remove ChatMemory
beans
  that interfered with aimock fixture matching, inject Spring-managed
  ObjectMapper into AgentConfigController

## Test plan

- [x] All 28/28 spring-ai D5 features pass locally (verified stable
across
  multiple consecutive runs)
- [x] Docker build succeeds
- [x] No regressions — previously passing 22 features remain green
2026-04-30 12:55:21 -07:00
Jordan Ritter 81a0fbe080 fix(showcase): fix spring-ai D5 failures — all 28 features green
Root cause: TOOL_CALL_RESULT events reused the parent assistant
message ID, causing React deduplicateMessages() to overwrite
assistant messages with tool messages (Map keyed by ID). Fix uses
unique UUIDs for each tool result message across all three
controllers. Also adds data-testid to the BYOC hashbrown renderer
so the D5 harness can detect assistant messages, registers AG-UI
Jackson mixins via JacksonConfig postConfigurer, normalizes
array-format content via ContentNormalizingModule, removes ChatMemory
beans that interfered with aimock fixture matching, and injects
Spring-managed ObjectMapper into AgentConfigController.
2026-04-30 12:54:52 -07:00
Tyler Slaton 26e245c009 chore: run pnpm format
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-04-30 12:32:31 -07:00
Jordan Ritter e28295dd3d fix(showcase): spring-ai HITL D5 features — 6/11 green (#4505)
## Summary

- Spring-ai StreamingToolAgent now classifies tool calls as frontend vs
backend, emitting TOOL_CALL events without TOOL_CALL_RESULT for frontend
tools so the CopilotKit runtime's processAgentResult handles them
- On HITL re-invocation (tool result sent back), sends full AG-UI
message history to aimock/LLM via convertMessages() for correct fixture
matching
- Fixes 3 HITL features: hitl-text-input, hitl-approve-deny, hitl-steps
(spring-ai now 6/11 D5 green, up from 3/11)

## Remaining 5 failures (pre-existing, not caused by this PR)

| Feature | Root cause |
|---------|-----------|
| tool-rendering | CopilotKit frontend re-render drops assistant
messages (count goes 1→0) |
| shared-state-read | SharedStateReadWriteController — separate
controller, not StreamingToolAgent |
| shared-state-write | Same as shared-state-read |
| subagents | SubagentsController — aimock returns "No fixture matched"
(404) |
| mcp-apps | Depends on external MCP server (excalidraw.com) unreachable
from Docker |

All 5 fail identically on baseline (main) without this PR's changes.

## Test plan

- [x] `showcase test spring-ai --d5` — 6 green, 5 red (same 5 red on
baseline)
- [x] Direct curl to Java backend confirms correct AG-UI event sequences
for all HITL flows
- [x] No regressions: agentic-chat, gen-ui-custom, gen-ui-headless still
pass
2026-04-30 09:02:43 -07:00
Jordan Ritter 78deb8b488 fix(showcase): spring-ai HITL features — frontend tool detection + multi-turn history
StreamingToolAgent now classifies tool calls as frontend vs backend by
comparing input.tools() (CopilotKit-injected frontend tools) against
the registered toolCallbacks (backend tools). Frontend-only tool calls
emit TOOL_CALL_START/ARGS/END without TOOL_CALL_RESULT so the CopilotKit
runtime's processAgentResult detects the missing result and executes the
frontend handler (useHumanInTheLoop, useFrontendTool).

On re-invocation (when the runtime sends back the tool result), the
agent now sends the full AG-UI message history to aimock/LLM via
convertMessages() so the fixture matcher sees the tool result and
returns a follow-up text response instead of repeating the tool call.

Fixes 3 HITL D5 features: hitl-text-input, hitl-approve-deny,
hitl-steps. Spring-ai now passes 6/11 D5 features locally (up from 3).
The remaining 5 failures (tool-rendering, shared-state-read/write,
subagents, mcp-apps) are pre-existing and unrelated to StreamingToolAgent
— they involve separate controllers, missing aimock fixtures, external
MCP servers, and CopilotKit frontend rendering issues.
2026-04-30 08:40:47 -07:00
Alem Tuzlak 797e4177f2 Merge branch 'main' into blitz/lgp-d5-coverage-design/integration 2026-04-30 16:42:48 +02:00
Jordan Ritter 1a2f388863 fix(showcase): get built-in-agent to all-D5-green (10/10) (#4500)
## Summary

- Fixes all 10 D5 features for the built-in-agent TanStack integration
(was 6/10)
- Custom stream converter bypasses the runtime's `runFinished` blocking
(PR #4476) that breaks TanStack's multi-turn agent loop for server tools
- Forwards AG-UI frontend tools (useHumanInTheLoop, useRenderTool) as
TanStack definition-only declarations
- Fixes HITL TimePickerCard status case mismatch (CopilotKit v2 uses
lowercase "executing" not "Executing")
- Migrates hitl-in-chat demo to CopilotKit v2 with proper agentId wiring

## Test plan

- [x] `showcase/bin/showcase test built-in-agent --d5 --verbose` passes
10/10 (2 consecutive runs)
- [x] All 10 features: agentic-chat, gen-ui-headless, gen-ui-custom,
tool-rendering, shared-state-read, shared-state-write, hitl-text-input,
hitl-approve-deny, subagents, mcp-apps
2026-04-30 07:24:41 -07:00
Jordan Ritter 4107ab486b fix(showcase): get built-in-agent to all-D5-green (10/10)
Three fixes for the built-in-agent TanStack integration:

1. **Custom stream converter** — the runtime's `convertTanStackStream`
   (PR #4476) blocks all events after the first `RUN_FINISHED`, which
   breaks TanStack's multi-turn agent loop. Server tools like
   `get_weather` and `set_notes` need the loop to execute the tool,
   emit TOOL_CALL_RESULT, and re-prompt for the text response. Switch
   to `type: "custom"` with a local converter that skips RUN_FINISHED
   without blocking subsequent events, and deduplicates tool-call
   events (TanStack's buildToolResultChunks re-emits START/ARGS/END
   for server tool results).

2. **Frontend tool forwarding** — register AG-UI frontend tools
   (useHumanInTheLoop, useRenderTool, useFrontendTool) as TanStack
   definition-only declarations so the LLM can call them. Without
   this, tools like `book_call` were unknown to TanStack and silently
   dropped.

3. **HITL status case mismatch** — CopilotKit v2's ToolCallStatus uses
   lowercase strings ("executing") but the TimePickerCard checked for
   PascalCase ("Executing"). Normalize with toLowerCase() so buttons
   enable correctly.

Also migrates hitl-in-chat demo from CopilotKitProvider (v1) to
CopilotKit (v2) with proper agentId wiring.
2026-04-30 07:24:09 -07:00
Jordan Ritter 63878c3b12 fix(showcase): register request_user_approval stub in llamaindex hitl-in-app agent
AGUIChatWorkflow only emits TOOL_CALL_CHUNK events for tools registered
via the frontend_tools constructor argument. Without a backend stub for
request_user_approval the workflow silently dropped the tool call from
the aimock response, so CopilotKit never intercepted it and the approval
dialog never opened.

Add a FunctionTool stub (same pattern as book_call in hitl_in_chat_agent)
and pass it in frontend_tools so the AG-UI event chain fires correctly.

All 11 llamaindex D5 features now pass locally.
2026-04-30 06:41:34 -07:00
Jordan Ritter 17d68e5a0d fix(showcase): test built-in-agent with runtime PR #4482 pkg-pr-new build (#4485)
## Summary
Install pkg-pr-new build of @copilotkit/runtime (from PR #4482) in
built-in-agent, and align all demo page wiring with the LangGraph-Python
D5 fixtures.

**Runtime fix** — The `@copilotkit/runtime` dependency points to a
`pkg.pr.new` URL instead of the `next` npm tag. This MUST be reverted to
`"next"` once a proper @copilotkit/runtime release includes the TanStack
RUN_FINISHED fix from PR #4482.

**D5 wiring fixes** — Seven D5 features failed because built-in-agent
demo pages used different tool names and hook types than the LGP
reference agent:

- **tool-rendering**: switched from `useComponent("weather")` to
`useRenderTool("get_weather")` with correct `{parameters, result,
status}` render shape
- **gen-ui-tool-based**: renamed `useComponent("haiku")` to
`useComponent("generate_haiku")`, rewrote HaikuCard to accept args as
direct props
- **hitl-in-chat**: created `/demos/hitl-in-chat` route (was missing);
reuses TimePickerCard from hitl-in-chat-booking with `book_call` tool
- **shared-state**: added `set_notes` server tool so the fixture's
`set_notes` call has a backend handler
- **subagents**: renamed `delegate_to_planner`/`delegate_to_researcher`
to `research_agent`/`writing_agent`/`critique_agent` matching LGP
fixture tool names
- **subagents page**: updated `useComponent` registrations and
DelegationCard for the renamed tools

## Results
- Before: 3/10 D5 features pass
- After: targeting 10/10 (pending D5 probe verification)

## Test plan
- [x] Docker image builds
- [x] TypeScript check — no new errors (only pre-existing Zod version
mismatch)
- [x] All 6 files modified/created verified
- [ ] D5 probe run against deployed built-in-agent
- [ ] Team review of runtime change scope
- [ ] Revert runtime dep to `"next"` after proper release
2026-04-30 06:26:29 -07:00
Jordan Ritter dadd89e083 fix(showcase): fix llamaindex D5 failures (tool-rendering, gen-ui-headless, hitl-steps) (#4488)
## Summary

Fixes three D5 (e2e-deep) probe failures for the llamaindex integration:

- **tool-rendering**: `get_weather` was registered as a backend tool, so
the LlamaIndex AG-UI workflow emitted `TOOL_CALL_CHUNK` but never
`TOOL_CALL_RESULT`. CopilotKit's `useRenderTool` stayed stuck in loading
state and the WeatherCard never rendered with
`data-testid="weather-card"`. Fix: move `get_weather` to
`frontend_tools`, add `ToolCallResultWorkflowEvent` (subclasses
`ToolCallEndWorkflowEvent` to pass the AG_UI_EVENTS isinstance filter),
override `aggregate_tool_calls` to emit it for render-only tools, and
make WeatherCard always render its testid wrapper even during loading.

- **gen-ui-headless**: the shared agent was missing a `show_card`
frontend tool stub, so the workflow never emitted `TOOL_CALL_CHUNK` for
it. Fix: add `show_card` stub and register in `frontend_tools`.

- **hitl-steps**: `human_in_the_loop` was routed to the hitl-in-chat
specialized agent (which only has `book_call`), not the shared agent
(which has `generate_task_steps`). Fix: move `human_in_the_loop` to
`sharedAgentNames`. Introduce `render_only_tool_names` set to
distinguish render-only tools from interactive tools -- only render-only
tools get premature `TOOL_CALL_RESULT`; interactive tools let CopilotKit
manage the result lifecycle.

Also fixes two harness probe bugs:
- esbuild's `keepNames` transform injected `__name()` wrappers in
`page.evaluate()` browser context, causing `ReferenceError: __name is
not defined`. Replaced with string-based `new Function()` construction.
- `querySelector` only returned the first match; on headless chat pages
the first assistant message is an empty wrapper. Switched to
`querySelectorAll` with iteration.

## Test plan

- [x] `showcase/bin/showcase test llamaindex --d5 --verbose` passes
10/11 (hitl-approve-deny is pre-existing)
- [x] Two consecutive stable runs confirm no flapping
- [x] LangGraph-Python regression check confirms no breakage from
harness changes
2026-04-30 06:26:26 -07:00
Jordan Ritter cd8b46eeab fix(showcase/spring-ai): prevent streaming crash on frontend tool calls (#4487)
## Summary

- **StreamingToolAgent Phase 1 (streaming)**: Set
`internalToolExecutionEnabled=false` via `OpenAiChatOptions` so Spring
AI detects `tool_calls` in the stream without attempting execution
through the global `ToolCallingManager`. Previously,
`OpenAiChatModel.internalStream()` would auto-execute tool calls, and
when the model called frontend tools (like `generate_task_steps`,
`show_card`) that aren't registered on the Java backend,
`StaticToolCallbackResolver` returned null causing
`DefaultToolCallingManager` to throw `IllegalStateException`.
- **BoundedToolCallingManagerConfig**: Wrap `StaticToolCallbackResolver`
with `LenientToolCallbackResolver` that returns a
`FrontendToolPlaceholder` for unknown tools instead of letting the
resolver return null. This prevents crashes during Phase 2 (`.call()`)
when the model calls frontend tools injected by the CopilotKit runtime.
- **AG-UI event ordering**: Reorder event emission so tool call events
are emitted BEFORE `textMessageEnd`, which is required for the
frontend's `useRenderTool` to see them while the message is still open.

## Why

PR #4475 introduced `StreamingToolAgent` which uses Spring AI's
`.stream()` for real-time text delivery. However, Spring AI's
`OpenAiChatModel.internalStream()` auto-executes tool calls through the
global `ToolCallingManager`, which only knows about backend tools.
Frontend tools injected by the CopilotKit runtime caused
`IllegalStateException` crashes, breaking all D5 tests (0/11).

This fix recovers agentic-chat, gen-ui-custom, and gen-ui-headless D5
tests (3/11). The remaining 8 failures are pre-existing issues in other
controllers (subagents, shared-state, hitl) unrelated to the streaming
regression.

## Test plan

- [ ] `showcase test spring-ai --d5 --verbose` passes agentic-chat,
gen-ui-custom, gen-ui-headless
- [ ] Docker build succeeds locally
- [ ] No `IllegalStateException` in Spring AI container logs during D5
runs
- [ ] Frontend tool calls (generate_task_steps, show_card) handled
gracefully via placeholder
2026-04-30 06:26:22 -07:00
Jordan Ritter dca50b7dc7 fix(showcase): remove trailing slash from ms-agent-python hitl-in-app agent URL (#4486)
## Summary

- Remove trailing slash from the `hitl-in-app` agent URL in
ms-agent-python's CopilotKit route handler

## Why

The `hitl-in-app` agent was the **only** agent registered with a
trailing slash in the URL (`/hitl-in-app/`). The FastAPI backend mounts
the endpoint at `/hitl-in-app` (no slash). FastAPI's default
`redirect_slashes=True` returns a **307 redirect** for POST requests to
the trailing-slash variant, and the AG-UI `HttpAgent` does not follow
POST redirects during streaming. This caused the agent to appear
completely unresponsive — the D5 `hitl-approve-deny` probe timed out at
60s with `baseline=0, current=0` (zero assistant messages).

Verified via container: `POST /hitl-in-app/` returns 307 → `POST
/hitl-in-app` returns 422 (correct routing, body validation).

The fix uses the shared `createAgent("/hitl-in-app")` helper (which does
not append a trailing slash) for consistency with every other agent
registration in the file.

## Test plan

- [ ] D5 `hitl-approve-deny` passes for ms-agent-python (`showcase test
ms-agent-python --d5`)
- [ ] No regression in other ms-agent-python D5 features (10/11 → 11/11)
2026-04-30 06:26:18 -07:00
Alem Tuzlak 0eb81b1406 fix(showcase): unbreak agent-config + byoc D5, reaching 31/31 green
agent-config: drop the AgentConfigLangGraphAgent subclass and use plain
LangGraphAgent. The subclass repacked CopilotKit provider properties
into forwardedProps.config.configurable.properties so the Python graph
could read them via RunnableConfig.configurable.properties — but
@ag-ui/langgraph@0.0.31 builds the LangGraph SDK request as
{ ..., config, context: { ...input.context, ...config.configurable } }
which merges configurable INTO context. LangGraph 0.6.0+ then rejects
with HTTP 400 'Cannot specify both configurable and context' on every
chat round-trip. Net effect: chat sent the user message, runtime 400'd,
no assistant response ever rendered. Removing the subclass unbreaks
the round-trip; the Python agent falls back to its DEFAULT_* constants
so the demo's frontend toggles no longer steer the system prompt
(known regression, tracked separately pending @ag-ui/langgraph fix
that decouples context from configurable).

byoc:
- D5 probe now sends the 'Sales dashboard' pill prompt (matches the
  fixtures added in main:f0a89b843 in feature-parity.json) instead of
  the previous generic 'render a byoc hashbrown' prompt that had no
  matching JSON-shaped fixture. Removed the now-obsolete byoc.json D5
  fixture file and regenerated the d5-all.json bundle (52 -> 50
  fixtures).
- Added data-testid='copilot-assistant-message' + data-message-role=
  'assistant' to the byoc-hashbrown and byoc-json-render renderer
  wrapper divs. The CopilotChat default assistantMessage slot includes
  these markers; overriding the slot with a custom JSON-rendering
  component dropped them, so the e2e-deep conversation runner's
  settle-detection cascade (which counts these selectors) never saw
  the response and timed out at 30s. Re-attaching the markers is a
  purely additive change that doesn't affect the renderers'
  behavior.
- D5 byoc assertion now waits for [data-testid='metric-card'] AND a
  chart (bar-chart or pie-chart) to render — a structural check on
  the BYOC contract output, not a transcript-keyword check that the
  custom renderer would never produce.

E2E status: 31/31 passing locally against
./bin/showcase up langgraph-python aimock with this branch's bundle.
2026-04-30 15:11:19 +02:00
Alem Tuzlak a966999a21 fix(showcase): stop infinite tool-call loop in beautiful-chat + restore brand styling (#4490)
## Summary

Two related Beautiful Chat bugs in the integration showcases:

### Bug 1 — Infinite tool-call loop on every suggestion click

In `showcase/aimock/feature-parity.json`, 10 tool-calling fixtures
(`pieChart`, `barChart`, `render_pie_chart`×3, `render_bar_chart`×2,
`scheduleTime`, `search_flights`, `toggleTheme`) lacked an explicit `id`
on the `toolCall` and lacked a paired `toolCallId` followup fixture.

aimock's matcher (`router.js:36-46`) matches `userMessage` by
**substring** against the **last** user message. After the agent ran the
returned toolCall and re-prompted the LLM with the tool result attached,
the last user message was unchanged → the same fixture matched → the
same toolCall was returned forever. Repro: click any of the Pie Chart /
Bar Chart / Schedule Meeting / Search Flights / Toggle Theme suggestions
on `langgraph-python`'s `beautiful-chat` demo and watch the chart
re-render until manually stopped.

Fix follows the existing convention in the same file (compare the `Ada
Lovelace` / `show_card` pair):

- Added explicit `id` to each broken `toolCall`
(`call_fp_pie_chart_001`, `call_fp_bar_chart_001`, …)
- Added 11 new `toolCallId` followup fixtures at the top of the file
that match each id and respond with a brief `content` summary instead of
another toolCall

This shared file is loaded by every integration's `beautiful-chat` demo,
so the fix benefits all of them.

### Bug 2 — Black/white background split + broken CopilotKit logo

8 integrations use the full `ExampleLayout` pattern with `ThemeProvider`
and an `<img src="/copilotkit-logo.svg" />` (crewai-crews,
langgraph-fastapi, langgraph-python, langgraph-typescript, mastra,
ms-agent-dotnet, ms-agent-python, pydantic-ai). Two issues:

1. `globals.css` hardcoded `body { background: #fafaf9 }` and never
defined the brand tokens (`--background`, `--foreground`, `--card`,
`--primary`, `--secondary`, `--muted`, `--accent`, `--destructive`,
`--border`, `--input`, `--ring`, `--radius`) that the layout,
mode-toggle, todo card/column, and chart components reference via
Tailwind 4 arbitrary values. `ThemeProvider` was also adding `dark` to
`<html>` from system preference, so CopilotKit's chat went dark via
`[data-copilotkit] { background: var(--background) }` while body stayed
cream — that's the visible split the user reported.
2. `example-layout/index.tsx` renders `<img src="/copilotkit-logo.svg"
/>` but the file did not exist in any integration's `public/`.

Fix per integration:

- Added the full token set (light + dark) under `:root` and `:root.dark,
.dark`, registered the Tailwind 4 dark variant with `@custom-variant
dark (&:where(.dark, .dark *));`, switched `body` to
`var(--background)`/`var(--foreground)` so it tracks the same `dark`
class CopilotKit's chat is already responding to.
- Copied `copilotkit-logo.svg` and `copilotkit-logo-mark.svg` into each
integration's `public/` from
`examples/integrations/langgraph-python/public/`.

The 10 simplified-layout integrations (ag2, agno, built-in-agent,
claude-sdk-*, google-adk, langroid, llamaindex, spring-ai, strands)
don't render the logo or canvas split, so they don't need either fix.

## Verification

- `feature-parity.json`, `d5-all.json`, `smoke.json` parse cleanly
- `pnpm tsx showcase/scripts/validate-fixture-tool-surface.ts` → `104
fixtures × 603 demos — no drift`
- Programmatic check: every `toolCalls[].id` in `feature-parity.json`
now has a paired `toolCallId` followup fixture (no orphans)
- All 8 updated `globals.css` files have balanced braces and the
`:root.dark` block

## Test plan

- [ ] Click each of the 9 suggestion pills in `langgraph-python`
`beautiful-chat`; confirm tool-using suggestions no longer loop and end
with a text summary
- [ ] Toggle system theme → confirm chat side and canvas/body side stay
in sync (both light or both dark) on `langgraph-python` `beautiful-chat`
- [ ] CopilotKit logo renders in the chat header (no broken-image
placeholder)
- [ ] Spot-check one Pattern A integration (`langgraph-fastapi` or
`pydantic-ai`) and one Pattern B (`mastra` or `crewai-crews`) for the
same behavior
2026-04-30 14:05:20 +02:00
Alem Tuzlak ef4d88b717 fix(showcase/langroid): drop DEBUG warning leak + update stale tool-result tests
Two bugs introduced in 534cd1efa (D5 integration fixes) when the
langroid adapter switched backend tool results from TEXT_MESSAGE_*
triples to TOOL_CALL_RESULT events:

1. Two leftover `logger.warning("DEBUG ...")` calls in agui_adapter.py
   that fired on every chat turn — exactly the noise pattern the
   `test_plain_text_turn_does_not_warn` test was written to prevent.

2. Three stale tests in test_agui_adapter.py (only run on 3.11+, so
   the failure was 3.12-only):
   - test_backend_tool_execution_happy_path: still expected the old
     TEXT_MESSAGE_START/CONTENT/END inner triple instead of a single
     TOOL_CALL_RESULT event after TOOL_CALL_END.
   - test_backend_tool_exception_returns_sanitized_error: still read
     the sanitized error JSON from TEXT_MESSAGE_CONTENT.delta — it
     now rides on TOOL_CALL_RESULT.content.
   - test_plain_text_turn_does_not_warn: caught the DEBUG leak above.

Tests are skipped on Python 3.10 (langroid imports `typing.Self`),
which is why this only shows up on the 3.12 matrix entry.
2026-04-30 12:59:28 +02:00
Alem Tuzlak f1b02a4616 fix(showcase): stop infinite tool-call loop in beautiful-chat + restore brand styling
Beautiful Chat suggestion clicks looped forever because feature-parity.json
tool-calling fixtures lacked an `id` and a paired `toolCallId` followup.
After the agent ran the tool and re-prompted aimock, the same userMessage
substring matched again and the same toolCall was returned indefinitely.
Added explicit ids to 10 broken fixtures (pieChart, barChart, render_*_chart,
scheduleTime, search_flights, toggleTheme) and 11 paired toolCallId
followups returning content summaries — same convention the file already
uses for show_card, weather, etc.

Beautiful Chat layout also showed a black/white split and a broken logo on
the 8 integrations using the full ExampleLayout pattern (crewai-crews,
langgraph-fastapi, langgraph-python, langgraph-typescript, mastra,
ms-agent-dotnet, ms-agent-python, pydantic-ai). Two issues:

1. globals.css hardcoded `body { background: #fafaf9 }` and never defined
   the brand tokens (--background, --foreground, --card, --primary, …) that
   the layout, mode-toggle, todo card/column, and chart components reference
   via Tailwind 4 arbitrary values. ThemeProvider was also adding `dark` to
   <html> from system preference, so CopilotKit's chat went dark while body
   stayed cream.
2. example-layout/index.tsx renders <img src="/copilotkit-logo.svg" /> but
   the file did not exist in any integration's public/.

Added the full token set (light + dark) under :root and :root.dark/.dark,
registered the Tailwind 4 dark variant, switched body to var(--background)
/var(--foreground), and copied copilotkit-logo.svg + copilotkit-logo-mark.svg
into each integration's public/ from examples/integrations/langgraph-python.
2026-04-30 12:42:26 +02:00
Alem Tuzlak d34bb1ac16 fix(showcase/langroid): drop DEBUG warning leak + update stale tool-result tests
Two bugs introduced in 534cd1efa (D5 integration fixes) when the
langroid adapter switched backend tool results from TEXT_MESSAGE_*
triples to TOOL_CALL_RESULT events:

1. Two leftover `logger.warning("DEBUG ...")` calls in agui_adapter.py
   that fired on every chat turn — exactly the noise pattern the
   `test_plain_text_turn_does_not_warn` test was written to prevent.

2. Three stale tests in test_agui_adapter.py (only run on 3.11+, so
   the failure was 3.12-only):
   - test_backend_tool_execution_happy_path: still expected the old
     TEXT_MESSAGE_START/CONTENT/END inner triple instead of a single
     TOOL_CALL_RESULT event after TOOL_CALL_END.
   - test_backend_tool_exception_returns_sanitized_error: still read
     the sanitized error JSON from TEXT_MESSAGE_CONTENT.delta — it
     now rides on TOOL_CALL_RESULT.content.
   - test_plain_text_turn_does_not_warn: caught the DEBUG leak above.

Tests are skipped on Python 3.10 (langroid imports `typing.Self`),
which is why this only shows up on the 3.12 matrix entry.
2026-04-30 11:56:08 +02:00
Alem Tuzlak 4f0301922a chore(showcase): unify unsupported demo convention
Drop gen-ui-interrupt and interrupt-headless demo entries from
manifest.yaml for langroid and claude-sdk-typescript, and delete
the orphan stub page.tsx + README.md files for those routes. Both
features stay listed in not_supported_features so the dashboard
keeps showing the no-entry icon with hover tooltip.

Aligns these two integrations with the convention used by the other
12 integrations that mark these features unsupported (ag2, agno,
built-in-agent, claude-sdk-python, crewai-crews, google-adk,
llamaindex, mastra, pydantic-ai, spring-ai, strands): icon-only
with tooltip rather than a Demo / Code row that links to a stub
page explaining why there is nothing to demo.
2026-04-30 11:35:56 +02:00
github-actions[bot] 2ed24a1cb5 style: auto-fix formatting 2026-04-30 08:49:30 +00:00
Jordan Ritter f0952e7656 fix(showcase): fix llamaindex D5 failures for tool-rendering, gen-ui-headless, hitl-steps
Three D5 probe failures fixed:

tool-rendering: get_weather was a backend tool so the workflow emitted
TOOL_CALL_CHUNK but no TOOL_CALL_RESULT, leaving useRenderTool stuck in
loading state forever. Move get_weather to frontend_tools so CopilotKit
manages the tool call lifecycle. Add ToolCallResultWorkflowEvent (which
subclasses ToolCallEndWorkflowEvent to pass the AG_UI_EVENTS isinstance
filter) and override aggregate_tool_calls to emit TOOL_CALL_RESULT for
render-only tools. The WeatherCard component now always renders with
data-testid="weather-card" even during loading, instead of switching to
a separate div that lacks the testid.

gen-ui-headless: the shared agent was missing a show_card frontend tool
stub, so the workflow never emitted TOOL_CALL_CHUNK for it. Add the
stub and register it in frontend_tools.

hitl-steps: human_in_the_loop was routed to the hitl-in-chat specialized
agent (which only has book_call), not the shared agent (which has
generate_task_steps). Move human_in_the_loop to sharedAgentNames so it
routes through the default agent. Introduce render_only_tool_names set
to distinguish render-only tools (get_weather) from interactive tools
(generate_task_steps, book_call, show_card) — only render-only tools
get premature TOOL_CALL_RESULT; interactive tools let CopilotKit manage
the result lifecycle to keep buttons enabled.
2026-04-30 01:47:37 -07:00
Jordan Ritter e7980c71fd fix(showcase/spring-ai): prevent streaming crash on frontend tool calls
Spring AI's OpenAiChatModel.internalStream() auto-executes tool calls
through the global ToolCallingManager, which only knows about backend
tools. When the model calls frontend tools (generate_task_steps,
show_card, etc.) injected by the CopilotKit runtime, the
StaticToolCallbackResolver returns null and DefaultToolCallingManager
throws IllegalStateException, crashing the stream.

Two fixes:

1. StreamingToolAgent Phase 1 (streaming): set
   internalToolExecutionEnabled=false via OpenAiChatOptions so Spring AI
   detects tool_calls in the stream without attempting execution. Phase 2
   (.call()) keeps internal execution enabled so Spring AI's built-in
   loop handles backend tools.

2. BoundedToolCallingManagerConfig: wrap StaticToolCallbackResolver with
   LenientToolCallbackResolver that returns a FrontendToolPlaceholder
   for unknown tools instead of letting the resolver return null. This
   prevents the IllegalStateException during Phase 2 when the model
   calls frontend tools.

Also reorder AG-UI event emission so tool call events are emitted
BEFORE textMessageEnd, which is required for the frontend's
useRenderTool to see them while the message is still open.

Recovers agentic-chat, gen-ui-custom, and gen-ui-headless D5 tests
from 0/11 to 3/11. Remaining failures are pre-existing issues in
other controllers (subagents, shared-state, hitl).
2026-04-30 01:30:56 -07:00
github-actions[bot] 73c90bf022 style: auto-fix formatting 2026-04-30 07:40:00 +00:00
Jordan Ritter 4c8a2efe37 fix(showcase): align built-in-agent D5 wiring with LGP fixture tool names
Seven D5 features fail because built-in-agent demo pages use different
tool names and hook types than the LangGraph-Python reference agent
that the D5 fixtures were recorded against.

- tool-rendering: switch from useComponent("weather") to
  useRenderTool("get_weather") with correct {parameters, result, status}
  shape
- gen-ui-tool-based: rename useComponent("haiku") to
  useComponent("generate_haiku"), fix HaikuCard to accept args as
  direct props instead of {status, result, parameters}
- hitl-in-chat: create /demos/hitl-in-chat route (was missing); reuses
  TimePickerCard from hitl-in-chat-booking with book_call tool
- shared-state: add set_notes server tool to baseServerTools so the
  fixture's set_notes call has a backend handler
- subagents: rename delegate_to_planner/researcher to
  research_agent/writing_agent/critique_agent matching LGP tool names
- subagents page: update useComponent registrations and DelegationCard
  for the renamed tools
2026-04-30 00:38:38 -07:00
Jordan Ritter b3fb89842d fix(showcase): remove trailing slash from ms-agent-python hitl-in-app agent URL
The hitl-in-app agent was registered with a trailing slash in the URL
(`/hitl-in-app/`), while the FastAPI backend mounts the endpoint at
`/hitl-in-app` (no trailing slash). FastAPI's default redirect_slashes
behavior returns a 307 redirect for POST requests to the trailing-slash
variant, and the AG-UI HttpAgent does not follow POST redirects. This
caused the agent to appear completely unresponsive — the D5
hitl-approve-deny probe timed out at 60s with zero assistant messages.

Use the shared `createAgent()` helper (which does not append a trailing
slash) for consistency with every other agent registration in the file.
2026-04-30 00:34:46 -07:00
Jordan Ritter f5c97aea1e fix(showcase): test built-in-agent with @copilotkit/runtime@4482 pkg-pr-new build
Install the pkg.pr.new build of @copilotkit/runtime from PR #4482 to
validate the runFinished fix that stops duplicate TOOL_CALL_END events
in convertTanStackStream after TanStack's RUN_FINISHED.
2026-04-30 00:26:21 -07:00
Jordan Ritter c1775f37ca fix(showcase): apply FixedAGUIChatWorkflow to all llamaindex HITL agents
PR #4464 only applied the upstream bug fixes to hitl_in_chat_agent.py.
The same three bugs (duplicate tool-call rendering, missing
parent_message_id, incorrect tool-result message roles) affect the
hitl_in_app_agent and the main agent router.

Switch both to use FixedAGUIChatWorkflow via workflow_factory so all
llamaindex demo features get the corrected AG-UI event stream.
2026-04-29 23:19:46 -07:00
Jordan Ritter 67df2dedce fix(showcase): streaming tool execution for spring-ai D5
Spring AI's ChatClient.stream() does NOT auto-execute tool callbacks
(only .call() has a built-in tool execution loop). The stock AG-UI
SpringAIAgent uses .stream() exclusively, so tools are never invoked
and the CopilotKit runtime re-invokes the agent infinitely.

Replace SpringAIAgent with a custom StreamingToolAgent that:
- Phase 1: streams text via .stream() for real-time UX delivery
- Phase 2: if tool calls detected, re-invokes via .call() with
  tool callbacks so Spring AI's internal loop handles execution
- Emits proper AG-UI tool call events via wrapper callbacks

Also fix Jackson deserialization crashes from CopilotKit runtime
messages with unrecognised roles (activity, reasoning) by disabling
FAIL_ON_INVALID_SUBTYPE, with null-filtering at controller boundaries
to prevent NPEs in LocalAgent.combineMessages().

Affects all spring-ai endpoints: agentic_chat, agent-config,
a2ui-fixed-schema, subagents, shared-state-read-write.
2026-04-29 22:37:42 -07:00
Jordan Ritter 69398c01c9 Revert "fix(showcase): replace SpringAIAgent with SyncAgent for spring-ai D5 (#4469)"
This reverts commit ad774aed70, reversing
changes made to f420ceb696.
2026-04-29 22:21:11 -07:00
Jordan Ritter ad774aed70 fix(showcase): replace SpringAIAgent with SyncAgent for spring-ai D5 (#4469)
## Summary

- Replace `SpringAIAgent` (streaming `.stream()`) with custom
`SyncAgent` (synchronous `.call()`) for all spring-ai showcase
controllers
- Add `JacksonConfig` to handle unknown AG-UI message roles (activity,
reasoning) gracefully
- Fix the root cause of spring-ai D5 timeouts on tool-rendering,
hitl-steps, gen-ui, mcp-apps, and shared-state features

## Why

Spring AI's streaming mode does NOT auto-execute tool callbacks. The
model returns `tool_calls` in the SSE stream but the tools are never
invoked. The AG-UI event stream emits `TOOL_CALL_START/ARGS/END` without
`TOOL_CALL_RESULT`, causing the CopilotKit runtime to re-invoke the
agent in an infinite loop (and eventual timeout).

By using `ChatClient.call()`, Spring AI's internal tool-execution loop
runs tools automatically. `SyncAgent` wraps each backend tool callback
to capture AG-UI events during auto-invocation, and registers frontend
tools as pass-through callbacks.

The `JacksonConfig` addresses a secondary issue: the AG-UI Java SDK's
`MessageMixin` only maps 5 roles (assistant, developer, user, system,
tool). Messages with roles like "reasoning" cause
`InvalidTypeIdException` during deserialization. The config overrides
the mixin with `defaultImpl = UnknownMessage.class` so unknown roles
deserialize harmlessly.

## Test plan

- [ ] Docker build succeeds (verified locally)
- [ ] D5 tool-rendering passes
- [ ] D5 subagents passes
- [ ] D5 hitl-steps passes
- [ ] D5 mcp-apps passes
- [ ] D5 shared-state passes
2026-04-29 22:18:46 -07:00
Jordan Ritter 44778e637e fix(showcase): replace SpringAIAgent with SyncAgent for spring-ai D5
SpringAIAgent from the AG-UI Java SDK uses streaming (.stream()) for
Spring AI's ChatClient. In streaming mode, Spring AI does NOT auto-execute
tool callbacks -- the model returns tool_calls but the tools are never
invoked. This causes the CopilotKit runtime to see incomplete tool cycles
(TOOL_CALL_START/ARGS/END without TOOL_CALL_RESULT) and re-invoke the
agent in an infinite loop, producing the D5 timeouts on tool-rendering,
hitl-steps, gen-ui, and mcp-apps features.

SyncAgent uses ChatClient.call() instead, which runs Spring AI's internal
tool-execution loop synchronously. Backend tools are auto-invoked and
their results are captured as AG-UI events (TOOL_CALL_START/ARGS/END/
RESULT). Frontend tools from the CopilotKit runtime are registered as
pass-through callbacks that emit start/args/end events without a result,
letting the runtime handle frontend execution.

Also adds JacksonConfig to handle unknown message roles (activity,
reasoning) that the AG-UI Java SDK doesn't model. Without this, Jackson
throws InvalidTypeIdException on deserialization, causing request failures
before any controller logic runs.

Changes:
- Add SyncAgent.java: LocalAgent subclass using .call() with event-
  capturing tool callback wrappers
- Add JacksonConfig.java: lenient MessageMixin with defaultImpl for
  unknown roles
- Update AgentConfig to return SyncAgent bean instead of SpringAIAgent
- Update AgentController to inject SyncAgent instead of SpringAIAgent
- Update A2uiFixedSchemaController to build SyncAgent per request
- Update AgentConfigController to build SyncAgent per request
2026-04-29 22:18:19 -07:00
Jordan Ritter 0d4cdc6625 fix(showcase): fix llamaindex hitl-text-input D5 test failure
The LlamaIndex AGUIChatWorkflow has three bugs that caused the
hitl-text-input test to fail:

1. ToolCallChunkWorkflowEvent emitted without parent_message_id,
   causing the AG-UI client to create a duplicate assistant message
   (one from MESSAGES_SNAPSHOT, one from dechunked TOOL_CALL_START).
   The duplicate produced 8 time-picker buttons instead of 4.

2. _snapshot_messages embeds toolCalls in the MESSAGES_SNAPSHOT AND
   emits separate TOOL_CALL_CHUNK events, so the client registers
   the same tool call twice on the same message.

3. ag_ui_message_to_llama_index_message converts AG-UI ToolMessages
   to ChatMessage(role='user') instead of role='tool', so the second-
   leg OpenAI API call has no tool-result message and aimock's
   hasToolResult matcher fails.

Fix: subclass AGUIChatWorkflow (FixedAGUIChatWorkflow) that:
- Assigns a stable ID to assistant messages and passes it as
  parent_message_id on ToolCallChunk events
- Strips toolCalls from MESSAGES_SNAPSHOT (letting TOOL_CALL_CHUNK
  be the sole mechanism)
- Corrects tool-result message role from 'user' to MessageRole.TOOL
  so the OpenAI API receives proper tool-result messages
2026-04-29 22:02:39 -07:00
Jordan Ritter c9b0c59a02 fix(showcase/ag2): remove __future__ annotations causing deploy crash (#4456)
## Summary

- Remove `from __future__ import annotations` from
`agent_config_agent.py` which causes the AG2 agent server to crash on
startup with `PydanticInvalidForJsonSchema: Cannot generate a JsonSchema
for core_schema.CallableSchema`
- The import turns `ContextVariables` type hints into string ForwardRefs
that AG2's pydantic TypeAdapter can't resolve at tool registration time
- This fix was previously applied (cb2ef941) but reverted as part of the
broader D2 revert (5a28b778)

## Test plan

- [x] Built Docker image locally and confirmed crash reproduction on
current main
- [x] Applied fix, rebuilt, confirmed agent starts successfully (`Agent
started (PID: 8)` vs previous `ERROR: Agent failed to start`)
- [x] Verified the current deployed GHCR image also crashes
(pre-existing since the D2 revert)
2026-04-29 20:00:55 -07:00
Jordan Ritter 6ddd3bb603 fix(showcase/ag2): remove __future__ annotations from agent_config_agent
The `from __future__ import annotations` import turns the
`ContextVariables` type hint on the @tool-decorated
`get_current_config` function into a string ForwardRef that AG2's
pydantic TypeAdapter cannot resolve at registration time, raising
`PydanticInvalidForJsonSchema: Cannot generate a JsonSchema for
core_schema.CallableSchema` and crashing the entire FastAPI agent
server on startup.

This fix was previously applied (cb2ef9411) but reverted as part of
the broader D2 revert (5a28b778c). The file uses no PEP 585/604
syntax, so the import was purely harmful.
2026-04-29 20:00:30 -07:00
Jordan Ritter af289671d0 fix(showcase): add missing @copilotkit/voice dep to mastra and google-adk
The voice demo route handler imports @copilotkit/voice which was not
declared in these two package.json files. Other integrations either
had it or resolved it via hoisting, but mastra's Docker build failed.
2026-04-29 19:58:05 -07:00
Jordan Ritter 6dfdc55ad3 fix: add missing byoc-json-render deps to mastra showcase
The byoc-json-render demo imports @json-render/core, @json-render/react,
@radix-ui/react-checkbox, and @radix-ui/react-separator, but these were
never added to mastra's package.json (they exist in langgraph-python and
all other integrations). This causes webpack Module not found errors
during next build in Docker.
2026-04-29 19:51:30 -07:00
Jordan Ritter 3a8c5131cb style(showcase/langroid): auto-format tool-rendering page 2026-04-29 19:45:48 -07:00
Jordan Ritter 534cd1efa7 fix(showcase): D5 integration fixes across 12 frameworks
Per-framework fixes to pass D5 e2e-deep probes:
- agno: deduplicate agent_server routes
- claude-sdk-python: handle ParsedContentBlockStopEvent (SDK v0.97+)
- claude-sdk-typescript: remove orphan tool-rendering page
- crewai-crews: add backend tool_rendering agent + shared_state fix
- google-adk: add AGUIToolset to all ADK agents for frontend tools
- langgraph-typescript: remove stale import
- langroid: emit ToolCallResultEvent for backend tools + fix adapter
- llamaindex: v2 provider import, book_call stub, PYTHONPATH fix
- ms-agent-python: disable Responses API store for aimock compat
- pydantic-ai: simplify gen-ui page component
- spring-ai: raise tool iteration cap (1→5) + fix connection pooling
- strands: shared tools symlink + requirements update
2026-04-29 19:40:10 -07:00
Sam Julien 8ba692c426 fix(showcase): regenerate all 18 integration package-lock.json files
Recent feature commits added new dependencies to integration package.json
files (@copilotkit/voice, @hashbrownai/{core,react}, @json-render/{core,react})
and bumped Next.js from 15.4.10 to 15.5.15, but never regenerated the
corresponding package-lock.json. The Showcase Build & Deploy workflow runs
`npm ci --legacy-peer-deps` which strictly enforces lock sync, so every
deploy attempt has been failing at the install step. No new images have been
pushed to GHCR, so Railway services have stayed on stale code and any cell
added since each fw's last successful deploy iframes 404.

Regenerated all 18 lockfiles via `npm install --legacy-peer-deps
--package-lock-only --ignore-scripts` per integration. Verified each with
`npm ci --dry-run --legacy-peer-deps` — all clean.

Refs PDX-90.
2026-04-29 15:39:13 -07:00
github-actions[bot] be073359f9 style: auto-fix formatting 2026-04-29 21:51:40 +00:00
Sam Julien 815d5b377a fix(showcase): dedupe React imports in custom-bubbles sibling snippets
`custom-bubbles.snippet.tsx` in google-adk and llamaindex was built in
PR #4439 by concatenating two source files (user-bubble.tsx +
assistant-bubble.tsx). Each source had its own `import React from "react"`,
so the resulting sibling carried two copies and tripped
oxlint's no-redeclare rule.

Drops the second `import React from "react"` in each file. React is
already imported by the first one — the duplicate was always dead.
Resolves the 2 oxlint errors that were causing CI failure.
2026-04-29 14:49:39 -07:00
github-actions[bot] c3dbba44c8 style: auto-fix formatting 2026-04-29 14:49:39 -07:00
Sam Julien 3b45398251 fix(showcase): repair @endregion[sample-audio-button] placement broken by region-marker script
The marker-insertion script in ac3885fe0 used a brace counter that
counted opening braces from the destructured function parameters as
the start of the function body, then matched the destructuring's
closing `}` as the body's close. The result on every fw was an
`@endregion[sample-audio-button]` jammed onto the same line as the
destructuring's `}`, with the actual function body falling outside the
region — broken structure plus a format violation (`}// @endregion` on
one line).

Fixes both: strips the broken inline endregion and appends a proper
@endregion marker at end-of-file (which is where the function actually
ends, since these files contain only the single SampleAudioButton
function below the imports + interface). 17 files restored.
2026-04-29 14:49:39 -07:00