## Summary
- Adds a minor version changeset for the multimodal builtin agent
feature that was merged without one
- Bumps `@copilotkit/runtime`, `@copilotkit/react-core`,
`@copilotkit/react-ui`, and `@copilotkit/shared` (fixed versioning
applies to all `@copilotkit/*` packages)
## Test plan
- [ ] Verify changeset is picked up by the release workflow
## Summary
- Reverts the `copy-dts.mjs` approach from #3612 — restores `"types"`
back to `.d.cts` and removes the post-build copy step from all 13
packages
- Adds `typesVersions` to `react-core` and `runtime` (the packages with
`./v2` subpath exports) so legacy `moduleResolution: "node"` consumers
can resolve subpath types
- Deletes `scripts/copy-dts.mjs`
From what I've read, `typesVersions` is the standard Node/TS mechanism
for this — we can safely revert the copy-dts changes and rely on it
instead.
@mxmzb heads up — this reverts your #3612 changes in favor of
`typesVersions`. Let me know if you have any concerns.
## Test plan
- [ ] Build all packages and verify `.d.cts` types are emitted (no
`.d.ts` copies)
- [ ] Verify `typesVersions` resolves `@copilotkit/react-core/v2` and
`@copilotkit/runtime/v2` types under `moduleResolution: "node"`
- [ ] Verify main entry types still resolve via the `"types"` field
pointing to `.d.cts`
## Summary
Addresses two review issues from #3604:
- **consumeAttachments race**: replaced the
side-effect-out-of-setState-updater pattern with a ref mirror
(`attachmentsRef`). `consumeAttachments` now reads from the ref
synchronously and uses the updater only for the state mutation. Safe
under React concurrent mode.
- **Codemod scope-awareness**: the rename logic now skips declaration
positions (variable, function, class, type, interface declarations),
object property keys, and member expression properties. When a local
declaration shadows the import name, only unambiguous type-position
references are renamed — value references are left alone to avoid
silently corrupting unrelated code.
## Test plan
- [x] All 21 codemod tests pass (including 2 new tests for
shadow/collision cases)
- [x] All 9 use-attachments hook tests pass
1. consumeAttachments: read from a ref mirror instead of side-effecting
out of a setState updater, avoiding reliance on synchronous updater
execution under React concurrent mode.
2. Codemod: skip declaration positions (variable, function, class, type,
interface) and non-reference positions (object keys, member accesses).
When a local declaration shadows the import name, only rename
unambiguous type-position references to avoid corrupting unrelated code.
Reverts the copy-dts.mjs approach from #3612 in favor of typesVersions
which is the standard Node/TS mechanism for resolving subpath types
under legacy moduleResolution: "node".
feat(runtime): add defaults and max caps for thread lock TTL and heartbeat
lockTtlSeconds defaults to 20s (max 3600s / 1 hour) and
lockHeartbeatIntervalSeconds defaults to 15s (max 3000s / 50 minutes).
Both values are always set, so the heartbeat timer now starts
unconditionally and the paired-option validation is removed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CopyButton setTimeout fires after the jsdom test environment is
torn down, causing an unhandled ReferenceError on Node 20. Track the
timer in a ref and clear it on cleanup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Finance ERP showcase powered by CopilotKit deep agents. Includes a
Next.js 16 frontend with 7 CopilotKit-registered tools, a LangGraph
multi-agent backend (orchestrator + research/projections subagents),
Postgres-backed dashboard gallery with 12 widget types and 4 templates,
and human-in-the-loop approval flows for invoices and inventory.
## Summary
- Fix the `/whats-new/v1-50` redirect destination from `/` (homepage) to
`/learn/whats-new/v1-50` (where the content actually lives)
This redirect was changed in commit `7a78f3f0` (Mar 20) to point to
root, but the v1.50 release notes page still exists at
`/learn/whats-new/v1-50`. Shared links and bookmarks to the old URL
currently land on the homepage instead of the content.
## Test plan
- [ ] Navigate to `/whats-new/v1-50` and verify it redirects to
`/learn/whats-new/v1-50`
- [ ] Verify `/learn/whats-new/v1-50` renders the v1.50 release notes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Fixes A2UI button responses not appearing in chat after PR #3525
introduced per-thread agent cloning.
- **Root cause:** `useRenderActivityMessage` was passing the registry
agent to `ReactSurfaceHost` instead of the per-thread clone. When a
button was clicked, `handleAction` called `runAgent` on the registry
agent, but `CopilotChat` was rendering from the per-thread clone — so
responses were silently lost.
- **Fix:** Mirror the existing pattern from `useRenderCustomMessages`:
resolve `getThreadClone(registryAgent, threadId) ?? registryAgent`
before passing the agent prop down.
- **Regression test:** New test in
`CopilotChatActivityRendering.e2e.test.tsx` asserts that the `agent`
prop passed to an activity renderer is the per-thread clone, not the
registry agent.
- **Demo:** New page at `/a2ui-demo` with a `DemoButtonAgent` — renders
an A2UI button on first run, confirms the fix is working when clicked.
## Why this was missed in #3525
`useRenderCustomMessages` was updated with the thread-clone pattern but
`useRenderActivityMessage` was not. The two hooks serve similar roles
but the PR review focused on `useAgent` and `CopilotChat`, not on every
consumer of the registry agent.
## Impact of the temporary hack in #3588
PR #3588 (`ae48d4761e5`) returned `existing` (registry agent) from
`useAgent` unconditionally, making both `CopilotChat` and the activity
renderer use the same instance — so button clicks worked again. But this
discards the thread isolation from #3525: multiple `CopilotChat`
components sharing a `threadId` would bleed messages into each other.
This PR fixes the root cause so the #3588 workaround is no longer
needed.
## Test plan
- [x] Run `nx run @copilotkit/react-core:test --
CopilotChatActivityRendering` — all 4 tests pass
- [x] Run `nx run demo:dev`, open `/a2ui-demo`, type anything, click
Confirm — confirmation message appears in chat
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Replace `ReactActivityMessageRenderer<unknown>` + `(content as any).resourceUri`
with `ReactActivityMessageRenderer<z.infer<typeof MCPAppsActivityContentSchema>>`
so the renderer prop is properly typed and the `as any` cast is eliminated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After the useRenderActivityMessage fix, MCPAppsActivityRenderer receives the
per-thread clone instead of the registry agent. The mock's clone() did not share
isRunning state, causing waitForAgentIdle(clone) to never resolve (emit() only
updated registry.isRunning). Also, tests that monkey-patch runAgent before
renderWithCopilotKit need the clone to delegate proxied MCP requests to the
registry (to pick up the monkey-patch) while running user-message flows on the
clone itself (so clone.messages is updated and rendered by CopilotKit).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a minimal demo at /a2ui-demo that uses the demo-button agent to
reproduce and validate the A2UI thread-clone bug fix. The agent renders
an A2UI surface with a Confirm button on first run; clicking it fires a
second run that emits a text confirmation message.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- All callbacks (processFiles, handleFileUpload, handleDragOver, handleDragLeave,
handleDrop, removeAttachment, consumeAttachments) are now wrapped in useCallback
with empty deps — referentially stable across renders
- Config values read from configRef to avoid dep array changes
- consumeAttachments no-ops on empty queue (returns same state reference)
- 9 new tests: referential stability across re-renders, re-render counting
(consumeAttachments on empty queue triggers zero re-renders), initial state,
consumeAttachments behavior, removeAttachment no-op
useRenderActivityMessage was calling copilotkit.getAgent() directly,
always returning the registry agent. When a user clicked an A2UI button,
handleAction → runAgent executed on the registry agent — messages
accumulated there while CopilotChat displayed from the per-thread clone
(created by useAgent), so responses appeared to silently vanish.
Apply the same getThreadClone(registryAgent, threadId) ?? registryAgent
pattern already used in useRenderCustomMessages.
Adds a regression test that asserts the renderer receives the clone,
and confirms the test catches the bug when the fix is reverted.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New docs/(root)/migration-guides/ section with migrate-to-v2, migrate-attachments,
migrate-to-1.10.X, migrate-to-1.8.2
- Troubleshooting now only contains error-debugging, observability-connectors, common-issues
- Update all @deprecated JSDoc URLs from /troubleshooting/ to /migration-guides/
- Update doc cross-links (multimodal-attachments page, snippet import)
- Move snippet to snippets/shared/migration-guides/
- Set minimum version to v1.56.0 (was vX.Y.Z placeholder)
- Restore console.error as safety net in processFiles catch blocks (errors no longer
silently vanish when onUploadFailed callback is not provided)
- Add try/catch to useBlobUrl atob() — gracefully handles malformed base64 instead of
crashing the component tree
- Fix DocumentLightboxContent: use blobUrl instead of undefined src variable
- Add .catch() to View Transition API transition.finished promise
- Codemod: preserve actual imageUploadsEnabled value (false, dynamic expressions)
instead of hardcoding true — adds 3 new test cases (18 total)
- Replace all placeholder @deprecated versions (v1.x.0) with @since 1.56.0
- Add missing @since to ImageRenderer, ImageRendererProps, AIMessage.image tags
Attachment queue & previews:
- Image lightbox with View Transition API morph animation
- Video lightbox with native controls and play button overlay
- Document lightbox (PDF via blob URL, text inline, info card fallback)
- Drop zone overlay with upload icon
- Filename preservation via InputContent metadata
- Proper video thumbnail sizing and play/pause indicator
- Fix attachment queue positioning (max-w-3xl constraint)
- Padding between X button and content for audio/document cards
- Document filenames wrap instead of truncating
Attachments config:
- onUploadFailed callback for validation/upload errors (file-too-large, invalid-type, upload-failed)
- onUpload accepts sync or async returns
- AttachmentUploadResult discriminated union with explicit interfaces
- Metadata field on Attachment and onUpload return type
AG-UI version bump:
- Bump @ag-ui/client, @ag-ui/core, @ag-ui/encoder, @ag-ui/proto to 0.0.51
- Remove process.env Vite workaround (fixed upstream in 0.0.51)
Deprecation lifecycle:
- @deprecated JSDoc on all legacy image upload APIs
- ImageRenderer, ImageRendererProps, ImageUpload type, imageUploadsEnabled prop,
inputFileAccept prop, ImageRenderer prop, AIMessage.image, ImageData
- Codemod at codemods/migrate-attachments.ts (15 tests)
- Migration guide updated with codemod instructions and new type shapes
Docs:
- New guide: docs/(root)/multimodal-attachments.mdx
- Updated migration guide with onUpload return type, metadata, codemod section
- Cross-links from prebuilt-components and migration guide
- Label change: "Add photos or files" → "Add attachments"
Tests:
- CopilotChat.attachments.test.tsx — 5 tests for onUploadFailed
- migrate-attachments codemod — 15 tests