Commit Graph

8572 Commits

Author SHA1 Message Date
Alem Tuzlak 8e67d42a66 Merge branch 'main' into fix/showcase-byoc-aimock-fixtures 2026-04-30 14:07:33 +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 5c945b6b09 chore(showcase): unify unsupported demo convention (#4489)
## Summary

Aligns `langroid` and `claude-sdk-typescript` with the rest of the
showcase fleet for how they expose unsupported HITL/interrupt demos on
the dashboard matrix.

Today these two integrations list `gen-ui-interrupt` and
`interrupt-headless` in BOTH `not_supported_features` AND `demos[]`
(with stub pages that explain why the demo doesn't work). Every other
integration that marks these features unsupported (ag2, agno,
built-in-agent, claude-sdk-python, crewai-crews, google-adk, llamaindex,
mastra, pydantic-ai, spring-ai, strands) lists them only in
`not_supported_features` — the dashboard then renders a single no-entry
icon with a hover tooltip and no demo link.

This PR moves langroid and claude-sdk-typescript onto that same
convention.

## Changes

- `showcase/integrations/langroid/manifest.yaml` — drop
`gen-ui-interrupt` and `interrupt-headless` entries from `demos:` (kept
in `not_supported_features`)
- `showcase/integrations/claude-sdk-typescript/manifest.yaml` — same
- Delete the orphan stub `page.tsx` + `README.md` files under
`src/app/demos/gen-ui-interrupt/` and
`src/app/demos/interrupt-headless/` for both integrations (8 files
total)

## Test plan

- [x] `pnpm run validate-manifests` — all 18 integrations pass
- [x] `pnpm exec oxfmt --check <both manifests>` — clean
- [x] `pnpm exec nx run @copilotkit/react-core:test` — passes (one flaky
retry from the pre-commit hook resolved on second run, per Nx flaky-task
warning)
- [ ] Verify on the dashboard matrix that langroid and
claude-sdk-typescript render an icon-only cell with hover tooltip for
`In-Chat HITL (useInterrupt — low-level primitive)` and `Interrupt
(Headless)`, matching the other 12 integrations
2026-04-30 14:04:56 +02:00
Alem Tuzlak d748bc6a83 chore(showcase): ratchet validate-pins hash baseline
Pre-existing drift on main: count held at 134, hash shifted (one
FAIL healed, another regressed). Captured the new sorted-FAIL hash
locally with the same algorithm CI uses (sort -u | shasum -a 256)
and updated showcase/scripts/fail-baseline.json to match.
2026-04-30 14:03:12 +02:00
Alem Tuzlak c3f3631e58 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 14:03:03 +02:00
Alem Tuzlak f0a89b8430 fix(showcase): add aimock fixtures for byoc-json-render + byoc-hashbrown pills
Both BYOC demo pills were getting eaten by older generic substring
fixtures ("dashboard", "revenue by category as a pie chart", "monthly
expenses as a bar chart") — the json-render pills came back as foreign
tool calls (render_pie_chart) and the hashbrown sales pill came back as
the "Working on your request..." placeholder, leaving both renderers
empty.

Add a dedicated fixture per pill keyed on the full pill prompt sentence,
placed before the conflicting generic rules so first-fixture-wins lands
on the right one. Each fixture returns the exact content shape the
demo's renderer expects:

  byoc-json-render -> {root, elements} flat spec for <Renderer />
  byoc-hashbrown   -> {ui:[{<tag>:{props:{...}}}]} for useJsonParser

Removes two pre-existing duplicates that had been added at the bottom of
the file but never matched because the conflicting generic rules came
first.
2026-04-30 13:54:29 +02:00
github-actions[bot] e1fc123332 style: auto-fix formatting 2026-04-30 11:36:20 +00:00
Alem Tuzlak 99868c7c46 feat(showcase): regenerate d5-all.json bundle and fix DOM typing in chat-css probe (F) 2026-04-30 13:25:27 +02:00
Alem Tuzlak 203da612db feat(showcase): D5 scripts for interrupt + BYOC families (B6) 2026-04-30 13:23:26 +02:00
Alem Tuzlak 56974444f8 feat(showcase): D5 scripts for gen-UI family (B5) 2026-04-30 13:22:00 +02:00
Alem Tuzlak b9246586b5 feat(showcase): D5 scripts for state family (B4) 2026-04-30 13:20:20 +02:00
Alem Tuzlak 465c9b697a feat(showcase): D5 scripts for frontend-tools + reasoning families (B3) 2026-04-30 13:19:15 +02:00
Alem Tuzlak 7f3d458cdf feat(showcase): D5 scripts for platform family (B2: auth, multimodal, agent-config) 2026-04-30 13:17:01 +02:00
Alem Tuzlak a5f347e88f feat(showcase): D5 scripts for chat-surface family (B1) 2026-04-30 13:12:16 +02:00
Alem Tuzlak e2065dc98f feat(showcase): scaffold 20 new D5FeatureType literals for LGP coverage 2026-04-30 13:06:33 +02:00
Alem Tuzlak b5e43b35c6 chore(showcase): ratchet validate-pins hash baseline
Pre-existing drift on main: count held at 134, hash shifted (one
FAIL healed, another regressed). Captured the new sorted-FAIL hash
locally with the same algorithm CI uses (sort -u | shasum -a 256)
and updated showcase/scripts/fail-baseline.json to match.
2026-04-30 12:59:28 +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 b243a21e95 docs: LGP D5 coverage design plan 2026-04-30 12:42:35 +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 bea43fb999 chore(showcase): ratchet validate-pins hash baseline
Pre-existing drift on main: count held at 134, hash shifted (one
FAIL healed, another regressed). Captured the new sorted-FAIL hash
locally with the same algorithm CI uses (sort -u | shasum -a 256)
and updated showcase/scripts/fail-baseline.json to match.
2026-04-30 11:41:03 +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
Alem Tuzlak 917c54a8d1 Merge branch 'main' into tyler/kind-mendeleev-636369 2026-04-30 11:03:19 +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 d44de79512 fix(showcase): fix gen-ui probe __name ReferenceError and querySelectorAll cascade
The gen-ui-headless D5 probe had two bugs:

1. esbuild's keepNames transform injects __name() wrappers around const
   arrow functions. When those functions run inside page.evaluate() in
   the browser context, __name is not defined. Replace with string-based
   new Function() construction using function declarations.

2. findFirstNonTrivial and readChildCountForSelector used querySelector
   which only returns the first match. On headless chat pages, the first
   assistant message div is an empty wrapper (children=0), causing the
   cascade to skip the selector even when a later match contains the
   rendered gen-UI component. Switch to querySelectorAll and iterate all
   matches.
2026-04-30 01:47:19 -07:00
Alem Tuzlak 8647a1fcb6 Merge branch 'main' into fix/spring-ai-streaming-regression 2026-04-30 10:39:02 +02:00
Alem Tuzlak 73c0e5e8eb fix(react-core): re-attach input overlay observer after welcome screen (#4472)
## Summary

Fixes a regression introduced by
[f9eee68](https://github.com/CopilotKit/CopilotKit/commit/f9eee688b)
(overlay chat input on scroll area) where late messages and "always"
suggestions slid underneath the absolute-positioned input pill once the
user submitted their first message.

**Root cause:** the `ResizeObserver` `useEffect` in `CopilotChatView`
had `[]` deps. On a fresh chat it mounted with the welcome-screen branch
active — `inputContainerRef.current` was null, the effect bailed, and it
never re-ran when the chat-view branch attached the overlay element.
`inputContainerHeight` stayed at 0, so the scroll content's reserved
bottom padding sat at 32px instead of ~input height.

**Fix:** hold the overlay element in state via a callback ref and key
the effect on the element. Same pattern already used by
`nonAutoScrollRefCallback` elsewhere in this file. The observer now
attaches and detaches reactively as the overlay mounts/unmounts.

## Test plan

- [x] New regression test in `CopilotChatView.inputOverlay.test.tsx`
mounts on the welcome screen, re-renders with messages, and asserts the
observer attaches to the new overlay element and feeds the correct
`paddingBottom` (88 + 32 = 120px). Reverting the fix makes it fail at
the post-transition padding assertion.
- [x] Existing 4 inputOverlay tests still pass.
- [ ] Verify in the demo: load a fresh chat, submit a message, confirm a
long assistant response leaves a gap above the input pill (no content
sliding under the pill).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-30 10:36:36 +02: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
Alem Tuzlak 672070946f fix(react): render image attachments as compact thumbnails (#4459)
## What does this PR do?

Polish image attachments in chat. Previously they rendered at the full
message
width, taking up most of the screen. After this PR they render as
compact 80x80
thumbnails — closer to how Claude shows attached images.

**Layout & sizing**
- Image attachments render as 80x80 thumbnails with `object-cover`, 12px
rounded corners, and a muted background so transparent PNGs stay
readable.
- Multiple attachments lay out in a horizontal row (`flex-row` +
`flex-wrap` +
  `justify-end`) instead of stacking vertically.
- Attachments render *above* the message text instead of below.

**Click-to-zoom**
- Clicking a thumbnail opens it in a fullscreen lightbox with a smooth
  view-transition morph (same UX as the attachment queue preview).
- The `Lightbox` + `useLightbox` previously private to
  `CopilotChatAttachmentQueue` got extracted into a shared module
(`packages/react-core/src/v2/components/chat/Lightbox.tsx`) so the queue
and
  the rendered message attachment share one modal implementation.

**Both renderers updated**
- v2 (Tailwind): `CopilotChatAttachmentRenderer.tsx` +
`CopilotChatUserMessage.tsx`
- legacy (CSS): `packages/react-ui/src/css/messages.css`

## Related PRs and Issues

- N/A

## 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-04-30 09:53:20 +02: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 f0c73fdebc fix(showcase): replace ? with strikethrough for unavailable probe depths (#4484)
## Summary

- When a dashboard cell has no probe data for a depth (D5, D6), the
badge now renders the dimension name with CSS `line-through` instead of
appending a `?` label
- Strikethrough communicates "this depth hasn't run" more clearly than
`D5 ?`
- Same treatment applied to the CellDrilldown panel (renders
strikethrough `n/a` instead of `?`)

## Test plan

- [x] cell-drilldown tests updated and passing
- [x] live-status tests passing (formatLabel still returns `?`
internally; rendering layer handles display)
- [x] depth-chip, depth-utils, chips-explainer tests all green
2026-04-30 00:08:58 -07:00
Jordan Ritter 7e5da38471 fix(showcase): replace ? with strikethrough for unavailable probe depths
When a dashboard cell has no probe data for a depth (D5, D6), render
the dimension name with CSS line-through instead of appending a "?"
label. Strikethrough communicates "this depth doesn't exist / hasn't
run" more clearly than "D5 ?".

Changes:
- Badge component: when label is "?", render name with line-through
  styling and suppress the question mark
- CellDrilldown BadgeRow: render "n/a" with line-through instead of "?"
- Update cell-drilldown test to verify strikethrough rendering
2026-04-30 00:08:34 -07:00
Tyler Slaton 98fbcd5ea4 feat(langgraph-py): add file-uploads and bug-fixes (#4483) 2026-04-30 00:01:21 -07:00
Tyler Slaton cff40fdf20 fix(react-core): re-attach overlay observer when leaving welcome screen
`CopilotChatView` mounts on the welcome-screen branch, where the absolute-
positioned input overlay (and its `inputContainerRef`) does not exist. The
ResizeObserver useEffect ran once with an empty `[]` dep array, found
`ref.current === null`, and bailed. Submitting the first message swapped
to the chat-view branch and attached the overlay element — but the effect
never re-ran, so `inputContainerHeight` stayed at 0 and the scroll
content's reserved bottom padding sat at 32px instead of ~input height.
Late messages and any "always" suggestion strip slid underneath the input
pill, invisible to the user.

Hold the overlay element in state via a callback ref and key the effect
on the element. Same pattern already used by `nonAutoScrollRefCallback`
in this file. Effect now attaches and detaches reactively as the overlay
mounts/unmounts (e.g. clearing messages and falling back to the welcome
screen also resets the measured height instead of holding stale data).

Add a test that mounts on the welcome screen, re-renders with messages,
and asserts the observer attaches to the new overlay element and feeds
the correct paddingBottom. Reverting the fix makes it fail on the
post-transition padding assertion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-29 23:55:26 -07:00
Tyler Slaton 01fd0ac6d7 feat(langgraph-py): add file-uploads and bug-fixes
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-04-29 23:54:10 -07:00
Jordan Ritter 0a7e1be184 fix(showcase): apply FixedAGUIChatWorkflow to all llamaindex agents (#4481)
## Summary
- Apply `FixedAGUIChatWorkflow` to `hitl_in_app_agent.py` and the main
`agent.py` router
- PR #4464 only fixed `hitl_in_chat_agent.py`; the same three upstream
llamaindex bugs affect all agents using `AGUIChatWorkflow`
- Switches both files to `workflow_factory` pattern importing
`FixedAGUIChatWorkflow`

## Why
The D5 probe failures for llamaindex hitl-approve-deny and hitl-steps
features are caused by the same upstream bugs (duplicate tool-call
events, missing parent_message_id, wrong tool-result message role) that
were already fixed for hitl-in-chat.

## Test plan
- [ ] GHCR image builds successfully
- [ ] D5 probes pass for llamaindex hitl-approve-deny and hitl-steps
features
2026-04-29 23:20:09 -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 bafd9f9fab docs(showcase): add production debugging section to RUNBOOK (#4480)
## Summary
- Production debugging section: harness log events, debug-level traces,
manual probe triggering
- Package.json rebuild requirement documentation

## Test plan
- [x] Documentation only
2026-04-29 22:59:37 -07:00
Jordan Ritter 495a1c8b03 docs(showcase): add production debugging section to RUNBOOK
Covers harness probe logging, debug-level conversation traces,
manual probe triggering, and package.json rebuild requirements.
2026-04-29 22:59:26 -07:00
Jordan Ritter c7967dd375 fix: add debug logging to D5 probe execution pipeline (#4479)
## Summary

Adds comprehensive `console.debug` logging to the D5 probe execution
pipeline so production probe failures are diagnosable from logs alone,
without requiring reproduction.

**conversation-runner.ts** (the core multi-turn conversation engine):
- Logs conversation start/end with turn count and settle configuration
- Logs chat input selector cascade resolution -- each selector miss and
the final hit
- Logs per-turn lifecycle: message send, assistant settle wait, message
count changes, assertion execution, and failures with elapsed times
- Logs the fillAndVerifySend retry loop with attempt counts and user
message baseline vs current counts
- Logs waitForAssistantSettled polling with count changes, periodic
status during long waits (~every 5s), and timeout details

**e2e-deep.ts** (the driver that orchestrates per-feature runs):
- Logs page navigation URL and result
- Logs React hydration wait start, success, and timeout
- Logs conversation turn count after buildTurns
- Logs conversation success/failure with diagnostic capture summary

**All 9 D5 scripts** (agentic-chat, gen-ui-custom, gen-ui-headless,
hitl-approve-deny, hitl-steps, hitl-text-input, mcp-subagents,
shared-state, tool-rendering):
- Logs expected tokens/fragments and actual assistant text at each
assertion checkpoint
- Logs DOM element discovery (matched selectors, child counts, card
structure)
- Logs polling progress for long-running assertions (tool card probe,
chained reply fragments)

All logging uses `console.debug(...)` which is suppressed at INFO level
in production but available when operators set `LOG_LEVEL=debug` for
investigation.

## Test plan

- [x] All 1372 existing tests pass (`cd showcase/harness && npx vitest
run` -- 70 test files, 0 failures)
- [x] Debug output is visible in test stdout (vitest captures it
per-test)
- [x] No functional changes -- all logging is additive `console.debug`
calls
2026-04-29 22:56:30 -07:00
Jordan Ritter 1320abb40f fix: add comprehensive debug logging to D5 probe execution pipeline
Instrument the conversation runner, e2e-deep driver, and all D5 scripts
with console.debug logging at every decision point so production probe
failures are diagnosable without reproduction.

conversation-runner.ts:
- Log conversation start/end with turn count and settle config
- Log chat input selector cascade resolution (each miss and final hit)
- Log per-turn lifecycle: message send, settle wait, count changes,
  assertions, and failures with elapsed times
- Log fillAndVerifySend retry loop with attempt counts and user message
  baseline/current counts
- Log waitForAssistantSettled polling with count changes, periodic
  status during long waits, and timeout details

e2e-deep.ts (runFeature):
- Log page navigation URL and result
- Log React hydration wait (start, success, timeout)
- Log conversation turn count after buildTurns
- Log conversation success/failure with diagnostics

All D5 scripts (d5-agentic-chat, d5-gen-ui-custom, d5-gen-ui-headless,
d5-hitl-approve-deny, d5-hitl-steps, d5-hitl-text-input,
d5-mcp-subagents, d5-shared-state, d5-tool-rendering):
- Log expected tokens and actual assistant text at each assertion
- Log DOM element discovery (selectors matched, child counts)
- Log polling progress for long-running assertions (tool card probe,
  chained reply fragments)
2026-04-29 22:56:00 -07:00
Jordan Ritter 46ab39b593 fix(showcase): scope D5 text extraction to prose div, not full message (#4478)
## Summary

- **Root cause**: `readLastAssistantText` was reading `textContent` from
the entire `[data-testid="copilot-assistant-message"]` wrapper, which
includes rendered tool-component output (PieChart SVG labels like
`Electronics42,000Clothing28,000...`) alongside the actual assistant
chat text
- Scopes the text extraction to the prose/markdown child div
(`[class*="prose"]`) inside the canonical CopilotKit message DOM
structure, which contains only the assistant's text response
- Falls back gracefully for headless/custom-composer demos that don't
use the canonical DOM layout
- Adds debug logging (`[readLastAssistantText]`) so production traces
show which DOM element was selected and what text was extracted

## Test plan

- [x] All 1372 harness unit tests pass (`npx vitest run`)
- [x] TypeScript compiles cleanly (`npx tsc --noEmit`)
- [ ] Local D5 test against langgraph-python gen-ui-custom passes
- [ ] Production D5 probe for langgraph-python stops flapping
2026-04-29 22:53:17 -07:00
Jordan Ritter 1834ffe2d0 fix(showcase): scope D5 text extraction to prose div, not full message
readLastAssistantText was reading textContent from the entire assistant
message wrapper, which includes rendered tool-component output (SVG
chart labels like "Electronics42,000Clothing28,000...") in addition to
the actual chat text. This caused gen-ui-custom probes to fail token
assertions because the extracted text was the rendered PieChart content
instead of the follow-up narration.

Scope the extraction to the prose/markdown child div inside the
canonical CopilotKit message structure, which contains only the
assistant's text response. Falls back gracefully when the expected
DOM structure isn't present (headless/custom composers).

Also adds debug logging so production traces show which element was
selected and what text was extracted.
2026-04-29 22:52:52 -07:00
Tyler Slaton 5fe7ec55ca Merge branch 'main' into tyler/kind-mendeleev-636369 2026-04-29 22:46:51 -07:00
Jordan Ritter 6c5304dff7 fix(runtime): stop converting TanStack stream after RUN_FINISHED (#4476)
## Summary

- Fixes built-in-agent D5 failures caused by duplicate `TOOL_CALL_END`
events from TanStack's internal tool execution loop
- TanStack's `chat()` engine runs a multi-turn agent loop that re-emits
`TOOL_CALL_END` for frontend-only tools (like `render_pie_chart`)
without a preceding `TOOL_CALL_START`, violating the ag-ui verify
middleware
- Adds `runFinished` flag to `convertTanStackStream` to discard all
events after the first `RUN_FINISHED`
- Adds built-in-agent to `docker-compose.local.yml` and
`local-ports.json`

## Test plan

- [x] Runtime test suite passes (1412/1412 tests, 101 files)
- [x] Container hotpatch verified: no more duplicate TOOL_CALL_END
errors in logs
- [x] D5 hitl-approve-deny now passes (was failing due to this bug)
- [x] aimock v1.16.3 released with complementary item_id fix
2026-04-29 22:42:22 -07:00
Jordan Ritter b355acd56c fix(runtime): stop converting TanStack stream after RUN_FINISHED
TanStack's chat() engine runs a multi-turn agent loop: after the model
returns tool calls, it tries to execute them via processToolCalls().
Frontend-only tools (like render_pie_chart) are unknown to TanStack, so
executeToolCalls() treats them as errors and buildToolResultChunks()
re-emits TOOL_CALL_END without a preceding TOOL_CALL_START. The ag-ui
verify middleware rejects this duplicate.

Fix: track a runFinished flag in convertTanStackStream and discard all
events after the first RUN_FINISHED, which marks the boundary between
the streaming pass and TanStack's internal tool execution loop.

Also adds built-in-agent to docker-compose.local.yml and local-ports.json.
2026-04-29 22:41:58 -07:00