@assistant-ui/react-ai-sdk 1.0.4 → 1.0.6
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.
- package/dist/ui/use-chat/useAISDKRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useAISDKRuntime.js +6 -3
- package/dist/ui/use-chat/useAISDKRuntime.js.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.js +2 -7
- package/dist/ui/use-chat/useChatRuntime.js.map +1 -1
- package/dist/ui/use-chat/useExternalHistory.js +1 -1
- package/dist/ui/use-chat/useExternalHistory.js.map +1 -1
- package/dist/ui/utils/convertMessage.d.ts.map +1 -1
- package/dist/ui/utils/convertMessage.js +22 -16
- package/dist/ui/utils/convertMessage.js.map +1 -1
- package/dist/ui/utils/toCreateMessage.d.ts +1 -1
- package/dist/ui/utils/toCreateMessage.d.ts.map +1 -1
- package/dist/ui/utils/toCreateMessage.js +34 -34
- package/dist/ui/utils/toCreateMessage.js.map +1 -1
- package/dist/ui/utils/vercelAttachmentAdapter.d.ts.map +1 -1
- package/dist/ui/utils/vercelAttachmentAdapter.js +15 -2
- package/dist/ui/utils/vercelAttachmentAdapter.js.map +1 -1
- package/package.json +4 -4
- package/src/ui/use-chat/useAISDKRuntime.tsx +5 -2
- package/src/ui/use-chat/useChatRuntime.tsx +1 -8
- package/src/ui/use-chat/useExternalHistory.tsx +1 -1
- package/src/ui/utils/convertMessage.ts +25 -20
- package/src/ui/utils/toCreateMessage.ts +33 -49
- package/src/ui/utils/vercelAttachmentAdapter.ts +19 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAISDKRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAEL,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"useAISDKRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAEL,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAIjB,MAAM,qBAAqB,CAAC;AAa7B,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EACL,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,GAAG;QAC/C,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;KAC5C,CAAC,GACF,SAAS,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACtE,aAAa,UAAU,CAAC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,EACnD,UAAS,mBAAwB,qBAiFlC,CAAC"}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/ui/use-chat/useAISDKRuntime.tsx
|
|
4
4
|
import {
|
|
5
|
-
useExternalStoreRuntime
|
|
5
|
+
useExternalStoreRuntime,
|
|
6
|
+
useRuntimeAdapters
|
|
6
7
|
} from "@assistant-ui/react";
|
|
7
8
|
import { sliceMessagesUntil } from "../utils/sliceMessagesUntil.js";
|
|
8
9
|
import { toCreateMessage } from "../utils/toCreateMessage.js";
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
import { useExternalHistory } from "./useExternalHistory.js";
|
|
16
17
|
import { useMemo } from "react";
|
|
17
18
|
var useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
19
|
+
const contextAdapters = useRuntimeAdapters();
|
|
18
20
|
const messages = AISDKMessageConverter.useThreadMessages({
|
|
19
21
|
isRunning: chatHelpers.status === "submitted" || chatHelpers.status == "streaming",
|
|
20
22
|
messages: chatHelpers.messages
|
|
@@ -44,7 +46,7 @@ var useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
44
46
|
),
|
|
45
47
|
onCancel: async () => chatHelpers.stop(),
|
|
46
48
|
onNew: async (message) => {
|
|
47
|
-
const createMessage =
|
|
49
|
+
const createMessage = toCreateMessage(message);
|
|
48
50
|
await chatHelpers.sendMessage(createMessage, {
|
|
49
51
|
metadata: message.runConfig
|
|
50
52
|
});
|
|
@@ -55,7 +57,7 @@ var useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
55
57
|
message.parentId
|
|
56
58
|
);
|
|
57
59
|
chatHelpers.setMessages(newMessages);
|
|
58
|
-
const createMessage =
|
|
60
|
+
const createMessage = toCreateMessage(message);
|
|
59
61
|
await chatHelpers.sendMessage(createMessage, {
|
|
60
62
|
metadata: message.runConfig
|
|
61
63
|
});
|
|
@@ -74,6 +76,7 @@ var useAISDKRuntime = (chatHelpers, adapter = {}) => {
|
|
|
74
76
|
},
|
|
75
77
|
adapters: {
|
|
76
78
|
attachments: vercelAttachmentAdapter,
|
|
79
|
+
...contextAdapters,
|
|
77
80
|
...adapter.adapters
|
|
78
81
|
},
|
|
79
82
|
isLoading
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport type { UIMessage, useChat } from \"@ai-sdk/react\";\nimport {\n useExternalStoreRuntime,\n ExternalStoreAdapter,\n ThreadHistoryAdapter,\n AssistantRuntime,\n ThreadMessage,\n MessageFormatAdapter,\n} from \"@assistant-ui/react\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../utils/toCreateMessage\";\nimport { vercelAttachmentAdapter } from \"../utils/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../utils/convertMessage\";\nimport {\n AISDKStorageFormat,\n aiSDKV5FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport { useExternalHistory } from \"./useExternalHistory\";\nimport { useMemo } from \"react\";\n\nexport type AISDKRuntimeAdapter = {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n })\n | undefined;\n};\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n adapter: AISDKRuntimeAdapter = {},\n) => {\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning:\n chatHelpers.status === \"submitted\" || chatHelpers.status == \"streaming\",\n messages: chatHelpers.messages,\n });\n\n const isLoading = useExternalHistory(\n useMemo(\n () => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n ),\n adapter.adapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV5FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const runtime = useExternalStoreRuntime({\n isRunning:\n chatHelpers.status === \"submitted\" || chatHelpers.status === \"streaming\",\n messages,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages.map(getVercelAIMessages<UI_MESSAGE>).flat(),\n ),\n onCancel: async () => chatHelpers.stop(),\n onNew: async (message) => {\n const createMessage =
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/use-chat/useAISDKRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport type { UIMessage, useChat } from \"@ai-sdk/react\";\nimport {\n useExternalStoreRuntime,\n ExternalStoreAdapter,\n ThreadHistoryAdapter,\n AssistantRuntime,\n ThreadMessage,\n MessageFormatAdapter,\n useRuntimeAdapters,\n} from \"@assistant-ui/react\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../utils/toCreateMessage\";\nimport { vercelAttachmentAdapter } from \"../utils/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../utils/convertMessage\";\nimport {\n AISDKStorageFormat,\n aiSDKV5FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport { useExternalHistory } from \"./useExternalHistory\";\nimport { useMemo } from \"react\";\n\nexport type AISDKRuntimeAdapter = {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n })\n | undefined;\n};\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n adapter: AISDKRuntimeAdapter = {},\n) => {\n const contextAdapters = useRuntimeAdapters();\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning:\n chatHelpers.status === \"submitted\" || chatHelpers.status == \"streaming\",\n messages: chatHelpers.messages,\n });\n\n const isLoading = useExternalHistory(\n useMemo(\n () => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n ),\n adapter.adapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV5FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const runtime = useExternalStoreRuntime({\n isRunning:\n chatHelpers.status === \"submitted\" || chatHelpers.status === \"streaming\",\n messages,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages.map(getVercelAIMessages<UI_MESSAGE>).flat(),\n ),\n onCancel: async () => chatHelpers.stop(),\n onNew: async (message) => {\n const createMessage = toCreateMessage<UI_MESSAGE>(message);\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onEdit: async (message) => {\n const newMessages = sliceMessagesUntil(\n chatHelpers.messages,\n message.parentId,\n );\n chatHelpers.setMessages(newMessages);\n\n const createMessage = toCreateMessage<UI_MESSAGE>(message);\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onReload: async (parentId: string | null, config) => {\n const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);\n chatHelpers.setMessages(newMessages);\n\n await chatHelpers.regenerate({ metadata: config.runConfig });\n },\n onAddToolResult: ({ toolCallId, result }) => {\n chatHelpers.addToolResult({\n tool: toolCallId,\n toolCallId,\n output: result,\n });\n },\n adapters: {\n attachments: vercelAttachmentAdapter,\n ...contextAdapters,\n ...adapter.adapters,\n },\n isLoading,\n });\n\n return runtime;\n};\n"],"mappings":";;;AAGA;AAAA,EACE;AAAA,EAMA;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAChC,SAAS,+BAA+B;AACxC,SAAS,2BAA2B;AACpC,SAAS,6BAA6B;AACtC;AAAA,EAEE;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC,SAAS,eAAe;AAUjB,IAAM,kBAAkB,CAC7B,aACA,UAA+B,CAAC,MAC7B;AACH,QAAM,kBAAkB,mBAAmB;AAC3C,QAAM,WAAW,sBAAsB,kBAAkB;AAAA,IACvD,WACE,YAAY,WAAW,eAAe,YAAY,UAAU;AAAA,IAC9D,UAAU,YAAY;AAAA,EACxB,CAAC;AAED,QAAM,YAAY;AAAA,IAChB;AAAA,MACE,OAAO;AAAA,QACL,IAAI,UAA4B;AAC9B,iBAAO;AAAA,QACT;AAAA,MACF;AAAA;AAAA,MAEA,CAAC;AAAA,IACH;AAAA,IACA,QAAQ,UAAU;AAAA,IAClB,sBAAsB;AAAA,IAGtB;AAAA,IAIA,CAACA,cAAa;AACZ,kBAAY,YAAYA,SAAQ;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,UAAU,wBAAwB;AAAA,IACtC,WACE,YAAY,WAAW,eAAe,YAAY,WAAW;AAAA,IAC/D;AAAA,IACA,aAAa,CAACA,cACZ,YAAY;AAAA,MACVA,UAAS,IAAI,mBAA+B,EAAE,KAAK;AAAA,IACrD;AAAA,IACF,UAAU,YAAY,YAAY,KAAK;AAAA,IACvC,OAAO,OAAO,YAAY;AACxB,YAAM,gBAAgB,gBAA4B,OAAO;AACzD,YAAM,YAAY,YAAY,eAAe;AAAA,QAC3C,UAAU,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,IACA,QAAQ,OAAO,YAAY;AACzB,YAAM,cAAc;AAAA,QAClB,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AACA,kBAAY,YAAY,WAAW;AAEnC,YAAM,gBAAgB,gBAA4B,OAAO;AACzD,YAAM,YAAY,YAAY,eAAe;AAAA,QAC3C,UAAU,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,IACA,UAAU,OAAO,UAAyB,WAAW;AACnD,YAAM,cAAc,mBAAmB,YAAY,UAAU,QAAQ;AACrE,kBAAY,YAAY,WAAW;AAEnC,YAAM,YAAY,WAAW,EAAE,UAAU,OAAO,UAAU,CAAC;AAAA,IAC7D;AAAA,IACA,iBAAiB,CAAC,EAAE,YAAY,OAAO,MAAM;AAC3C,kBAAY,cAAc;AAAA,QACxB,MAAM;AAAA,QACN;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,IACA,UAAU;AAAA,MACR,aAAa;AAAA,MACb,GAAG;AAAA,MACH,GAAG,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AACT;","names":["messages"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACL,gBAAgB,
|
|
1
|
+
{"version":3,"file":"useChatRuntime.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACL,gBAAgB,EAGjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAG9B,MAAM,MAAM,qBAAqB,CAAC,UAAU,SAAS,SAAS,GAAG,SAAS,IACxE,QAAQ,CAAC,UAAU,CAAC,GAAG;IACrB,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;CACxD,CAAC;AAEJ,eAAO,MAAM,oBAAoB,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EAC3E,UAAU,qBAAqB,CAAC,UAAU,CAAC,KAC1C,gBAgDF,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EAAE,wBAGtE,qBAAqB,CAAC,UAAU,CAAM,KAAG,gBAQ3C,CAAC"}
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
import { useChat } from "@ai-sdk/react";
|
|
5
5
|
import {
|
|
6
6
|
unstable_useCloudThreadListAdapter,
|
|
7
|
-
unstable_useRemoteThreadListRuntime
|
|
8
|
-
useRuntimeAdapters
|
|
7
|
+
unstable_useRemoteThreadListRuntime
|
|
9
8
|
} from "@assistant-ui/react";
|
|
10
9
|
import { useAISDKRuntime } from "./useAISDKRuntime.js";
|
|
11
10
|
import { AssistantChatTransport } from "./AssistantChatTransport.js";
|
|
@@ -16,7 +15,6 @@ var useChatThreadRuntime = (options) => {
|
|
|
16
15
|
...chatOptions
|
|
17
16
|
} = options ?? {};
|
|
18
17
|
const transport = transportOptions ?? new AssistantChatTransport();
|
|
19
|
-
const contextAdapters = useRuntimeAdapters();
|
|
20
18
|
const chat = useChat({
|
|
21
19
|
...chatOptions,
|
|
22
20
|
transport,
|
|
@@ -49,10 +47,7 @@ var useChatThreadRuntime = (options) => {
|
|
|
49
47
|
}
|
|
50
48
|
});
|
|
51
49
|
const runtime = useAISDKRuntime(chat, {
|
|
52
|
-
adapters
|
|
53
|
-
...contextAdapters,
|
|
54
|
-
...adapters
|
|
55
|
-
}
|
|
50
|
+
adapters
|
|
56
51
|
});
|
|
57
52
|
if (transport instanceof AssistantChatTransport) {
|
|
58
53
|
transport.setRuntime(runtime);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useChat, type UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n AssistantRuntime,\n unstable_useCloudThreadListAdapter,\n unstable_useRemoteThreadListRuntime,\n
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/use-chat/useChatRuntime.tsx"],"sourcesContent":["\"use client\";\n\nimport { useChat, type UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n AssistantRuntime,\n unstable_useCloudThreadListAdapter,\n unstable_useRemoteThreadListRuntime,\n} from \"@assistant-ui/react\";\nimport { useAISDKRuntime, type AISDKRuntimeAdapter } from \"./useAISDKRuntime\";\nimport { ChatInit } from \"ai\";\nimport { AssistantChatTransport } from \"./AssistantChatTransport\";\n\nexport type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> & {\n cloud?: AssistantCloud | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n };\n\nexport const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n options?: UseChatRuntimeOptions<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n ...chatOptions\n } = options ?? {};\n const transport = transportOptions ?? new AssistantChatTransport();\n\n const chat = useChat({\n ...chatOptions,\n transport,\n onToolCall: async ({ toolCall }) => {\n await chatOptions.onToolCall?.({ toolCall });\n\n const tools = runtime.thread.getModelContext().tools;\n const tool = tools?.[toolCall.toolName];\n if (tool) {\n try {\n const result = await tool.execute?.(toolCall.input, {\n toolCallId: toolCall.toolCallId,\n abortSignal: new AbortController().signal, // dummy signal for now\n });\n chat.addToolResult({\n tool: toolCall.toolName,\n toolCallId: toolCall.toolCallId,\n output: result,\n });\n } catch (error) {\n chat.addToolResult({\n tool: toolCall.toolName,\n toolCallId: toolCall.toolCallId,\n output: {\n error: error instanceof Error ? error.message : String(error),\n },\n });\n }\n }\n },\n });\n\n const runtime = useAISDKRuntime(chat as any, {\n adapters,\n });\n if (transport instanceof AssistantChatTransport) {\n transport.setRuntime(runtime);\n }\n\n return runtime;\n};\n\nexport const useChatRuntime = <UI_MESSAGE extends UIMessage = UIMessage>({\n cloud,\n ...options\n}: UseChatRuntimeOptions<UI_MESSAGE> = {}): AssistantRuntime => {\n const cloudAdapter = unstable_useCloudThreadListAdapter({ cloud });\n return unstable_useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n });\n};\n"],"mappings":";;;AAEA,SAAS,eAA+B;AAExC;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAiD;AAE1D,SAAS,8BAA8B;AAQhC,IAAM,uBAAuB,CAClC,YACqB;AACrB,QAAM;AAAA,IACJ;AAAA,IACA,WAAW;AAAA,IACX,GAAG;AAAA,EACL,IAAI,WAAW,CAAC;AAChB,QAAM,YAAY,oBAAoB,IAAI,uBAAuB;AAEjE,QAAM,OAAO,QAAQ;AAAA,IACnB,GAAG;AAAA,IACH;AAAA,IACA,YAAY,OAAO,EAAE,SAAS,MAAM;AAClC,YAAM,YAAY,aAAa,EAAE,SAAS,CAAC;AAE3C,YAAM,QAAQ,QAAQ,OAAO,gBAAgB,EAAE;AAC/C,YAAM,OAAO,QAAQ,SAAS,QAAQ;AACtC,UAAI,MAAM;AACR,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,UAAU,SAAS,OAAO;AAAA,YAClD,YAAY,SAAS;AAAA,YACrB,aAAa,IAAI,gBAAgB,EAAE;AAAA;AAAA,UACrC,CAAC;AACD,eAAK,cAAc;AAAA,YACjB,MAAM,SAAS;AAAA,YACf,YAAY,SAAS;AAAA,YACrB,QAAQ;AAAA,UACV,CAAC;AAAA,QACH,SAAS,OAAO;AACd,eAAK,cAAc;AAAA,YACjB,MAAM,SAAS;AAAA,YACf,YAAY,SAAS;AAAA,YACrB,QAAQ;AAAA,cACN,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC9D;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,UAAU,gBAAgB,MAAa;AAAA,IAC3C;AAAA,EACF,CAAC;AACD,MAAI,qBAAqB,wBAAwB;AAC/C,cAAU,WAAW,OAAO;AAAA,EAC9B;AAEA,SAAO;AACT;AAEO,IAAM,iBAAiB,CAA2C;AAAA,EACvE;AAAA,EACA,GAAG;AACL,IAAuC,CAAC,MAAwB;AAC9D,QAAM,eAAe,mCAAmC,EAAE,MAAM,CAAC;AACjE,SAAO,oCAAoC;AAAA,IACzC,aAAa,SAAS,cAAc;AAClC,aAAO,qBAAqB,OAAO;AAAA,IACrC;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AACH;","names":[]}
|
|
@@ -64,7 +64,7 @@ var useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storageF
|
|
|
64
64
|
for (let i = 0; i < messages.length; i++) {
|
|
65
65
|
const message = messages[i];
|
|
66
66
|
if (message.status === void 0 || message.status.type === "complete" || message.status.type === "incomplete") {
|
|
67
|
-
if (historyIds.current.has(message.id))
|
|
67
|
+
if (historyIds.current.has(message.id)) continue;
|
|
68
68
|
historyIds.current.add(message.id);
|
|
69
69
|
const parentId = i > 0 ? messages[i - 1].id : null;
|
|
70
70
|
await historyAdapter?.withFormat?.(storageFormatAdapter).append({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/use-chat/useExternalHistory.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n AssistantRuntime,\n ThreadHistoryAdapter,\n ThreadMessage,\n MessageFormatAdapter,\n getExternalStoreMessages,\n MessageFormatRepository,\n ExportedMessageRepository,\n INTERNAL,\n} from \"@assistant-ui/react\";\nimport { useRef, useEffect, useState, RefObject } from \"react\";\n\nconst { MessageRepository } = INTERNAL;\n\nexport const toExportedMessageRepository = <TMessage,>(\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n messages: MessageFormatRepository<TMessage>,\n): ExportedMessageRepository => {\n return {\n headId: messages.headId!,\n messages: messages.messages.map((m) => {\n const message = toThreadMessages([m.message])[0]!;\n return {\n ...m,\n message,\n };\n }),\n };\n};\n\nexport const useExternalHistory = <TMessage,>(\n runtimeRef: RefObject<AssistantRuntime>,\n historyAdapter: ThreadHistoryAdapter | undefined,\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n storageFormatAdapter: MessageFormatAdapter<TMessage, any>,\n onSetMessages: (messages: TMessage[]) => void,\n) => {\n const loadedRef = useRef(false);\n const [isLoading, setIsLoading] = useState(true);\n const historyIds = useRef(new Set<string>());\n\n const onSetMessagesRef = useRef<typeof onSetMessages>(() => onSetMessages);\n useEffect(() => {\n onSetMessagesRef.current = onSetMessages;\n });\n\n // Load messages from history adapter on mount\n useEffect(() => {\n if (!historyAdapter || loadedRef.current) return;\n\n const loadHistory = async () => {\n setIsLoading(true);\n try {\n const repo = await historyAdapter\n .withFormat?.(storageFormatAdapter)\n .load();\n if (repo && repo.messages.length > 0) {\n const converted = toExportedMessageRepository(toThreadMessages, repo);\n runtimeRef.current.thread.import(converted);\n\n const tempRepo = new MessageRepository();\n tempRepo.import(converted);\n const messages = tempRepo.getMessages();\n\n onSetMessagesRef.current(\n messages.map(getExternalStoreMessages<TMessage>).flat(),\n );\n\n historyIds.current = new Set(\n converted.messages.map((m) => m.message.id),\n );\n }\n } catch (error) {\n console.error(\"Failed to load message history:\", error);\n } finally {\n setIsLoading(false);\n }\n };\n\n if (!loadedRef.current) {\n loadedRef.current = true;\n loadHistory();\n }\n }, [historyAdapter, storageFormatAdapter, toThreadMessages, runtimeRef]);\n\n useEffect(() => {\n return runtimeRef.current.thread.subscribe(async () => {\n const { messages, isRunning } = runtimeRef.current.thread.getState();\n if (isRunning) return;\n\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i]!;\n if (\n message.status === undefined ||\n message.status.type === \"complete\" ||\n message.status.type === \"incomplete\"\n ) {\n if (historyIds.current.has(message.id))
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/use-chat/useExternalHistory.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n AssistantRuntime,\n ThreadHistoryAdapter,\n ThreadMessage,\n MessageFormatAdapter,\n getExternalStoreMessages,\n MessageFormatRepository,\n ExportedMessageRepository,\n INTERNAL,\n} from \"@assistant-ui/react\";\nimport { useRef, useEffect, useState, RefObject } from \"react\";\n\nconst { MessageRepository } = INTERNAL;\n\nexport const toExportedMessageRepository = <TMessage,>(\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n messages: MessageFormatRepository<TMessage>,\n): ExportedMessageRepository => {\n return {\n headId: messages.headId!,\n messages: messages.messages.map((m) => {\n const message = toThreadMessages([m.message])[0]!;\n return {\n ...m,\n message,\n };\n }),\n };\n};\n\nexport const useExternalHistory = <TMessage,>(\n runtimeRef: RefObject<AssistantRuntime>,\n historyAdapter: ThreadHistoryAdapter | undefined,\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n storageFormatAdapter: MessageFormatAdapter<TMessage, any>,\n onSetMessages: (messages: TMessage[]) => void,\n) => {\n const loadedRef = useRef(false);\n const [isLoading, setIsLoading] = useState(true);\n const historyIds = useRef(new Set<string>());\n\n const onSetMessagesRef = useRef<typeof onSetMessages>(() => onSetMessages);\n useEffect(() => {\n onSetMessagesRef.current = onSetMessages;\n });\n\n // Load messages from history adapter on mount\n useEffect(() => {\n if (!historyAdapter || loadedRef.current) return;\n\n const loadHistory = async () => {\n setIsLoading(true);\n try {\n const repo = await historyAdapter\n .withFormat?.(storageFormatAdapter)\n .load();\n if (repo && repo.messages.length > 0) {\n const converted = toExportedMessageRepository(toThreadMessages, repo);\n runtimeRef.current.thread.import(converted);\n\n const tempRepo = new MessageRepository();\n tempRepo.import(converted);\n const messages = tempRepo.getMessages();\n\n onSetMessagesRef.current(\n messages.map(getExternalStoreMessages<TMessage>).flat(),\n );\n\n historyIds.current = new Set(\n converted.messages.map((m) => m.message.id),\n );\n }\n } catch (error) {\n console.error(\"Failed to load message history:\", error);\n } finally {\n setIsLoading(false);\n }\n };\n\n if (!loadedRef.current) {\n loadedRef.current = true;\n loadHistory();\n }\n }, [historyAdapter, storageFormatAdapter, toThreadMessages, runtimeRef]);\n\n useEffect(() => {\n return runtimeRef.current.thread.subscribe(async () => {\n const { messages, isRunning } = runtimeRef.current.thread.getState();\n if (isRunning) return;\n\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i]!;\n if (\n message.status === undefined ||\n message.status.type === \"complete\" ||\n message.status.type === \"incomplete\"\n ) {\n if (historyIds.current.has(message.id)) continue;\n historyIds.current.add(message.id);\n\n const parentId = i > 0 ? messages[i - 1]!.id : null;\n await historyAdapter?.withFormat?.(storageFormatAdapter).append({\n parentId,\n message: getExternalStoreMessages<TMessage>(message)[0]!,\n });\n }\n }\n });\n }, [historyAdapter, storageFormatAdapter, runtimeRef]);\n\n return isLoading;\n};\n"],"mappings":";;;AAEA;AAAA,EAKE;AAAA,EAGA;AAAA,OACK;AACP,SAAS,QAAQ,WAAW,gBAA2B;AAEvD,IAAM,EAAE,kBAAkB,IAAI;AAEvB,IAAM,8BAA8B,CACzC,kBACA,aAC8B;AAC9B,SAAO;AAAA,IACL,QAAQ,SAAS;AAAA,IACjB,UAAU,SAAS,SAAS,IAAI,CAAC,MAAM;AACrC,YAAM,UAAU,iBAAiB,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC;AAC/C,aAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,IAAM,qBAAqB,CAChC,YACA,gBACA,kBACA,sBACA,kBACG;AACH,QAAM,YAAY,OAAO,KAAK;AAC9B,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,aAAa,OAAO,oBAAI,IAAY,CAAC;AAE3C,QAAM,mBAAmB,OAA6B,MAAM,aAAa;AACzE,YAAU,MAAM;AACd,qBAAiB,UAAU;AAAA,EAC7B,CAAC;AAGD,YAAU,MAAM;AACd,QAAI,CAAC,kBAAkB,UAAU,QAAS;AAE1C,UAAM,cAAc,YAAY;AAC9B,mBAAa,IAAI;AACjB,UAAI;AACF,cAAM,OAAO,MAAM,eAChB,aAAa,oBAAoB,EACjC,KAAK;AACR,YAAI,QAAQ,KAAK,SAAS,SAAS,GAAG;AACpC,gBAAM,YAAY,4BAA4B,kBAAkB,IAAI;AACpE,qBAAW,QAAQ,OAAO,OAAO,SAAS;AAE1C,gBAAM,WAAW,IAAI,kBAAkB;AACvC,mBAAS,OAAO,SAAS;AACzB,gBAAM,WAAW,SAAS,YAAY;AAEtC,2BAAiB;AAAA,YACf,SAAS,IAAI,wBAAkC,EAAE,KAAK;AAAA,UACxD;AAEA,qBAAW,UAAU,IAAI;AAAA,YACvB,UAAU,SAAS,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE;AAAA,UAC5C;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,mCAAmC,KAAK;AAAA,MACxD,UAAE;AACA,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAEA,QAAI,CAAC,UAAU,SAAS;AACtB,gBAAU,UAAU;AACpB,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,gBAAgB,sBAAsB,kBAAkB,UAAU,CAAC;AAEvE,YAAU,MAAM;AACd,WAAO,WAAW,QAAQ,OAAO,UAAU,YAAY;AACrD,YAAM,EAAE,UAAU,UAAU,IAAI,WAAW,QAAQ,OAAO,SAAS;AACnE,UAAI,UAAW;AAEf,eAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,cAAM,UAAU,SAAS,CAAC;AAC1B,YACE,QAAQ,WAAW,UACnB,QAAQ,OAAO,SAAS,cACxB,QAAQ,OAAO,SAAS,cACxB;AACA,cAAI,WAAW,QAAQ,IAAI,QAAQ,EAAE,EAAG;AACxC,qBAAW,QAAQ,IAAI,QAAQ,EAAE;AAEjC,gBAAM,WAAW,IAAI,IAAI,SAAS,IAAI,CAAC,EAAG,KAAK;AAC/C,gBAAM,gBAAgB,aAAa,oBAAoB,EAAE,OAAO;AAAA,YAC9D;AAAA,YACA,SAAS,yBAAmC,OAAO,EAAE,CAAC;AAAA,UACxD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,gBAAgB,sBAAsB,UAAU,CAAC;AAErD,SAAO;AACT;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,SAAS,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"convertMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/convertMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,SAAS,EAAE,MAAM,IAAI,CAAC;AA8I7C,eAAO,MAAM,qBAAqB;;;;;;;0HAvHb,sDACF;yHAIM,sDACT;;;CAqLf,CAAC"}
|
|
@@ -7,7 +7,7 @@ var convertParts = (message) => {
|
|
|
7
7
|
if (!message.parts || message.parts.length === 0) {
|
|
8
8
|
return [];
|
|
9
9
|
}
|
|
10
|
-
return message.parts.filter((p) => p.type !== "step-start").map((part) => {
|
|
10
|
+
return message.parts.filter((p) => p.type !== "step-start" && p.type !== "file").map((part) => {
|
|
11
11
|
const type = part.type;
|
|
12
12
|
if (type === "text") {
|
|
13
13
|
return {
|
|
@@ -88,13 +88,6 @@ var convertParts = (message) => {
|
|
|
88
88
|
);
|
|
89
89
|
return null;
|
|
90
90
|
}
|
|
91
|
-
if (type === "file") {
|
|
92
|
-
return {
|
|
93
|
-
type: "file",
|
|
94
|
-
data: part.url,
|
|
95
|
-
mimeType: part.mediaType
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
91
|
if (type.startsWith("data-")) {
|
|
99
92
|
console.warn(
|
|
100
93
|
`Data part type ${type} is not yet supported in conversion`
|
|
@@ -115,14 +108,27 @@ var AISDKMessageConverter = unstable_createMessageConverter(
|
|
|
115
108
|
id: message.id,
|
|
116
109
|
createdAt,
|
|
117
110
|
content: convertParts(message),
|
|
118
|
-
attachments: message.parts?.filter((p) => p.type === "file").map((part, idx) =>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
111
|
+
attachments: message.parts?.filter((p) => p.type === "file").map((part, idx) => {
|
|
112
|
+
return {
|
|
113
|
+
id: idx.toString(),
|
|
114
|
+
type: part.mediaType.startsWith("image/") ? "image" : "file",
|
|
115
|
+
name: part.filename ?? "file",
|
|
116
|
+
content: [
|
|
117
|
+
part.mediaType.startsWith("image/") ? {
|
|
118
|
+
type: "image",
|
|
119
|
+
image: part.url,
|
|
120
|
+
filename: part.filename
|
|
121
|
+
} : {
|
|
122
|
+
type: "file",
|
|
123
|
+
filename: part.filename,
|
|
124
|
+
data: part.url,
|
|
125
|
+
mimeType: part.mediaType
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
contentType: part.mediaType ?? "unknown/unknown",
|
|
129
|
+
status: { type: "complete" }
|
|
130
|
+
};
|
|
131
|
+
})
|
|
126
132
|
};
|
|
127
133
|
case "system":
|
|
128
134
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/utils/convertMessage.ts"],"sourcesContent":["import { isToolUIPart, UIMessage } from \"ai\";\nimport {\n unstable_createMessageConverter,\n type ReasoningMessagePart,\n type ToolCallMessagePart,\n type TextMessagePart,\n type SourceMessagePart,\n
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/utils/convertMessage.ts"],"sourcesContent":["import { isToolUIPart, UIMessage } from \"ai\";\nimport {\n unstable_createMessageConverter,\n type ReasoningMessagePart,\n type ToolCallMessagePart,\n type TextMessagePart,\n type SourceMessagePart,\n} from \"@assistant-ui/react\";\n\nconst convertParts = (message: UIMessage) => {\n if (!message.parts || message.parts.length === 0) {\n return [];\n }\n\n return message.parts\n .filter((p) => p.type !== \"step-start\" && p.type !== \"file\")\n .map((part) => {\n const type = part.type;\n\n // Handle text parts\n if (type === \"text\") {\n return {\n type: \"text\",\n text: part.text,\n } satisfies TextMessagePart;\n }\n\n // Handle reasoning parts\n if (type === \"reasoning\") {\n return {\n type: \"reasoning\",\n text: part.text,\n } satisfies ReasoningMessagePart;\n }\n\n // Handle tool-* parts (AI SDK v5 tool calls)\n if (isToolUIPart(part)) {\n const toolName = type.replace(\"tool-\", \"\");\n const toolCallId = part.toolCallId;\n\n // Extract args and result based on state\n let args: any = {};\n let result: any = undefined;\n let isError = false;\n\n if (\n part.state === \"input-streaming\" ||\n part.state === \"input-available\"\n ) {\n args = part.input || {};\n } else if (part.state === \"output-available\") {\n args = part.input || {};\n result = part.output;\n } else if (part.state === \"output-error\") {\n args = part.input || {};\n isError = true;\n result = { error: part.errorText };\n }\n\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText: JSON.stringify(args),\n args,\n result,\n isError,\n } satisfies ToolCallMessagePart;\n }\n\n // Handle dynamic-tool parts\n if (type === \"dynamic-tool\") {\n const toolName = part.toolName;\n const toolCallId = part.toolCallId;\n\n // Extract args and result based on state\n let args: any = {};\n let result: any = undefined;\n let isError = false;\n\n if (\n part.state === \"input-streaming\" ||\n part.state === \"input-available\"\n ) {\n args = part.input || {};\n } else if (part.state === \"output-available\") {\n args = part.input || {};\n result = part.output;\n } else if (part.state === \"output-error\") {\n args = part.input || {};\n isError = true;\n result = { error: part.errorText };\n }\n\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText: JSON.stringify(args),\n args,\n result,\n isError,\n } satisfies ToolCallMessagePart;\n }\n\n // Handle source-url parts\n if (type === \"source-url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.sourceId,\n url: part.url,\n title: part.title || \"\",\n } satisfies SourceMessagePart;\n }\n\n // Handle source-document parts\n if (type === \"source-document\") {\n console.warn(\n `Source document part type ${type} is not yet supported in conversion`,\n );\n return null;\n }\n\n // Handle data-* parts (AI SDK v5 data parts)\n if (type.startsWith(\"data-\")) {\n // For now, we'll skip data parts as they don't have a direct equivalent\n // in the assistant-ui types. They could be converted to a custom message part\n // or handled differently based on the specific use case.\n console.warn(\n `Data part type ${type} is not yet supported in conversion`,\n );\n return null;\n }\n\n // For unsupported types, we'll skip them instead of throwing\n console.warn(`Unsupported message part type: ${type}`);\n return null;\n })\n .filter(Boolean) as any[];\n};\n\nexport const AISDKMessageConverter = unstable_createMessageConverter(\n (message: UIMessage) => {\n // UIMessage doesn't have createdAt, so we'll use current date or undefined\n const createdAt = new Date();\n switch (message.role) {\n case \"user\":\n return {\n role: \"user\",\n id: message.id,\n createdAt,\n content: convertParts(message),\n attachments: message.parts\n ?.filter((p) => p.type === \"file\")\n .map((part, idx) => {\n return {\n id: idx.toString(),\n type: part.mediaType.startsWith(\"image/\") ? \"image\" : \"file\",\n name: part.filename ?? \"file\",\n content: [\n part.mediaType.startsWith(\"image/\")\n ? {\n type: \"image\",\n image: part.url,\n filename: part.filename!,\n }\n : {\n type: \"file\",\n filename: part.filename!,\n data: part.url,\n mimeType: part.mediaType,\n },\n ],\n contentType: part.mediaType ?? \"unknown/unknown\",\n status: { type: \"complete\" as const },\n };\n }),\n };\n\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n createdAt,\n content: convertParts(message),\n };\n\n case \"assistant\":\n return {\n role: \"assistant\",\n id: message.id,\n createdAt,\n content: convertParts(message),\n metadata: {\n unstable_annotations: (message as any).annotations,\n unstable_data: Array.isArray((message as any).data)\n ? (message as any).data\n : (message as any).data\n ? [(message as any).data]\n : undefined,\n custom: {},\n },\n };\n\n default:\n console.warn(`Unsupported message role: ${message.role}`);\n return [];\n }\n },\n);\n"],"mappings":"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","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { AppendMessage } from "@assistant-ui/react";
|
|
2
2
|
import { CreateUIMessage, UIMessage } from "ai";
|
|
3
|
-
export declare const toCreateMessage: <UI_MESSAGE extends UIMessage = UIMessage>(message: AppendMessage) =>
|
|
3
|
+
export declare const toCreateMessage: <UI_MESSAGE extends UIMessage = UIMessage>(message: AppendMessage) => CreateUIMessage<UI_MESSAGE>;
|
|
4
4
|
//# sourceMappingURL=toCreateMessage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCreateMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/toCreateMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,eAAe,
|
|
1
|
+
{"version":3,"file":"toCreateMessage.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/toCreateMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,eAAe,EAGf,SAAS,EAGV,MAAM,IAAI,CAAC;AAEZ,eAAO,MAAM,eAAe,GAAI,UAAU,SAAS,SAAS,GAAG,SAAS,EACtE,SAAS,aAAa,KACrB,eAAe,CAAC,UAAU,CA0C5B,CAAC"}
|
|
@@ -2,47 +2,47 @@
|
|
|
2
2
|
import {
|
|
3
3
|
generateId
|
|
4
4
|
} from "ai";
|
|
5
|
-
var toCreateMessage =
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
var toCreateMessage = (message) => {
|
|
6
|
+
const inputParts = [
|
|
7
|
+
...message.content.filter((c) => c.type !== "file"),
|
|
8
|
+
...message.attachments?.flatMap(
|
|
9
|
+
(a) => a.content.map((c) => ({
|
|
10
|
+
...c,
|
|
11
|
+
filename: a.name
|
|
12
|
+
}))
|
|
13
|
+
) ?? []
|
|
12
14
|
];
|
|
13
|
-
const
|
|
14
|
-
(part)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
const parts = inputParts.map((part) => {
|
|
16
|
+
switch (part.type) {
|
|
17
|
+
case "text":
|
|
18
|
+
return {
|
|
19
|
+
type: "text",
|
|
20
|
+
text: part.text
|
|
21
|
+
};
|
|
22
|
+
case "image":
|
|
23
|
+
return {
|
|
24
|
+
type: "file",
|
|
25
|
+
url: part.image,
|
|
26
|
+
...part.filename && { filename: part.filename },
|
|
27
|
+
mediaType: "image/png"
|
|
28
|
+
};
|
|
29
|
+
case "file":
|
|
30
|
+
return {
|
|
31
|
+
type: "file",
|
|
32
|
+
url: part.data,
|
|
33
|
+
mediaType: part.mimeType,
|
|
34
|
+
...part.filename && { filename: part.filename }
|
|
35
|
+
};
|
|
36
|
+
default:
|
|
37
|
+
throw new Error(`Unsupported part type: ${part.type}`);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
34
40
|
return {
|
|
35
41
|
id: generateId(),
|
|
36
42
|
role: message.role,
|
|
37
43
|
parts
|
|
38
44
|
};
|
|
39
45
|
};
|
|
40
|
-
var getFileDataURL = (file) => new Promise((resolve, reject) => {
|
|
41
|
-
const reader = new FileReader();
|
|
42
|
-
reader.onload = () => resolve(reader.result);
|
|
43
|
-
reader.onerror = (error) => reject(error);
|
|
44
|
-
reader.readAsDataURL(file);
|
|
45
|
-
});
|
|
46
46
|
export {
|
|
47
47
|
toCreateMessage
|
|
48
48
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/utils/toCreateMessage.ts"],"sourcesContent":["import { AppendMessage } from \"@assistant-ui/react\";\nimport {\n CreateUIMessage,\n
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/utils/toCreateMessage.ts"],"sourcesContent":["import { AppendMessage } from \"@assistant-ui/react\";\nimport {\n CreateUIMessage,\n generateId,\n UIDataTypes,\n UIMessage,\n UIMessagePart,\n UITools,\n} from \"ai\";\n\nexport const toCreateMessage = <UI_MESSAGE extends UIMessage = UIMessage>(\n message: AppendMessage,\n): CreateUIMessage<UI_MESSAGE> => {\n const inputParts = [\n ...message.content.filter((c) => c.type !== \"file\"),\n ...(message.attachments?.flatMap((a) =>\n a.content.map((c) => ({\n ...c,\n filename: a.name,\n })),\n ) ?? []),\n ];\n\n const parts = inputParts.map((part): UIMessagePart<UIDataTypes, UITools> => {\n switch (part.type) {\n case \"text\":\n return {\n type: \"text\",\n text: part.text,\n };\n case \"image\":\n return {\n type: \"file\",\n url: part.image,\n ...(part.filename && { filename: part.filename }),\n mediaType: \"image/png\",\n };\n case \"file\":\n return {\n type: \"file\",\n url: part.data,\n mediaType: part.mimeType,\n ...(part.filename && { filename: part.filename }),\n };\n default:\n throw new Error(`Unsupported part type: ${part.type}`);\n }\n });\n\n return {\n id: generateId(),\n role: message.role,\n parts,\n } satisfies CreateUIMessage<UIMessage> as CreateUIMessage<UI_MESSAGE>;\n};\n"],"mappings":";AACA;AAAA,EAEE;AAAA,OAKK;AAEA,IAAM,kBAAkB,CAC7B,YACgC;AAChC,QAAM,aAAa;AAAA,IACjB,GAAG,QAAQ,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AAAA,IAClD,GAAI,QAAQ,aAAa;AAAA,MAAQ,CAAC,MAChC,EAAE,QAAQ,IAAI,CAAC,OAAO;AAAA,QACpB,GAAG;AAAA,QACH,UAAU,EAAE;AAAA,MACd,EAAE;AAAA,IACJ,KAAK,CAAC;AAAA,EACR;AAEA,QAAM,QAAQ,WAAW,IAAI,CAAC,SAA8C;AAC1E,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,KAAK;AAAA,QACb;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,KAAK,KAAK;AAAA,UACV,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;AAAA,UAC/C,WAAW;AAAA,QACb;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,KAAK,KAAK;AAAA,UACV,WAAW,KAAK;AAAA,UAChB,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;AAAA,QACjD;AAAA,MACF;AACE,cAAM,IAAI,MAAM,0BAA0B,KAAK,IAAI,EAAE;AAAA,IACzD;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,IAAI,WAAW;AAAA,IACf,MAAM,QAAQ;AAAA,IACd;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercelAttachmentAdapter.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/vercelAttachmentAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"vercelAttachmentAdapter.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/vercelAttachmentAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAaxD,eAAO,MAAM,uBAAuB,EAAE,iBAgCrC,CAAC"}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
// src/ui/utils/vercelAttachmentAdapter.ts
|
|
2
2
|
import { generateId } from "ai";
|
|
3
|
+
var getFileDataURL = (file) => new Promise((resolve, reject) => {
|
|
4
|
+
const reader = new FileReader();
|
|
5
|
+
reader.onload = () => resolve(reader.result);
|
|
6
|
+
reader.onerror = (error) => reject(error);
|
|
7
|
+
reader.readAsDataURL(file);
|
|
8
|
+
});
|
|
3
9
|
var vercelAttachmentAdapter = {
|
|
4
10
|
accept: "image/*, text/plain, text/html, text/markdown, text/csv, text/xml, text/json, text/css",
|
|
5
11
|
async add({ file }) {
|
|
6
12
|
return {
|
|
7
13
|
id: generateId(),
|
|
8
|
-
type: "file",
|
|
14
|
+
type: file.type.startsWith("image/") ? "image" : "file",
|
|
9
15
|
name: file.name,
|
|
10
16
|
file,
|
|
11
17
|
contentType: file.type,
|
|
@@ -17,7 +23,14 @@ var vercelAttachmentAdapter = {
|
|
|
17
23
|
return {
|
|
18
24
|
...attachment,
|
|
19
25
|
status: { type: "complete" },
|
|
20
|
-
content: [
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: "file",
|
|
29
|
+
mimeType: attachment.contentType,
|
|
30
|
+
filename: attachment.name,
|
|
31
|
+
data: await getFileDataURL(attachment.file)
|
|
32
|
+
}
|
|
33
|
+
]
|
|
21
34
|
};
|
|
22
35
|
},
|
|
23
36
|
async remove() {
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/utils/vercelAttachmentAdapter.ts"],"sourcesContent":["import { AttachmentAdapter } from \"@assistant-ui/react\";\nimport { generateId } from \"ai\";\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\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.type.startsWith(\"image/\") ? \"image\" : \"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 type: \"file\",\n mimeType: attachment.contentType,\n filename: attachment.name,\n data: await getFileDataURL(attachment.file),\n },\n ],\n };\n },\n async remove() {\n // noop\n },\n};\n"],"mappings":";AACA,SAAS,kBAAkB;AAE3B,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;AAEI,IAAM,0BAA6C;AAAA,EACxD,QACE;AAAA,EACF,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,WAAO;AAAA,MACL,IAAI,WAAW;AAAA,MACf,MAAM,KAAK,KAAK,WAAW,QAAQ,IAAI,UAAU;AAAA,MACjD,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;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,UAAU,WAAW;AAAA,UACrB,UAAU,WAAW;AAAA,UACrB,MAAM,MAAM,eAAe,WAAW,IAAI;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;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": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"zustand": "^5.0.7"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@assistant-ui/react": "^0.10.
|
|
32
|
+
"@assistant-ui/react": "^0.10.50",
|
|
33
33
|
"@types/react": "*",
|
|
34
34
|
"assistant-cloud": "*",
|
|
35
35
|
"react": "^18 || ^19 || ^19.0.0-rc"
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"eslint-config-next": "15.4.6",
|
|
50
50
|
"react": "19.1.1",
|
|
51
51
|
"tsx": "^4.20.4",
|
|
52
|
-
"@assistant-ui/
|
|
53
|
-
"@assistant-ui/
|
|
52
|
+
"@assistant-ui/react": "0.10.50",
|
|
53
|
+
"@assistant-ui/x-buildutils": "0.0.1"
|
|
54
54
|
},
|
|
55
55
|
"publishConfig": {
|
|
56
56
|
"access": "public",
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
AssistantRuntime,
|
|
9
9
|
ThreadMessage,
|
|
10
10
|
MessageFormatAdapter,
|
|
11
|
+
useRuntimeAdapters,
|
|
11
12
|
} from "@assistant-ui/react";
|
|
12
13
|
import { sliceMessagesUntil } from "../utils/sliceMessagesUntil";
|
|
13
14
|
import { toCreateMessage } from "../utils/toCreateMessage";
|
|
@@ -33,6 +34,7 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
33
34
|
chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,
|
|
34
35
|
adapter: AISDKRuntimeAdapter = {},
|
|
35
36
|
) => {
|
|
37
|
+
const contextAdapters = useRuntimeAdapters();
|
|
36
38
|
const messages = AISDKMessageConverter.useThreadMessages({
|
|
37
39
|
isRunning:
|
|
38
40
|
chatHelpers.status === "submitted" || chatHelpers.status == "streaming",
|
|
@@ -72,7 +74,7 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
72
74
|
),
|
|
73
75
|
onCancel: async () => chatHelpers.stop(),
|
|
74
76
|
onNew: async (message) => {
|
|
75
|
-
const createMessage =
|
|
77
|
+
const createMessage = toCreateMessage<UI_MESSAGE>(message);
|
|
76
78
|
await chatHelpers.sendMessage(createMessage, {
|
|
77
79
|
metadata: message.runConfig,
|
|
78
80
|
});
|
|
@@ -84,7 +86,7 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
84
86
|
);
|
|
85
87
|
chatHelpers.setMessages(newMessages);
|
|
86
88
|
|
|
87
|
-
const createMessage =
|
|
89
|
+
const createMessage = toCreateMessage<UI_MESSAGE>(message);
|
|
88
90
|
await chatHelpers.sendMessage(createMessage, {
|
|
89
91
|
metadata: message.runConfig,
|
|
90
92
|
});
|
|
@@ -104,6 +106,7 @@ export const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
104
106
|
},
|
|
105
107
|
adapters: {
|
|
106
108
|
attachments: vercelAttachmentAdapter,
|
|
109
|
+
...contextAdapters,
|
|
107
110
|
...adapter.adapters,
|
|
108
111
|
},
|
|
109
112
|
isLoading,
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
AssistantRuntime,
|
|
7
7
|
unstable_useCloudThreadListAdapter,
|
|
8
8
|
unstable_useRemoteThreadListRuntime,
|
|
9
|
-
useRuntimeAdapters,
|
|
10
9
|
} from "@assistant-ui/react";
|
|
11
10
|
import { useAISDKRuntime, type AISDKRuntimeAdapter } from "./useAISDKRuntime";
|
|
12
11
|
import { ChatInit } from "ai";
|
|
@@ -28,9 +27,6 @@ export const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
28
27
|
} = options ?? {};
|
|
29
28
|
const transport = transportOptions ?? new AssistantChatTransport();
|
|
30
29
|
|
|
31
|
-
// Get adapters from context (including history adapter from cloud)
|
|
32
|
-
const contextAdapters = useRuntimeAdapters();
|
|
33
|
-
|
|
34
30
|
const chat = useChat({
|
|
35
31
|
...chatOptions,
|
|
36
32
|
transport,
|
|
@@ -64,10 +60,7 @@ export const useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
64
60
|
});
|
|
65
61
|
|
|
66
62
|
const runtime = useAISDKRuntime(chat as any, {
|
|
67
|
-
adapters
|
|
68
|
-
...contextAdapters,
|
|
69
|
-
...adapters,
|
|
70
|
-
},
|
|
63
|
+
adapters,
|
|
71
64
|
});
|
|
72
65
|
if (transport instanceof AssistantChatTransport) {
|
|
73
66
|
transport.setRuntime(runtime);
|
|
@@ -97,7 +97,7 @@ export const useExternalHistory = <TMessage,>(
|
|
|
97
97
|
message.status.type === "complete" ||
|
|
98
98
|
message.status.type === "incomplete"
|
|
99
99
|
) {
|
|
100
|
-
if (historyIds.current.has(message.id))
|
|
100
|
+
if (historyIds.current.has(message.id)) continue;
|
|
101
101
|
historyIds.current.add(message.id);
|
|
102
102
|
|
|
103
103
|
const parentId = i > 0 ? messages[i - 1]!.id : null;
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
type ToolCallMessagePart,
|
|
6
6
|
type TextMessagePart,
|
|
7
7
|
type SourceMessagePart,
|
|
8
|
-
type FileMessagePart,
|
|
9
8
|
} from "@assistant-ui/react";
|
|
10
9
|
|
|
11
10
|
const convertParts = (message: UIMessage) => {
|
|
@@ -14,7 +13,7 @@ const convertParts = (message: UIMessage) => {
|
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
return message.parts
|
|
17
|
-
.filter((p) => p.type !== "step-start")
|
|
16
|
+
.filter((p) => p.type !== "step-start" && p.type !== "file")
|
|
18
17
|
.map((part) => {
|
|
19
18
|
const type = part.type;
|
|
20
19
|
|
|
@@ -123,15 +122,6 @@ const convertParts = (message: UIMessage) => {
|
|
|
123
122
|
return null;
|
|
124
123
|
}
|
|
125
124
|
|
|
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
125
|
// Handle data-* parts (AI SDK v5 data parts)
|
|
136
126
|
if (type.startsWith("data-")) {
|
|
137
127
|
// For now, we'll skip data parts as they don't have a direct equivalent
|
|
@@ -162,15 +152,30 @@ export const AISDKMessageConverter = unstable_createMessageConverter(
|
|
|
162
152
|
createdAt,
|
|
163
153
|
content: convertParts(message),
|
|
164
154
|
attachments: message.parts
|
|
165
|
-
?.filter((p
|
|
166
|
-
.map((part
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
155
|
+
?.filter((p) => p.type === "file")
|
|
156
|
+
.map((part, idx) => {
|
|
157
|
+
return {
|
|
158
|
+
id: idx.toString(),
|
|
159
|
+
type: part.mediaType.startsWith("image/") ? "image" : "file",
|
|
160
|
+
name: part.filename ?? "file",
|
|
161
|
+
content: [
|
|
162
|
+
part.mediaType.startsWith("image/")
|
|
163
|
+
? {
|
|
164
|
+
type: "image",
|
|
165
|
+
image: part.url,
|
|
166
|
+
filename: part.filename!,
|
|
167
|
+
}
|
|
168
|
+
: {
|
|
169
|
+
type: "file",
|
|
170
|
+
filename: part.filename!,
|
|
171
|
+
data: part.url,
|
|
172
|
+
mimeType: part.mediaType,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
contentType: part.mediaType ?? "unknown/unknown",
|
|
176
|
+
status: { type: "complete" as const },
|
|
177
|
+
};
|
|
178
|
+
}),
|
|
174
179
|
};
|
|
175
180
|
|
|
176
181
|
case "system":
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { AppendMessage } from "@assistant-ui/react";
|
|
2
2
|
import {
|
|
3
3
|
CreateUIMessage,
|
|
4
|
-
FileUIPart,
|
|
5
4
|
generateId,
|
|
6
5
|
UIDataTypes,
|
|
7
6
|
UIMessage,
|
|
@@ -9,49 +8,44 @@ import {
|
|
|
9
8
|
UITools,
|
|
10
9
|
} from "ai";
|
|
11
10
|
|
|
12
|
-
export const toCreateMessage =
|
|
11
|
+
export const toCreateMessage = <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
13
12
|
message: AppendMessage,
|
|
14
|
-
):
|
|
15
|
-
const
|
|
16
|
-
.filter((
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
text: textParts,
|
|
24
|
-
},
|
|
13
|
+
): CreateUIMessage<UI_MESSAGE> => {
|
|
14
|
+
const inputParts = [
|
|
15
|
+
...message.content.filter((c) => c.type !== "file"),
|
|
16
|
+
...(message.attachments?.flatMap((a) =>
|
|
17
|
+
a.content.map((c) => ({
|
|
18
|
+
...c,
|
|
19
|
+
filename: a.name,
|
|
20
|
+
})),
|
|
21
|
+
) ?? []),
|
|
25
22
|
];
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
const parts = inputParts.map((part): UIMessagePart<UIDataTypes, UITools> => {
|
|
25
|
+
switch (part.type) {
|
|
26
|
+
case "text":
|
|
27
|
+
return {
|
|
28
|
+
type: "text",
|
|
29
|
+
text: part.text,
|
|
30
|
+
};
|
|
31
|
+
case "image":
|
|
32
|
+
return {
|
|
33
33
|
type: "file",
|
|
34
|
-
mediaType: "image/png", // Default to PNG, could be made more dynamic
|
|
35
34
|
url: part.image,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
} satisfies FileUIPart;
|
|
51
|
-
}),
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
parts.push(...attachmentParts);
|
|
35
|
+
...(part.filename && { filename: part.filename }),
|
|
36
|
+
mediaType: "image/png",
|
|
37
|
+
};
|
|
38
|
+
case "file":
|
|
39
|
+
return {
|
|
40
|
+
type: "file",
|
|
41
|
+
url: part.data,
|
|
42
|
+
mediaType: part.mimeType,
|
|
43
|
+
...(part.filename && { filename: part.filename }),
|
|
44
|
+
};
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Unsupported part type: ${part.type}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
55
49
|
|
|
56
50
|
return {
|
|
57
51
|
id: generateId(),
|
|
@@ -59,13 +53,3 @@ export const toCreateMessage = async <UI_MESSAGE extends UIMessage = UIMessage>(
|
|
|
59
53
|
parts,
|
|
60
54
|
} satisfies CreateUIMessage<UIMessage> as CreateUIMessage<UI_MESSAGE>;
|
|
61
55
|
};
|
|
62
|
-
|
|
63
|
-
const getFileDataURL = (file: File) =>
|
|
64
|
-
new Promise<string>((resolve, reject) => {
|
|
65
|
-
const reader = new FileReader();
|
|
66
|
-
|
|
67
|
-
reader.onload = () => resolve(reader.result as string);
|
|
68
|
-
reader.onerror = (error) => reject(error);
|
|
69
|
-
|
|
70
|
-
reader.readAsDataURL(file);
|
|
71
|
-
});
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { AttachmentAdapter } from "@assistant-ui/react";
|
|
2
2
|
import { generateId } from "ai";
|
|
3
3
|
|
|
4
|
+
const getFileDataURL = (file: File) =>
|
|
5
|
+
new Promise<string>((resolve, reject) => {
|
|
6
|
+
const reader = new FileReader();
|
|
7
|
+
|
|
8
|
+
reader.onload = () => resolve(reader.result as string);
|
|
9
|
+
reader.onerror = (error) => reject(error);
|
|
10
|
+
|
|
11
|
+
reader.readAsDataURL(file);
|
|
12
|
+
});
|
|
13
|
+
|
|
4
14
|
export const vercelAttachmentAdapter: AttachmentAdapter = {
|
|
5
15
|
accept:
|
|
6
16
|
"image/*, text/plain, text/html, text/markdown, text/csv, text/xml, text/json, text/css",
|
|
7
17
|
async add({ file }) {
|
|
8
18
|
return {
|
|
9
19
|
id: generateId(),
|
|
10
|
-
type: "file",
|
|
20
|
+
type: file.type.startsWith("image/") ? "image" : "file",
|
|
11
21
|
name: file.name,
|
|
12
22
|
file,
|
|
13
23
|
contentType: file.type,
|
|
@@ -20,7 +30,14 @@ export const vercelAttachmentAdapter: AttachmentAdapter = {
|
|
|
20
30
|
return {
|
|
21
31
|
...attachment,
|
|
22
32
|
status: { type: "complete" },
|
|
23
|
-
content: [
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "file",
|
|
36
|
+
mimeType: attachment.contentType,
|
|
37
|
+
filename: attachment.name,
|
|
38
|
+
data: await getFileDataURL(attachment.file),
|
|
39
|
+
},
|
|
40
|
+
],
|
|
24
41
|
};
|
|
25
42
|
},
|
|
26
43
|
async remove() {
|