Commit Graph

132 Commits

Author SHA1 Message Date
Alem Tuzlak d4aca6664b fix: export CopilotModal and CopilotModalProps from react-ui (#2194) (#3817)
## Summary

Fixes #2194

`CopilotModal` and `CopilotModalProps` were not exported from
`@copilotkit/react-ui`, making them inaccessible to consumers. Adds both
exports to the chat barrel file.

## Test plan

- [ ] Verify `CopilotModal` and `CopilotModalProps` are importable from
`@copilotkit/react-ui`
2026-04-16 12:26:08 +02:00
Alem Tuzlak e9148b6e92 fix: show loading indicator during tool execution (#3833)
## Summary
- The loading spinner only appeared when the last message had role
"user"
- During tool execution the last message can have role "tool", hiding
the indicator
- Now also show it when the trailing message is a tool result

Closes #3055
2026-04-16 12:22:41 +02:00
Alem Tuzlak a7e7fbeef6 fix: pass urlTransform prop through to ReactMarkdown (#3845)
Closes #1921

The Markdown component accepted `components` but not `urlTransform`,
preventing users from customizing URL sanitization. Added `urlTransform`
as an optional prop with passthrough to `MemoizedReactMarkdown`.

Split from #3838.
2026-04-16 12:20:18 +02:00
Alem Tuzlak 057f159db0 fix: skip version check when showDevConsole is false (#3827)
## Summary

- `checkForUpdates()` in dev console is now gated on `showDevConsole`,
preventing unnecessary network requests when the console is disabled

Closes #2751

## Test plan

- [x] `@copilotkit/react-core` tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-16 12:00:23 +02:00
ranst91 cfb5921108 chore: release monorepo v1.56.0 2026-04-15 17:22:27 +00:00
Jordan Ritter a46218557c fix: add remarkPlugins/rehypePlugins passthrough support (#2296) 2026-04-14 15:55:08 -07:00
Jordan Ritter bcea46771b fix: handle urlTransform=null correctly in Markdown component
The truthiness check swallowed null, which is a valid value in
react-markdown that explicitly disables the default URL sanitizer.
Changed to an explicit undefined check.
2026-04-14 15:53:40 -07:00
Jordan Ritter 1e0de53a25 fix: add null check for navigator.clipboard across all copy-to-clipboard calls (#2114) (#3813)
Fixes #2114

Red-green tested locally.
2026-04-14 14:31:13 -07:00
Jordan Ritter 0106b1bf19 fix: remove unstable key on CodeBlock to prevent flickering during streaming (#3826)
## Summary

- Removes the `key` prop from `CodeBlock` in `Markdown.tsx` entirely
- The original `Math.random()` key caused React to remount the component
on every render, producing visible flickering
- A content-based key (language + content prefix) still changes every
streaming token, causing the same problem
- Without an explicit key, React uses positional identity — stable
across re-renders while content streams in

Closes #2669

## Test plan

- [x] `@copilotkit/react-ui` tests pass
- [x] `@copilotkit/react-ui` build succeeds
- [ ] Manual: verify code blocks no longer flicker during streaming in
chat UI
2026-04-14 14:26:13 -07:00
Jordan Ritter 9e5b458612 fix: use div instead of p tag in Markdown to prevent hydration errors (#2234) (#3821)
## Summary

Fixes #2234

React's hydration fails when block-level elements (like `<div>`) are
nested inside `<p>` tags in the Markdown component. Replaces the `<p>`
wrapper with `<div>` (adding `copilotKitParagraph` class for styling) to
prevent SSR hydration mismatches.

## Test plan

- [ ] Verify Markdown rendering in SSR context has no hydration errors
- [ ] Verify paragraph styling is preserved via `copilotKitParagraph`
class
2026-04-14 14:26:02 -07:00
Jordan Ritter 093f41907a fix: extract shared copyToClipboard utility to eliminate clipboard duplication
Address review feedback: extract the repeated clipboard availability check +
writeText + error handling pattern into a shared copyToClipboard() utility in
@copilotkit/shared. All 9 call sites across angular, react-core, and react-ui
now use the shared utility instead of duplicating the same code block.
2026-04-14 13:39:42 -07:00
Jordan Ritter b7b885e086 fix: scope dark theme CSS variables in colors.css
Same bug pattern as console.css and input.css: bare `.dark,` was a
standalone selector leaking all --copilot-kit-* CSS custom properties
onto any element with a .dark class. Also removed broken `:root`
pseudo-element from `body[style*="color-scheme: dark"] :root` — :root
cannot be a descendant of body, so this selector never matched.

Fix: drop standalone `.dark,` (redundant with `html.dark` and
`body.dark`) and remove the non-functional `:root` descendant.
2026-04-14 13:33:59 -07:00
Jordan Ritter 5e9fec77ba fix: update blockquote nested paragraph selector after p-to-div change
The blockquote.copilotKitMarkdownElement p selector targeted literal <p>
elements inside blockquotes, but paragraphs now render as <div> after
the hydration fix. Updated to target .copilotKitParagraph class instead.

Also removes unused import and adds a regression test for this selector.
2026-04-13 14:38:22 -07:00
Jordan Ritter 8244b0f31f fix: guard clipboard calls and only show copied state on success (#2114)
Add null checks for navigator.clipboard across all copy-to-clipboard
calls to prevent TypeError in non-localhost environments where the
Clipboard API is unavailable. The copied indicator now only appears
after a confirmed successful write, preventing false positive UX
feedback when the clipboard API is missing or the write fails.
2026-04-13 09:16:11 -07:00
Jordan Ritter 23ea810c5a fix: remove unstable key on CodeBlock to prevent flickering during streaming
The original Math.random() key caused React to remount the CodeBlock on
every render. The PR's content-based key (language + content prefix) still
changed every streaming token, causing the same flickering. Removing the
key entirely lets React use positional identity, which is stable across
re-renders while content streams in.

Closes #2669
2026-04-13 08:28:28 -07:00
Jordan Ritter 7998a46659 fix: update CSS selectors to match div-based paragraph component
The p tag was changed to div to fix hydration errors, but CSS selectors
still targeted p.copilotKitMarkdownElement. Updated to use the
.copilotKitParagraph class selector so paragraph styling (line-height,
font-size, margin) applies correctly to the new div element.
2026-04-13 08:25:22 -07:00
github-actions[bot] 65b8f05e8d style: auto-fix formatting 2026-04-12 22:26:58 +00:00
Jordan Ritter 49be36eeb9 fix: scope .dark CSS selectors to CopilotKit elements (#2920) 2026-04-12 15:24:54 -07:00
Jordan Ritter 00b14e54ba fix: pass urlTransform prop through to ReactMarkdown (#1921)
The Markdown component accepted components but not urlTransform,
preventing users from customizing URL sanitization. Added urlTransform
as an optional prop with passthrough to MemoizedReactMarkdown.
2026-04-12 15:16:55 -07:00
Jordan Ritter 2e85fd6428 fix: show loading indicator during tool execution (#3055)
The loading spinner only appeared when the last message had role "user".
During tool execution the last message can have role "tool", hiding the
indicator. Now also show it when the trailing message is a tool result.
2026-04-12 15:09:37 -07:00
Jordan Ritter f07501bbb8 fix: skip version check when showDevConsole is false (#2751)
checkForUpdates() fired unconditionally on mount, making a network
request even when the dev console was disabled. Now the useEffect
short-circuits when showDevConsole is false.
2026-04-12 15:05:06 -07:00
Jordan Ritter 859304a770 fix: use div instead of p tag in Markdown to prevent hydration errors (#2234) 2026-04-12 15:01:34 -07:00
Jordan Ritter f278eda07d fix: export CopilotModal and CopilotModalProps from react-ui (#2194) 2026-04-12 14:59:37 -07:00
Jordan Ritter 0db1fda63c fix: configurable audio mediaType and release mic tracks on stop (#2049, #2050) 2026-04-12 14:59:02 -07:00
Jordan Ritter a12134ce35 fix: replace hardcoded width 97% with 100% on messages footer (#2325)
The .copilotKitMessagesFooter used width:97% which caused horizontal
overflow in constrained containers. Changed to width:100% with
box-sizing:border-box so padding is included in the width calculation.
2026-04-12 13:21:43 -07:00
Jordan Ritter d1ac73da4c fix: handle void return from sendFunction in usePushToTalk (#3011)
sendMessage returns Promise<void> but usePushToTalk accessed .id on
the result, causing a TypeError crash. Guard the .id access with an
existence check and update the SendFunction type to accept void.
2026-04-12 13:20:10 -07:00
tylerslaton ccdd276a6d chore: release monorepo v1.55.3 2026-04-11 06:24:17 +00:00
github-actions[bot] 087cbae689 chore: version packages 2026-04-10 23:38:59 +00:00
Martha Schumann 6fdf106620 fix(react-ui): remove min-height from CopilotSidebarContentWrapper
818e4e767 added min-height: 100vh / height: 100% to
.copilotKitSidebarContentWrapper and its children in an attempt to
support full-height children inside the sidebar. This caused empty
space equal to the full viewport height to appear below the app
content whenever CopilotSidebar was mounted, even when collapsed.

The wrapper only needs to push the page content left (via margin-right)
when the sidebar expands — it does not need to control its own height.
Remove the height rules; child layout is the responsibility of the
app, not the sidebar wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 15:35:33 -07:00
Martha Schumann 1121ea6150 fix(react-ui): pin chat body wrapper to fill window height
The drag-and-drop wrapper div added in fc1cfa09d (attachments feature)
broke the flex layout of the chat window. The div had no class when
not dragging, so no CSS rule applied flex-grow — messages and input
collapsed to their natural height instead of filling the window.

Add copilotKitChatBody class to the wrapper and give it flex: 1 1 0%
so it claims the remaining window height, restoring the input-pinned-
to-bottom behaviour present in 1.51.1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 15:29:14 -07:00
github-actions[bot] 3e43f35131 chore: version packages (next) 2026-04-10 18:29:58 +00:00
Alem Tuzlak ff2093102c chore(lint): add new oxlint rules and auto-fix violations
Enable stricter oxlint rules for better code health:
- typescript/consistent-type-imports: enforce `import type` for type-only imports
- typescript/no-import-type-side-effects: prefer top-level type imports
- import/consistent-type-specifier-style: consistent type specifier placement
- typescript/no-unnecessary-type-assertion: bump to error
- react/self-closing-comp: enforce self-closing JSX components
- unicorn/prefer-optional-catch-binding: drop unused catch params
- eslint/no-useless-computed-key: simplify object keys
- unicorn/prefer-string-slice: prefer .slice() over .substring()
- unicorn/prefer-array-flat-map: prefer .flatMap() over .map().flat()

All existing violations auto-fixed via oxlint --fix.
2026-04-10 19:29:32 +02:00
github-actions[bot] 1bc4786759 chore: version packages (next) 2026-04-09 18:09:30 +00:00
github-actions[bot] 0093bdbaa4 chore: version packages 2026-04-09 02:26:42 +00:00
github-actions[bot] c2837a3001 chore: version packages (next) 2026-04-09 01:53:20 +00:00
github-actions[bot] 00cace6abf chore: version packages 2026-04-08 23:54:54 +00:00
Alem Tuzlak 4b11b995a2 feat: multimodal attachments — images, audio, video, documents in CopilotChat (#3604)
## Summary

Adds full multimodal attachment support to CopilotKit's v2 chat
components. Users can send images, audio, video, and documents alongside
text messages to any AG-UI-compatible agent.

### Frontend
- **`attachments` prop** on `CopilotChat` — `{ enabled, accept, maxSize,
onUpload, onUploadFailed }`
- **`useAttachments` hook** — reusable, referentially stable hook for
custom chat UIs (all callbacks memoized, zero unnecessary re-renders)
- **Attachment queue** with lightbox previews (View Transition API),
video player, PDF/text document viewer
- **Drag-and-drop**, **clipboard paste**, and **file picker** upload
flows
- **Drop zone overlay** with visual indicator
- **Filename preservation** via `InputContent` metadata
- **`onUploadFailed` callback** with typed error reasons
(`file-too-large`, `invalid-type`, `upload-failed`)
- **`AttachmentUploadResult` discriminated union** for type-safe
`onUpload` returns
- Memoized attachment renderer components (v1 and v2)

### Backend
- `BuiltInAgent` properly converts multimodal `InputContent[]` to Vercel
AI SDK format
- Handles image, audio, video, document, and legacy binary content parts

### Deprecation lifecycle
- `@deprecated` JSDoc on all legacy image upload APIs (9 symbols) with
`@since 1.56.0`
- **Codemod** at `codemods/migrate-attachments.ts` — transforms props +
imports (18 tests)
- Migration guide moved to new **Migration Guides** docs section

### Docs
- New guide: `docs/(root)/multimodal-attachments.mdx`
- Updated migration guide with codemod instructions, new `onUpload`
type, metadata
- Cross-links from prebuilt-components page
- New **Migration Guides** section (moved from troubleshooting)

### AG-UI
- Bumped `@ag-ui/client`, `@ag-ui/core`, `@ag-ui/encoder`,
`@ag-ui/proto` to 0.0.51

### Example
- React Router example with dual agent setup (BuiltInAgent + TanStack
AI)
- Multimodal content properly forwarded to TanStack AI `chat()`

## Test plan

- [x] `useAttachments` hook stability tests — 9 tests (referential
stability, re-render counting, state defaults)
- [x] `CopilotChat.attachments` tests — 5 tests (onUploadFailed for
invalid-type, file-too-large, upload-failed, multiple rejections, valid
files)
- [x] Codemod tests — 18 tests (prop transforms, import renames,
idempotency, edge cases)
- [x] Full react-core suite — 966 tests passing
- [x] Tool call streaming tests pass (messagesMemoKey fingerprint fix)
2026-04-07 14:26:03 +02:00
Alem Tuzlak 1317e51302 fix: revert copy-dts script, use typesVersions for legacy TS consumers
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".
2026-04-07 11:39:15 +02:00
Alem Tuzlak 9ae7a97823 fix: address PR review feedback from Martha
Bugs fixed:
- v1 Chat.tsx: onUpload now reads result.type/result.value (was result.data/result.url)
- v1 Chat.tsx: metadata captured from onUpload and forwarded in InputContent parts
- v1 Chat.tsx: onUploadFailed callback now invoked at all three error paths
- useAttachments: consumeAttachments preserves in-flight uploads (was dropping them)

Should-fix addressed:
- Lightbox: vtCounter replaced with React.useId() (concurrent mode + SSR safe)
- Lightbox: SSR guard before createPortal(document.body)
- useBlobUrl: useEffect deps changed to scalar values (was object reference)
- Codemod: dynamic inputFileAccept expressions preserved (was silently dropped)
- Codemod: scope-awareness limitation documented in comment

Tests: 966/966 react-core, 19/19 codemod
2026-04-07 09:42:28 +02:00
Alem Tuzlak d7578216d3 refactor: extract useAttachments hook, memoize attachment renderers
- Extract all attachment logic from CopilotChat into reusable useAttachments hook
  (state, processFiles, drag/drop, paste, consumeAttachments, removeAttachment)
- Export useAttachments from hooks/index.ts for custom chat UI builders
- Memoize v2 CopilotChatAttachmentRenderer sub-components
  (ImageAttachment, AudioAttachment, VideoAttachment, DocumentAttachment)
- Memoize v1 AttachmentRenderer sub-components to match v2 structure,
  align props (content → filename)
- Guard process.env in attachment-utils.ts for browser environments
- Remove debug logging (existing.debug = true) from use-agent.tsx
2026-04-06 15:17:56 +02:00
Alem Tuzlak 0fd3ddf960 refactor(docs): create migration-guides section, move migration pages from troubleshooting
- 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)
2026-04-06 14:55:09 +02:00
Alem Tuzlak 89d39d639b fix: address code review findings — error handling, codemod correctness, deprecation versions
- 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
2026-04-06 14:55:08 +02:00
Alem Tuzlak 18c7a6001d feat: multimodal attachments — UI polish, deprecations, docs, codemod
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
2026-04-06 14:55:06 +02:00
Alem Tuzlak f6c15cdbfe refactor(shared): move attachment utilities to shared package 2026-04-06 14:54:42 +02:00
Alem Tuzlak 7c774e9eb6 refactor(shared): move attachment types to shared package 2026-04-06 14:54:41 +02:00
Alem Tuzlak 152d1ade96 style: format code with oxfmt 2026-04-06 14:54:40 +02:00
Alem Tuzlak 928c385516 fix(react-ui): add baseline error logging, thumbnail diagnostics, rejected file feedback, mimeType fallback 2026-04-06 14:54:39 +02:00
Alem Tuzlak 2c546e44b5 test(react-ui): add tests for attachment utility functions 2026-04-06 14:54:37 +02:00
Alem Tuzlak e683f9386c fix(react-ui): address code review findings — stale closures, error handling, type safety
- Fix stale closure in paste handler by using processFilesRef pattern
- Wrap processFiles calls in try/catch across paste, file upload, and drop handlers
- Add early return for empty/falsy accept string in matchesAcceptFilter
- Block send while attachments are still uploading
- Add id field to Attachment interface, replace _id hack with randomUUID()
- Add 10s timeout to generateVideoThumbnail to prevent infinite hanging
- Show placeholder div for uploading attachments instead of rendering incomplete source
- Include filename context in upload error messages
2026-04-06 14:54:36 +02:00
Alem Tuzlak 1d62da913d chore: add deprecation annotations and suppressable runtime warnings 2026-04-06 14:54:34 +02:00