@assistant-ui/mcp-docs-server 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/.docs/organized/code-examples/waterfall.md +2 -2
  2. package/.docs/organized/code-examples/with-a2a.md +4 -3
  3. package/.docs/organized/code-examples/with-ag-ui.md +5 -4
  4. package/.docs/organized/code-examples/with-ai-sdk-v7.md +12 -11
  5. package/.docs/organized/code-examples/with-artifacts.md +10 -9
  6. package/.docs/organized/code-examples/with-assistant-transport.md +4 -3
  7. package/.docs/organized/code-examples/with-browser-extension.md +3 -3
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +14 -12
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +5 -5
  10. package/.docs/organized/code-examples/with-cloud.md +9 -8
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +8 -7
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +12 -11
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +12 -11
  14. package/.docs/organized/code-examples/with-eve.md +5 -4
  15. package/.docs/organized/code-examples/with-expo.md +214 -31
  16. package/.docs/organized/code-examples/with-external-store.md +4 -3
  17. package/.docs/organized/code-examples/with-ffmpeg.md +9 -8
  18. package/.docs/organized/code-examples/with-generative-ui.md +13 -15
  19. package/.docs/organized/code-examples/with-google-adk.md +4 -3
  20. package/.docs/organized/code-examples/with-heat-graph.md +2 -2
  21. package/.docs/organized/code-examples/with-image-generation.md +7 -6
  22. package/.docs/organized/code-examples/with-interactables.md +9 -8
  23. package/.docs/organized/code-examples/with-langchain.md +6 -5
  24. package/.docs/organized/code-examples/with-langgraph.md +6 -5
  25. package/.docs/organized/code-examples/with-livekit.md +13 -12
  26. package/.docs/organized/code-examples/with-mcp.md +11 -9
  27. package/.docs/organized/code-examples/with-nuxt.md +502 -502
  28. package/.docs/organized/code-examples/with-opencode.md +3 -3
  29. package/.docs/organized/code-examples/with-openui.md +14 -13
  30. package/.docs/organized/code-examples/with-pi.md +5 -4
  31. package/.docs/organized/code-examples/with-react-hook-form.md +13 -10
  32. package/.docs/organized/code-examples/with-react-ink-web.md +64 -14
  33. package/.docs/organized/code-examples/with-react-ink.md +3 -2
  34. package/.docs/organized/code-examples/with-react-router.md +6 -5
  35. package/.docs/organized/code-examples/with-resumable-stream.md +10 -9
  36. package/.docs/organized/code-examples/with-store.md +2 -2
  37. package/.docs/organized/code-examples/with-svelte.md +3 -3
  38. package/.docs/organized/code-examples/with-sveltekit.md +9 -9
  39. package/.docs/organized/code-examples/with-tanstack.md +8 -7
  40. package/.docs/organized/code-examples/with-tap-runtime.md +4 -3
  41. package/.docs/organized/code-examples/with-virtualized-thread.md +5 -4
  42. package/.docs/organized/code-examples/with-vue.md +2 -2
  43. package/.docs/raw/docs/{(docs) → (getting-started)}/devtools.mdx +1 -1
  44. package/.docs/raw/docs/{(docs) → (getting-started)}/index.mdx +4 -2
  45. package/.docs/raw/docs/{(docs) → (getting-started)}/installation.mdx +24 -24
  46. package/.docs/raw/docs/(reference)/api-reference/adapters/suggestions.mdx +6 -0
  47. package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +1 -1
  48. package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +6 -1
  49. package/.docs/raw/docs/(reference)/api-reference/integrations/{react-ai-sdk.mdx → ai-sdk.mdx} +19 -19
  50. package/.docs/raw/docs/(reference)/api-reference/integrations/eve.mdx +22 -1
  51. package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +3 -3
  52. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +2 -2
  53. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +20 -2
  54. package/.docs/raw/docs/(reference)/api-reference/tools/interactables.mdx +1 -1
  55. package/.docs/raw/docs/(reference)/api-reference/transport/frame.mdx +1 -1
  56. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +3 -0
  57. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +10 -10
  58. package/.docs/raw/docs/cloud/ai-sdk.mdx +2 -0
  59. package/.docs/raw/docs/copilots/assistant-frame.mdx +19 -8
  60. package/.docs/raw/docs/guides/attachments.mdx +2 -2
  61. package/.docs/raw/docs/guides/branching.mdx +1 -1
  62. package/.docs/raw/docs/guides/chatgpt-subscription.mdx +1 -1
  63. package/.docs/raw/docs/guides/dictation.mdx +1 -1
  64. package/.docs/raw/docs/guides/electron.mdx +1 -1
  65. package/.docs/raw/docs/guides/latex.mdx +1 -1
  66. package/.docs/raw/docs/guides/message-timing.mdx +11 -5
  67. package/.docs/raw/docs/guides/quoting.mdx +1 -1
  68. package/.docs/raw/docs/guides/resumable-streams.mdx +3 -3
  69. package/.docs/raw/docs/guides/speech.mdx +1 -1
  70. package/.docs/raw/docs/guides/suggestions.mdx +2 -2
  71. package/.docs/raw/docs/guides/voice.mdx +1 -1
  72. package/.docs/raw/docs/ink/hooks.mdx +1 -1
  73. package/.docs/raw/docs/ink/index.mdx +3 -2
  74. package/.docs/raw/docs/ink/migration.mdx +1 -1
  75. package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +3 -3
  76. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +3 -3
  77. package/.docs/raw/docs/integrations/frameworks/{cloudflare-agents/overview.mdx → cloudflare-agents.mdx} +4 -3
  78. package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +1 -1
  79. package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
  80. package/.docs/raw/docs/integrations/index.mdx +2 -2
  81. package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +3 -3
  82. package/.docs/raw/docs/migrations/toolkit-tools.mdx +2 -2
  83. package/.docs/raw/docs/primitives/action-bar.mdx +1 -1
  84. package/.docs/raw/docs/primitives/assistant-modal.mdx +1 -1
  85. package/.docs/raw/docs/primitives/attachment.mdx +1 -1
  86. package/.docs/raw/docs/primitives/branch-picker.mdx +1 -1
  87. package/.docs/raw/docs/primitives/chain-of-thought.mdx +3 -3
  88. package/.docs/raw/docs/primitives/composer.mdx +1 -1
  89. package/.docs/raw/docs/primitives/error.mdx +1 -1
  90. package/.docs/raw/docs/primitives/message.mdx +1 -1
  91. package/.docs/raw/docs/primitives/selection-toolbar.mdx +1 -1
  92. package/.docs/raw/docs/primitives/suggestion.mdx +1 -1
  93. package/.docs/raw/docs/primitives/thread-list.mdx +1 -1
  94. package/.docs/raw/docs/primitives/thread.mdx +1 -1
  95. package/.docs/raw/docs/react-native/adapters.mdx +1 -1
  96. package/.docs/raw/docs/react-native/index.mdx +2 -2
  97. package/.docs/raw/docs/react-native/migration.mdx +2 -2
  98. package/.docs/raw/docs/react-native/primitives.mdx +142 -5
  99. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +13 -1
  100. package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +3 -3
  101. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +4 -4
  102. package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +31 -16
  103. package/.docs/raw/docs/runtimes/concepts/adapters.mdx +3 -3
  104. package/.docs/raw/docs/runtimes/concepts/architecture.mdx +3 -3
  105. package/.docs/raw/docs/runtimes/concepts/threads.mdx +5 -5
  106. package/.docs/raw/docs/runtimes/langchain.mdx +1 -1
  107. package/.docs/raw/docs/runtimes/opencode/quickstart.mdx +1 -1
  108. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +1 -1
  109. package/.docs/raw/docs/tools/backend.mdx +4 -4
  110. package/.docs/raw/docs/tools/defining-tools.mdx +2 -2
  111. package/.docs/raw/docs/tools/generative-ui.mdx +2 -2
  112. package/.docs/raw/docs/tools/interactables.mdx +3 -3
  113. package/.docs/raw/docs/tools/mcp-apps.mdx +18 -1
  114. package/.docs/raw/docs/tools/mcp.mdx +2 -2
  115. package/.docs/raw/docs/tools/openui.mdx +2 -2
  116. package/.docs/raw/docs/tools/tool-ui.mdx +17 -5
  117. package/.docs/raw/docs/tools/user-managed-mcp.mdx +2 -2
  118. package/.docs/raw/docs/ui/assistant-modal.mdx +3 -3
  119. package/.docs/raw/docs/ui/assistant-sidebar.mdx +1 -1
  120. package/.docs/raw/docs/ui/attachment.mdx +30 -10
  121. package/.docs/raw/docs/ui/composer-trigger-popover.mdx +36 -1
  122. package/.docs/raw/docs/ui/context-display.mdx +1 -1
  123. package/.docs/raw/docs/ui/directive-text.mdx +1 -1
  124. package/.docs/raw/docs/ui/file.mdx +1 -1
  125. package/.docs/raw/docs/ui/follow-up-suggestions.mdx +1 -1
  126. package/.docs/raw/docs/ui/image.mdx +1 -1
  127. package/.docs/raw/docs/ui/markdown.mdx +40 -1
  128. package/.docs/raw/docs/ui/mermaid.mdx +1 -1
  129. package/.docs/raw/docs/ui/message-timing.mdx +1 -1
  130. package/.docs/raw/docs/ui/model-selector.mdx +4 -4
  131. package/.docs/raw/docs/ui/part-grouping.mdx +1 -1
  132. package/.docs/raw/docs/ui/quote.mdx +3 -3
  133. package/.docs/raw/docs/ui/reasoning.mdx +31 -3
  134. package/.docs/raw/docs/ui/scrollbar.mdx +1 -1
  135. package/.docs/raw/docs/ui/sources.mdx +10 -1
  136. package/.docs/raw/docs/ui/streamdown.mdx +2 -2
  137. package/.docs/raw/docs/ui/syntax-highlighting.mdx +1 -1
  138. package/.docs/raw/docs/ui/thread-list.mdx +40 -1
  139. package/.docs/raw/docs/ui/thread.mdx +49 -2
  140. package/.docs/raw/docs/ui/tool-fallback.mdx +23 -9
  141. package/.docs/raw/docs/ui/tool-group.mdx +1 -1
  142. package/.docs/raw/docs/ui/voice.mdx +1 -1
  143. package/.docs/raw/docs/utilities/react-o11y.mdx +2 -2
  144. package/dist/xulux/catalog-client.d.ts.map +1 -1
  145. package/dist/xulux/catalog-client.js +51 -6
  146. package/dist/xulux/catalog-client.js.map +1 -1
  147. package/dist/xulux/types.d.ts +7 -7
  148. package/dist/xulux/types.d.ts.map +1 -1
  149. package/dist/xulux/types.js.map +1 -1
  150. package/package.json +3 -3
  151. package/src/tools/tests/docs.test.ts +10 -7
  152. package/src/tools/tests/path-traversal.test.ts +5 -2
  153. package/src/tools/tests/xulux-templates.test.ts +63 -0
  154. package/src/xulux/catalog-client.ts +68 -23
  155. package/src/xulux/types.ts +17 -13
  156. package/.docs/raw/docs/ui/accordion.mdx +0 -266
  157. package/.docs/raw/docs/ui/badge.mdx +0 -150
  158. package/.docs/raw/docs/ui/diff-viewer.mdx +0 -280
  159. package/.docs/raw/docs/ui/dot-matrix.mdx +0 -133
  160. package/.docs/raw/docs/ui/number-roll.mdx +0 -154
  161. package/.docs/raw/docs/ui/select.mdx +0 -254
  162. package/.docs/raw/docs/ui/tabs.mdx +0 -271
  163. /package/.docs/raw/docs/{(docs) → (getting-started)}/architecture.mdx +0 -0
  164. /package/.docs/raw/docs/{(docs) → (getting-started)}/base-ui.mdx +0 -0
  165. /package/.docs/raw/docs/{(docs) → (getting-started)}/cli.mdx +0 -0
  166. /package/.docs/raw/docs/{(docs) → (getting-started)}/llm.mdx +0 -0
  167. /package/.docs/raw/docs/{(docs) → (getting-started)}/rtl.mdx +0 -0
@@ -336,9 +336,9 @@ export default withEve(withAui(nextConfig));
336
336
  "@assistant-ui/ui": "workspace:*",
337
337
  "class-variance-authority": "^0.7.1",
338
338
  "clsx": "^2.1.1",
339
- "eve": "^0.37.0",
340
- "lucide-react": "^1.31.0",
341
- "next": "^16.3.0",
339
+ "eve": "^0.44.4",
340
+ "lucide-react": "^1.33.0",
341
+ "next": "^16.3.2",
342
342
  "react": "^19.2.8",
343
343
  "react-dom": "^19.2.8",
344
344
  "tailwind-merge": "^3.6.0"
@@ -349,7 +349,7 @@ export default withEve(withAui(nextConfig));
349
349
  "@tailwindcss/postcss": "^4.3.3",
350
350
  "@types/node": "^26.2.0",
351
351
  "@types/react": "^19.2.18",
352
- "@types/react-dom": "^19.2.4",
352
+ "@types/react-dom": "^19.2.5",
353
353
  "postcss": "^8.5.26",
354
354
  "tailwindcss": "^4.3.3",
355
355
  "tw-animate-css": "^1.4.0",
@@ -385,6 +385,7 @@ The Eve channel is served on the same origin as the Next app, so the browser UI
385
385
  "@/components/assistant-ui/*": [
386
386
  "../../packages/ui/src/components/assistant-ui/*"
387
387
  ],
388
+ "@/hooks/*": ["../../packages/ui/src/hooks/*"],
388
389
  "@/components/ui/*": [
389
390
  "../../packages/ui/src/components/ui/base/*",
390
391
  "../../packages/ui/src/components/ui/radix/*"
@@ -115,6 +115,7 @@ function NewChatButton() {
115
115
  return (
116
116
  <Pressable
117
117
  accessibilityLabel="New chat"
118
+ accessibilityRole="button"
118
119
  hitSlop={8}
119
120
  onPress={() => {
120
121
  haptics.selection();
@@ -191,7 +192,7 @@ export default function RootLayout() {
191
192
  ## app/api/chat+api.ts
192
193
 
193
194
  ```typescript
194
- import { frontendTools } from "@assistant-ui/react-ai-sdk";
195
+ import { frontendTools } from "@assistant-ui/ai-sdk";
195
196
  import { openai } from "@ai-sdk/openai";
196
197
  import {
197
198
  convertToModelMessages,
@@ -375,6 +376,7 @@ function AttachButton() {
375
376
  return (
376
377
  <Pressable
377
378
  accessibilityLabel="Add image"
379
+ accessibilityRole="button"
378
380
  onPress={pickImage}
379
381
  hitSlop={6}
380
382
  style={({ pressed }) => [
@@ -636,6 +638,7 @@ import { useEffect, useRef } from "react";
636
638
  import { View, Text, Animated, Platform, StyleSheet } from "react-native";
637
639
  import { Image } from "expo-image";
638
640
  import {
641
+ AuiIf,
639
642
  useAuiState,
640
643
  MessagePrimitive,
641
644
  ErrorPrimitive,
@@ -764,12 +767,19 @@ function AssistantMessage() {
764
767
  />
765
768
  </ErrorPrimitive.Root>
766
769
  </View>
767
- <MessagePrimitive.If running={false}>
770
+ <AuiIf
771
+ condition={(s) =>
772
+ !(
773
+ s.message.role === "assistant" &&
774
+ s.message.status.type === "running"
775
+ )
776
+ }
777
+ >
768
778
  <View style={styles.actionsRow}>
769
779
  <MessageBranchPicker align="flex-start" />
770
780
  <MessageActionBar />
771
781
  </View>
772
- </MessagePrimitive.If>
782
+ </AuiIf>
773
783
  </MessagePrimitive.Root>
774
784
  );
775
785
  }
@@ -864,7 +874,7 @@ import {
864
874
  import { useSafeAreaInsets } from "react-native-safe-area-context";
865
875
  import { MessageBubble } from "./message";
866
876
  import { Composer } from "./composer";
867
- import { ThreadPrimitive } from "@assistant-ui/react-native";
877
+ import { AuiIf, ThreadPrimitive } from "@assistant-ui/react-native";
868
878
  import { useTheme } from "@/hooks/use-theme";
869
879
  import { Radius, Spacing } from "@/constants/theme";
870
880
  import { haptics } from "@/lib/haptics";
@@ -916,10 +926,10 @@ function EmptyState() {
916
926
  function ChatMessages() {
917
927
  return (
918
928
  <>
919
- <ThreadPrimitive.Empty>
929
+ <AuiIf condition={(s) => s.thread.isEmpty}>
920
930
  <EmptyState />
921
- </ThreadPrimitive.Empty>
922
- <ThreadPrimitive.If empty={false}>
931
+ </AuiIf>
932
+ <AuiIf condition={(s) => !s.thread.isEmpty}>
923
933
  <ThreadPrimitive.MessagesFlatList
924
934
  style={styles.flex}
925
935
  contentContainerStyle={styles.messageList}
@@ -927,7 +937,7 @@ function ChatMessages() {
927
937
  >
928
938
  {() => <MessageBubble />}
929
939
  </ThreadPrimitive.MessagesFlatList>
930
- </ThreadPrimitive.If>
940
+ </AuiIf>
931
941
  </>
932
942
  );
933
943
  }
@@ -1423,7 +1433,11 @@ const styles = StyleSheet.create({
1423
1433
  ```tsx
1424
1434
  import { View, Text, Pressable, StyleSheet } from "react-native";
1425
1435
  import { useSafeAreaInsets } from "react-native-safe-area-context";
1426
- import { ThreadListPrimitive, useAui } from "@assistant-ui/react-native";
1436
+ import {
1437
+ ThreadListPrimitive,
1438
+ useAui,
1439
+ useAuiState,
1440
+ } from "@assistant-ui/react-native";
1427
1441
  import type { DrawerContentComponentProps } from "expo-router/build/react-navigation/drawer/types";
1428
1442
  import { ThreadListItem } from "./ThreadListItem";
1429
1443
  import { Icon } from "@/components/ui/icon";
@@ -1434,6 +1448,9 @@ import { haptics } from "@/lib/haptics";
1434
1448
  export function ThreadListDrawer({ navigation }: DrawerContentComponentProps) {
1435
1449
  const { colors } = useTheme();
1436
1450
  const aui = useAui();
1451
+ const isNewThreadActive = useAuiState(
1452
+ (s) => s.threads.newThreadId === s.threads.mainThreadId,
1453
+ );
1437
1454
  const insets = useSafeAreaInsets();
1438
1455
 
1439
1456
  return (
@@ -1445,6 +1462,8 @@ export function ThreadListDrawer({ navigation }: DrawerContentComponentProps) {
1445
1462
  >
1446
1463
  <ThreadListPrimitive.Root style={styles.root}>
1447
1464
  <Pressable
1465
+ accessibilityRole="button"
1466
+ accessibilityState={{ selected: isNewThreadActive }}
1448
1467
  onPressIn={haptics.selection}
1449
1468
  onPress={() => {
1450
1469
  aui.threads.switchToNewThread();
@@ -1540,6 +1559,8 @@ export function ThreadListItem({ onSelect }: { onSelect: () => void }) {
1540
1559
  return (
1541
1560
  <ThreadListItemPrimitive.Root>
1542
1561
  <Pressable
1562
+ accessibilityRole="button"
1563
+ accessibilityState={{ selected: isActive }}
1543
1564
  onPressIn={haptics.selection}
1544
1565
  onPress={() => {
1545
1566
  aui.threadListItem.switchTo();
@@ -1771,21 +1792,181 @@ export const Spacing = {
1771
1792
 
1772
1793
  ```
1773
1794
 
1795
+ ## hooks/anonymous-session-fetch.test.ts
1796
+
1797
+ ```typescript
1798
+ import { describe, expect, it, vi } from "vitest";
1799
+ import {
1800
+ createAnonymousSessionFetch,
1801
+ shouldUseAnonymousSessionFetch,
1802
+ } from "./anonymous-session-fetch";
1803
+
1804
+ describe("Expo anonymous session fetch", () => {
1805
+ it("only bootstraps the protected browser flow on web", () => {
1806
+ expect(
1807
+ shouldUseAnonymousSessionFetch(
1808
+ "https://www.assistant-ui.com/api/chat",
1809
+ "web",
1810
+ ),
1811
+ ).toBe(true);
1812
+ expect(
1813
+ shouldUseAnonymousSessionFetch(
1814
+ "https://www.assistant-ui.com/api/chat",
1815
+ "ios",
1816
+ ),
1817
+ ).toBe(false);
1818
+ expect(shouldUseAnonymousSessionFetch("/api/chat", "web")).toBe(false);
1819
+ });
1820
+
1821
+ it("retries bootstrap on the next request after issuance fails", async () => {
1822
+ const fetchMock = vi
1823
+ .fn<typeof fetch>()
1824
+ .mockRejectedValueOnce(new Error("temporary network failure"))
1825
+ .mockResolvedValueOnce(new Response(null, { status: 403 }))
1826
+ .mockResolvedValueOnce(Response.json({ token: "signed-session" }))
1827
+ .mockResolvedValueOnce(new Response("ok"));
1828
+ const sessionFetch = createAnonymousSessionFetch(
1829
+ "https://www.assistant-ui.com/api/chat",
1830
+ fetchMock,
1831
+ );
1832
+
1833
+ const failedResponse = await sessionFetch(
1834
+ "https://www.assistant-ui.com/api/chat",
1835
+ { method: "POST" },
1836
+ );
1837
+ const recoveredResponse = await sessionFetch(
1838
+ "https://www.assistant-ui.com/api/chat",
1839
+ { method: "POST" },
1840
+ );
1841
+
1842
+ expect(failedResponse.status).toBe(403);
1843
+ expect(recoveredResponse.status).toBe(200);
1844
+ expect(fetchMock).toHaveBeenCalledTimes(4);
1845
+ expect(
1846
+ new Headers(fetchMock.mock.calls[1]?.[1]?.headers).get(
1847
+ "x-assistant-ui-anonymous-session",
1848
+ ),
1849
+ ).toBeNull();
1850
+ expect(
1851
+ new Headers(fetchMock.mock.calls[3]?.[1]?.headers).get(
1852
+ "x-assistant-ui-anonymous-session",
1853
+ ),
1854
+ ).toBe("signed-session");
1855
+ });
1856
+
1857
+ it("accepts a same-origin 204 cookie bootstrap", async () => {
1858
+ const fetchMock = vi
1859
+ .fn<typeof fetch>()
1860
+ .mockResolvedValueOnce(new Response(null, { status: 204 }))
1861
+ .mockResolvedValueOnce(new Response("ok"));
1862
+ const sessionFetch = createAnonymousSessionFetch(
1863
+ "https://example.com/api/chat",
1864
+ fetchMock,
1865
+ );
1866
+
1867
+ const response = await sessionFetch("https://example.com/api/chat", {
1868
+ method: "POST",
1869
+ });
1870
+
1871
+ expect(response.status).toBe(200);
1872
+ expect(fetchMock.mock.calls[0]?.[1]?.credentials).toBe("same-origin");
1873
+ expect(
1874
+ new Headers(fetchMock.mock.calls[1]?.[1]?.headers).get(
1875
+ "x-assistant-ui-anonymous-session",
1876
+ ),
1877
+ ).toBeNull();
1878
+ });
1879
+ });
1880
+
1881
+ ```
1882
+
1883
+ ## hooks/anonymous-session-fetch.ts
1884
+
1885
+ ```typescript
1886
+ // Mirrored inline in examples/with-react-ink-web/app/ink-app.tsx; keep in sync.
1887
+ const ANONYMOUS_SESSION_HEADER = "x-assistant-ui-anonymous-session";
1888
+
1889
+ export function shouldUseAnonymousSessionFetch(
1890
+ chatApi: string,
1891
+ platform: string,
1892
+ ): boolean {
1893
+ return platform === "web" && chatApi.startsWith("http");
1894
+ }
1895
+
1896
+ export function createAnonymousSessionFetch(
1897
+ chatApi: string,
1898
+ fetchImplementation: typeof fetch = fetch,
1899
+ ): typeof fetch {
1900
+ let tokenPromise: Promise<string | null> | null = null;
1901
+
1902
+ const getToken = () => {
1903
+ tokenPromise ??= (async () => {
1904
+ const endpoint = new URL("/api/anonymous-session", chatApi);
1905
+ const response = await fetchImplementation(endpoint, {
1906
+ credentials: "same-origin",
1907
+ });
1908
+ if (!response.ok) {
1909
+ throw new Error("Unable to start an anonymous session");
1910
+ }
1911
+ if (response.status === 204) return null;
1912
+ const payload = (await response.json()) as { token?: unknown };
1913
+ if (typeof payload.token !== "string" || !payload.token) {
1914
+ throw new Error("Anonymous session token is missing");
1915
+ }
1916
+ return payload.token;
1917
+ })().catch(() => {
1918
+ tokenPromise = null;
1919
+ return null;
1920
+ });
1921
+ return tokenPromise;
1922
+ };
1923
+
1924
+ return async (input, init) => {
1925
+ const requestTemplate =
1926
+ input instanceof Request ? new Request(input, init) : null;
1927
+
1928
+ const send = async () => {
1929
+ const headers = new Headers(requestTemplate?.headers ?? init?.headers);
1930
+ const token = await getToken();
1931
+ if (token) headers.set(ANONYMOUS_SESSION_HEADER, token);
1932
+ if (requestTemplate) {
1933
+ return fetchImplementation(requestTemplate.clone(), { headers });
1934
+ }
1935
+ return fetchImplementation(input, { ...init, headers });
1936
+ };
1937
+
1938
+ const response = await send();
1939
+ if (response.status !== 401) return response;
1940
+ tokenPromise = null;
1941
+ return send();
1942
+ };
1943
+ }
1944
+
1945
+ ```
1946
+
1774
1947
  ## hooks/use-app-runtime.ts
1775
1948
 
1776
1949
  ```typescript
1777
1950
  import { useMemo } from "react";
1778
- import {
1779
- useChatRuntime,
1780
- AssistantChatTransport,
1781
- } from "@assistant-ui/react-ai-sdk";
1951
+ import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/ai-sdk";
1782
1952
  import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
1953
+ import { Platform } from "react-native";
1954
+ import {
1955
+ createAnonymousSessionFetch,
1956
+ shouldUseAnonymousSessionFetch,
1957
+ } from "./anonymous-session-fetch";
1783
1958
 
1784
1959
  const CHAT_API = process.env.EXPO_PUBLIC_CHAT_ENDPOINT_URL ?? "/api/chat";
1785
1960
 
1786
1961
  export function useAppRuntime() {
1787
1962
  const transport = useMemo(
1788
- () => new AssistantChatTransport({ api: CHAT_API }),
1963
+ () =>
1964
+ new AssistantChatTransport({
1965
+ api: CHAT_API,
1966
+ ...(shouldUseAnonymousSessionFetch(CHAT_API, Platform.OS)
1967
+ ? { fetch: createAnonymousSessionFetch(CHAT_API) }
1968
+ : {}),
1969
+ }),
1789
1970
  [],
1790
1971
  );
1791
1972
  return useChatRuntime({
@@ -1927,28 +2108,29 @@ module.exports = withAui(config);
1927
2108
  "android": "expo run:android",
1928
2109
  "ios": "expo run:ios",
1929
2110
  "web": "expo start --web",
1930
- "export:web": "expo export --platform web && node scripts/flatten-assets.mjs"
2111
+ "export:web": "expo export --platform web && node scripts/flatten-assets.mjs",
2112
+ "test": "vitest run"
1931
2113
  },
1932
2114
  "dependencies": {
1933
- "@ai-sdk/openai": "^4.0.40",
1934
- "@ai-sdk/react": "^4.0.65",
1935
- "@assistant-ui/react-ai-sdk": "workspace:*",
2115
+ "@ai-sdk/openai": "^4.0.42",
2116
+ "@ai-sdk/react": "^4.0.69",
2117
+ "@assistant-ui/ai-sdk": "workspace:*",
1936
2118
  "@assistant-ui/react-native": "workspace:*",
1937
2119
  "@expo/vector-icons": "^15.1.1",
1938
2120
  "@react-navigation/drawer": "7.9.4",
1939
2121
  "@react-navigation/native": "7.1.33",
1940
- "ai": "^7.0.62",
1941
- "expo": "~57.0.12",
2122
+ "ai": "^7.0.66",
2123
+ "expo": "~57.0.16",
1942
2124
  "expo-clipboard": "~57.0.1",
1943
- "expo-constants": "~57.0.10",
2125
+ "expo-constants": "~57.0.14",
1944
2126
  "expo-font": "~57.0.1",
1945
2127
  "expo-haptics": "~57.0.1",
1946
- "expo-image": "~57.0.2",
1947
- "expo-image-picker": "~57.0.9",
1948
- "expo-linking": "~57.0.5",
1949
- "expo-router": "~57.0.12",
1950
- "expo-server": "~57.0.2",
1951
- "expo-splash-screen": "~57.0.6",
2128
+ "expo-image": "~57.0.3",
2129
+ "expo-image-picker": "~57.0.13",
2130
+ "expo-linking": "~57.0.6",
2131
+ "expo-router": "~57.0.16",
2132
+ "expo-server": "~57.0.3",
2133
+ "expo-splash-screen": "~57.0.8",
1952
2134
  "expo-status-bar": "~57.0.1",
1953
2135
  "expo-symbols": "^57.0.2",
1954
2136
  "expo-system-ui": "~57.0.2",
@@ -1968,7 +2150,8 @@ module.exports = withAui(config);
1968
2150
  "@babel/core": "^7.29.7",
1969
2151
  "@types/react": "~19.2.18",
1970
2152
  "typescript": "npm:@typescript/typescript6@^6.0.2",
1971
- "typescript-7": "npm:typescript@~7.0.2"
2153
+ "typescript-7": "npm:typescript@~7.0.2",
2154
+ "vitest": "^4.1.10"
1972
2155
  },
1973
2156
  "private": true
1974
2157
  }
@@ -1982,7 +2165,7 @@ module.exports = withAui(config);
1982
2165
 
1983
2166
  A native chat app built with [assistant-ui](https://www.assistant-ui.com) and [Expo](https://expo.dev). It runs on iOS, Android, and the web from a single codebase, and is styled to match the assistant-ui web kit: a clean, neutral, ChatGPT-grade look with subtle hairline borders.
1984
2167
 
1985
- The chat is powered by `@assistant-ui/react-native` with the AI SDK runtime (`@assistant-ui/react-ai-sdk`). The example leans on native Expo APIs throughout:
2168
+ The chat is powered by `@assistant-ui/react-native` with the AI SDK runtime (`@assistant-ui/ai-sdk`). The example leans on native Expo APIs throughout:
1986
2169
 
1987
2170
  - **SF Symbols** (`expo-symbols`) for native iconography on iOS, with a Material Icons fallback on Android and the web.
1988
2171
  - **Haptics** (`expo-haptics`) for tactile feedback on send, stop, and selection.
@@ -2006,7 +2189,7 @@ It follows the assistant-ui component conventions: `MessagePrimitive.Parts` for
2006
2189
  cp .env.example .env
2007
2190
  ```
2008
2191
 
2009
- The bundled API route (`app/api/chat+api.ts`) needs `OPENAI_API_KEY`. To point the app at a separately hosted backend instead, set `EXPO_PUBLIC_CHAT_ENDPOINT_URL`.
2192
+ The bundled API route (`app/api/chat+api.ts`) needs `OPENAI_API_KEY`. To point the app at a separately hosted backend instead, set `EXPO_PUBLIC_CHAT_ENDPOINT_URL`. Browser deployments use `/api/anonymous-session` when the hosted backend supports it and otherwise send the request normally. Native deployments should use a backend intended for their app.
2010
2193
 
2011
2194
  3. Start the app:
2012
2195
 
@@ -2054,7 +2237,7 @@ It follows the assistant-ui component conventions: `MessagePrimitive.Parts` for
2054
2237
  {
2055
2238
  "$schema": "https://openapi.vercel.sh/vercel.json",
2056
2239
  "ignoreCommand": "bash ../../scripts/vercel-ignore-changeset-release.sh",
2057
- "buildCommand": "cd ../.. && pnpm turbo build --filter=@assistant-ui/react-native --filter=@assistant-ui/react-ai-sdk --filter=@assistant-ui/metro && cd examples/with-expo && pnpm run export:web",
2240
+ "buildCommand": "cd ../.. && pnpm turbo build --filter=@assistant-ui/react-native --filter=@assistant-ui/ai-sdk --filter=@assistant-ui/metro && cd examples/with-expo && pnpm run export:web",
2058
2241
  "outputDirectory": "dist",
2059
2242
  "framework": null
2060
2243
  }
@@ -324,8 +324,8 @@ export default withAui(nextConfig);
324
324
  "@assistant-ui/ui": "workspace:*",
325
325
  "class-variance-authority": "^0.7.1",
326
326
  "clsx": "^2.1.1",
327
- "lucide-react": "^1.31.0",
328
- "next": "^16.3.0",
327
+ "lucide-react": "^1.33.0",
328
+ "next": "^16.3.2",
329
329
  "react": "^19.2.8",
330
330
  "react-dom": "^19.2.8",
331
331
  "tailwind-merge": "^3.6.0"
@@ -336,7 +336,7 @@ export default withAui(nextConfig);
336
336
  "@tailwindcss/postcss": "^4.3.3",
337
337
  "@types/node": "^26.2.0",
338
338
  "@types/react": "^19.2.18",
339
- "@types/react-dom": "^19.2.4",
339
+ "@types/react-dom": "^19.2.5",
340
340
  "postcss": "^8.5.26",
341
341
  "tailwindcss": "^4.3.3",
342
342
  "tw-animate-css": "^1.4.0",
@@ -401,6 +401,7 @@ npm run dev
401
401
  "@/components/assistant-ui/*": [
402
402
  "../../packages/ui/src/components/assistant-ui/*"
403
403
  ],
404
+ "@/hooks/*": ["../../packages/ui/src/hooks/*"],
404
405
  "@/components/ui/*": [
405
406
  "../../packages/ui/src/components/ui/base/*",
406
407
  "../../packages/ui/src/components/ui/radix/*"
@@ -4,7 +4,7 @@
4
4
 
5
5
  ```typescript
6
6
  import { openai } from "@ai-sdk/openai";
7
- import { frontendTools } from "@assistant-ui/react-ai-sdk";
7
+ import { frontendTools } from "@assistant-ui/ai-sdk";
8
8
  import { convertToModelMessages, streamText } from "ai";
9
9
 
10
10
  export const maxDuration = 30;
@@ -190,7 +190,7 @@ export default function RootLayout({
190
190
 
191
191
  import { AssistantRuntimeProvider, generateId } from "@assistant-ui/react";
192
192
  import type { AttachmentAdapter } from "@assistant-ui/react";
193
- import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
193
+ import { useChatRuntime } from "@assistant-ui/ai-sdk";
194
194
  import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
195
195
 
196
196
  const attachmentAdapter: AttachmentAdapter = {
@@ -720,18 +720,18 @@ export default withAui(nextConfig);
720
720
  "start": "next start"
721
721
  },
722
722
  "dependencies": {
723
- "@ai-sdk/openai": "^4.0.40",
723
+ "@ai-sdk/openai": "^4.0.46",
724
+ "@assistant-ui/ai-sdk": "workspace:*",
724
725
  "@assistant-ui/react": "workspace:*",
725
- "@assistant-ui/react-ai-sdk": "workspace:*",
726
726
  "@assistant-ui/react-markdown": "workspace:*",
727
727
  "@assistant-ui/ui": "workspace:*",
728
728
  "@ffmpeg/ffmpeg": "^0.12.15",
729
729
  "@ffmpeg/util": "^0.12.2",
730
- "ai": "^7.0.62",
730
+ "ai": "^7.0.77",
731
731
  "class-variance-authority": "^0.7.1",
732
732
  "clsx": "^2.1.1",
733
- "lucide-react": "^1.31.0",
734
- "next": "^16.3.0",
733
+ "lucide-react": "^1.33.0",
734
+ "next": "^16.3.2",
735
735
  "react": "^19.2.8",
736
736
  "react-dom": "^19.2.8",
737
737
  "tailwind-merge": "^3.6.0",
@@ -743,7 +743,7 @@ export default withAui(nextConfig);
743
743
  "@tailwindcss/postcss": "^4.3.3",
744
744
  "@types/node": "^26.2.0",
745
745
  "@types/react": "^19.2.18",
746
- "@types/react-dom": "^19.2.4",
746
+ "@types/react-dom": "^19.2.5",
747
747
  "postcss": "^8.5.26",
748
748
  "tailwindcss": "^4.3.3",
749
749
  "tw-animate-css": "^1.4.0",
@@ -809,6 +809,7 @@ npm run dev
809
809
  "@/components/assistant-ui/*": [
810
810
  "../../packages/ui/src/components/assistant-ui/*"
811
811
  ],
812
+ "@/hooks/*": ["../../packages/ui/src/hooks/*"],
812
813
  "@/components/ui/*": [
813
814
  "../../packages/ui/src/components/ui/base/*",
814
815
  "../../packages/ui/src/components/ui/radix/*"
@@ -16,7 +16,7 @@ import { z } from "zod";
16
16
  import {
17
17
  AISDKToolkit,
18
18
  type AISDKToolkitToolsOptions,
19
- } from "@assistant-ui/react-ai-sdk";
19
+ } from "@assistant-ui/ai-sdk";
20
20
  import {
21
21
  renderGuiToolDescription,
22
22
  renderGuiToolInputSchema,
@@ -121,7 +121,7 @@ import type { UIMessage } from "ai";
121
121
  import {
122
122
  AISDKToolkit,
123
123
  type AISDKToolkitToolsOptions,
124
- } from "@assistant-ui/react-ai-sdk";
124
+ } from "@assistant-ui/ai-sdk";
125
125
  import presentToolkit from "../../present-toolkit";
126
126
 
127
127
  export const maxDuration = 30;
@@ -301,7 +301,7 @@ import {
301
301
  Suggestions,
302
302
  useAssistantInstructions,
303
303
  } from "@assistant-ui/react";
304
- import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
304
+ import { useChatRuntime } from "@assistant-ui/ai-sdk";
305
305
  import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
306
306
  import { renderGuiChatInstructions } from "@/lib/render-gui-tool";
307
307
 
@@ -407,10 +407,7 @@ import {
407
407
  Suggestions,
408
408
  Tools,
409
409
  } from "@assistant-ui/react";
410
- import {
411
- AssistantChatTransport,
412
- useChatRuntime,
413
- } from "@assistant-ui/react-ai-sdk";
410
+ import { AssistantChatTransport, useChatRuntime } from "@assistant-ui/ai-sdk";
414
411
  import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
415
412
  import { ExampleNav } from "@/components/example-nav";
416
413
  import toolkit from "./present-toolkit";
@@ -632,7 +629,7 @@ import {
632
629
  Suggestions,
633
630
  Tools,
634
631
  } from "@assistant-ui/react";
635
- import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
632
+ import { useChatRuntime } from "@assistant-ui/ai-sdk";
636
633
  import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
637
634
  import { ExampleNav } from "@/components/example-nav";
638
635
  import toolkit from "../toolkit";
@@ -1735,16 +1732,16 @@ export default withAui(nextConfig);
1735
1732
  "test": "vitest run"
1736
1733
  },
1737
1734
  "dependencies": {
1738
- "@ai-sdk/openai": "^4.0.40",
1735
+ "@ai-sdk/openai": "^4.0.46",
1736
+ "@assistant-ui/ai-sdk": "workspace:*",
1739
1737
  "@assistant-ui/react": "workspace:*",
1740
- "@assistant-ui/react-ai-sdk": "workspace:*",
1741
1738
  "@assistant-ui/react-generative-ui": "workspace:*",
1742
1739
  "@assistant-ui/ui": "workspace:*",
1743
- "ai": "^7.0.62",
1740
+ "ai": "^7.0.77",
1744
1741
  "class-variance-authority": "^0.7.1",
1745
1742
  "clsx": "^2.1.1",
1746
- "lucide-react": "^1.31.0",
1747
- "next": "^16.3.0",
1743
+ "lucide-react": "^1.33.0",
1744
+ "next": "^16.3.2",
1748
1745
  "react": "^19.2.8",
1749
1746
  "react-dom": "^19.2.8",
1750
1747
  "recharts": "^3.10.1",
@@ -1757,12 +1754,12 @@ export default withAui(nextConfig);
1757
1754
  "@tailwindcss/postcss": "^4.3.3",
1758
1755
  "@types/node": "^26.2.0",
1759
1756
  "@types/react": "^19.2.18",
1760
- "@types/react-dom": "^19.2.4",
1757
+ "@types/react-dom": "^19.2.5",
1761
1758
  "postcss": "^8.5.26",
1762
1759
  "tailwindcss": "^4.3.3",
1763
1760
  "tw-animate-css": "^1.4.0",
1764
1761
  "typescript": "^7.0.2",
1765
- "vitest": "^4.1.10"
1762
+ "vitest": "^4.1.11"
1766
1763
  }
1767
1764
  }
1768
1765
 
@@ -1779,6 +1776,7 @@ export default withAui(nextConfig);
1779
1776
  "@/components/assistant-ui/*": [
1780
1777
  "../../packages/ui/src/components/assistant-ui/*"
1781
1778
  ],
1779
+ "@/hooks/*": ["../../packages/ui/src/hooks/*"],
1782
1780
  "@/components/ui/*": [
1783
1781
  "../../packages/ui/src/components/ui/base/*",
1784
1782
  "../../packages/ui/src/components/ui/radix/*"
@@ -314,8 +314,8 @@ export default withAui(nextConfig);
314
314
  "@google/adk": "^1.6.0",
315
315
  "class-variance-authority": "^0.7.1",
316
316
  "clsx": "^2.1.1",
317
- "lucide-react": "^1.31.0",
318
- "next": "^16.3.0",
317
+ "lucide-react": "^1.33.0",
318
+ "next": "^16.3.2",
319
319
  "react": "^19.2.8",
320
320
  "react-dom": "^19.2.8",
321
321
  "tailwind-merge": "^3.6.0",
@@ -327,7 +327,7 @@ export default withAui(nextConfig);
327
327
  "@tailwindcss/postcss": "^4.3.3",
328
328
  "@types/node": "^26.2.0",
329
329
  "@types/react": "^19.2.18",
330
- "@types/react-dom": "^19.2.4",
330
+ "@types/react-dom": "^19.2.5",
331
331
  "postcss": "^8.5.26",
332
332
  "tailwindcss": "^4.3.3",
333
333
  "tw-animate-css": "^1.4.0",
@@ -348,6 +348,7 @@ export default withAui(nextConfig);
348
348
  "@/components/assistant-ui/*": [
349
349
  "../../packages/ui/src/components/assistant-ui/*"
350
350
  ],
351
+ "@/hooks/*": ["../../packages/ui/src/hooks/*"],
351
352
  "@/components/ui/*": [
352
353
  "../../packages/ui/src/components/ui/base/*",
353
354
  "../../packages/ui/src/components/ui/radix/*"
@@ -269,7 +269,7 @@ export default withAui(nextConfig);
269
269
  },
270
270
  "dependencies": {
271
271
  "heat-graph": "workspace:*",
272
- "next": "^16.3.0",
272
+ "next": "^16.3.2",
273
273
  "react": "^19.2.8",
274
274
  "react-dom": "^19.2.8"
275
275
  },
@@ -279,7 +279,7 @@ export default withAui(nextConfig);
279
279
  "@tailwindcss/postcss": "^4.3.3",
280
280
  "@types/node": "^26.2.0",
281
281
  "@types/react": "^19.2.18",
282
- "@types/react-dom": "^19.2.4",
282
+ "@types/react-dom": "^19.2.5",
283
283
  "postcss": "^8.5.26",
284
284
  "tailwindcss": "^4.3.3",
285
285
  "typescript": "^7.0.2"