Commit Graph

58 Commits

Author SHA1 Message Date
Tyler Slaton 6926d88f0f fix(shared): update PDX-199 docs error anchors 2026-05-27 13:59:35 -07:00
Sam Julien 33f669ba7b fix(packages): canonicalize docs.copilotkit.ai URLs in user-facing messages
Replace docs URLs that currently 301 through the legacy redirect catalog
with their canonical post-cutover destinations so users clicking links
from console warnings, JSDoc, and in-product help land in one hop.

URLs updated:
- /premium#how-do-i-get-access-to-premium-features
  -> /premium/overview#getting-access
- /coagents/quickstart/langgraph -> /langgraph-python/quickstart
- /coagents/shared-state/predictive-state-updates
  -> /langgraph-python/shared-state/predictive-state-updates
- /reference/v1/hooks/useCopilotChatHeadless_c
  -> /reference/v2/hooks/useCopilotChatHeadless_c
- /coagents/troubleshooting/common-issues
  -> /langgraph-python/troubleshooting/common-issues
- /quickstart#get-a-copilot-cloud-public-api-key
  -> /built-in-agent/quickstart#create-a-free-account
- /premium -> /premium/overview

URLs left as-is because they already resolve 200 with no redirect:
/migration-guides/migrate-attachments, /migration/render-message,
/telemetry.

Hook bypassed: pre-commit test failed in @copilotkit/web-inspector due
to missing jsdom dependency in its package.json (unrelated to this
change; no overlap with edited files or URLs). Tests for the four
affected packages (react-core, react-ui, shared, runtime) pass.
2026-05-22 16:37:21 -07:00
github-actions[bot] 5a35bef248 style: auto-fix formatting 2026-05-21 14:45:20 -05:00
Benjamin Taylor b684fae377 review(telemetry): address CR findings on client-side sampling
- Rework shared helper: parseAndWarnTelemetryId returns parsed id AND
  warns, so both v1 and v2 setLicenseToken call it once without
  inlining duplicate code or double-parsing the JWT.
- Fix v1 sampleWeight bug: identified events bypass the sample gate
  and ship at effective rate 1.0, so a single global sampleWeight =
  1/sampleRate would overweight identified-customer counts by
  1/sampleRate (20x at the 0.05 default). Move sample metadata
  (sampleRate / sampleRateAdjustmentFactor / sampleWeight) out of
  globalProperties and compute per-event using effectiveSampleRate.
- Guard setSampleRate against parseFloat("nonsense") = NaN slipping
  past the range check. With the default now 0.05, env-var overrides
  are more common and a typo would otherwise produce silent
  always-drop.
- Add tests: sampleWeight differs for identified vs anonymous,
  malformed JWT stays anonymous, license-token cache is overwritable,
  NaN env override is rejected, v2 default sampleRate = 0.05 is pinned.
2026-05-21 14:45:20 -05:00
Benjamin Taylor 674caacabd feat(telemetry): gate anonymous v1 events client-side, bypass for identified
Cache parsed telemetry_id at setLicenseToken time and use it to branch
in capture():
- Identified callers (token with telemetry_id) always send to both sinks.
- Anonymous callers are sampled at sampleRate (default 0.05); one dice
  roll gates both lambda and Segment.

The Lambda no longer needs to bypass-from-sampling for identified
events — that decision moves entirely to the client. Reduces lambda
invocations by ~95% for the anonymous OSS-runtime firehose.
2026-05-21 14:45:20 -05:00
Benjamin Taylor e03de792c3 review(telemetry): address PR feedback on sink migration
- Mark v1 licenseToken private to match v2 visibility
- Extract shared warnIfLicenseTokenLacksTelemetryId helper to keep v1
  and v2 setLicenseToken bodies in lockstep
- Remove dead v2 scarf-client and its test block (migration leftover)
- Add v1 shared TelemetryClient test coverage: lambda always-send,
  segment sample gating, setLicenseToken warn paths, cloud config,
  telemetryDisabled gate, sample-rate range, env-var matrix
2026-05-21 14:45:20 -05:00
Benjamin Taylor 3be4c6b1e7 feat(telemetry): warn when license token yields no telemetry_id
Operators currently get silent attribution loss if a license token is
configured but parses without a telemetry_id field — useful as a smoke
signal during the issuer rollout, when older licenses lack the field
entirely.

Each TelemetryClient setter (v1 shared, v2 singleton) now calls
parseTelemetryIdFromLicense at configuration time and emits a one-shot
console.warn when the result is null. No per-event spam.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:20 -05:00
Benjamin Taylor 274057530f docs(telemetry): generalize comment above STRIPPED_KEYS
Drops the Lambda/Segment specifics in favor of an implementation-neutral
description: these fields aren't used by the telemetry service, so we
strip them at the wire boundary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:20 -05:00
Benjamin Taylor ed5f44849e feat(telemetry): strip cloud API key from lambda payload
The CopilotCloud customer key (`ck_<env>_<id>.<secret>`) is routed to
Segment for downstream user analytics, but has no role in the
telemetry-sink Lambda. Worse, the secret half should never leave the
customer's runtime.

Strips both wire-format variants at the lambda-client boundary:
- `cloud.public_api_key` (v2 event property convention)
- `cloud.publicApiKey` (v1 globalProperties from setCloudConfiguration)

The strip happens at the lambda-client wire layer rather than in each
caller, so any future caller (or accidental property regression) is
covered by default. Boolean indicators like `cloud.api_key_provided`
and unrelated fields like `cloud.baseUrl` continue to ride through.

New unit test (`lambda-client.test.ts`) exercises the strip with a real
fetch spy, plus end-to-end JWT extraction including the
no-`telemetry_id` and not-a-JWT fallback paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:20 -05:00
Benjamin Taylor ff33123c93 feat(telemetry): source telemetry-id from EIP license JWT
The CopilotCloud customer API key (`ck_<env>_<id>.<secret>`) is unrelated
to telemetry attribution — it flows into Segment/PostHog only. The
attribution signal lives in the EIP / Intelligence license JWT, whose
payload carries `telemetry_id` (alongside license_id, owner.org_id,
features, etc.).

Rewires the lambda-client to base64url-decode the license JWT payload
and emit X-CopilotKit-Telemetry-Id from `telemetry_id`. No signature
verification — that's license-verifier's job, and the Lambda is
claim-only by design.

Plumbing:
- Shared TelemetryClient (v1) and v2 telemetry singleton each get a
  `setLicenseToken` setter; the v1 client drops `apiKey:` from its
  lambdaClient.send call, the v2 client drops the
  cloud.public_api_key extraction from event properties.
- Both runtime constructors call `telemetry.setLicenseToken(...)` once,
  resolving `options.licenseToken ?? process.env.COPILOTKIT_LICENSE_TOKEN`
  to match license-verifier's own env-fallback. Without that, customers
  who set only the env var would get a working licenseChecker but
  anonymous telemetry.

Tests: v2 telemetry test refreshed — old "cloud api key extraction"
assertion replaced with one that confirms cloud.public_api_key rides
in properties (not as licenseToken), and a new test asserts that
setLicenseToken plumbs through to lambdaClient.send.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:19 -05:00
Benjamin Taylor 348410c4fa feat(telemetry): drop HMAC signing for plain telemetry-id header
The HMAC scheme bound identity to "holder of API key X," but since the
secret is shipped inside distributed customer keys it never actually
prevented a determined attacker from impersonating that customer — and
the Lambda still accepted unsigned requests anyway, so the signing path
provided attribution, not abuse control.

Replaces ~85 lines of Web Crypto / HMAC / nonce / canonical-string
machinery with a single `X-CopilotKit-Telemetry-Id: <id>` header. The
SDK now extracts the id from `ck_<env>_<id>.<secret>` keys and ignores
the secret half. Anonymous sends (no/legacy keys) are unchanged.

Drops the implicit Node ≥19 / edge-runtime requirement that the
WebCrypto path imposed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:19 -05:00
Benjamin Taylor 1ca532252d feat(telemetry): point lambda-client at telemetry.copilotkit.ai
Locks in the production telemetry-sink endpoint (the API Gateway custom
domain backed by the ingest Lambda). Customers can still override with
COPILOTKIT_TELEMETRY_URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:19 -05:00
Benjamin Taylor ce3697aad8 feat(telemetry): route runtime telemetry through CopilotKit telemetry sink
Adds @copilotkit/shared/telemetry/lambda-client which posts events to a
CopilotKit-controlled telemetry-sink endpoint, replacing the direct Scarf
calls in both v1 (shared) and v2 (runtime) telemetry clients. When the
configured CopilotCloud API key parses as the new ck_<env>_<id>.<secret>
format, the request is HMAC-signed (CK1, sha256 over ts/nonce/body) so
the sink can verify and enrich with the customer email; otherwise it
falls through to an unsigned send (legacy keys, OSS-only installs). v1
keeps its existing Segment path with 5% client sampling; v2 sends 100%
to the sink and lets the sink sample server-side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:19 -05:00
Martha Schumann ce35cba85e feat(inspector/telemetry): propagate telemetryDisabled from runtime env var through inspector
- Add telemetryDisabled to RuntimeInfo from COPILOTKIT_TELEMETRY_DISABLED/DO_NOT_TRACK env vars
- Mirror through AgentRegistry and expose via CopilotKitCore getter
- Guard track calls, URL param appending, and console disclosure on core.telemetryDisabled
- Move maybeShowDisclosure() to onRuntimeConnectionStatusChanged (fires after core attaches)
- Update docs to replace localStorage toggle description with env var approach
- Add telemetryDisabled test suite to get-runtime-info tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
Max Korp bec1fd0811 fix(a2ui): document id="root" entry-point requirement in generation guidelines
The A2UI React renderer (packages/a2ui-renderer/src/react-renderer/a2ui-react/A2uiSurface.tsx:152)
always begins rendering at the component with id="root":

    export const A2uiSurface: React.FC<{...}> = ({ surface }) => {
      // The root component always has ID 'root' and base path '/'
      return <DeferredChild surface={surface} id="root" basePath="/" />;
    };

If no component has that ID, DeferredChild falls through to its loading-
shimmer placeholder, so the surface silently renders as an empty ~30px
rectangle regardless of how many other components are on the surface.

The generation guidelines shipped to the sub-LLM (in @copilotkit/shared
and copilotkit sdk-python) never stated this requirement. Fixed-schema
demos hard-code a component with id="root" in their JSON and work; dynamic
demos relied on the LLM guessing, which it sometimes did and sometimes
didn't. The failure mode is particularly nasty: no error, no warning,
just a loading spinner that never resolves.

Adds the requirement to COMPONENT ID RULES in both the TS and Python
guideline strings. Both strings are injected into the sub-LLM's context
by A2UICatalogContext (packages/react-core) and
copilotkit.a2ui.a2ui_prompt() respectively, so every A2UI-enabled app
picks it up automatically — no per-demo change needed.

Stacked on #4216, which restores the same instruction to the
langgraph-python-threads demo's tool docstring (belt-and-braces until
consumers update their shared package version).
2026-04-23 13:21:07 -07:00
Alem Tuzlak e71b27ed97 Merge remote-tracking branch 'origin/main' into fix/issue-2651
# Conflicts:
#	packages/shared/src/utils/json-schema.ts
2026-04-22 12:02:32 +02:00
Alem Tuzlak 1eb4a154ad Merge origin/main into feature branch: resolve 7 conflicts 2026-04-16 16:16:48 +02:00
Alem Tuzlak ada147ef84 feat(runtime): add DebugEventBus and DebugEventEnvelope type 2026-04-16 12:09:25 +02:00
Alem Tuzlak bddf0a0189 fix: add Zod v4 compatibility for schema-to-JSON conversion (#3837)
## Summary
- Detects Zod v4 schemas by checking for `toJSONSchema()` method on the
schema object
- Calls `schema.toJSONSchema()` directly for Zod v4 (avoids
`zod-to-json-schema` v3, which can't handle Zod v4 internals)
- Preserves existing Zod v3 path via injected `zodToJsonSchema` fallback
- Removes dead `vendor === "zod4"` check (Zod v4 reports vendor as
`"zod"`, not `"zod4"`)
- Removes `_def` duck-typing fallback (unnecessary with `toJSONSchema`
detection)

### Priority order:
1. Standard JSON Schema V1 (`~standard.jsonSchema.input`)
2. Zod v4 native (`schema.toJSONSchema()`)
3. Zod v3 fallback (injected `zodToJsonSchema`)

### Tests added:
- Verifies `toJSONSchema()` is called when present
- Verifies it works without `zodToJsonSchema` option
- Verifies it takes priority over `zodToJsonSchema` fallback
- Verifies `~standard.jsonSchema` still takes top priority over
`toJSONSchema()`

Closes #3636
2026-04-16 11:58:56 +02:00
Alem Tuzlak 9953b8a264 Merge branch 'main' into worktree-lucky-popping-wren 2026-04-15 17:12:55 +02:00
Jordan Ritter fb6b518362 fix: mock navigator in clipboard test for Node 20 compatibility 2026-04-15 13:10:48 +02:00
Jordan Ritter 2f4152c8ec 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-15 13:10:42 +02:00
Jordan Ritter 7c9ac787f0 fix: clone visited-refs set to prevent false circular-ref detection across sibling branches
The shared visitedRefs Set was mutated in place, so when two sibling
properties referenced the same $def (e.g. billing and shipping both
referencing Address), the second resolution was incorrectly flagged as
circular. Clone the set before recursing so each branch has its own
ancestry path. Added regression test that fails without this fix.
2026-04-15 13:10:37 +02:00
Jordan Ritter 6b391c6538 fix: add circular $ref cycle detection in JSON schema to Zod conversion
Recursive JSON schemas that reference themselves via $ref would cause
infinite recursion and stack overflow. This adds a visited set that
tracks which $ref paths have been seen during resolution. When a cycle
is detected, it breaks with z.any() and logs a console.warn so users
get feedback. Also adds console.warn for the generic z.any() fallback
on unsupported schema types.

Adds tests for circular refs, non-circular $ref resolution, anyOf with
$ref variants, integer type, null type, and unsupported type warning.
2026-04-15 13:10:36 +02:00
github-actions[bot] 3c32e469d8 style: auto-fix formatting 2026-04-15 13:10:36 +02:00
Jordan Ritter 8ebbba20df fix: handle anyOf/oneOf/ in JSON schema to Zod conversion (#2220) 2026-04-15 13:10:35 +02:00
Markus Ecker 0f02aae198 fix: align A2UI schema format with v0.9 spec and improve path binding prompts
- Replace custom { name, props } schema format with spec-aligned inline
  catalog format (allOf + properties) so the LLM sees the same flat
  structure it must produce — eliminates "props" nesting confusion.
- Restructure generation prompts: inline literal values are the default,
  path binding is a narrow schema-driven exception for form inputs.
- Export InlineCatalogSchema type from a2ui-renderer.
2026-04-15 12:28:13 +02:00
Markus Ecker abd0d5c11c fix: add path binding schema rule to A2UI generation prompts
LLMs sometimes use path bindings (e.g. {"path": "/chartData"}) on
component properties that only accept literal values, causing silent
render failures. The new guideline tells the LLM to check the schema's
anyOf type before using path bindings.
2026-04-15 11:51:05 +02:00
Jordan Ritter 97acd2e4d9 fix: add Zod v4 compatibility for schema-to-JSON conversion
Detect Zod v4 schemas by checking for a toJSONSchema() method on the
schema object. When present, call it directly instead of routing through
zod-to-json-schema (which cannot handle Zod v4 internals).

Priority order:
1. Standard JSON Schema V1 (~standard.jsonSchema.input)
2. Zod v4 native (schema.toJSONSchema())
3. Zod v3 fallback (injected zodToJsonSchema)

Removes the dead vendor === "zod4" check (Zod v4 reports "zod") and
the _def duck-typing fallback (unnecessary with toJSONSchema detection).

Closes #3636
2026-04-14 16:15:58 -07:00
Jordan Ritter 8aa369b58f fix: preserve nullable semantics and add Zod support for null-union types
- Mark parameters as optional when null is present in the type union
- Add matching null-union handling to convertJsonSchemaToZodSchema
- Add 7 tests covering null-union edge cases for both converters
2026-04-14 15:47:40 -07:00
Jordan Ritter afc36a3da9 fix: mock navigator in clipboard test for Node 20 compatibility 2026-04-14 15:11:35 -07:00
Jordan Ritter 971a8165aa fix: default verbose to false when debug: true to prevent PII exposure
When users pass the boolean shorthand `debug: true`, verbose previously
defaulted to true, logging full event payloads including user messages,
tool args, and state snapshots. Now defaults to false — users must
explicitly opt in with `debug: { verbose: true }`.
2026-04-14 14:57:22 -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 2c45e24e90 fix: handle anyOf/oneOf/$ref/null in JSON schema to Zod conversion (#3849)
## Summary
- Handle `anyOf`, `oneOf`, `$ref`, and null type entries when converting
JSON schema to Zod schemas
- Prevents runtime errors when LLM tool parameters use union types or
nullable fields

Closes #2220

---
*Split from #3847*
2026-04-14 14:26:09 -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
Alem Tuzlak e977a49972 fix: address CR findings for debug mode feature
- Fix clone() dropping debug config on ProxiedCopilotRuntimeAgent
- Pass raw DebugConfig to agents instead of collapsing to boolean
- Clamp verbose to false when enabled is false
- Fix pino-pretty log format in docs (parentheses, timestamps, levels)
- Add loggedEventCount to doc example
- Fix "Agent run started/finished" → actual log messages in arch docs
2026-04-14 18:35:32 +02:00
Alem Tuzlak 7e0a632e64 test: add debug mode tests for shared, runtime, and core packages 2026-04-14 18:34:47 +02:00
Alem Tuzlak cc5410dc4f feat(shared): add DebugConfig type and resolveDebugConfig utility 2026-04-14 18:34:07 +02:00
Jordan Ritter 0b26088586 fix: clone visited-refs set to prevent false circular-ref detection across sibling branches
The shared visitedRefs Set was mutated in place, so when two sibling
properties referenced the same $def (e.g. billing and shipping both
referencing Address), the second resolution was incorrectly flagged as
circular. Clone the set before recursing so each branch has its own
ancestry path. Added regression test that fails without this fix.
2026-04-13 09:08:54 -07:00
Jordan Ritter 18552b561f fix: add circular $ref cycle detection in JSON schema to Zod conversion
Recursive JSON schemas that reference themselves via $ref would cause
infinite recursion and stack overflow. This adds a visited set that
tracks which $ref paths have been seen during resolution. When a cycle
is detected, it breaks with z.any() and logs a console.warn so users
get feedback. Also adds console.warn for the generic z.any() fallback
on unsupported schema types.

Adds tests for circular refs, non-circular $ref resolution, anyOf with
$ref variants, integer type, null type, and unsupported type warning.
2026-04-13 08:30:33 -07:00
Alem Tuzlak 327d134ecd Merge remote-tracking branch 'origin/main' into worktree-nested-tinkering-quail
# Conflicts:
#	packages/angular/package.json
#	packages/core/package.json
#	packages/demo-agents/package.json
#	packages/react-core/package.json
#	packages/runtime/package.json
#	packages/shared/package.json
#	packages/sqlite-runner/package.json
#	packages/web-inspector/package.json
#	pnpm-lock.yaml
2026-04-13 11:12:25 +02:00
github-actions[bot] c4d50a3ec7 style: auto-fix formatting 2026-04-12 22:26:58 +00:00
Jordan Ritter fac52dbf9b fix: handle anyOf/oneOf/ in JSON schema to Zod conversion (#2220) 2026-04-12 15:24:46 -07:00
Jordan Ritter 1dcaf752d4 fix: handle null-union types in convertJsonSchemaToParameter (#2651)
JSON schemas from tools like Zod can produce union types like
["string", "null"]. The switch statement only handles single type
strings, causing these to fall through silently. Now we detect
Array.isArray(schema.type), filter out "null", and recurse with
the resolved scalar type.
2026-04-12 15:04:51 -07:00
Markus Ecker 05ddcfc12a feat(react-core): Open Generative UI — sandboxed HTML/CSS/JS rendering via iframe
AI-generated UI streamed into chat via websandbox iframe (allow-scripts only,
no allow-same-origin), progressive HTML preview with throttled updates,
one-shot auto-resize, sandboxFunctions for host-to-iframe calls, designSkill
styling guidelines, A2UI catalog context injection.
2026-04-08 12:49:38 -07:00
Markus Ecker 93d0a76ddc feat(a2ui-renderer): A2UI v0.9 — BYOC catalogs, dark mode, component-neutral guidelines
Replace @a2ui/lit with @a2ui/web_core 0.9, introduce createCatalog() API for
custom component catalogs, add basic (18 components) and minimal (5 components)
built-in catalogs, CSS variable theming for dark mode, eliminate XSS vector
(dangerouslySetInnerHTML removed from Text component).
2026-04-08 12:48:47 -07: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 ae1dc0ce4c feat(react-core): add v2 attachment renderer, update user message for multimodal, DRY shared utils 2026-04-06 14:54:43 +02:00