fix(react-native): add /headless subpath so custom-UI consumers skip chat/attachment native deps - #6142
Merged
Conversation
…chat/attachment native deps The `@copilotkit/react-native` barrel statically re-exports the prebuilt chat UI (CopilotChat / CopilotModal / CopilotSidebar / CopilotPopup, which import `@gorhom/bottom-sheet`) and `useAttachments` (which imports `expo-document-picker` + `expo-file-system`). Those are optional peer deps, but a static re-export still forces Metro to resolve them at bundle time. A headless consumer that uses only `CopilotKitProvider` + `useAgent` + `useFrontendTool` (a fully custom UI) had to install every chat/attachment native dep or stub them in `metro.config.js`, or the release bundle fails with `Unable to resolve module expo-document-picker`. Add a lean `@copilotkit/react-native/headless` entry that re-exports only the provider, the platform-agnostic hooks, the render-tool registry, and the core/AG-UI types — none of the chat UI or `useAttachments` — so those native deps never enter the bundle graph and the metro-stub workaround is retired. Mirrors `@copilotkit/react-core/v2/headless` (#5883): a standalone entry file, wired into the tsdown entry list, the package.json `exports` map, and `sideEffects` (it side-effect-imports the polyfills). The default barrel now does `export * from "./headless"` and layers the chat UI on top, so it stays fully backward compatible. Adds a static import-graph regression test asserting the headless graph never reaches the chat/attachment modules or their native peer deps. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
davidmckayv
requested review from
jpr5,
marthakelly,
mme,
ranst91 and
tylerslaton
as code owners
July 23, 2026 21:57
@copilotkit/a2ui-renderer
@copilotkit/agentcore-runner
@copilotkit/angular
@copilotkit/channels
@copilotkit/channels-core
@copilotkit/channels-discord
@copilotkit/channels-intelligence
@copilotkit/channels-slack
@copilotkit/channels-teams
@copilotkit/channels-telegram
@copilotkit/channels-ui
@copilotkit/channels-whatsapp
@copilotkit/core
@copilotkit/react-core
@copilotkit/react-native
@copilotkit/react-textarea
@copilotkit/react-ui
@copilotkit/runtime
@copilotkit/runtime-client-gql
@copilotkit/sdk-js
@copilotkit/shared
@copilotkit/sqlite-runner
@copilotkit/voice
@copilotkit/vue
@copilotkit/web-components
@copilotkit/web-inspector
commit: |
Contributor
|
Size Change: 0 B Total Size: 1.19 MB ℹ️ View Unchanged
|
tylerslaton
approved these changes
Jul 24, 2026
samjulien
added a commit
that referenced
this pull request
Jul 28, 2026
## What Expands the React Native docs page from a "get to first chat" quickstart into a full production guide, matching the depth of the Slack/Teams frontend pages. The existing quickstart Steps are unchanged; the new material is added after them. ### Production sections added - **Headless imports** — `@copilotkit/react-native/headless` for a custom-UI app, avoiding the chat/attachment native peer deps the default barrel re-exports. - **Metro configuration for release bundles** — `unstable_enablePackageExports` + browser-first `unstable_conditionNames` so the transitive `jose` dependency resolves to its browser build (fails only at release-bundle time otherwise). - **Polyfills** — documents the real auto-installed barrel + granular subpaths, including the `crypto` polyfill (backed by `Math.random`) and the recommendation to install a secure RNG for production. - **Provider options** — the full `CopilotKitProvider` prop surface: `runtimeUrl`, `headers` (auth), `credentials`, `properties`, `onError`, `debug`, `defaultThrottleMs`, `useSingleEndpoint`. - **Runtime and model wiring** — the string model form, `OPENAI_BASE_URL` (and Anthropic/Google equivalents) for OpenAI-compatible endpoints, `createCopilotNodeListener` zero-dep serving, and `BuiltInAgent` options. - **Connecting from a device or bench** — LAN IP, Android emulator `10.0.2.2`, `adb reverse` for USB, and Android release cleartext HTTP via `expo-build-properties`. - **Frontend tools and generative UI** — `useFrontendTool` with zod/Standard Schema, the send-a-turn recipe, `useAgent` read-only subscribe + `threadId`, discriminated-union params, and variable-length `ScrollView` rendering. - **Run lifecycle and UI** — `isRunning` outliving the visible compose, and gating overlays/reveal motion accordingly. - **Voice and speech-to-text** — DIY STT with a graceful-fallback warning for de-Googled/automotive hardware. - Refreshed **What's included** and **Known limitations**, plus a **Next steps** section. ### Dependency on runtime / react-native fixes Three of the four fixes this guide relies on are now **merged to `main`**, so it documents them as current behavior: - `@copilotkit/react-native/headless` subpath (headless provider + hooks without chat/attachment deps) — #6142 ✅ merged - `resolveModel` honoring `OPENAI_BASE_URL` / `ANTHROPIC_BASE_URL` / `GOOGLE_GENERATIVE_AI_BASE_URL` for the string model form — #6140 ✅ merged - union / `anyOf` / `oneOf` tool-param schemas surviving JSON-schema→zod conversion — #6143 ✅ merged The fourth — `useAgent` accepting an optional `threadId` (#6141) — is **still open**. The guide therefore does **not** document it as working; it is listed under **Known limitations** instead, and will be promoted once #6141 lands. Every API, export, env var, and behavior in the page was independently re-verified against the package source (three parallel source audits over `packages/{react-native,react-core,runtime}`). That pass turned up one overstatement, fixed in 6eefe2b: only `/headless` and the root barrel side-effect-import the polyfill barrel — `@copilotkit/react-native/components` does not, so the "all three surfaces auto-install" wording was corrected. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
3 tasks
BenTaylorDev
added a commit
that referenced
this pull request
Aug 27, 2026
… below it (closes OSS-956) (#6725) ## What does this PR do? The React Native guide imports `CopilotKitProvider`, `useAgent` and `useCopilotKit` from `@copilotkit/react-native/headless` and names no version. That subpath first ships in **1.64.0** (#6142), so a project pinned to 1.63.x or earlier fails every one of those imports with: ``` Unable to resolve module @copilotkit/react-native/headless ``` On Metro that reads like a broken install rather than a version skew, and it sends the reader into the package-exports and polyfill debugging the same guide warns about a few sections later. The actual fix is one word in an import path. This states the boundary in the three places a reader meets the subpath. Prose only — no snippet in this page changed. ### The version boundary, verified against the registry Not inferred from a changelog — `npm view @copilotkit/react-native@<v> exports` on each: | version | `./headless` | | -- | -- | | 1.62.0, 1.62.2, 1.62.3 | absent | | 1.63.0, 1.63.1, 1.63.2 | absent | | **1.64.0** | **present** | | 1.64.1+, 1.65.0, 1.69.2 | present | `./components` and the polyfill subpaths exist across all of the above, so `/headless` is the only path in the guide that carries a version boundary. Introduced by 0a582df / #6142. ### What changed - **Intro line** — `/headless` is marked `1.64.0+` where the three import surfaces are first introduced. - **Install step** — a `type="warn"` callout, placed where the resolved version is actually decided. States the boundary, quotes the exact Metro error, gives `npm ls @copilotkit/react-native` to check what you resolved, and covers the fallback. - **Import surfaces table** — a new "Available since" column. - **Import surfaces prose** — records what `/headless` *is*, which the guide never said: a lean alternative entry added so custom-UI consumers skip the chat and attachment native deps — **not** a replacement for the root barrel, which remains the package's default full surface and re-exports everything in `/headless`. ### The fallback advice is deliberately not just "import from the root" On 1.62.2 and 1.63.2 the root barrel does export all three names (checked in the shipped tarballs, not assumed). But `package/dist/index.mjs` on those versions statically imports `expo-document-picker` and `expo-file-system`. A reader who switches to the root therefore inherits exactly the peer-dependency resolution failure that this guide's `/headless` choice exists to avoid: ``` Unable to resolve module expo-document-picker ``` So the callout says to prefer upgrading to 1.64.0+, and if you cannot (because you are matching a pinned `@copilotkit/runtime`), names the install-or-stub requirement that comes with the root import rather than presenting it as a free swap. ### Why not backport `./headless` to 1.62.x That was the alternative the issue floated, and it looks unnecessary. `/headless` was never intended as the canonical entry that supersedes the root — #6142's message, `src/index.ts` (`export * from "./headless"`, with a root quick-start that uses the root), and `src/headless.ts` ("existing imports from `@copilotkit/react-native` are unchanged") all agree it is a lean *alternative*. Adding an entry point in a patch of an older line would also change what "the pinned set" means for anyone matching client to runtime. ## Related PRs and Issues - Closes OSS-956 - #6142 — added the `/headless` subpath in 1.64.0 - #5883 — the `@copilotkit/react-core/v2/headless` entry that #6142 mirrors ## Verification - MDX compiles via `@mdx-js/mdx` + `remark-gfm`, edited and baseline both - 4-column Import surfaces table parses; 19/19 `<Callout>` tags balanced - `commitlint` exit 0 - `pnpm check:intelligence-env-names` passes - `.mdx` is not in lefthook's `lint-fix` glob, so oxfmt/oxlint never applied to this file - This page carries no `doctest=` fences, and no fence in it changed, so the guide's snippets stay runnable as they were ## 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 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Naz-Ovh
pushed a commit
to 0x-fork/CopilotKit
that referenced
this pull request
Aug 27, 2026
… below it (closes OSS-956) The React Native guide imports `CopilotKitProvider`, `useAgent` and `useCopilotKit` from `@copilotkit/react-native/headless` and names no version. That subpath first ships in 1.64.0 (CopilotKit#6142), so a project pinned to 1.63.x or earlier fails every one of those imports with `Unable to resolve module @copilotkit/react-native/headless` — which on Metro reads like a broken install rather than a version skew, and sends the reader into the package-exports and polyfill debugging the same guide warns about. The actual fix is one word in an import path. Verified against the registry rather than inferred: `./headless` is absent from 1.62.0, 1.62.2, 1.62.3, 1.63.0, 1.63.1 and 1.63.2, and present from 1.64.0 onward. `./components` and the polyfill subpaths exist across all of them, so `/headless` is the only path in the guide with a version boundary. State the boundary in the three places a reader meets the subpath: the intro line that introduces the surfaces, a callout in the install step (where the resolved version is actually decided, with `npm ls` to check it), and an "Available since" column in the Import surfaces table. The fallback advice is deliberately not just "import from the root". On 1.62.2 and 1.63.2 the root barrel does export all three names — but its `dist/index.mjs` statically imports `expo-document-picker` and `expo-file-system`, so a reader who switches to the root inherits exactly the peer-dependency resolution failure that this guide's `/headless` choice exists to avoid. The note says so and points at the stub/install requirement. Also records what `/headless` is, since the guide never said: a lean alternative entry added so custom-UI consumers skip the chat and attachment native deps, not a replacement for the root barrel, which remains the package's default full surface and re-exports everything in `/headless`. Prose only — no snippet in this page changed, and the page carries no doctest fences, so the guide's snippets stay runnable as they were. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
@copilotkit/react-native's entry (packages/react-native/src/index.ts) statically re-exports the prebuilt chat UI —CopilotChat/CopilotModal/CopilotSidebar/CopilotPopup, which import@gorhom/bottom-sheet— anduseAttachments, which importsexpo-document-picker+expo-file-system.Those are declared as optional peer deps, but a static re-export still forces Metro to resolve them at bundle time. So a headless consumer that mounts only
CopilotKitProvider+useAgent+useFrontendTool(a fully custom UI, no prebuilt chat) is still forced to install all of those native deps, or Metro's release bundle fails:Today the only workaround is stubbing the modules in
metro.config.js.Fix
Add a lean
@copilotkit/react-native/headlesssubpath entry that re-exports only the provider (CopilotKitProvider), the platform-agnostic hooks (useAgent,useFrontendTool,useCopilotKit,useHumanInTheLoop,useInterrupt,useThreads,useSuggestions,useRenderTool, …), the render-tool registry, and the core/AG-UI types — and none of the chat components oruseAttachments. Those native deps therefore never enter the bundle graph:This retires the
metro.config.jsstub workaround for headless consumers.How it mirrors the precedent (#5883)
Directly mirrors
@copilotkit/react-core/v2/headless(PR #5883, which cut multi-MB bundle bloat by exposing lean hooks from a dedicated entry — and which this RN provider already consumes):src/headless.ts(the lean surface).entrylist (RN's tsdown auto-externalizes deps/peerDeps, so the native modules stay external and simply never get imported by this entry).package.json— new./headlesscondition inexports, and./dist/headless.*added tosideEffects(the entry side-effect-imports the polyfills).headless-entry-surface.test.ts) that walks the transitive graph fromsrc/headless.tsand fails if it ever reaches the chat/attachment modules or@gorhom/bottom-sheet/expo-document-picker/expo-file-system. This is the guarantee a normal typecheck can't catch, since those are optional peers.Backward compatibility
Fully backward compatible. The default barrel (
@copilotkit/react-native) now doesexport * from "./headless"and layers the chat UI +useAttachmentson top, so every existing import from@copilotkit/react-nativeis unchanged. The polyfills still auto-install from both entries.🤖 Generated with Claude Code