@assistant-ui/react-ai-sdk 0.10.15 → 0.11.0-alpha.0-alpha

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 (95) hide show
  1. package/dist/frontendTools.d.ts +1 -1
  2. package/dist/frontendTools.js +1 -1
  3. package/dist/frontendTools.js.map +1 -1
  4. package/dist/index.d.ts +0 -4
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -16
  7. package/dist/index.js.map +1 -1
  8. package/dist/ui/getVercelAIMessages.d.ts +2 -2
  9. package/dist/ui/getVercelAIMessages.d.ts.map +1 -1
  10. package/dist/ui/getVercelAIMessages.js.map +1 -1
  11. package/dist/ui/index.d.ts +1 -4
  12. package/dist/ui/index.d.ts.map +1 -1
  13. package/dist/ui/index.js +2 -8
  14. package/dist/ui/index.js.map +1 -1
  15. package/dist/ui/use-chat/useAISDKRuntime.d.ts +7 -0
  16. package/dist/ui/use-chat/useAISDKRuntime.d.ts.map +1 -0
  17. package/dist/ui/use-chat/useAISDKRuntime.js +53 -0
  18. package/dist/ui/use-chat/useAISDKRuntime.js.map +1 -0
  19. package/dist/ui/utils/convertMessage.d.ts +5 -5
  20. package/dist/ui/utils/convertMessage.d.ts.map +1 -1
  21. package/dist/ui/utils/convertMessage.js +115 -86
  22. package/dist/ui/utils/convertMessage.js.map +1 -1
  23. package/dist/ui/utils/sliceMessagesUntil.d.ts +2 -2
  24. package/dist/ui/utils/sliceMessagesUntil.d.ts.map +1 -1
  25. package/dist/ui/utils/sliceMessagesUntil.js.map +1 -1
  26. package/dist/ui/utils/toCreateMessage.d.ts +2 -2
  27. package/dist/ui/utils/toCreateMessage.d.ts.map +1 -1
  28. package/dist/ui/utils/toCreateMessage.js +29 -17
  29. package/dist/ui/utils/toCreateMessage.js.map +1 -1
  30. package/dist/ui/utils/vercelAttachmentAdapter.js +1 -1
  31. package/dist/ui/utils/vercelAttachmentAdapter.js.map +1 -1
  32. package/package.json +16 -12
  33. package/src/frontendTools.ts +1 -1
  34. package/src/index.ts +0 -11
  35. package/src/ui/getVercelAIMessages.tsx +2 -2
  36. package/src/ui/index.ts +1 -4
  37. package/src/ui/use-chat/{useVercelUseChatRuntime.tsx → useAISDKRuntime.tsx} +13 -39
  38. package/src/ui/utils/convertMessage.ts +162 -117
  39. package/src/ui/utils/sliceMessagesUntil.tsx +2 -2
  40. package/src/ui/utils/toCreateMessage.ts +45 -20
  41. package/src/ui/utils/vercelAttachmentAdapter.ts +1 -1
  42. package/dist/rsc/RSCDisplay.d.ts +0 -3
  43. package/dist/rsc/RSCDisplay.d.ts.map +0 -1
  44. package/dist/rsc/RSCDisplay.js +0 -26
  45. package/dist/rsc/RSCDisplay.js.map +0 -1
  46. package/dist/rsc/VercelRSCAdapter.d.ts +0 -17
  47. package/dist/rsc/VercelRSCAdapter.d.ts.map +0 -1
  48. package/dist/rsc/VercelRSCAdapter.js +0 -1
  49. package/dist/rsc/VercelRSCAdapter.js.map +0 -1
  50. package/dist/rsc/VercelRSCMessage.d.ts +0 -8
  51. package/dist/rsc/VercelRSCMessage.d.ts.map +0 -1
  52. package/dist/rsc/VercelRSCMessage.js +0 -2
  53. package/dist/rsc/VercelRSCMessage.js.map +0 -1
  54. package/dist/rsc/index.d.ts +0 -5
  55. package/dist/rsc/index.d.ts.map +0 -1
  56. package/dist/rsc/index.js +0 -8
  57. package/dist/rsc/index.js.map +0 -1
  58. package/dist/rsc/useVercelRSCRuntime.d.ts +0 -3
  59. package/dist/rsc/useVercelRSCRuntime.d.ts.map +0 -1
  60. package/dist/rsc/useVercelRSCRuntime.js +0 -57
  61. package/dist/rsc/useVercelRSCRuntime.js.map +0 -1
  62. package/dist/rsc/utils/RSCThreadExtras.d.ts +0 -8
  63. package/dist/rsc/utils/RSCThreadExtras.d.ts.map +0 -1
  64. package/dist/rsc/utils/RSCThreadExtras.js +0 -8
  65. package/dist/rsc/utils/RSCThreadExtras.js.map +0 -1
  66. package/dist/ui/use-assistant/useVercelUseAssistantRuntime.d.ts +0 -7
  67. package/dist/ui/use-assistant/useVercelUseAssistantRuntime.d.ts.map +0 -1
  68. package/dist/ui/use-assistant/useVercelUseAssistantRuntime.js +0 -48
  69. package/dist/ui/use-assistant/useVercelUseAssistantRuntime.js.map +0 -1
  70. package/dist/ui/use-chat/useVercelUseChatRuntime.d.ts +0 -8
  71. package/dist/ui/use-chat/useVercelUseChatRuntime.d.ts.map +0 -1
  72. package/dist/ui/use-chat/useVercelUseChatRuntime.js +0 -75
  73. package/dist/ui/use-chat/useVercelUseChatRuntime.js.map +0 -1
  74. package/dist/ui/utils/useInputSync.d.ts +0 -6
  75. package/dist/ui/utils/useInputSync.d.ts.map +0 -1
  76. package/dist/ui/utils/useInputSync.js +0 -18
  77. package/dist/ui/utils/useInputSync.js.map +0 -1
  78. package/dist/useChatRuntime.d.ts +0 -4
  79. package/dist/useChatRuntime.d.ts.map +0 -1
  80. package/dist/useChatRuntime.js +0 -12
  81. package/dist/useChatRuntime.js.map +0 -1
  82. package/dist/useCloudRuntime.d.ts +0 -12
  83. package/dist/useCloudRuntime.d.ts.map +0 -1
  84. package/dist/useCloudRuntime.js +0 -15
  85. package/dist/useCloudRuntime.js.map +0 -1
  86. package/src/rsc/RSCDisplay.tsx +0 -23
  87. package/src/rsc/VercelRSCAdapter.tsx +0 -21
  88. package/src/rsc/VercelRSCMessage.tsx +0 -9
  89. package/src/rsc/index.ts +0 -4
  90. package/src/rsc/useVercelRSCRuntime.tsx +0 -70
  91. package/src/rsc/utils/RSCThreadExtras.tsx +0 -11
  92. package/src/ui/use-assistant/useVercelUseAssistantRuntime.tsx +0 -60
  93. package/src/ui/utils/useInputSync.tsx +0 -26
  94. package/src/useChatRuntime.ts +0 -13
  95. package/src/useCloudRuntime.ts +0 -21
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/utils/toCreateMessage.ts"],"sourcesContent":["import { AppendMessage } from \"@assistant-ui/react\";\nimport { CreateMessage } from \"@ai-sdk/ui-utils\";\n\nexport const toCreateMessage = async (\n message: AppendMessage,\n): Promise<CreateMessage> => {\n const content = message.content\n .filter((part) => part.type === \"text\")\n .map((t) => t.text)\n .join(\"\\n\\n\");\n\n const images = message.content\n .filter((part) => part.type === \"image\")\n .map((part) => ({ url: part.image }));\n\n return {\n role: message.role,\n content,\n experimental_attachments: [\n ...images,\n ...(await Promise.all(\n (message.attachments ?? []).map(async (m) => {\n if (m.file == null)\n throw new Error(\"Attachment did not contain a file\");\n return {\n contentType: m.file.type,\n name: m.file.name,\n url: await getFileDataURL(m.file),\n };\n }),\n )),\n ],\n };\n};\n\nconst getFileDataURL = (file: File) =>\n new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = (error) => reject(error);\n\n reader.readAsDataURL(file);\n });\n"],"mappings":";AAGO,IAAM,kBAAkB,OAC7B,YAC2B;AAC3B,QAAM,UAAU,QAAQ,QACrB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,MAAM;AAEd,QAAM,SAAS,QAAQ,QACpB,OAAO,CAAC,SAAS,KAAK,SAAS,OAAO,EACtC,IAAI,CAAC,UAAU,EAAE,KAAK,KAAK,MAAM,EAAE;AAEtC,SAAO;AAAA,IACL,MAAM,QAAQ;AAAA,IACd;AAAA,IACA,0BAA0B;AAAA,MACxB,GAAG;AAAA,MACH,GAAI,MAAM,QAAQ;AAAA,SACf,QAAQ,eAAe,CAAC,GAAG,IAAI,OAAO,MAAM;AAC3C,cAAI,EAAE,QAAQ;AACZ,kBAAM,IAAI,MAAM,mCAAmC;AACrD,iBAAO;AAAA,YACL,aAAa,EAAE,KAAK;AAAA,YACpB,MAAM,EAAE,KAAK;AAAA,YACb,KAAK,MAAM,eAAe,EAAE,IAAI;AAAA,UAClC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,iBAAiB,CAAC,SACtB,IAAI,QAAgB,CAAC,SAAS,WAAW;AACvC,QAAM,SAAS,IAAI,WAAW;AAE9B,SAAO,SAAS,MAAM,QAAQ,OAAO,MAAgB;AACrD,SAAO,UAAU,CAAC,UAAU,OAAO,KAAK;AAExC,SAAO,cAAc,IAAI;AAC3B,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/utils/toCreateMessage.ts"],"sourcesContent":["import { AppendMessage } from \"@assistant-ui/react\";\nimport {\n CreateUIMessage,\n FileUIPart,\n UIDataTypes,\n UIMessage,\n UIMessagePart,\n UITools,\n} from \"ai\";\n\nexport const toCreateMessage = async (\n message: AppendMessage,\n): Promise<CreateUIMessage<UIMessage>> => {\n const textParts = message.content\n .filter((part) => part.type === \"text\")\n .map((t) => t.text)\n .join(\"\\n\\n\");\n\n const parts: UIMessagePart<UIDataTypes, UITools>[] = [\n {\n type: \"text\",\n text: textParts,\n },\n ];\n\n // Add image parts\n const imageParts = message.content\n .filter((part) => part.type === \"image\")\n .map(\n (part) =>\n ({\n type: \"file\",\n mediaType: \"image/png\", // Default to PNG, could be made more dynamic\n url: part.image,\n }) satisfies FileUIPart,\n );\n\n parts.push(...imageParts);\n\n // Add attachment parts\n const attachmentParts = await Promise.all(\n (message.attachments ?? []).map(async (m) => {\n if (m.file == null) throw new Error(\"Attachment did not contain a file\");\n return {\n type: \"file\",\n mediaType: m.file.type,\n filename: m.file.name,\n url: await getFileDataURL(m.file),\n } satisfies FileUIPart;\n }),\n );\n\n parts.push(...attachmentParts);\n\n return {\n role: message.role,\n parts,\n };\n};\n\nconst getFileDataURL = (file: File) =>\n new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = (error) => reject(error);\n\n reader.readAsDataURL(file);\n });\n"],"mappings":";AAUO,IAAM,kBAAkB,OAC7B,YACwC;AACxC,QAAM,YAAY,QAAQ,QACvB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,MAAM;AAEd,QAAM,QAA+C;AAAA,IACnD;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,EACF;AAGA,QAAM,aAAa,QAAQ,QACxB,OAAO,CAAC,SAAS,KAAK,SAAS,OAAO,EACtC;AAAA,IACC,CAAC,UACE;AAAA,MACC,MAAM;AAAA,MACN,WAAW;AAAA;AAAA,MACX,KAAK,KAAK;AAAA,IACZ;AAAA,EACJ;AAEF,QAAM,KAAK,GAAG,UAAU;AAGxB,QAAM,kBAAkB,MAAM,QAAQ;AAAA,KACnC,QAAQ,eAAe,CAAC,GAAG,IAAI,OAAO,MAAM;AAC3C,UAAI,EAAE,QAAQ,KAAM,OAAM,IAAI,MAAM,mCAAmC;AACvE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,WAAW,EAAE,KAAK;AAAA,QAClB,UAAU,EAAE,KAAK;AAAA,QACjB,KAAK,MAAM,eAAe,EAAE,IAAI;AAAA,MAClC;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,KAAK,GAAG,eAAe;AAE7B,SAAO;AAAA,IACL,MAAM,QAAQ;AAAA,IACd;AAAA,EACF;AACF;AAEA,IAAM,iBAAiB,CAAC,SACtB,IAAI,QAAgB,CAAC,SAAS,WAAW;AACvC,QAAM,SAAS,IAAI,WAAW;AAE9B,SAAO,SAAS,MAAM,QAAQ,OAAO,MAAgB;AACrD,SAAO,UAAU,CAAC,UAAU,OAAO,KAAK;AAExC,SAAO,cAAc,IAAI;AAC3B,CAAC;","names":[]}
@@ -1,5 +1,5 @@
1
1
  // src/ui/utils/vercelAttachmentAdapter.ts
2
- import { generateId } from "@ai-sdk/ui-utils";
2
+ import { generateId } from "ai";
3
3
  var vercelAttachmentAdapter = {
4
4
  accept: "image/*, text/plain, text/html, text/markdown, text/csv, text/xml, text/json, text/css",
5
5
  async add({ file }) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/utils/vercelAttachmentAdapter.ts"],"sourcesContent":["import { AttachmentAdapter } from \"@assistant-ui/react\";\nimport { generateId } from \"@ai-sdk/ui-utils\";\n\nexport const vercelAttachmentAdapter: AttachmentAdapter = {\n accept:\n \"image/*, text/plain, text/html, text/markdown, text/csv, text/xml, text/json, text/css\",\n async add({ file }) {\n return {\n id: generateId(),\n type: \"file\",\n name: file.name,\n file,\n contentType: file.type,\n content: [],\n status: { type: \"requires-action\", reason: \"composer-send\" },\n };\n },\n async send(attachment) {\n // noop\n return {\n ...attachment,\n status: { type: \"complete\" },\n content: [],\n };\n },\n async remove() {\n // noop\n },\n};\n"],"mappings":";AACA,SAAS,kBAAkB;AAEpB,IAAM,0BAA6C;AAAA,EACxD,QACE;AAAA,EACF,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,WAAO;AAAA,MACL,IAAI,WAAW;AAAA,MACf,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,MACX;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,SAAS,CAAC;AAAA,MACV,QAAQ,EAAE,MAAM,mBAAmB,QAAQ,gBAAgB;AAAA,IAC7D;AAAA,EACF;AAAA,EACA,MAAM,KAAK,YAAY;AAErB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,EAAE,MAAM,WAAW;AAAA,MAC3B,SAAS,CAAC;AAAA,IACZ;AAAA,EACF;AAAA,EACA,MAAM,SAAS;AAAA,EAEf;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/utils/vercelAttachmentAdapter.ts"],"sourcesContent":["import { AttachmentAdapter } from \"@assistant-ui/react\";\nimport { generateId } from \"ai\";\n\nexport const vercelAttachmentAdapter: AttachmentAdapter = {\n accept:\n \"image/*, text/plain, text/html, text/markdown, text/csv, text/xml, text/json, text/css\",\n async add({ file }) {\n return {\n id: generateId(),\n type: \"file\",\n name: file.name,\n file,\n contentType: file.type,\n content: [],\n status: { type: \"requires-action\", reason: \"composer-send\" },\n };\n },\n async send(attachment) {\n // noop\n return {\n ...attachment,\n status: { type: \"complete\" },\n content: [],\n };\n },\n async remove() {\n // noop\n },\n};\n"],"mappings":";AACA,SAAS,kBAAkB;AAEpB,IAAM,0BAA6C;AAAA,EACxD,QACE;AAAA,EACF,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,WAAO;AAAA,MACL,IAAI,WAAW;AAAA,MACf,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,MACX;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,SAAS,CAAC;AAAA,MACV,QAAQ,EAAE,MAAM,mBAAmB,QAAQ,gBAAgB;AAAA,IAC7D;AAAA,EACF;AAAA,EACA,MAAM,KAAK,YAAY;AAErB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,EAAE,MAAM,WAAW;AAAA,MAC3B,SAAS,CAAC;AAAA,IACZ;AAAA,EACF;AAAA,EACA,MAAM,SAAS;AAAA,EAEf;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-ai-sdk",
3
- "version": "0.10.15",
3
+ "version": "0.11.0-alpha.0-alpha",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -18,16 +18,19 @@
18
18
  ],
19
19
  "sideEffects": false,
20
20
  "dependencies": {
21
- "@ai-sdk/react": "*",
22
- "@ai-sdk/ui-utils": "*",
21
+ "@ai-sdk/provider": "^2.0.0",
22
+ "@ai-sdk/react": "^2.0.0",
23
+ "ai": "^5.0.0",
23
24
  "@radix-ui/react-use-callback-ref": "^1.1.1",
24
25
  "@types/json-schema": "^7.0.15",
25
- "zod": "^3.25.67",
26
- "zustand": "^5.0.6",
27
- "@assistant-ui/react-edge": "0.2.13"
26
+ "assistant-stream": "^0.2.21",
27
+ "json-schema": "^0.4.0",
28
+ "zod": "^4.0.14",
29
+ "zod-to-json-schema": "^3.24.6",
30
+ "zustand": "^5.0.7"
28
31
  },
29
32
  "peerDependencies": {
30
- "@assistant-ui/react": "^0.10.25",
33
+ "@assistant-ui/react": "^0.10.33",
31
34
  "@types/react": "*",
32
35
  "react": "^18 || ^19 || ^19.0.0-rc"
33
36
  },
@@ -37,12 +40,13 @@
37
40
  }
38
41
  },
39
42
  "devDependencies": {
40
- "@types/node": "^24.0.4",
41
- "@types/react": "^19.1.8",
43
+ "@types/node": "^24.1.0",
44
+ "@types/react": "^19.1.9",
42
45
  "eslint": "^9",
43
- "eslint-config-next": "15.3.4",
44
- "react": "^19.1.0",
46
+ "eslint-config-next": "15.4.5",
47
+ "react": "19.1.0",
45
48
  "tsx": "^4.20.3",
49
+ "@assistant-ui/react": "0.10.33",
46
50
  "@assistant-ui/x-buildutils": "0.0.1"
47
51
  },
48
52
  "publishConfig": {
@@ -51,7 +55,7 @@
51
55
  },
52
56
  "repository": {
53
57
  "type": "git",
54
- "url": "https://github.com/assistant-ui/assistant-ui/tree/main/packages/react-ai-sdk"
58
+ "url": "https://github.com/assistant-ui/assistant-ui/tree/main/packages/react-ai-sdk-v5"
55
59
  },
56
60
  "bugs": {
57
61
  "url": "https://github.com/assistant-ui/assistant-ui/issues"
@@ -1,4 +1,4 @@
1
- import { jsonSchema } from "@ai-sdk/ui-utils";
1
+ import { jsonSchema } from "ai";
2
2
  import type { JSONSchema7 } from "json-schema";
3
3
 
4
4
  export const frontendTools = (
package/src/index.ts CHANGED
@@ -1,13 +1,2 @@
1
- export * from "./rsc";
2
1
  export * from "./ui";
3
- export * from "./useChatRuntime";
4
- export * from "./useCloudRuntime";
5
-
6
- export {
7
- toLanguageModelMessages,
8
- toLanguageModelTools,
9
- fromLanguageModelMessages,
10
- fromLanguageModelTools,
11
- useDangerousInBrowserRuntime,
12
- } from "@assistant-ui/react-edge";
13
2
  export { frontendTools } from "./frontendTools";
@@ -2,8 +2,8 @@ import {
2
2
  getExternalStoreMessages,
3
3
  type ThreadMessage,
4
4
  } from "@assistant-ui/react";
5
- import type { Message } from "@ai-sdk/ui-utils";
5
+ import type { UIMessage } from "ai";
6
6
 
7
7
  export const getVercelAIMessages = (message: ThreadMessage) => {
8
- return getExternalStoreMessages(message) as Message[];
8
+ return getExternalStoreMessages(message) as UIMessage[];
9
9
  };
package/src/ui/index.ts CHANGED
@@ -1,4 +1 @@
1
- export { useVercelUseChatRuntime } from "./use-chat/useVercelUseChatRuntime";
2
- export { useVercelUseAssistantRuntime } from "./use-assistant/useVercelUseAssistantRuntime";
3
- export { getVercelAIMessages } from "./getVercelAIMessages";
4
- export { AISDKMessageConverter } from "./utils/convertMessage";
1
+ export { useAISDKRuntime } from "./use-chat/useAISDKRuntime";
@@ -2,44 +2,38 @@
2
2
 
3
3
  import type { useChat } from "@ai-sdk/react";
4
4
  import { useExternalStoreRuntime } from "@assistant-ui/react";
5
- import { useInputSync } from "../utils/useInputSync";
6
5
  import { sliceMessagesUntil } from "../utils/sliceMessagesUntil";
7
6
  import { toCreateMessage } from "../utils/toCreateMessage";
8
7
  import { vercelAttachmentAdapter } from "../utils/vercelAttachmentAdapter";
9
8
  import { getVercelAIMessages } from "../getVercelAIMessages";
10
9
  import { ExternalStoreAdapter } from "@assistant-ui/react";
11
- import { useState } from "react";
12
- import { generateId } from "@ai-sdk/ui-utils";
13
10
  import { AISDKMessageConverter } from "../utils/convertMessage";
14
11
 
15
- export type VercelUseChatAdapter = {
12
+ export type AISDKRuntimeAdapter = {
16
13
  adapters?:
17
14
  | Omit<NonNullable<ExternalStoreAdapter["adapters"]>, "attachments">
18
15
  | undefined;
19
- unstable_joinStrategy?: "concat-content" | "none";
20
16
  };
21
17
 
22
- export const useVercelUseChatRuntime = (
18
+ export const useAISDKRuntime = (
23
19
  chatHelpers: ReturnType<typeof useChat>,
24
- adapter: VercelUseChatAdapter = {},
20
+ adapter: AISDKRuntimeAdapter = {},
25
21
  ) => {
26
22
  const messages = AISDKMessageConverter.useThreadMessages({
27
23
  isRunning:
28
24
  chatHelpers.status === "submitted" || chatHelpers.status == "streaming",
29
25
  messages: chatHelpers.messages,
30
- joinStrategy: adapter.unstable_joinStrategy,
31
26
  });
32
27
 
33
- const [threadId, setThreadId] = useState<string>(generateId());
34
-
35
28
  const runtime = useExternalStoreRuntime({
36
- isRunning: chatHelpers.isLoading,
29
+ isRunning:
30
+ chatHelpers.status === "submitted" || chatHelpers.status === "streaming",
37
31
  messages,
38
32
  setMessages: (messages) =>
39
33
  chatHelpers.setMessages(messages.map(getVercelAIMessages).flat()),
40
34
  onCancel: async () => chatHelpers.stop(),
41
35
  onNew: async (message) => {
42
- await chatHelpers.append(await toCreateMessage(message));
36
+ await chatHelpers.sendMessage(await toCreateMessage(message));
43
37
  },
44
38
  onEdit: async (message) => {
45
39
  const newMessages = sliceMessagesUntil(
@@ -48,46 +42,26 @@ export const useVercelUseChatRuntime = (
48
42
  );
49
43
  chatHelpers.setMessages(newMessages);
50
44
 
51
- await chatHelpers.append(await toCreateMessage(message));
45
+ await chatHelpers.sendMessage(await toCreateMessage(message));
52
46
  },
53
47
  onReload: async (parentId: string | null) => {
54
48
  const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);
55
49
  chatHelpers.setMessages(newMessages);
56
50
 
57
- await chatHelpers.reload();
51
+ await chatHelpers.regenerate();
58
52
  },
59
53
  onAddToolResult: ({ toolCallId, result }) => {
60
- chatHelpers.addToolResult({ toolCallId, result });
54
+ chatHelpers.addToolResult({
55
+ tool: toolCallId,
56
+ toolCallId,
57
+ output: result,
58
+ });
61
59
  },
62
60
  adapters: {
63
61
  attachments: vercelAttachmentAdapter,
64
62
  ...adapter.adapters,
65
- threadList: new Proxy(adapter.adapters?.threadList ?? {}, {
66
- get(target, prop, receiver) {
67
- if (prop === "threadId") {
68
- return target.threadId ?? threadId;
69
- }
70
- if (prop === "onSwitchToNewThread") {
71
- return () => {
72
- chatHelpers.messages = [];
73
- chatHelpers.input = "";
74
- chatHelpers.setMessages([]);
75
- chatHelpers.setInput("");
76
- setThreadId(generateId());
77
-
78
- if (typeof target.onSwitchToNewThread === "function") {
79
- return target.onSwitchToNewThread.call(target);
80
- }
81
- };
82
- }
83
-
84
- return Reflect.get(target, prop, receiver);
85
- },
86
- }),
87
63
  },
88
64
  });
89
65
 
90
- useInputSync(chatHelpers, runtime);
91
-
92
66
  return runtime;
93
67
  };
@@ -1,100 +1,183 @@
1
- import { Message } from "@ai-sdk/ui-utils";
1
+ import { isToolUIPart, UIMessage } from "ai";
2
2
  import {
3
3
  unstable_createMessageConverter,
4
4
  type ReasoningMessagePart,
5
5
  type ToolCallMessagePart,
6
6
  type TextMessagePart,
7
- type CompleteAttachment,
8
7
  type SourceMessagePart,
9
8
  type FileMessagePart,
10
9
  } from "@assistant-ui/react";
11
10
 
12
- const convertParts = (message: Message) => {
13
- if (message.parts && message.parts.length > 0) {
14
- return message.parts
15
- .filter((p) => p.type !== "step-start")
16
- .map((part) => {
17
- const type = part.type;
18
- switch (type) {
19
- case "text":
20
- return {
21
- type: "text",
22
- text: part.text,
23
- } satisfies TextMessagePart;
24
- case "tool-invocation":
25
- return {
26
- type: "tool-call",
27
- toolName: part.toolInvocation.toolName,
28
- toolCallId: part.toolInvocation.toolCallId,
29
- argsText: JSON.stringify(part.toolInvocation.args),
30
- args: part.toolInvocation.args,
31
- result:
32
- part.toolInvocation.state === "result" &&
33
- part.toolInvocation.result,
34
- } satisfies ToolCallMessagePart;
35
- case "reasoning":
36
- return {
37
- type: "reasoning",
38
- text: part.reasoning,
39
- } satisfies ReasoningMessagePart;
40
- case "source":
41
- return {
42
- type: "source",
43
- ...part.source,
44
- } satisfies SourceMessagePart;
45
- case "file":
46
- return {
47
- type: "file",
48
- data: part.data,
49
- mimeType: part.mimeType,
50
- } satisfies FileMessagePart;
51
- default: {
52
- const _unsupported: never = type;
53
- throw new Error(
54
- `You have a message with an unsupported part type. The type ${_unsupported} is not supported.`,
55
- );
56
- }
57
- }
58
- });
11
+ const convertParts = (message: UIMessage) => {
12
+ if (!message.parts || message.parts.length === 0) {
13
+ return [];
59
14
  }
60
15
 
61
- return message.content
62
- ? [
63
- {
16
+ return message.parts
17
+ .filter((p) => p.type !== "step-start")
18
+ .map((part) => {
19
+ const type = part.type;
20
+
21
+ // Handle text parts
22
+ if (type === "text") {
23
+ return {
64
24
  type: "text",
65
- text: message.content,
66
- } satisfies TextMessagePart,
67
- ]
68
- : [];
25
+ text: part.text,
26
+ } satisfies TextMessagePart;
27
+ }
28
+
29
+ // Handle reasoning parts
30
+ if (type === "reasoning") {
31
+ return {
32
+ type: "reasoning",
33
+ text: part.text,
34
+ } satisfies ReasoningMessagePart;
35
+ }
36
+
37
+ // Handle tool-* parts (AI SDK v5 tool calls)
38
+ if (isToolUIPart(part)) {
39
+ const toolName = type.replace("tool-", "");
40
+ const toolCallId = part.toolCallId;
41
+
42
+ // Extract args and result based on state
43
+ let args: any = {};
44
+ let result: any = undefined;
45
+ let isError = false;
46
+
47
+ if (
48
+ part.state === "input-streaming" ||
49
+ part.state === "input-available"
50
+ ) {
51
+ args = part.input || {};
52
+ } else if (part.state === "output-available") {
53
+ args = part.input || {};
54
+ result = part.output;
55
+ } else if (part.state === "output-error") {
56
+ args = part.input || {};
57
+ isError = true;
58
+ result = { error: part.errorText };
59
+ }
60
+
61
+ return {
62
+ type: "tool-call",
63
+ toolName,
64
+ toolCallId,
65
+ argsText: JSON.stringify(args),
66
+ args,
67
+ result,
68
+ isError,
69
+ } satisfies ToolCallMessagePart;
70
+ }
71
+
72
+ // Handle dynamic-tool parts
73
+ if (type === "dynamic-tool") {
74
+ const toolName = part.toolName;
75
+ const toolCallId = part.toolCallId;
76
+
77
+ // Extract args and result based on state
78
+ let args: any = {};
79
+ let result: any = undefined;
80
+ let isError = false;
81
+
82
+ if (
83
+ part.state === "input-streaming" ||
84
+ part.state === "input-available"
85
+ ) {
86
+ args = part.input || {};
87
+ } else if (part.state === "output-available") {
88
+ args = part.input || {};
89
+ result = part.output;
90
+ } else if (part.state === "output-error") {
91
+ args = part.input || {};
92
+ isError = true;
93
+ result = { error: part.errorText };
94
+ }
95
+
96
+ return {
97
+ type: "tool-call",
98
+ toolName,
99
+ toolCallId,
100
+ argsText: JSON.stringify(args),
101
+ args,
102
+ result,
103
+ isError,
104
+ } satisfies ToolCallMessagePart;
105
+ }
106
+
107
+ // Handle source-url parts
108
+ if (type === "source-url") {
109
+ return {
110
+ type: "source",
111
+ sourceType: "url",
112
+ id: part.sourceId,
113
+ url: part.url,
114
+ title: part.title || "",
115
+ } satisfies SourceMessagePart;
116
+ }
117
+
118
+ // Handle source-document parts
119
+ if (type === "source-document") {
120
+ console.warn(
121
+ `Source document part type ${type} is not yet supported in conversion`,
122
+ );
123
+ return null;
124
+ }
125
+
126
+ // Handle file parts
127
+ if (type === "file") {
128
+ return {
129
+ type: "file",
130
+ data: part.url,
131
+ mimeType: part.mediaType,
132
+ } satisfies FileMessagePart;
133
+ }
134
+
135
+ // Handle data-* parts (AI SDK v5 data parts)
136
+ if (type.startsWith("data-")) {
137
+ // For now, we'll skip data parts as they don't have a direct equivalent
138
+ // in the assistant-ui types. They could be converted to a custom message part
139
+ // or handled differently based on the specific use case.
140
+ console.warn(
141
+ `Data part type ${type} is not yet supported in conversion`,
142
+ );
143
+ return null;
144
+ }
145
+
146
+ // For unsupported types, we'll skip them instead of throwing
147
+ console.warn(`Unsupported message part type: ${type}`);
148
+ return null;
149
+ })
150
+ .filter(Boolean) as any[];
69
151
  };
70
152
 
71
153
  export const AISDKMessageConverter = unstable_createMessageConverter(
72
- (message: Message) => {
154
+ (message: UIMessage) => {
155
+ // UIMessage doesn't have createdAt, so we'll use current date or undefined
156
+ const createdAt = new Date();
73
157
  switch (message.role) {
74
158
  case "user":
75
159
  return {
76
160
  role: "user",
77
161
  id: message.id,
78
- createdAt: message.createdAt,
162
+ createdAt,
79
163
  content: convertParts(message),
80
- attachments: message.experimental_attachments?.map(
81
- (attachment, idx) =>
82
- ({
83
- id: idx.toString(),
84
- type: "file",
85
- name: attachment.name ?? attachment.url,
86
- content: [],
87
- contentType: attachment.contentType ?? "unknown/unknown",
88
- status: { type: "complete" },
89
- }) satisfies CompleteAttachment,
90
- ),
164
+ attachments: message.parts
165
+ ?.filter((p: any) => p.type === "file")
166
+ .map((part: any, idx) => ({
167
+ id: idx.toString(),
168
+ type: "file" as const,
169
+ name: part.name ?? part.url ?? "file",
170
+ content: [],
171
+ contentType: part.mediaType ?? part.mimeType ?? "unknown/unknown",
172
+ status: { type: "complete" as const },
173
+ })),
91
174
  };
92
175
 
93
176
  case "system":
94
177
  return {
95
178
  role: "system",
96
179
  id: message.id,
97
- createdAt: message.createdAt,
180
+ createdAt,
98
181
  content: convertParts(message),
99
182
  };
100
183
 
@@ -102,60 +185,22 @@ export const AISDKMessageConverter = unstable_createMessageConverter(
102
185
  return {
103
186
  role: "assistant",
104
187
  id: message.id,
105
- createdAt: message.createdAt,
188
+ createdAt,
106
189
  content: convertParts(message),
107
190
  metadata: {
108
- unstable_annotations: message.annotations,
109
- unstable_data: Array.isArray(message.data)
110
- ? message.data
111
- : message.data
112
- ? [message.data]
191
+ unstable_annotations: (message as any).annotations,
192
+ unstable_data: Array.isArray((message as any).data)
193
+ ? (message as any).data
194
+ : (message as any).data
195
+ ? [(message as any).data]
113
196
  : undefined,
197
+ custom: {},
114
198
  },
115
199
  };
116
200
 
117
- case "data": {
118
- type MaybeSupportedDataMessage =
119
- | { type?: "unsafe_other" }
120
- | ToolCallMessagePart
121
- | {
122
- type: "tool-result";
123
- toolCallId: string;
124
- result: any;
125
- };
126
-
127
- if (
128
- !message.data ||
129
- !(typeof message.data === "object") ||
130
- Array.isArray(message.data)
131
- )
132
- return [];
133
-
134
- const data = message.data as MaybeSupportedDataMessage;
135
-
136
- if (data.type === "tool-call") {
137
- return {
138
- role: "assistant",
139
- id: message.id,
140
- createdAt: message.createdAt,
141
- content: [data],
142
- };
143
- } else if (data.type === "tool-result") {
144
- return {
145
- role: "tool",
146
- id: message.id,
147
- toolCallId: data.toolCallId,
148
- result: data.result,
149
- };
150
- }
151
- return [];
152
- }
153
-
154
201
  default:
155
- const _unsupported: "function" | "tool" = message.role;
156
- throw new Error(
157
- `You have a message with an unsupported role. The role ${_unsupported} is not supported.`,
158
- );
202
+ console.warn(`Unsupported message role: ${message.role}`);
203
+ return [];
159
204
  }
160
205
  },
161
206
  );
@@ -1,7 +1,7 @@
1
- import type { Message } from "@ai-sdk/ui-utils";
1
+ import type { UIMessage } from "ai";
2
2
 
3
3
  export const sliceMessagesUntil = (
4
- messages: Message[],
4
+ messages: UIMessage[],
5
5
  messageId: string | null,
6
6
  ) => {
7
7
  if (messageId == null) return [];
@@ -1,35 +1,60 @@
1
1
  import { AppendMessage } from "@assistant-ui/react";
2
- import { CreateMessage } from "@ai-sdk/ui-utils";
2
+ import {
3
+ CreateUIMessage,
4
+ FileUIPart,
5
+ UIDataTypes,
6
+ UIMessage,
7
+ UIMessagePart,
8
+ UITools,
9
+ } from "ai";
3
10
 
4
11
  export const toCreateMessage = async (
5
12
  message: AppendMessage,
6
- ): Promise<CreateMessage> => {
7
- const content = message.content
13
+ ): Promise<CreateUIMessage<UIMessage>> => {
14
+ const textParts = message.content
8
15
  .filter((part) => part.type === "text")
9
16
  .map((t) => t.text)
10
17
  .join("\n\n");
11
18
 
12
- const images = message.content
19
+ const parts: UIMessagePart<UIDataTypes, UITools>[] = [
20
+ {
21
+ type: "text",
22
+ text: textParts,
23
+ },
24
+ ];
25
+
26
+ // Add image parts
27
+ const imageParts = message.content
13
28
  .filter((part) => part.type === "image")
14
- .map((part) => ({ url: part.image }));
29
+ .map(
30
+ (part) =>
31
+ ({
32
+ type: "file",
33
+ mediaType: "image/png", // Default to PNG, could be made more dynamic
34
+ url: part.image,
35
+ }) satisfies FileUIPart,
36
+ );
37
+
38
+ parts.push(...imageParts);
39
+
40
+ // Add attachment parts
41
+ const attachmentParts = await Promise.all(
42
+ (message.attachments ?? []).map(async (m) => {
43
+ if (m.file == null) throw new Error("Attachment did not contain a file");
44
+ return {
45
+ type: "file",
46
+ mediaType: m.file.type,
47
+ filename: m.file.name,
48
+ url: await getFileDataURL(m.file),
49
+ } satisfies FileUIPart;
50
+ }),
51
+ );
52
+
53
+ parts.push(...attachmentParts);
15
54
 
16
55
  return {
17
56
  role: message.role,
18
- content,
19
- experimental_attachments: [
20
- ...images,
21
- ...(await Promise.all(
22
- (message.attachments ?? []).map(async (m) => {
23
- if (m.file == null)
24
- throw new Error("Attachment did not contain a file");
25
- return {
26
- contentType: m.file.type,
27
- name: m.file.name,
28
- url: await getFileDataURL(m.file),
29
- };
30
- }),
31
- )),
32
- ],
57
+ parts,
33
58
  };
34
59
  };
35
60
 
@@ -1,5 +1,5 @@
1
1
  import { AttachmentAdapter } from "@assistant-ui/react";
2
- import { generateId } from "@ai-sdk/ui-utils";
2
+ import { generateId } from "ai";
3
3
 
4
4
  export const vercelAttachmentAdapter: AttachmentAdapter = {
5
5
  accept:
@@ -1,3 +0,0 @@
1
- import { FC } from "react";
2
- export declare const RSCDisplay: FC;
3
- //# sourceMappingURL=RSCDisplay.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RSCDisplay.d.ts","sourceRoot":"","sources":["../../src/rsc/RSCDisplay.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAE3B,eAAO,MAAM,UAAU,EAAE,EAUxB,CAAC"}