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.
Picks up ag-ui-protocol/ag-ui#1578 — `import * as jsonpatch from
"fast-json-patch"` produced an empty namespace under Node native ESM
because fast-json-patch@3.x populates exports via Object.assign, which
the CJS→ESM named-export detector cannot see. Result: every STATE_DELTA
and ACTIVITY_DELTA event threw "applyPatch is not a function", and
LangGraph generative UI streams floods the console with the failure on
each patch.
0.0.53 switches to a default import so the emitted bundle works under
both ESM and CJS consumers. Bumped @ag-ui/core and @ag-ui/encoder in
lockstep since they share the release.
## Summary
- Replace `SpringAIAgent` (AG-UI SDK) with custom `StreamingToolAgent`
that uses `.stream()` for real-time text delivery and `.call()` with
tool callbacks when tools are needed
- Spring AI's `ChatClient.stream()` fundamentally does NOT auto-execute
tool callbacks; only `.call()` has the built-in tool execution loop. The
stock `SpringAIAgent` used `.stream()` exclusively, so tools were never
invoked and the CopilotKit runtime re-invoked the agent infinitely
- Fix Jackson `InvalidTypeIdException` crashes from CopilotKit runtime
messages with unrecognized roles (`activity`, `reasoning`) by disabling
`FAIL_ON_INVALID_SUBTYPE`, with null-filtering at controller boundaries
## Root cause
The AG-UI Java SDK's `SpringAIAgent` calls
`chatClient.prompt().stream().chatResponse().subscribe()`. In Spring AI
1.0.1, the `.stream()` path does not execute tool callbacks — it only
streams text chunks. When the model returns `tool_calls` in the stream,
they're captured as AG-UI events but the actual Java tool functions are
never invoked. The CopilotKit runtime sees incomplete tool cycles and
re-invokes the agent infinitely.
## Approach
`StreamingToolAgent` implements a two-phase approach:
1. **Phase 1 (stream)**: Uses `.stream()` WITHOUT tool callbacks for
real-time text delivery. Detects whether the model wants to call tools.
2. **Phase 2 (call with tools)**: If tools are needed, re-invokes via
`.call()` WITH tool callbacks. Spring AI's built-in tool execution loop
handles all iterations automatically. AG-UI tool events are emitted via
`AgUiToolCallbackWrapper`.
When no tools are needed, the agent behaves as a pure streaming agent
(no regression from the previous `SpringAIAgent` behavior for tool-free
conversations).
## Why not the previous fix (PR #4469)?
PR #4469 replaced `SpringAIAgent` with `SyncAgent` which used `.call()`
only — this fixed tools but broke streaming entirely. This PR preserves
streaming for the happy path (no tools) and only falls back to `.call()`
when tool execution is actually needed.
## Files changed
- **New**: `StreamingToolAgent.java` — custom `LocalAgent` with
stream+call hybrid
- **New**: `JacksonConfig.java` — tolerant deserialization for unknown
message roles
- **New**: `MessageListFilter.java` — strips null messages from
deserialized lists
- **Modified**: `AgentConfig.java`, `AgentController.java`,
`AgentConfigController.java`, `A2uiFixedSchemaController.java` — use
`StreamingToolAgent` instead of `SpringAIAgent`
- **Modified**: `SubagentsController.java`,
`SharedStateReadWriteController.java` — add
`MessageListFilter.filterNulls()` at controller boundary
## Test plan
- [x] Docker build passes (`depot build --platform linux/amd64`)
- [ ] D5 agentic_chat features with tool calls (weather, flights, etc.)
complete without infinite loop
- [ ] D5 agentic_chat features without tools stream text correctly
- [ ] D5 subagents feature works (already used `.call()`, just added
null filtering)
- [ ] D5 shared-state-read-write feature works
- [ ] D5 a2ui-fixed-schema feature works
- [ ] D5 agent-config feature works
## Summary
- Restores the Railway `serviceInstanceRedeploy` call after each GHCR
image push in the build workflow
- PR #4471 removed this trigger assuming Railway
`environmentPatchCommit` auto-update would handle deploys, but not all
services have auto-update configured
- Without the explicit trigger, GHCR images get pushed and nothing tells
Railway to pull them
## Changes
- `showcase_build.yml`: Replace the "no deploy step" comment with the
actual Railway redeploy step (matching the old `showcase_deploy.yml`
behavior)
- `showcase_deploy.yml`: Update comments to reflect that the build
workflow triggers deploys (verify workflow only checks health)
## Test plan
- [ ] Merge and observe that the next showcase push to main triggers
Railway redeploys
- [ ] Verify the "Showcase: Verify Deploy" workflow confirms services
are healthy after build completes
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.
The decoupled build workflow (PR #4471) removed the Railway deploy
trigger, assuming environmentPatchCommit auto-update would handle
deploys. Not all services have auto-update configured, so GHCR images
were pushed but Railway never pulled them. Restore the explicit
serviceInstanceRedeploy call after each GHCR push.
## What does this PR do?
Removes the `prepack` script from
`@copilotkit/a2ui-renderer/package.json`, which was causing the canary
publish job to fail with `ENOENT` on the staging tarball.
### The failure
[Failed
run](https://github.com/CopilotKit/CopilotKit/actions/runs/25148053109/job/73712052657):
\`\`\`
✔ Build complete in 3002ms
ENOENT ENOENT: no such file or directory, open
'/tmp/.../copilotkit-a2ui-renderer-1.56.4-canary.tyler/romantic-spence-2261fe.tgz'
Error: Command failed: pnpm publish --no-git-checks --tag canary
--access public
\`\`\`
### Root cause
The release scripts already build the workspace before publishing:
- `scripts/release/prerelease.ts:77` runs `pnpm run build` across the
monorepo
- `scripts/release/publish-release.ts:145` does the same
`a2ui-renderer` was the **only** package in the monorepo with
`"prepack": "pnpm run build"`. That script fired during `pnpm publish`
and rebuilt the package a second time. Combined with tsdown's `exports:
true` (which regenerates `package.json`'s exports field on every build),
the second rewrite happened mid-publish and pnpm's pack step failed
silently — leaving an empty staging directory and the ENOENT we see.
### Why removal is safe
- All 12 other monorepo-scope packages publish without `prepack` and
work fine.
- Both release scripts (`prerelease.ts`, `publish-release.ts`) build the
whole workspace before the publish loop, so dist is always ready.
- No CI workflow or script invokes `pnpm pack` directly.
- Consumer-side installs, workspace deps, and `pnpm link` don't run
`prepack` anyway.
The only behavioral change: a developer manually running `pnpm publish`
or `pnpm pack` from the package directory now needs to `pnpm build`
first — matching the rest of the monorepo.
## Related PRs and Issues
- Failed CI run:
https://github.com/CopilotKit/CopilotKit/actions/runs/25148053109/job/73712052657
## 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
## Summary
The old "Showcase: Build & Deploy" workflow used a single concurrency
group
with cancel-in-progress. Every push to main cancelled in-flight builds,
which meant rapid-fire PR merges routinely killed deploys mid-run. The
harness logging PR (#4465) never deployed because a subsequent merge
cancelled it.
This splits the workflow into two independent files:
- **showcase_build.yml** ("Showcase: Build & Push") -- triggered on push
to
main, builds Docker images and pushes to GHCR. Has NO concurrency group
so every run completes. Railway auto-update picks up the new :latest
tag.
- **showcase_deploy.yml** ("Showcase: Verify Deploy") -- triggered by
workflow_run from the build workflow. Polls Railway to verify each
service
picked up the new image and is healthy. Uses cancel-in-progress since
verification is idempotent.
Also updates showcase_capture-previews.yml to reference the renamed
build
workflow.
## Test plan
- Workflow YAML validates (checked locally)
- Build workflow: no concurrency group, every push-to-main build
completes
- Verify workflow: triggered by workflow_run, cancel-in-progress is safe
- showcase-aimock included in both workflows (from #4458)
The old "Showcase: Build & Deploy" workflow used a single concurrency group
that cancelled in-flight builds on every push to main. When multiple PRs
merged in quick succession, most service builds got cancelled and never
deployed.
Split into two workflows:
1. showcase_build.yml ("Showcase: Build & Push") - triggered on push to main,
builds Docker images and pushes to GHCR. Has NO concurrency group so every
run completes. Railway auto-update picks up the new :latest tag.
2. showcase_deploy.yml ("Showcase: Verify Deploy") - triggered by workflow_run
from the build workflow. Polls Railway to verify each service picked up the
new image and is healthy. Uses cancel-in-progress since verification is
idempotent. Posts results to showcase-harness via webhook.
Also updates showcase_capture-previews.yml to trigger from the renamed build
workflow.
## Summary
Reverts PR #4469 which replaced SpringAIAgent (streaming) with SyncAgent
(synchronous).
The fix changed the nature of the demo — spring-ai should demonstrate
streaming, not synchronous calls.
The proper fix needs to make SpringAIAgent.stream() correctly
auto-execute tool callbacks.
## Test plan
- [x] Revert verified — restores original SpringAIAgent code
## 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
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
Previous harness deploy was cancelled by CI concurrency. This no-op
triggers a rebuild to pick up PRs #4460 (pool starvation fix), #4461
(pool logging), and #4465 (comprehensive harness logging).
## Summary
- Fixes `ERR_MODULE_NOT_FOUND: Cannot find package 'tsx'` crash in the
local langgraph-typescript container
- Root cause: the host bind mount `src:/app/src` clobbers
`src/agent/node_modules` that was installed during the Docker build
- Fix: anonymous volume `/app/src/agent/node_modules` preserves the
image's copy through the bind mount overlay
- google-adk D5 intermittent failures are pool starvation (already
addressed by #4460); no code change needed
## Test plan
- [x] Verified the compose container crash-loops before the fix
- [x] Verified the container starts healthy after the fix
- [x] Confirmed the production GHCR image works correctly (the issue
is compose-local only)
The prepack script ran `pnpm run build` during `pnpm publish`, duplicating
the build that prerelease.ts/publish-release.ts already do across the
workspace. With tsdown's `exports: true` regenerating package.json's
exports field on every build, the second rewrite happened mid-publish
and pnpm's pack step failed with ENOENT on the staging tarball.
No other monorepo package has prepack — bringing a2ui-renderer in line.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The host bind mount `src:/app/src` in docker-compose.local.yml overlays
the container's /app/src directory, clobbering src/agent/node_modules
that was installed during the Docker build. This causes `node --import tsx`
to fail with ERR_MODULE_NOT_FOUND at container startup.
Add an anonymous volume for /app/src/agent/node_modules so Docker
preserves the image's copy even when the parent directory is bind-mounted.
## Summary
- Introduces `FixedAGUIChatWorkflow` in the llamaindex hitl-in-chat
agent to work around 3 upstream bugs in `llama-index-protocols-ag-ui`
v0.2.2:
1. **Missing `parentMessageId`** on `ToolCallChunkWorkflowEvent` —
patched to propagate parent message ID
2. **Duplicate tool calls** from both `MESSAGES_SNAPSHOT` and
`TOOL_CALL_CHUNK` events — deduplicates by tracking emitted tool call
IDs
3. **Wrong role on tool results** — tool result messages sent as
`role="user"` instead of `role="tool"` — patched to correct the role
## Test plan
- [ ] D5 probe for `llamaindex / hitl-text-input` passes
- [ ] No regressions in other llamaindex features
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
## Summary
- Log pool stats when abort signal force-releases a browser back to the
pool
- Provides visibility into starvation events for diagnosis in Railway
logs
Follow-up to PR #4460 which added the abort-release mechanism but no
telemetry.
## Test plan
- [x] 1372 harness tests pass
Log pool stats and context counts when the abort signal fires and
force-releases a browser, so pool starvation events are visible in
Railway logs for diagnosis.
## Summary
- Wire abort signal through to `createPooledE2eDeepLauncher` so pooled
browsers are force-released when the invoker's timeout fires
- Track open browser contexts and close them before releasing on abort
to prevent orphaned contexts
- Guard against double-release with a `forceReleased` flag so the
driver's finally block is a no-op after abort
## Root cause
When `executeOne`'s `Promise.race` timeout fires, it returns the timeout
result but the driver promise continues running with a pooled browser
acquired. The browser is not released back to the pool until the driver
eventually finishes (up to 5 minutes later). Since pool size (4) equals
`max_concurrency` (4), one orphaned browser means the next probe run (15
minutes later) can only acquire 3 browsers. Orphans accumulate across
ticks, causing cascading starvation that manifests as D5 probe flapping
in production.
## Changes
- `E2eDeepBrowserLauncher` type now accepts an optional `AbortSignal`
- `createPooledE2eDeepLauncher` registers an abort listener that closes
open contexts and releases the browser back to the pool immediately
- Driver's `run()` passes its abort signal to the launcher
- 5 new tests covering: abort release, context cleanup on abort,
pre-aborted signal, full starvation scenario with pool recovery, and
backwards-compat no-signal path
## Test plan
- [x] 5 new unit tests for the pooled launcher abort behavior (all pass)
- [x] Full harness test suite: 1372 tests pass, 0 failures
- [x] TypeScript typecheck clean
When the probe invoker's timeout fires, Promise.race returns the timeout
result but the driver promise keeps running with a pooled browser held.
The browser is not released back to the pool until the driver eventually
finishes (up to 5 minutes later). Since pool size (4) equals
max_concurrency (4), orphaned browsers accumulate across ticks and cause
cascading starvation -- each 15-minute probe run has fewer available
browsers until the pool is completely exhausted.
The fix wires the abort signal through to createPooledE2eDeepLauncher.
When abort fires, the launcher force-closes open browser contexts and
releases the browser back to the pool immediately. A forceReleased flag
prevents the driver's finally block from double-releasing.
Iterate on the image attachment rendering based on review feedback:
- Reduce thumbnail size to 80x80 (down from 300x300) so attachments
read as compact thumbnails like Claude's chat UI
- Render attachments above the message text instead of below, and lay
multiple attachments out in a horizontal row (flex-row + flex-wrap +
justify-end) instead of stacking vertically
- Add a muted background so transparent images stay readable
- Extract Lightbox + useLightbox into a shared module so the rendered
attachment can reuse the same click-to-zoom modal as the queue preview;
clicking a thumbnail now opens it in a fullscreen lightbox with a
view-transition morph
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Constrain image attachments to a 300x300 max size with object-cover and
12px rounded corners so they appear as small thumbnails in chat instead
of filling the message width. Applies to both the v2 renderer (Tailwind)
and the legacy react-ui renderer (CSS).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Summary
- **Restores the eval system** accidentally deleted by PR #4449 ("D5
all-green" session removed it as "superseded by D5 depth probes" while
unaware #4448 had just merged)
- **Per-test JSON granularity** — eval runner now injects
`--reporter=list,json` + `PLAYWRIGHT_JSON_OUTPUT_NAME` when spawning
test subprocesses, reads JSON file after exit for per-test results,
falls back to exit-code when absent
- **Slug-keyed baselines** — `transformHarnessResponse` restructured to
key by integration slug (via `summary.services[]`) instead of probe ID,
matching `collectResults` format so `computeRegressions` works against
harness-prod baselines
## Context
PR #4448 added the eval system (5 CR rounds, 8 bugs fixed, 35+ agent
reviews). PR #4449 (a concurrent session) deleted it. This PR restores
the CR-converged code and adds two follow-up improvements from the eval
plan.
## Test plan
- [x] `npx nx run @copilotkit/showcase-harness:test` — 1375 tests pass
(70 files)
- [x] All 8 CR fixes from #4448 verified present in restored code
- [ ] CI green
## Summary
- Add `showcase-aimock` to the Build & Deploy workflow matrix so fixture
file changes in `showcase/aimock/` auto-deploy on merge to main
- Create `showcase/aimock/Dockerfile` -- thin overlay on
`ghcr.io/copilotkit/aimock:latest` that bakes fixture files into the
image
- Add local-vs-production parity comment in `docker-compose.local.yml`
explaining that new fixture files must be added to both the volume
mounts and the Dockerfile
- Add "Aimock Fixture Deployment" section to `showcase/RUNBOOK.md` with
manual build command and new-fixture checklist
## Why
Production showcase-aimock was running a week-old image with no D5
fixtures because fixture file changes did not trigger a CI rebuild. This
caused D5 probe failures that required manual intervention to resolve.
## Test plan
- [ ] CI workflow parses correctly (no YAML syntax errors)
- [ ] `workflow_dispatch` with `service=showcase-aimock` triggers the
aimock build
- [ ] Push to `main` touching `showcase/aimock/**` triggers the aimock
matrix leg
Production showcase-aimock was running a week-old image because fixture
file changes in showcase/aimock/ did not trigger a CI rebuild. This adds
showcase-aimock to the Build & Deploy workflow matrix so it auto-deploys
on merge, creates a thin Dockerfile that bakes fixture files into the
image, documents the local-vs-production parity requirement in
docker-compose.local.yml, and adds an aimock fixture deployment section
to the RUNBOOK.
Runner: inject --reporter=list,json and PLAYWRIGHT_JSON_OUTPUT_NAME
when spawning test subprocesses; read JSON file after exit for per-
test granularity; fall back to stdout then exit-code.
Baseline: restructure transformHarnessResponse to iterate
summary.services[] and produce slug-keyed results with _status
sub-keys matching collectResults format. Worst-status-wins when
same slug appears in multiple probes.
PR #4449 removed the eval tier system while unaware #4448 had just
merged. Restoring orchestrator, matrix, scope, config, GHA workflow,
and CLI wiring with all 8 CR fixes intact.
Heater shield with CopilotKit kite logo in magenta on dark
background, matching the sub-property icon style across
copilotkit.dev properties. Wires up Next.js metadata for
title, description, icons, and openGraph.
## 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)
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.
## Summary
- Add `@copilotkit/voice` to mastra and google-adk package.json
- Mastra build was failing in CI; google-adk resolved via hoisting but
adding explicitly
## Test plan
- [x] Audit confirmed these are the only two packages missing this dep
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.
## Summary
- Adds 4 missing dependencies to
`showcase/integrations/mastra/package.json`:
- `@json-render/core` (0.18.0)
- `@json-render/react` (0.18.0)
- `@radix-ui/react-checkbox` (^1.3.3)
- `@radix-ui/react-separator` (^1.1.8)
## Why
The `byoc-json-render` and `beautiful-chat` demos import these modules,
but they were never added to mastra's package.json. Every other
integration that ships these demos (langgraph-python, agno, etc.)
already has them. The omission causes webpack `Module not found` errors
during `next build`, blocking the mastra Docker deploy.
## Test plan
- [ ] CI builds mastra showcase successfully
- [ ] Docker build no longer fails on missing module errors
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.