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
Wrap all three new URL() call sites in try/catch so a malformed URL string
skips the part with a console.warn rather than crashing message conversion.
Add a default switch case to warn on unrecognized content part types.
Add a test covering the malformed-URL skip behaviour.
Introduce the framework-agnostic fetch handler layer:
- fetch-handler.ts: single Request→Response pipeline for all routes
- fetch-cors.ts: CORS preflight and response header handling
- fetch-router.ts: path-based routing for multi-endpoint setups
- hooks.ts: lifecycle hooks (onBeforeRequest, onAfterResponse, onError)
Also migrates handler error responses from Response.json() to
new Response(JSON.stringify(...)) for broader runtime compatibility
(Node.js <20, CF Workers, Deno).
- Call closeReasoningIfOpen() once before the switch instead of in every case branch
- Remove as-casts from closeReasoningIfOpen by using typed const variables
- Remove as-casts from new test code; use typed imports and unknown-safe casts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add cardinality assertions (toHaveLength(1)) to all 5 auto-close tests
so duplicate REASONING_MESSAGE_END / REASONING_END events are caught
- Add missing RUN_FINISHED final-event assertion to abort auto-close test
- Add test for consecutive reasoning blocks with no reasoning-end between
them (exercises closeReasoningIfOpen inside reasoning-start)
- Add test for exception thrown mid-stream (exercises catch block path)
- Add test for stream exhaustion without terminal event while reasoning is
open (exercises !terminalEventEmitted fallback)
- Expand changeset description to cover all three behavioral fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- reasoning-end case now delegates to closeReasoningIfOpen() so a late
SDK-emitted reasoning-end is a no-op when auto-close already fired,
preventing duplicate REASONING_MESSAGE_END + REASONING_END events
- Hoist isInReasoning / reasoningMessageId / closeReasoningIfOpen before
the try block so the catch block can call closeReasoningIfOpen() --
exceptions thrown mid-reasoning now emit proper lifecycle events before
RUN_ERROR instead of leaking an unclosed reasoning state
- Remove dead (part as any).delta fallback in reasoning-delta case; the
SDK always provides part.text in this branch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When closeReasoningIfOpen() auto-closes a prior block and a second
reasoning-start arrives with id="0" or no id, the handler was silently
reusing the previous reasoningMessageId. Mirror the text-start pattern:
always call randomUUID() when the provider id is falsy or "0".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Call closeReasoningIfOpen() in the reasoning-start handler before opening
a new block, guarding against consecutive reasoning blocks without an
intervening reasoning-end (e.g. Anthropic extended thinking with tools)
- Call closeReasoningIfOpen() in the !terminalEventEmitted fallback block
so streams that end without a finish/abort/error event still close properly
- Add abort() test-helper and tests for abort + error cases with open reasoning
- Strengthen auto-close ordering assertions to explicitly verify
REASONING_MESSAGE_END precedes REASONING_END in all three auto-close tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two fixes for Anthropic model stalls (fixes#3323):
1. Skip reasoning-delta events with empty text — EventSchemas.parse()
rejects delta: "" and kills the RxJS Observable before any other
events can fire.
2. Auto-close open reasoning lifecycle at every phase transition —
@ai-sdk/anthropic never emits reasoning-end, leaving the state
machine stuck.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Flatten all packages from packages/v1/* and packages/v2/* into packages/* —
every package now lives directly under the @copilotkit/ scope with no v1/v2
subdirectories.
- Move all v1 packages (react-core, react-ui, runtime, shared, etc.) from
packages/v1/* to packages/*
- Absorb v2 react code into packages/react-core/src/v2/ (exported via /v2 subpath)
- Absorb v2 agent code into packages/runtime/src/agent/ (exported via /v2 subpath)
- Move v2 packages (core, angular, demo-agents, etc.) to packages/*
- Replace all @copilotkitnext/* imports with @copilotkit/* equivalents
- Keep @copilotkitnext/angular as the sole exception (angular remains on next)
- Update CI workflows, renovate config, release scripts for flat structure
- No public API surface changes — all exports fields are preserved
Co-authored-by: Alem Tuzlak <t.zlak@hotmail.com>
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>