@assistant-ui/ai-sdk 0.0.1

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/LICENSE +21 -0
  2. package/README.md +32 -0
  3. package/dist/adapters/aiSDKFormatAdapter.d.ts +8 -0
  4. package/dist/adapters/aiSDKFormatAdapter.d.ts.map +1 -0
  5. package/dist/adapters/aiSDKFormatAdapter.js +26 -0
  6. package/dist/adapters/aiSDKFormatAdapter.js.map +1 -0
  7. package/dist/adapters/vercelAttachmentAdapter.d.ts +6 -0
  8. package/dist/adapters/vercelAttachmentAdapter.d.ts.map +1 -0
  9. package/dist/adapters/vercelAttachmentAdapter.js +37 -0
  10. package/dist/adapters/vercelAttachmentAdapter.js.map +1 -0
  11. package/dist/aiSDKExtras.d.ts +11 -0
  12. package/dist/aiSDKExtras.d.ts.map +1 -0
  13. package/dist/aiSDKExtras.js +7 -0
  14. package/dist/aiSDKExtras.js.map +1 -0
  15. package/dist/converters/convertMessage.d.ts +28 -0
  16. package/dist/converters/convertMessage.d.ts.map +1 -0
  17. package/dist/converters/convertMessage.js +249 -0
  18. package/dist/converters/convertMessage.js.map +1 -0
  19. package/dist/converters/modelContentEnvelope.d.ts +16 -0
  20. package/dist/converters/modelContentEnvelope.d.ts.map +1 -0
  21. package/dist/converters/modelContentEnvelope.js +22 -0
  22. package/dist/converters/modelContentEnvelope.js.map +1 -0
  23. package/dist/converters/toCreateMessage.d.ts +7 -0
  24. package/dist/converters/toCreateMessage.d.ts.map +1 -0
  25. package/dist/converters/toCreateMessage.js +58 -0
  26. package/dist/converters/toCreateMessage.js.map +1 -0
  27. package/dist/converters/toolOutputConversion.d.ts +29 -0
  28. package/dist/converters/toolOutputConversion.d.ts.map +1 -0
  29. package/dist/converters/toolOutputConversion.js +31 -0
  30. package/dist/converters/toolOutputConversion.js.map +1 -0
  31. package/dist/hooks.d.ts +19 -0
  32. package/dist/hooks.d.ts.map +1 -0
  33. package/dist/hooks.js +20 -0
  34. package/dist/hooks.js.map +1 -0
  35. package/dist/index.d.ts +14 -0
  36. package/dist/index.js +13 -0
  37. package/dist/index.native.d.ts +12 -0
  38. package/dist/index.native.js +11 -0
  39. package/dist/model-context/injectInteractableContext.d.ts +37 -0
  40. package/dist/model-context/injectInteractableContext.d.ts.map +1 -0
  41. package/dist/model-context/injectInteractableContext.js +52 -0
  42. package/dist/model-context/injectInteractableContext.js.map +1 -0
  43. package/dist/model-context/injectQuoteContext.d.ts +27 -0
  44. package/dist/model-context/injectQuoteContext.d.ts.map +1 -0
  45. package/dist/model-context/injectQuoteContext.js +51 -0
  46. package/dist/model-context/injectQuoteContext.js.map +1 -0
  47. package/dist/runtime/AISDKChat.d.ts +16 -0
  48. package/dist/runtime/AISDKChat.d.ts.map +1 -0
  49. package/dist/runtime/AISDKChat.js +69 -0
  50. package/dist/runtime/AISDKChat.js.map +1 -0
  51. package/dist/runtime/AISDKThreads.d.ts +45 -0
  52. package/dist/runtime/AISDKThreads.d.ts.map +1 -0
  53. package/dist/runtime/AISDKThreads.js +203 -0
  54. package/dist/runtime/AISDKThreads.js.map +1 -0
  55. package/dist/runtime/useAISDKRuntime.d.ts +49 -0
  56. package/dist/runtime/useAISDKRuntime.d.ts.map +1 -0
  57. package/dist/runtime/useAISDKRuntime.js +266 -0
  58. package/dist/runtime/useAISDKRuntime.js.map +1 -0
  59. package/dist/runtime/useChatRuntime.d.ts +13 -0
  60. package/dist/runtime/useChatRuntime.d.ts.map +1 -0
  61. package/dist/runtime/useChatRuntime.js +52 -0
  62. package/dist/runtime/useChatRuntime.js.map +1 -0
  63. package/dist/runtime/useChatThread.d.ts +77 -0
  64. package/dist/runtime/useChatThread.d.ts.map +1 -0
  65. package/dist/runtime/useChatThread.js +134 -0
  66. package/dist/runtime/useChatThread.js.map +1 -0
  67. package/dist/runtime/useExternalHistory.d.ts +11 -0
  68. package/dist/runtime/useExternalHistory.d.ts.map +1 -0
  69. package/dist/runtime/useExternalHistory.js +278 -0
  70. package/dist/runtime/useExternalHistory.js.map +1 -0
  71. package/dist/runtime/useResourceCleanup.d.ts +5 -0
  72. package/dist/runtime/useResourceCleanup.d.ts.map +1 -0
  73. package/dist/runtime/useResourceCleanup.js +47 -0
  74. package/dist/runtime/useResourceCleanup.js.map +1 -0
  75. package/dist/runtime/useStreamingTiming.d.ts +15 -0
  76. package/dist/runtime/useStreamingTiming.d.ts.map +1 -0
  77. package/dist/runtime/useStreamingTiming.js +38 -0
  78. package/dist/runtime/useStreamingTiming.js.map +1 -0
  79. package/dist/tools/frontendTools.d.ts +33 -0
  80. package/dist/tools/frontendTools.d.ts.map +1 -0
  81. package/dist/tools/frontendTools.js +33 -0
  82. package/dist/tools/frontendTools.js.map +1 -0
  83. package/dist/tools/generativeTools.d.ts +73 -0
  84. package/dist/tools/generativeTools.d.ts.map +1 -0
  85. package/dist/tools/generativeTools.js +245 -0
  86. package/dist/tools/generativeTools.js.map +1 -0
  87. package/dist/tools/mcp-stdio.node.d.ts +2 -0
  88. package/dist/tools/mcp-stdio.node.js +2 -0
  89. package/dist/tools/mcp-stdio.unsupported.d.ts +6 -0
  90. package/dist/tools/mcp-stdio.unsupported.d.ts.map +1 -0
  91. package/dist/tools/mcp-stdio.unsupported.js +11 -0
  92. package/dist/tools/mcp-stdio.unsupported.js.map +1 -0
  93. package/dist/transport/AssistantChatTransport.d.ts +23 -0
  94. package/dist/transport/AssistantChatTransport.d.ts.map +1 -0
  95. package/dist/transport/AssistantChatTransport.js +134 -0
  96. package/dist/transport/AssistantChatTransport.js.map +1 -0
  97. package/dist/transport/resumable.d.ts +38 -0
  98. package/dist/transport/resumable.d.ts.map +1 -0
  99. package/dist/transport/resumable.js +113 -0
  100. package/dist/transport/resumable.js.map +1 -0
  101. package/dist/usage.d.ts +19 -0
  102. package/dist/usage.d.ts.map +1 -0
  103. package/dist/usage.js +127 -0
  104. package/dist/usage.js.map +1 -0
  105. package/dist/utils/getVercelAIMessages.d.ts +7 -0
  106. package/dist/utils/getVercelAIMessages.d.ts.map +1 -0
  107. package/dist/utils/getVercelAIMessages.js +9 -0
  108. package/dist/utils/getVercelAIMessages.js.map +1 -0
  109. package/dist/utils/sliceMessagesUntil.d.ts +6 -0
  110. package/dist/utils/sliceMessagesUntil.d.ts.map +1 -0
  111. package/dist/utils/sliceMessagesUntil.js +12 -0
  112. package/dist/utils/sliceMessagesUntil.js.map +1 -0
  113. package/package.json +100 -0
  114. package/src/__tests__/standalone.e2e.ts +59 -0
  115. package/src/adapters/aiSDKFormatAdapter.ts +41 -0
  116. package/src/adapters/vercelAttachmentAdapter.test.ts +29 -0
  117. package/src/adapters/vercelAttachmentAdapter.ts +36 -0
  118. package/src/aiSDKExtras.ts +11 -0
  119. package/src/converters/convertMessage.test.ts +1130 -0
  120. package/src/converters/convertMessage.ts +457 -0
  121. package/src/converters/modelContentEnvelope.ts +41 -0
  122. package/src/converters/toCreateMessage.test.ts +596 -0
  123. package/src/converters/toCreateMessage.ts +99 -0
  124. package/src/converters/toolOutputConversion.ts +26 -0
  125. package/src/hooks.ts +23 -0
  126. package/src/index.native.ts +21 -0
  127. package/src/index.ts +29 -0
  128. package/src/model-context/injectInteractableContext.test.ts +167 -0
  129. package/src/model-context/injectInteractableContext.ts +61 -0
  130. package/src/model-context/injectQuoteContext.test.ts +33 -0
  131. package/src/model-context/injectQuoteContext.ts +62 -0
  132. package/src/runtime/AISDKChat.integration.test.tsx +47 -0
  133. package/src/runtime/AISDKChat.react-compiler.test.ts +49 -0
  134. package/src/runtime/AISDKChat.test.ts +193 -0
  135. package/src/runtime/AISDKChat.ts +47 -0
  136. package/src/runtime/AISDKThreads.cloud.test.ts +136 -0
  137. package/src/runtime/AISDKThreads.test.ts +548 -0
  138. package/src/runtime/AISDKThreads.ts +223 -0
  139. package/src/runtime/__tests__/controlled-transport.ts +43 -0
  140. package/src/runtime/useAISDKRuntime.approval.test.tsx +69 -0
  141. package/src/runtime/useAISDKRuntime.test.ts +1021 -0
  142. package/src/runtime/useAISDKRuntime.tool-output.test.tsx +113 -0
  143. package/src/runtime/useAISDKRuntime.ts +524 -0
  144. package/src/runtime/useChatOnTap.test.ts +58 -0
  145. package/src/runtime/useChatRuntime.integration.test.tsx +67 -0
  146. package/src/runtime/useChatRuntime.test.ts +522 -0
  147. package/src/runtime/useChatRuntime.ts +49 -0
  148. package/src/runtime/useChatThread.ts +286 -0
  149. package/src/runtime/useExternalHistory.test.ts +1289 -0
  150. package/src/runtime/useExternalHistory.ts +435 -0
  151. package/src/runtime/useResourceCleanup.ts +32 -0
  152. package/src/runtime/useStreamingTiming.ts +68 -0
  153. package/src/tools/frontendTools.test.ts +205 -0
  154. package/src/tools/frontendTools.ts +83 -0
  155. package/src/tools/generativeTools.test.ts +785 -0
  156. package/src/tools/generativeTools.ts +470 -0
  157. package/src/tools/mcp-stdio.node.ts +1 -0
  158. package/src/tools/mcp-stdio.unsupported.ts +12 -0
  159. package/src/transport/AssistantChatTransport.test.ts +300 -0
  160. package/src/transport/AssistantChatTransport.ts +204 -0
  161. package/src/transport/resumable.test.ts +262 -0
  162. package/src/transport/resumable.ts +161 -0
  163. package/src/usage.test.ts +186 -0
  164. package/src/usage.ts +174 -0
  165. package/src/utils/getVercelAIMessages.ts +11 -0
  166. package/src/utils/sliceMessagesUntil.test.ts +55 -0
  167. package/src/utils/sliceMessagesUntil.ts +20 -0
@@ -0,0 +1,7 @@
1
+ import { UIMessage } from "ai";
2
+ import { ThreadMessage } from "@assistant-ui/core";
3
+ //#region src/utils/getVercelAIMessages.d.ts
4
+ declare const getVercelAIMessages: <UI_MESSAGE extends UIMessage = UIMessage>(message: ThreadMessage) => UI_MESSAGE[];
5
+ //#endregion
6
+ export { getVercelAIMessages };
7
+ //# sourceMappingURL=getVercelAIMessages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getVercelAIMessages.d.ts","names":[],"sources":["../../src/utils/getVercelAIMessages.ts"],"mappings":";;;cAMa,sBAAuB,mBAAmB,YAAY,WACjE,SAAS,kBAEmC"}
@@ -0,0 +1,9 @@
1
+ import { getExternalStoreMessages } from "@assistant-ui/core";
2
+ //#region src/utils/getVercelAIMessages.ts
3
+ const getVercelAIMessages = (message) => {
4
+ return getExternalStoreMessages(message);
5
+ };
6
+ //#endregion
7
+ export { getVercelAIMessages };
8
+
9
+ //# sourceMappingURL=getVercelAIMessages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getVercelAIMessages.js","names":["getExternalStoreMessages","ThreadMessage","UIMessage","getVercelAIMessages","message","UI_MESSAGE"],"sources":["../../src/utils/getVercelAIMessages.ts"],"sourcesContent":["import {\n getExternalStoreMessages,\n type ThreadMessage,\n} from \"@assistant-ui/core\";\nimport type { UIMessage } from \"ai\";\n\nexport const getVercelAIMessages = <UI_MESSAGE extends UIMessage = UIMessage>(\n message: ThreadMessage,\n) => {\n return getExternalStoreMessages(message) as UI_MESSAGE[];\n};\n"],"mappings":";;AAMA,MAAaG,uBACXC,YACG;CACH,OAAOJ,yBAAyBI,OAAO;AACzC"}
@@ -0,0 +1,6 @@
1
+ import { UIMessage } from "ai";
2
+ //#region src/utils/sliceMessagesUntil.d.ts
3
+ declare const sliceMessagesUntil: <UI_MESSAGE extends UIMessage = UIMessage>(messages: UI_MESSAGE[], messageId: string | null) => UI_MESSAGE[];
4
+ //#endregion
5
+ export { sliceMessagesUntil };
6
+ //# sourceMappingURL=sliceMessagesUntil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliceMessagesUntil.d.ts","names":[],"sources":["../../src/utils/sliceMessagesUntil.ts"],"mappings":";;cAEa,qBAAsB,mBAAmB,YAAY,WAChE,UAAU,cACV,6BAAwB"}
@@ -0,0 +1,12 @@
1
+ //#region src/utils/sliceMessagesUntil.ts
2
+ const sliceMessagesUntil = (messages, messageId) => {
3
+ if (messageId == null) return [];
4
+ let messageIdx = messages.findIndex((m) => m.id === messageId);
5
+ if (messageIdx === -1) throw new Error(`sliceMessagesUntil: Message "${messageId}" not found in AI SDK messages. This is likely an internal bug in assistant-ui.`);
6
+ while (messages[messageIdx + 1]?.role === "assistant") messageIdx++;
7
+ return messages.slice(0, messageIdx + 1);
8
+ };
9
+ //#endregion
10
+ export { sliceMessagesUntil };
11
+
12
+ //# sourceMappingURL=sliceMessagesUntil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliceMessagesUntil.js","names":["UIMessage","sliceMessagesUntil","messages","UI_MESSAGE","messageId","messageIdx","findIndex","m","id","Error","role","slice"],"sources":["../../src/utils/sliceMessagesUntil.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\n\nexport const sliceMessagesUntil = <UI_MESSAGE extends UIMessage = UIMessage>(\n messages: UI_MESSAGE[],\n messageId: string | null,\n) => {\n if (messageId == null) return [];\n\n let messageIdx = messages.findIndex((m) => m.id === messageId);\n if (messageIdx === -1)\n throw new Error(\n `sliceMessagesUntil: Message \"${messageId}\" not found in AI SDK messages. This is likely an internal bug in assistant-ui.`,\n );\n\n while (messages[messageIdx + 1]?.role === \"assistant\") {\n messageIdx++;\n }\n\n return messages.slice(0, messageIdx + 1);\n};\n"],"mappings":";AAEA,MAAaC,sBACXC,UACAE,cACG;CACH,IAAIA,aAAa,MAAM,OAAO,CAAA;CAE9B,IAAIC,aAAaH,SAASI,WAAWC,MAAMA,EAAEC,OAAOJ,SAAS;CAC7D,IAAIC,eAAe,IACjB,MAAM,IAAII,MACR,gCAAgCL,UAAS,gFAC3C;CAEF,OAAOF,SAASG,aAAa,EAAE,EAAEK,SAAS,aACxCL;CAGF,OAAOH,SAASS,MAAM,GAAGN,aAAa,CAAC;AACzC"}
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "@assistant-ui/ai-sdk",
3
+ "version": "0.0.1",
4
+ "description": "Vercel AI SDK adapter for assistant-ui",
5
+ "keywords": [
6
+ "ai-sdk",
7
+ "vercel",
8
+ "assistant-ui",
9
+ "react",
10
+ "ai",
11
+ "chat",
12
+ "openai",
13
+ "streaming"
14
+ ],
15
+ "author": "AgentbaseAI Inc.",
16
+ "license": "MIT",
17
+ "type": "module",
18
+ "imports": {
19
+ "#mcp-stdio": {
20
+ "types": "./src/tools/mcp-stdio.node.ts",
21
+ "react-native": "./dist/tools/mcp-stdio.unsupported.js",
22
+ "edge-light": "./dist/tools/mcp-stdio.unsupported.js",
23
+ "workerd": "./dist/tools/mcp-stdio.unsupported.js",
24
+ "browser": "./dist/tools/mcp-stdio.unsupported.js",
25
+ "node": "./dist/tools/mcp-stdio.node.js",
26
+ "default": "./dist/tools/mcp-stdio.unsupported.js"
27
+ }
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "react-native": {
32
+ "types": "./dist/index.native.d.ts",
33
+ "default": "./dist/index.native.js"
34
+ },
35
+ "types": "./dist/index.d.ts",
36
+ "default": "./dist/index.js"
37
+ }
38
+ },
39
+ "main": "./dist/index.js",
40
+ "react-native": "./dist/index.native.js",
41
+ "types": "./dist/index.d.ts",
42
+ "files": [
43
+ "dist",
44
+ "src",
45
+ "README.md"
46
+ ],
47
+ "sideEffects": false,
48
+ "dependencies": {
49
+ "@ai-sdk/mcp": "^2.0.31",
50
+ "@ai-sdk/react": "^4.0.65",
51
+ "@assistant-ui/core": "^0.3.14",
52
+ "@assistant-ui/store": "^0.3.10",
53
+ "@assistant-ui/tap": "^0.9.13",
54
+ "ai": "^7.0.62",
55
+ "assistant-cloud": "*",
56
+ "assistant-stream": "^0.3.38"
57
+ },
58
+ "peerDependencies": {
59
+ "@types/react": "*",
60
+ "react": "^18 || ^19"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "@types/react": {
64
+ "optional": true
65
+ },
66
+ "react": {
67
+ "optional": true
68
+ }
69
+ },
70
+ "devDependencies": {
71
+ "@testing-library/react": "^16.3.2",
72
+ "@types/json-schema": "^7.0.15",
73
+ "@types/react": "^19.2.18",
74
+ "@types/react-dom": "^19.2.4",
75
+ "jsdom": "^30.0.1",
76
+ "react": "^19.2.8",
77
+ "vitest": "^4.1.10",
78
+ "@assistant-ui/x-buildutils": "0.0.23"
79
+ },
80
+ "publishConfig": {
81
+ "access": "public",
82
+ "provenance": true
83
+ },
84
+ "homepage": "https://www.assistant-ui.com/",
85
+ "repository": {
86
+ "type": "git",
87
+ "url": "git+https://github.com/assistant-ui/assistant-ui.git",
88
+ "directory": "packages/ai-sdk"
89
+ },
90
+ "bugs": {
91
+ "url": "https://github.com/assistant-ui/assistant-ui/issues"
92
+ },
93
+ "scripts": {
94
+ "build": "aui-build",
95
+ "test": "vitest run",
96
+ "test:react-compiler": "vitest run --config vitest.react-compiler.config.ts",
97
+ "test:standalone": "vitest run --project standalone",
98
+ "test:watch": "vitest"
99
+ }
100
+ }
@@ -0,0 +1,59 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { flushTapSync } from "@assistant-ui/tap";
3
+ import { AuiConfig, createAssistantClient } from "@assistant-ui/store/client";
4
+ import * as aiSdk from "../index";
5
+ import { createControlledTransport } from "../runtime/__tests__/controlled-transport";
6
+
7
+ describe("react-less standalone graph", () => {
8
+ it("resolves react to the standalone shim", async () => {
9
+ const react = await import("react");
10
+ expect(() => react.useState(0)).toThrow(/standalone-shim/);
11
+ });
12
+
13
+ it("loads the whole barrel under the standalone shim", () => {
14
+ expect(typeof aiSdk.AISDKChat).toBe("function");
15
+ expect(typeof aiSdk.useChatRuntime).toBe("function");
16
+ expect(typeof aiSdk.useAISDKRuntime).toBe("function");
17
+ expect(typeof aiSdk.frontendTools).toBe("function");
18
+ expect(typeof aiSdk.AssistantChatTransport).toBe("function");
19
+ });
20
+
21
+ it("streams a chat round trip with the shim as the only react", async () => {
22
+ const { transport, emit, close } = createControlledTransport();
23
+ const handle = createAssistantClient(
24
+ AuiConfig({ threads: aiSdk.AISDKChat({ transport }) }),
25
+ );
26
+ try {
27
+ handle.subscribe(() => {});
28
+ const aui = handle.getClient();
29
+
30
+ flushTapSync(() => aui.composer.setText("hi"));
31
+ flushTapSync(() => aui.composer.send());
32
+
33
+ await vi.waitFor(() => {
34
+ expect(aui.thread.getState().isRunning).toBe(true);
35
+ });
36
+
37
+ emit(
38
+ { type: "start" },
39
+ { type: "text-start", id: "t1" },
40
+ { type: "text-delta", id: "t1", delta: "hello " },
41
+ { type: "text-delta", id: "t1", delta: "world" },
42
+ { type: "text-end", id: "t1" },
43
+ { type: "finish" },
44
+ );
45
+ close();
46
+
47
+ await vi.waitFor(() => {
48
+ const state = aui.thread.getState();
49
+ expect(state.isRunning).toBe(false);
50
+ expect(state.messages).toHaveLength(2);
51
+ expect(state.messages.at(-1)?.content).toContainEqual(
52
+ expect.objectContaining({ type: "text", text: "hello world" }),
53
+ );
54
+ });
55
+ } finally {
56
+ handle.destroy();
57
+ }
58
+ });
59
+ });
@@ -0,0 +1,41 @@
1
+ import type { UIMessage } from "ai";
2
+ import type {
3
+ MessageFormatAdapter,
4
+ MessageFormatItem,
5
+ MessageStorageEntry,
6
+ } from "@assistant-ui/core";
7
+
8
+ // Storage format for AI SDK messages - just the UIMessage
9
+ export type AISDKStorageFormat = Omit<UIMessage, "id">;
10
+
11
+ export const aiSDKV6FormatAdapter: MessageFormatAdapter<
12
+ UIMessage,
13
+ AISDKStorageFormat
14
+ > = {
15
+ format: "ai-sdk/v6",
16
+
17
+ encode({
18
+ message: { id, parts, ...message },
19
+ }: MessageFormatItem<UIMessage>): AISDKStorageFormat {
20
+ return {
21
+ ...message,
22
+ parts,
23
+ };
24
+ },
25
+
26
+ decode(
27
+ stored: MessageStorageEntry<AISDKStorageFormat>,
28
+ ): MessageFormatItem<UIMessage> {
29
+ return {
30
+ parentId: stored.parent_id,
31
+ message: {
32
+ id: stored.id,
33
+ ...stored.content,
34
+ },
35
+ };
36
+ },
37
+
38
+ getId(message: UIMessage): string {
39
+ return message.id;
40
+ },
41
+ };
@@ -0,0 +1,29 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { vercelAttachmentAdapter } from "./vercelAttachmentAdapter";
3
+
4
+ const originalFileReader = globalThis.FileReader;
5
+
6
+ afterEach(() => {
7
+ globalThis.FileReader = originalFileReader;
8
+ });
9
+
10
+ describe("vercelAttachmentAdapter", () => {
11
+ it("sends a file as a data URL via the shared core encoder", async () => {
12
+ globalThis.FileReader = undefined as unknown as typeof FileReader;
13
+
14
+ const file = new File(["hello"], "a.txt", { type: "text/plain" });
15
+ const result = await vercelAttachmentAdapter.send({
16
+ id: "1",
17
+ type: "file",
18
+ name: file.name,
19
+ file,
20
+ contentType: file.type,
21
+ content: [],
22
+ status: { type: "requires-action", reason: "composer-send" },
23
+ });
24
+
25
+ const part = result.content[0];
26
+ if (part?.type !== "file") throw new Error("expected file content part");
27
+ expect(part.data).toBe("data:text/plain;base64,aGVsbG8=");
28
+ });
29
+ });
@@ -0,0 +1,36 @@
1
+ import type { AttachmentAdapter } from "@assistant-ui/core";
2
+ import { getFileDataURL } from "@assistant-ui/core/internal";
3
+ import { generateId } from "ai";
4
+
5
+ export const vercelAttachmentAdapter: AttachmentAdapter = {
6
+ accept: "*",
7
+ async add({ file }) {
8
+ return {
9
+ id: generateId(),
10
+ type: file.type.startsWith("image/") ? "image" : "file",
11
+ name: file.name,
12
+ file,
13
+ contentType: file.type,
14
+ content: [],
15
+ status: { type: "requires-action", reason: "composer-send" },
16
+ };
17
+ },
18
+ async send(attachment) {
19
+ // noop
20
+ return {
21
+ ...attachment,
22
+ status: { type: "complete" },
23
+ content: [
24
+ {
25
+ type: "file",
26
+ mimeType: attachment.contentType ?? "",
27
+ filename: attachment.name,
28
+ data: await getFileDataURL(attachment.file),
29
+ },
30
+ ],
31
+ };
32
+ },
33
+ async remove() {
34
+ // noop
35
+ },
36
+ };
@@ -0,0 +1,11 @@
1
+ import { createRuntimeExtras } from "@assistant-ui/core/react";
2
+ import type { UseChatHelpers } from "@ai-sdk/react";
3
+ import type { UIMessage } from "ai";
4
+
5
+ export type AISDKRuntimeExtras = {
6
+ chat: UseChatHelpers<UIMessage>;
7
+ error: Error | undefined;
8
+ };
9
+
10
+ export const aiSDKExtras =
11
+ createRuntimeExtras<AISDKRuntimeExtras>("useAISDKRuntime");